2 // Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <boost/cstdint.hpp>
22 #include <boost/shared_ptr.hpp>
23 #include <boost/scoped_ptr.hpp>
27 #include "SimpleBuffer.h"
30 #define RTMP_DEFAULT_CHUNKSIZE 128
32 // Forward declarations.
43 /// Known control / ping codes
45 /// See http://jira.red5.org/confluence/display/docs/Ping (may not exist).
47 /// 0x00: Clear the stream. No third and fourth parameters. The second
48 /// parameter could be 0. After the connection is established, a
49 /// Ping 0,0 will be sent from server to client. The message will
50 /// also be sent to client on the start of Play and in response of
51 /// a Seek or Pause/Resume request. This Ping tells client to
52 /// re-calibrate the clock with the timestamp of the next packet
54 /// 0x01: Tell the stream to clear the playing buffer.
55 /// 0x02: Stream dry (not sure what this means!)
56 /// 0x03: Buffer time of the client. The third parameter is the buffer
57 /// time in milliseconds.
58 /// 0x04: Reset a stream. Used together with type 0 in the case of VOD.
59 /// Often sent before type 0.
60 /// 0x06: Ping the client from server. The second parameter is the current
62 /// 0x07: Pong reply from client. The second parameter is the time the
63 /// server sent with his ping request.
64 /// 0x1a: SWFVerification request
65 /// 0x1b: SWFVerification response
66 /// 0x1f: Not sure, maybe buffer empty.
67 /// 0x20: Buffer ready.
70 CONTROL_CLEAR_STREAM
= 0x00,
71 CONTROL_CLEAR_BUFFER
= 0x01,
72 CONTROL_STREAM_DRY
= 0x02,
73 CONTROL_BUFFER_TIME
= 0x03,
74 CONTROL_RESET_STREAM
= 0x04,
77 CONTROL_REQUEST_VERIFY
= 0x1a,
78 CONTROL_RESPOND_VERIFY
= 0x1b,
79 CONTROL_BUFFER_EMPTY
= 0x1f,
80 CONTROL_BUFFER_READY
= 0x20
83 /// The known channels.
85 /// CHANNEL_CONTROL1 is for internal controls:
88 /// send bytes received.
90 /// These contain no AMF data.
92 /// CHANNEL_CONTROL2 is for ActionScript controls
95 /// connect: Maybe from ASNative(2100, 0) (connect)
97 /// deleteStream: Maybe ASNative(2100, 1) (close)
98 /// FCSubscribe: Don't know.
100 /// These all contain AMF data.
103 CHANNEL_CONTROL1
= 0x02,
104 CHANNEL_CONTROL2
= 0x03,
108 /// The known packet types.
111 PACKET_TYPE_NONE
= 0x00,
112 PACKET_TYPE_CHUNK_SIZE
= 0x01,
113 PACKET_TYPE_BYTES_READ
= 0x03,
114 PACKET_TYPE_CONTROL
= 0x04,
115 PACKET_TYPE_SERVERBW
= 0x05,
116 PACKET_TYPE_CLIENTBW
= 0x06,
117 PACKET_TYPE_AUDIO
= 0x08,
118 PACKET_TYPE_VIDEO
= 0x09,
119 PACKET_TYPE_FLEX_STREAM_SEND
= 0x0f,
120 PACKET_TYPE_FLEX_SHARED_OBJECT
= 0x10,
121 PACKET_TYPE_FLEX_MESSAGE
= 0x11,
122 PACKET_TYPE_METADATA
= 0x12,
123 PACKET_TYPE_SHARED_OBJECT
= 0x13,
124 PACKET_TYPE_INVOKE
= 0x14,
125 PACKET_TYPE_FLV
= 0x16
128 /// The PacketSize specifies the number of fields contained in the header.
130 /// 1. A large packet has all header fields.
131 /// We would expect the first packet on any channel to be large.
132 /// 2. A medium packet has the same m_nInfoField2 and packet type.
133 /// 3. A small packet has the same data size.
134 /// 4. A minimal packet has all fields the same.
136 /// The minimal and small data packets can be used to send a payload in more
137 /// than one packet. If the data received is smaller than the specified data
138 /// size, the packet remains in the channel with its payload. Data from each
139 /// new packet is added to this stored payload until all the advertised data
142 /// These names are taken from rtmpdump.
144 RTMP_PACKET_SIZE_LARGE
= 0,
145 RTMP_PACKET_SIZE_MEDIUM
= 1,
146 RTMP_PACKET_SIZE_SMALL
= 2,
147 RTMP_PACKET_SIZE_MINIMUM
= 3
150 /// The RTMPHeader contains all the fields for the packet header.
153 /// The maximum header size of an RTMP packet.
154 static const size_t headerSize
= 18;
158 headerType(RTMP_PACKET_SIZE_LARGE
),
159 packetType(PACKET_TYPE_NONE
),
166 PacketSize headerType
;
167 PacketType packetType
;
171 /// This is encoded either as in the 3-byte relative timestamp field or the
172 /// 4 byte extended (absolute) timestamp field.
173 boost::uint32_t _timestamp
;
175 /// This seems to be used for NetStream.play.
176 boost::uint32_t _streamID
;
180 // The size of the data.
185 /// An RTMPPacket class contains a full description of an RTMP packet.
188 /// header information
191 /// An RTMPPacket may be copied without a large penalty. This is to allow
192 /// storage in the RTMP client's channels.
195 /// Construct a packet with an optional reserved memory allocation.
197 /// @param reserve The amount of space in bytes to reserve for the
198 /// message body. This can save reallocations when
199 /// appending AMF data. Space for the header is
200 /// always reserved and is not affected by this
202 explicit RTMPPacket(size_t reserve
= 0);
204 /// Copy constructor.
206 /// Creates an identical RTMPPacket with shared ownership of the
208 RTMPPacket(const RTMPPacket
& other
);
214 /// A buffer with enough storage to write the entire message.
216 /// This always includes at least the header. Storage for the message
217 /// payload is added as necessary.
218 boost::shared_ptr
<SimpleBuffer
> buffer
;
224 /// Check whether an RTMPPacket has a payload.
226 /// Only stored packets may not have a payload. A packet without a payload
227 /// has already been processed and is only used for its header information.
229 hasPayload(const RTMPPacket
& p
)
231 return (p
.buffer
.get());
234 /// Clear the message body and the bytes read of an RTMPPacket.
236 /// This is to be used to free used information from packets in a channel.
237 /// The header information must be preserved for future packets, but the
238 /// payload is no longer needed once read.
240 clearPayload(RTMPPacket
& p
)
246 /// The current size of the space allocated for the message payload.
248 /// For messages we create, this matches the exact size of the payload. For
249 /// messages we read, this is the expected size of the data.
251 payloadSize(const RTMPPacket
& p
)
253 assert(hasPayload(p
));
254 const SimpleBuffer
& buf
= *p
.buffer
;
255 assert(buf
.size() >= RTMPHeader::headerSize
);
256 return buf
.size() - RTMPHeader::headerSize
;
259 /// Access the payload data section of the buffer.
260 inline boost::uint8_t*
261 payloadData(RTMPPacket
& p
)
263 assert(hasPayload(p
));
264 SimpleBuffer
& buf
= *p
.buffer
;
265 return buf
.data() + RTMPHeader::headerSize
;
268 /// Access the payload data section of the buffer.
269 inline const boost::uint8_t*
270 payloadData(const RTMPPacket
& p
)
272 assert(hasPayload(p
));
273 const SimpleBuffer
& buf
= *p
.buffer
;
274 return buf
.data() + RTMPHeader::headerSize
;
277 /// Get the end of the allocated payload data section of the buffer.
279 /// Note that this is only valid for packets we create, and for packets
280 /// we have fully read. Stored packets that have not yet received all data
281 /// have allocated space that has not yet been written.
282 inline const boost::uint8_t*
283 payloadEnd(const RTMPPacket
& p
)
285 assert(hasPayload(p
));
286 SimpleBuffer
& buf
= *p
.buffer
;
287 return buf
.data() + buf
.size();
290 /// Check if a packet is ready for processing.
292 /// A packet is ready for processing if its payload size matches the data
293 /// size in its header. It may take several successive packets to form a
296 isReady(const RTMPPacket
& p
) {
297 return p
.bytesRead
== p
.header
.dataSize
;
301 /// This class is for handling the RTMP protocol.
303 /// Only the RTMP protocol itself is handled in this class. An RTMP connection
304 /// is valid only when connected() is true.
306 /// An RTMP object may be closed and reconnected. As soon as connect() returns
307 /// true, callers are responsible for calling close().
309 /// RTMP has a set of channels for incoming and outgoing packets. Packets
310 /// are stored here for two reasons:
311 /// 1. The payload size exceeds the chunk size, so a single payload requires
312 /// several complete packets. A packet is not 'ready' unless it has a
313 /// complete payload, or is the packet that completes the payload of
314 /// previous packets.
315 /// 2. Subsequent packets sent on the same channel can be compressed if they
316 /// have the same header information. The stored packet header is used for
317 /// comparison. For this case, the payload is no longer necessary.
319 /// A different case applies to incomplete packets. The payload of a single
320 /// packet (whether the packet is 'ready' or not) is the smaller of (a) the
321 /// advertised data size and (b) the chunk size. Until this much data has
322 /// been read, the packet is incomplete. Whereas Gnash always
323 /// expects a complete header to be available or none at all, the payload
324 /// can be read over several calls to update().
325 struct DSOEXPORT RTMP
328 /// Construct a non-connected RTMP handler.
333 /// Initiate a network connection.
335 /// Note that this only creates the TCP connection and carries out the
336 /// handshake. An active data connection needs an AMF connect request,
337 /// which is not part of the RTMP protocol.
339 /// @return true if the connection attempt starts, otherwise false.
340 /// A return of false means that the RTMP object is in a
341 /// closed state and can be reconnected.
342 bool connect(const URL
& url
);
344 /// This is used for sending call requests from the core.
346 /// These are sent as invoke packets on CHANNEL_CONTROL2. The AMF data
349 /// 2. callback number,
352 void call(const SimpleBuffer
& amf
);
354 /// This is used for sending NetStream requests.
356 /// These include play and pause. They are sent as invoke packets on the
359 /// @param id The stream ID to control. This is encoded in the header,
360 /// not the AMF payload.
361 void play(const SimpleBuffer
& amf
, int id
);
363 /// Instruct server to buffer this much data.
365 /// @param time time in milliseconds.
366 /// @param streamID the ID of the stream to set buffer time on.
367 void setBufferTime(size_t time
, int streamID
);
369 /// Whether we have a basic connection to a server.
371 /// This only means that the handshake is complete and that AMF requests
372 /// can be sent to the server. It does not mean that was can send or
373 /// receive media streams.
375 /// You should ensure that connected() is true before attempting to send
377 bool connected() const {
381 /// Whether the RTMP connection is in error condition.
383 /// This is a fatal error.
388 /// This function handles reading incoming data and filling data queues.
390 /// You should call this function regularly once the initial connection
391 /// has been initiated.
393 /// Its tasks involve:
394 /// 1. completing the handshake
395 /// 2. checking for socket errors
396 /// 3. reading incoming data
397 /// 4. filling data queues.
399 /// None of those things should concern you. Just call the function
400 /// regularly and use connected(), error(), and check the message
404 /// Close the connection.
406 /// A new connection may now be opened.
409 /// Get an AMF message received from the server.
411 /// TODO: this returns the whole RTMP message, which is ugly. And it
412 /// only returns one at time, and can return a null pointer. We need
413 /// a better way to retrieve the messages.
414 boost::shared_ptr
<SimpleBuffer
> getMessage() {
415 if (_messageQueue
.empty()) return boost::shared_ptr
<SimpleBuffer
>();
416 boost::shared_ptr
<SimpleBuffer
> b
= _messageQueue
.front();
417 _messageQueue
.pop_front();
421 /// Get an FLV packet received from the server
423 /// TODO: this returns the whole RTMP message, which is ugly. And it
424 /// only returns one at time, and can return a null pointer. We need
425 /// a better way to retrieve the frames.
426 boost::shared_ptr
<SimpleBuffer
> getFLVFrame() {
427 if (_flvQueue
.empty()) return boost::shared_ptr
<SimpleBuffer
>();
428 boost::shared_ptr
<SimpleBuffer
> b
= _flvQueue
.front();
429 _flvQueue
.pop_front();
433 /// Handle an RTMPPacket.
434 void handlePacket(const RTMPPacket
& packet
);
436 /// Read from the socket.
437 int readSocket(boost::uint8_t* dst
, int num
);
439 /// Send an RTMPPacket on the connection.
440 bool sendPacket(RTMPPacket
& packet
);
442 /// Store the server bandwidth
444 /// Not sure why we need this.
445 void setServerBandwidth(boost::uint32_t bw
) {
446 _serverBandwidth
= bw
;
449 /// Get the stored server bandwidth.
450 boost::uint32_t serverBandwidth() const {
451 return _serverBandwidth
;
454 /// Store our bandwidth
455 void setBandwidth(boost::uint32_t bw
) {
459 /// Get our bandwidth.
460 boost::uint32_t bandwidth() const {
466 boost::uint8_t m_nClientBW2
;
477 /// Read an RTMP packet from the connection.
478 bool readPacketHeader(RTMPPacket
& packet
);
480 bool readPacketPayload(RTMPPacket
& packet
);
482 /// Check whether a packet exists on a channel.
483 bool hasPacket(ChannelType t
, size_t channel
) const;
485 /// Retrieve a stored packet.
487 /// If no packet exists on the channel, a new one will be created and
488 /// returned. Use hasPacket() to check whether a previous packet exists.
489 RTMPPacket
& getPacket(ChannelType t
, size_t channel
);
491 /// Store a packet in a channel.
493 /// A copy of the packet is stored and returned. Any data is shared
494 /// between the copies until explicitly reset.
495 RTMPPacket
& storePacket(ChannelType t
, size_t channel
, const RTMPPacket
& p
);
497 /// A set of channels. An RTMP handler has two sets.
499 /// Packets are stored on these channels. As soon as a packet has been
500 /// processed, its payload is removed. The header remains in memory to
501 /// allow compression of later packets.
503 /// RTMPPackets must be stored with an absolute timestamp.
504 typedef std::map
<size_t, RTMPPacket
> ChannelSet
;
508 /// A set of channels for receiving packets.
509 ChannelSet _inChannels
;
511 /// A set of channels for sending packets.
512 ChannelSet _outChannels
;
514 std::deque
<boost::shared_ptr
<SimpleBuffer
> > _messageQueue
;
515 std::deque
<boost::shared_ptr
<SimpleBuffer
> > _flvQueue
;
517 /// Stored server bandwidth (reported by server).
518 boost::uint32_t _serverBandwidth
;
520 /// Stored client bandwidth (ours), reported by server.
521 boost::uint32_t _bandwidth
;
523 /// Chunk size for sending.
524 size_t _outChunkSize
;
526 boost::scoped_ptr
<HandShaker
> _handShaker
;
532 /// If a packet could not be read in one go, it is stored here.
534 /// This is not the same as a non-ready packet. It applies only to packets
535 /// waiting for payload data.
536 boost::scoped_ptr
<RTMPPacket
> _incompletePacket
;
540 /// Send a bandwidth ping to the server.
541 bool sendServerBW(RTMP
& r
);
543 /// Send a control packet
544 bool sendCtrl(RTMP
& r
, ControlType
, unsigned int nObject
, unsigned int nTime
);
546 /// Logging assistance for PacketType.
547 std::ostream
& operator<<(std::ostream
& o
, PacketType p
);
549 /// Logging assistance for ControlType.
550 std::ostream
& operator<<(std::ostream
& o
, ControlType t
);