Update with current status
[gnash.git] / libbase / RTMP.h
blob0eacf87091099c759e93feb8fce46bda3893d4af
1 //
2 // Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifndef GNASH_RTMP_H
20 #define GNASH_RTMP_H
22 #include <cstdint>
23 #include <memory>
24 #include <deque>
25 #include <map>
27 #include "SimpleBuffer.h"
28 #include "Socket.h"
29 #include "dsodefs.h"
31 #define RTMP_DEFAULT_CHUNKSIZE 128
33 // Forward declarations.
34 namespace gnash {
35 namespace rtmp {
36 class HandShaker;
38 class URL;
41 namespace gnash {
42 namespace rtmp {
44 /// Known control / ping codes
46 /// See http://jira.red5.org/confluence/display/docs/Ping (may not exist).
48 /// 0x00: Clear the stream. No third and fourth parameters. The second
49 /// parameter could be 0. After the connection is established, a
50 /// Ping 0,0 will be sent from server to client. The message will
51 /// also be sent to client on the start of Play and in response of
52 /// a Seek or Pause/Resume request. This Ping tells client to
53 /// re-calibrate the clock with the timestamp of the next packet
54 /// server sends.
55 /// 0x01: Tell the stream to clear the playing buffer.
56 /// 0x02: Stream dry (not sure what this means!)
57 /// 0x03: Buffer time of the client. The third parameter is the buffer
58 /// time in milliseconds.
59 /// 0x04: Reset a stream. Used together with type 0 in the case of VOD.
60 /// Often sent before type 0.
61 /// 0x06: Ping the client from server. The second parameter is the current
62 /// time.
63 /// 0x07: Pong reply from client. The second parameter is the time the
64 /// server sent with his ping request.
65 /// 0x1a: SWFVerification request
66 /// 0x1b: SWFVerification response
67 /// 0x1f: Not sure, maybe buffer empty.
68 /// 0x20: Buffer ready.
69 enum ControlType
71 CONTROL_CLEAR_STREAM = 0x00,
72 CONTROL_CLEAR_BUFFER = 0x01,
73 CONTROL_STREAM_DRY = 0x02,
74 CONTROL_BUFFER_TIME = 0x03,
75 CONTROL_RESET_STREAM = 0x04,
76 CONTROL_PING = 0x06,
77 CONTROL_PONG = 0x07,
78 CONTROL_REQUEST_VERIFY = 0x1a,
79 CONTROL_RESPOND_VERIFY = 0x1b,
80 CONTROL_BUFFER_EMPTY = 0x1f,
81 CONTROL_BUFFER_READY = 0x20
84 /// The known channels.
86 /// CHANNEL_CONTROL1 is for internal controls:
87 /// sendCtrl
88 /// send server BW
89 /// send bytes received.
91 /// These contain no AMF data.
93 /// CHANNEL_CONTROL2 is for ActionScript controls
94 /// _checkbw: AS
95 /// _result:
96 /// connect: Maybe from ASNative(2100, 0) (connect)
97 /// createStream: AS
98 /// deleteStream: Maybe ASNative(2100, 1) (close)
99 /// FCSubscribe: Don't know.
101 /// These all contain AMF data.
102 enum Channels
104 CHANNEL_CONTROL1 = 0x02,
105 CHANNEL_CONTROL2 = 0x03,
106 CHANNEL_VIDEO = 0x08
109 /// The known packet types.
110 enum PacketType
112 PACKET_TYPE_NONE = 0x00,
113 PACKET_TYPE_CHUNK_SIZE = 0x01,
114 PACKET_TYPE_BYTES_READ = 0x03,
115 PACKET_TYPE_CONTROL = 0x04,
116 PACKET_TYPE_SERVERBW = 0x05,
117 PACKET_TYPE_CLIENTBW = 0x06,
118 PACKET_TYPE_AUDIO = 0x08,
119 PACKET_TYPE_VIDEO = 0x09,
120 PACKET_TYPE_FLEX_STREAM_SEND = 0x0f,
121 PACKET_TYPE_FLEX_SHARED_OBJECT = 0x10,
122 PACKET_TYPE_FLEX_MESSAGE = 0x11,
123 PACKET_TYPE_METADATA = 0x12,
124 PACKET_TYPE_SHARED_OBJECT = 0x13,
125 PACKET_TYPE_INVOKE = 0x14,
126 PACKET_TYPE_FLV = 0x16
129 /// The PacketSize specifies the number of fields contained in the header.
131 /// 1. A large packet has all header fields.
132 /// We would expect the first packet on any channel to be large.
133 /// 2. A medium packet has the same m_nInfoField2 and packet type.
134 /// 3. A small packet has the same data size.
135 /// 4. A minimal packet has all fields the same.
137 /// The minimal and small data packets can be used to send a payload in more
138 /// than one packet. If the data received is smaller than the specified data
139 /// size, the packet remains in the channel with its payload. Data from each
140 /// new packet is added to this stored payload until all the advertised data
141 /// is read.
143 /// These names are taken from rtmpdump.
144 enum PacketSize {
145 RTMP_PACKET_SIZE_LARGE = 0,
146 RTMP_PACKET_SIZE_MEDIUM = 1,
147 RTMP_PACKET_SIZE_SMALL = 2,
148 RTMP_PACKET_SIZE_MINIMUM = 3
151 /// The RTMPHeader contains all the fields for the packet header.
152 struct RTMPHeader
154 /// The maximum header size of an RTMP packet.
155 static const size_t headerSize = 18;
157 RTMPHeader()
159 headerType(RTMP_PACKET_SIZE_LARGE),
160 packetType(PACKET_TYPE_NONE),
161 _timestamp(0),
162 _streamID(0),
163 channel(0),
164 dataSize(0)
167 PacketSize headerType;
168 PacketType packetType;
170 /// The timestamp.
172 /// This is encoded either as in the 3-byte relative timestamp field or the
173 /// 4 byte extended (absolute) timestamp field.
174 std::uint32_t _timestamp;
176 /// This seems to be used for NetStream.play.
177 std::uint32_t _streamID;
179 size_t channel;
181 // The size of the data.
182 size_t dataSize;
186 /// An RTMPPacket class contains a full description of an RTMP packet.
188 /// This comprises:
189 /// header information
190 /// an AMF payload.
192 /// An RTMPPacket may be copied without a large penalty. This is to allow
193 /// storage in the RTMP client's channels.
194 struct RTMPPacket
196 /// Construct a packet with an optional reserved memory allocation.
198 /// @param reserve The amount of space in bytes to reserve for the
199 /// message body. This can save reallocations when
200 /// appending AMF data. Space for the header is
201 /// always reserved and is not affected by this
202 /// parameter.
203 explicit RTMPPacket(size_t reserve = 0);
205 /// Copy constructor.
207 /// Creates an identical RTMPPacket with shared ownership of the
208 /// buffer.
209 RTMPPacket(const RTMPPacket& other);
211 ~RTMPPacket() {}
213 RTMPHeader header;
215 /// A buffer with enough storage to write the entire message.
217 /// This always includes at least the header. Storage for the message
218 /// payload is added as necessary.
219 std::shared_ptr<SimpleBuffer> buffer;
221 size_t bytesRead;
225 /// Check whether an RTMPPacket has a payload.
227 /// Only stored packets may not have a payload. A packet without a payload
228 /// has already been processed and is only used for its header information.
229 inline bool
230 hasPayload(const RTMPPacket& p)
232 return (p.buffer.get());
235 /// Clear the message body and the bytes read of an RTMPPacket.
237 /// This is to be used to free used information from packets in a channel.
238 /// The header information must be preserved for future packets, but the
239 /// payload is no longer needed once read.
240 inline void
241 clearPayload(RTMPPacket& p)
243 p.buffer.reset();
244 p.bytesRead = 0;
247 /// The current size of the space allocated for the message payload.
249 /// For messages we create, this matches the exact size of the payload. For
250 /// messages we read, this is the expected size of the data.
251 inline size_t
252 payloadSize(const RTMPPacket& p)
254 assert(hasPayload(p));
255 const SimpleBuffer& buf = *p.buffer;
256 assert(buf.size() >= RTMPHeader::headerSize);
257 return buf.size() - RTMPHeader::headerSize;
260 /// Access the payload data section of the buffer.
261 inline std::uint8_t*
262 payloadData(RTMPPacket& p)
264 assert(hasPayload(p));
265 SimpleBuffer& buf = *p.buffer;
266 return buf.data() + RTMPHeader::headerSize;
269 /// Access the payload data section of the buffer.
270 inline const std::uint8_t*
271 payloadData(const RTMPPacket& p)
273 assert(hasPayload(p));
274 const SimpleBuffer& buf = *p.buffer;
275 return buf.data() + RTMPHeader::headerSize;
278 /// Get the end of the allocated payload data section of the buffer.
280 /// Note that this is only valid for packets we create, and for packets
281 /// we have fully read. Stored packets that have not yet received all data
282 /// have allocated space that has not yet been written.
283 inline const std::uint8_t*
284 payloadEnd(const RTMPPacket& p)
286 assert(hasPayload(p));
287 SimpleBuffer& buf = *p.buffer;
288 return buf.data() + buf.size();
291 /// Check if a packet is ready for processing.
293 /// A packet is ready for processing if its payload size matches the data
294 /// size in its header. It may take several successive packets to form a
295 /// complete packet.
296 inline bool
297 isReady(const RTMPPacket& p) {
298 return p.bytesRead == p.header.dataSize;
302 /// This class is for handling the RTMP protocol.
304 /// Only the RTMP protocol itself is handled in this class. An RTMP connection
305 /// is valid only when connected() is true.
307 /// An RTMP object may be closed and reconnected. As soon as connect() returns
308 /// true, callers are responsible for calling close().
310 /// RTMP has a set of channels for incoming and outgoing packets. Packets
311 /// are stored here for two reasons:
312 /// 1. The payload size exceeds the chunk size, so a single payload requires
313 /// several complete packets. A packet is not 'ready' unless it has a
314 /// complete payload, or is the packet that completes the payload of
315 /// previous packets.
316 /// 2. Subsequent packets sent on the same channel can be compressed if they
317 /// have the same header information. The stored packet header is used for
318 /// comparison. For this case, the payload is no longer necessary.
320 /// A different case applies to incomplete packets. The payload of a single
321 /// packet (whether the packet is 'ready' or not) is the smaller of (a) the
322 /// advertised data size and (b) the chunk size. Until this much data has
323 /// been read, the packet is incomplete. Whereas Gnash always
324 /// expects a complete header to be available or none at all, the payload
325 /// can be read over several calls to update().
326 struct DSOEXPORT RTMP
329 /// Construct a non-connected RTMP handler.
330 RTMP();
332 ~RTMP();
334 /// Initiate a network connection.
336 /// Note that this only creates the TCP connection and carries out the
337 /// handshake. An active data connection needs an AMF connect request,
338 /// which is not part of the RTMP protocol.
340 /// @return true if the connection attempt starts, otherwise false.
341 /// A return of false means that the RTMP object is in a
342 /// closed state and can be reconnected.
343 bool connect(const URL& url);
345 /// This is used for sending call requests from the core.
347 /// These are sent as invoke packets on CHANNEL_CONTROL2. The AMF data
348 /// should contain:
349 /// 1. method name,
350 /// 2. callback number,
351 /// 3. null,
352 /// 4. arg0..argn
353 void call(const SimpleBuffer& amf);
355 /// This is used for sending NetStream requests.
357 /// These include play and pause. They are sent as invoke packets on the
358 /// video channel.
360 /// @param id The stream ID to control. This is encoded in the header,
361 /// not the AMF payload.
362 void play(const SimpleBuffer& amf, int id);
364 /// Instruct server to buffer this much data.
366 /// @param time time in milliseconds.
367 /// @param streamID the ID of the stream to set buffer time on.
368 void setBufferTime(size_t time, int streamID);
370 /// Whether we have a basic connection to a server.
372 /// This only means that the handshake is complete and that AMF requests
373 /// can be sent to the server. It does not mean that was can send or
374 /// receive media streams.
376 /// You should ensure that connected() is true before attempting to send
377 /// or receive data.
378 bool connected() const {
379 return _connected;
382 /// Whether the RTMP connection is in error condition.
384 /// This is a fatal error.
385 bool error() const {
386 return _error;
389 /// This function handles reading incoming data and filling data queues.
391 /// You should call this function regularly once the initial connection
392 /// has been initiated.
394 /// Its tasks involve:
395 /// 1. completing the handshake
396 /// 2. checking for socket errors
397 /// 3. reading incoming data
398 /// 4. filling data queues.
400 /// None of those things should concern you. Just call the function
401 /// regularly and use connected(), error(), and check the message
402 /// queues.
403 void update();
405 /// Close the connection.
407 /// A new connection may now be opened.
408 void close();
410 /// Get an AMF message received from the server.
412 /// TODO: this returns the whole RTMP message, which is ugly. And it
413 /// only returns one at time, and can return a null pointer. We need
414 /// a better way to retrieve the messages.
415 std::shared_ptr<SimpleBuffer> getMessage() {
416 if (_messageQueue.empty()) return std::shared_ptr<SimpleBuffer>();
417 std::shared_ptr<SimpleBuffer> b = _messageQueue.front();
418 _messageQueue.pop_front();
419 return b;
422 /// Get an FLV packet received from the server
424 /// TODO: this returns the whole RTMP message, which is ugly. And it
425 /// only returns one at time, and can return a null pointer. We need
426 /// a better way to retrieve the frames.
427 std::shared_ptr<SimpleBuffer> getFLVFrame() {
428 if (_flvQueue.empty()) return std::shared_ptr<SimpleBuffer>();
429 std::shared_ptr<SimpleBuffer> b = _flvQueue.front();
430 _flvQueue.pop_front();
431 return b;
434 /// Handle an RTMPPacket.
435 void handlePacket(const RTMPPacket& packet);
437 /// Read from the socket.
438 int readSocket(std::uint8_t* dst, int num);
440 /// Send an RTMPPacket on the connection.
441 bool sendPacket(RTMPPacket& packet);
443 /// Store the server bandwidth
445 /// Not sure why we need this.
446 void setServerBandwidth(std::uint32_t bw) {
447 _serverBandwidth = bw;
450 /// Get the stored server bandwidth.
451 std::uint32_t serverBandwidth() const {
452 return _serverBandwidth;
455 /// Store our bandwidth
456 void setBandwidth(std::uint32_t bw) {
457 _bandwidth = bw;
460 /// Get our bandwidth.
461 std::uint32_t bandwidth() const {
462 return _bandwidth;
465 int _inChunkSize;
466 int m_mediaChannel;
467 std::uint8_t m_nClientBW2;
468 size_t _bytesIn;
469 size_t _bytesInSent;
471 private:
473 enum ChannelType {
474 CHANNELS_IN,
475 CHANNELS_OUT
478 /// Read an RTMP packet from the connection.
479 bool readPacketHeader(RTMPPacket& packet);
481 bool readPacketPayload(RTMPPacket& packet);
483 /// Check whether a packet exists on a channel.
484 bool hasPacket(ChannelType t, size_t channel) const;
486 /// Retrieve a stored packet.
488 /// If no packet exists on the channel, a new one will be created and
489 /// returned. Use hasPacket() to check whether a previous packet exists.
490 RTMPPacket& getPacket(ChannelType t, size_t channel);
492 /// Store a packet in a channel.
494 /// A copy of the packet is stored and returned. Any data is shared
495 /// between the copies until explicitly reset.
496 RTMPPacket& storePacket(ChannelType t, size_t channel, const RTMPPacket& p);
498 /// A set of channels. An RTMP handler has two sets.
500 /// Packets are stored on these channels. As soon as a packet has been
501 /// processed, its payload is removed. The header remains in memory to
502 /// allow compression of later packets.
504 /// RTMPPackets must be stored with an absolute timestamp.
505 typedef std::map<size_t, RTMPPacket> ChannelSet;
507 Socket _socket;
509 /// A set of channels for receiving packets.
510 ChannelSet _inChannels;
512 /// A set of channels for sending packets.
513 ChannelSet _outChannels;
515 std::deque<std::shared_ptr<SimpleBuffer> > _messageQueue;
516 std::deque<std::shared_ptr<SimpleBuffer> > _flvQueue;
518 /// Stored server bandwidth (reported by server).
519 std::uint32_t _serverBandwidth;
521 /// Stored client bandwidth (ours), reported by server.
522 std::uint32_t _bandwidth;
524 /// Chunk size for sending.
525 size_t _outChunkSize;
527 std::unique_ptr<HandShaker> _handShaker;
529 bool _connected;
531 bool _error;
533 /// If a packet could not be read in one go, it is stored here.
535 /// This is not the same as a non-ready packet. It applies only to packets
536 /// waiting for payload data.
537 std::unique_ptr<RTMPPacket> _incompletePacket;
541 /// Send a bandwidth ping to the server.
542 DSOEXPORT bool sendServerBW(RTMP& r);
544 /// Send a control packet
545 bool sendCtrl(RTMP& r, ControlType, unsigned int nObject, unsigned int nTime);
547 /// Logging assistance for PacketType.
548 std::ostream& operator<<(std::ostream& o, PacketType p);
550 /// Logging assistance for ControlType.
551 std::ostream& operator<<(std::ostream& o, ControlType t);
553 } // namespace rtmp
555 } // namespace gnash
556 #endif