update copyright date
[gnash.git] / libbase / RTMP.h
blob9d33d670e6a712aa5dc3003b099797f3e1b4cb48
1 //
2 // Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
3 //
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.
8 //
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
18 #ifndef GNASH_RTMP_H
19 #define GNASH_RTMP_H
21 #include <boost/cstdint.hpp>
22 #include <boost/shared_ptr.hpp>
23 #include <boost/scoped_ptr.hpp>
24 #include <deque>
25 #include <map>
27 #include "SimpleBuffer.h"
28 #include "Socket.h"
30 #define RTMP_DEFAULT_CHUNKSIZE 128
32 // Forward declarations.
33 namespace gnash {
34 namespace rtmp {
35 class HandShaker;
37 class URL;
40 namespace gnash {
41 namespace rtmp {
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
53 /// server sends.
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
61 /// time.
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.
68 enum ControlType
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,
75 CONTROL_PING = 0x06,
76 CONTROL_PONG = 0x07,
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:
86 /// sendCtrl
87 /// send server BW
88 /// send bytes received.
90 /// These contain no AMF data.
92 /// CHANNEL_CONTROL2 is for ActionScript controls
93 /// _checkbw: AS
94 /// _result:
95 /// connect: Maybe from ASNative(2100, 0) (connect)
96 /// createStream: AS
97 /// deleteStream: Maybe ASNative(2100, 1) (close)
98 /// FCSubscribe: Don't know.
100 /// These all contain AMF data.
101 enum Channels
103 CHANNEL_CONTROL1 = 0x02,
104 CHANNEL_CONTROL2 = 0x03,
105 CHANNEL_VIDEO = 0x08
108 /// The known packet types.
109 enum PacketType
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
140 /// is read.
142 /// These names are taken from rtmpdump.
143 enum PacketSize {
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.
151 struct RTMPHeader
153 /// The maximum header size of an RTMP packet.
154 static const size_t headerSize = 18;
156 RTMPHeader()
158 headerType(RTMP_PACKET_SIZE_LARGE),
159 packetType(PACKET_TYPE_NONE),
160 _timestamp(0),
161 _streamID(0),
162 channel(0),
163 dataSize(0)
166 PacketSize headerType;
167 PacketType packetType;
169 /// The timestamp.
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;
178 size_t channel;
180 // The size of the data.
181 size_t dataSize;
185 /// An RTMPPacket class contains a full description of an RTMP packet.
187 /// This comprises:
188 /// header information
189 /// an AMF payload.
191 /// An RTMPPacket may be copied without a large penalty. This is to allow
192 /// storage in the RTMP client's channels.
193 struct RTMPPacket
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
201 /// parameter.
202 explicit RTMPPacket(size_t reserve = 0);
204 /// Copy constructor.
206 /// Creates an identical RTMPPacket with shared ownership of the
207 /// buffer.
208 RTMPPacket(const RTMPPacket& other);
210 ~RTMPPacket() {}
212 RTMPHeader header;
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;
220 size_t bytesRead;
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.
228 inline bool
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.
239 inline void
240 clearPayload(RTMPPacket& p)
242 p.buffer.reset();
243 p.bytesRead = 0;
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.
250 inline size_t
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
294 /// complete packet.
295 inline bool
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.
329 RTMP();
331 ~RTMP();
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
347 /// should contain:
348 /// 1. method name,
349 /// 2. callback number,
350 /// 3. null,
351 /// 4. arg0..argn
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
357 /// video channel.
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
376 /// or receive data.
377 bool connected() const {
378 return _connected;
381 /// Whether the RTMP connection is in error condition.
383 /// This is a fatal error.
384 bool error() const {
385 return _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
401 /// queues.
402 void update();
404 /// Close the connection.
406 /// A new connection may now be opened.
407 void close();
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();
418 return b;
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();
430 return b;
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) {
456 _bandwidth = bw;
459 /// Get our bandwidth.
460 boost::uint32_t bandwidth() const {
461 return _bandwidth;
464 int _inChunkSize;
465 int m_mediaChannel;
466 boost::uint8_t m_nClientBW2;
467 size_t _bytesIn;
468 size_t _bytesInSent;
470 private:
472 enum ChannelType {
473 CHANNELS_IN,
474 CHANNELS_OUT
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;
506 Socket _socket;
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;
528 bool _connected;
530 bool _error;
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);
552 } // namespace rtmp
554 } // namespace gnash
555 #endif