gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] /srv/bzr/gnash/rtmp r9606: add support for decoding multi


From: rob
Subject: [Gnash-commit] /srv/bzr/gnash/rtmp r9606: add support for decoding multiple RTMP messages.
Date: Wed, 27 Aug 2008 19:24:04 -0600
User-agent: Bazaar (1.5)

------------------------------------------------------------
revno: 9606
committer: address@hidden
branch nick: rtmp
timestamp: Wed 2008-08-27 19:24:04 -0600
message:
  add support for decoding multiple RTMP messages.
modified:
  libnet/rtmp.cpp
  libnet/rtmp.h
=== modified file 'libnet/rtmp.cpp'
--- a/libnet/rtmp.cpp   2008-08-26 22:49:14 +0000
+++ b/libnet/rtmp.cpp   2008-08-28 01:24:04 +0000
@@ -21,10 +21,10 @@
 #include "gnashconfig.h"
 #endif
 
-#include <boost/detail/endian.hpp>
 #include <iostream>
 #include <string>
 #include <map>
+#include <vector>
 
 #if ! (defined(_WIN32) || defined(WIN32))
 #      include <netinet/in.h>
@@ -33,6 +33,7 @@
 #include "log.h"
 #include "amf.h"
 #include "rtmp.h"
+#include "cque.h"
 #include "network.h"
 #include "element.h"
 #include "handler.h"
@@ -46,6 +47,8 @@
 namespace gnash
 {
 
+CQue incoming;
+
 extern map<int, Handler *> handlers;
 
 const char *content_str[] = {
@@ -170,26 +173,28 @@
 }
 
 RTMP::RTMP() 
-    : _handshake(0), _handler(0)
+    : _handshake(0),
+      _handler(0),
+      _chunksize(RTMP_VIDEO_PACKET_SIZE),
+      _timeout(1)
 {
 //    GNASH_REPORT_FUNCTION;
-//     _inbytes = 0;
-//     _outbytes = 0;
-    
-//    _body = new unsigned char(RTMP_BODY_SIZE+1);
-//    memset(_body, 0, RTMP_BODY_SIZE+1);
+//    _queues.resize(MAX_AMF_INDEXES);
+//    for (size_t i=0; i<MAX_AMF_INDEXES; i++) {
+//     string name = "channel #";
+//     for (size_t i=0; i<10; i++) {
+//     name[9] = i+'0';
+//     _queues[i].setName(name.c_str());
+//     }
 }
 
 RTMP::~RTMP()
 {
 //    GNASH_REPORT_FUNCTION;
-    _variables.clear();
-    if (_handshake) {
-       delete _handshake;
-    }
-    if (_handler) {
-       delete _handler;
-    }
+    _properties.clear();
+    delete _handshake;
+    delete _handler;
+    
 //    delete _body;
 }
 
@@ -197,23 +202,23 @@
 RTMP::addProperty(amf::Element *el)
 {
 //    GNASH_REPORT_FUNCTION;
-    _variables[el->getName()] = el;
+    _properties[el->getName()] = el;
 }
 
 void
 RTMP::addProperty(char *name, amf::Element *el)
 { 
 //    GNASH_REPORT_FUNCTION;
-    _variables[name] = el;
+    _properties[name] = el;
 }
 
 amf::Element *
 RTMP::getProperty(const std::string &name)
 {
 //    GNASH_REPORT_FUNCTION;
-//    return _variables[name.c_str()];
+//    return _properties[name.c_str()];
     map<const char *, amf::Element *>::iterator it;
-    for (it = _variables.begin(); it != _variables.end(); it++) {
+    for (it = _properties.begin(); it != _properties.end(); it++) {
        const char *title = it->first;
        amf::Element *el = it->second;
        if (name == title) {
@@ -227,7 +232,7 @@
 RTMP::rtmp_head_t *
 RTMP::decodeHeader(Buffer *buf)
 {
-    GNASH_REPORT_FUNCTION;
+//    GNASH_REPORT_FUNCTION;
     return decodeHeader(buf->reference());
 }
 
@@ -265,15 +270,39 @@
     }
 
     if (_header.head_size >= 8) {
-       char c = *(reinterpret_cast<char *>(tmpptr));
-       _header.type = static_cast<content_types_e>(c);
+       Network::byte_t byte = *tmpptr;
+        _header.type = (content_types_e)byte;
         tmpptr++;
-        log_debug(_("The type is: %s"), content_str[_header.type]);
+       if (_header.type <= RTMP::INVOKE ) {
+           log_debug(_("The type is: %s"), content_str[_header.type]);
+       } else {
+           log_debug(_("The type is: 0x%x"), _header.type);
+       }
     }
+
+//     switch(_header.type) {
+//       case CHUNK_SIZE:
+//       case BYTES_READ:
+//       case PING:
+//       case SERVER:
+//       case CLIENT:
+//       case VIDEO_DATA:
+//       case NOTIFY:
+//       case SHARED_OBJ:
+//       case INVOKE:
+//           _packet_size = RTMP_VIDEO_PACKET_SIZE;
+//           break;
+//       case AUDIO_DATA:
+//           _packet_size = RTMP_AUDIO_PACKET_SIZE;
+//           break;
+//       default:
+//           log_error (_("ERROR: Unidentified AMF header data type 0x%x"), 
_type);
+//           break;
+//     };
     
     if (_header.head_size == 12) {
         _header.src_dest = *(reinterpret_cast<RTMPMsg::rtmp_source_e 
*>(tmpptr));
-        tmpptr += sizeof(boost::uint32_t);
+        tmpptr += sizeof(unsigned int);
         log_debug(_("The source/destination is: %x"), _header.src_dest);
     }
 
@@ -346,13 +375,24 @@
     // Add the size of the message if the header size is 8 or more.
     // and add the type of the object if the header size is 8 or more.
     if ((head_size == HEADER_8) || (head_size == HEADER_12)) {
-// RTMP uses a 3 byte length field, which is the total size of the packet
-       boost::uint32_t length = total_size << 8;
-       swapBytes(&length, 4);
-       memcpy(ptr, &length, 3);
-       ptr += 3;
-       
-       // Add the type
+        int length = total_size;
+       Network::byte_t *lenptr = reinterpret_cast<Network::byte_t *>(&length);
+//#ifndef      BOOST_BIG_ENDIAN
+//     swapBytes(&length, 4);
+       *ptr++ = *(lenptr + 2);
+       *ptr++ = *(lenptr + 1);
+       *ptr++ = *lenptr;       
+//     *(lenptr + 3) = *(lenptr);
+//     memcpy(ptr, lenptr, 3);
+// #else
+// #ifdef BOOST_BIG_ENDIAN
+//     memcpy(ptr, &length, 3);
+// #else
+// #error "No Endianess specified!"
+// #endif
+//#endif
+//      swapBytes(&length, 4);
+//        ptr += 3;
         *ptr = type;
         ptr++;
     }
@@ -377,6 +417,7 @@
     Network::byte_t *tooFar = ptr+buf->size();
     AMF amf;
     
+//    
address@hidden@\000\000\000\000\000\000\003\000\003app\002\000#software/gnash/tests/1153948634.flv\000\bflashVer\002\000\fLNX
 
6,0,82,0\000\006swfUrl\002\000\035file:///file|address@hidden://localhost/software/gnash/tests/1153948634
     amf_index = *buf->reference() & RTMP_INDEX_MASK;
     headersize = headerSize(*buf->reference());
     log_debug (_("The Header size is: %d"), headersize);
@@ -450,9 +491,9 @@
 void
 RTMP::dump()
 {
-    cerr << "RTMP packet contains " << _variables.size() << " variables." << 
endl;
+    cerr << "RTMP packet contains " << _properties.size() << " variables." << 
endl;
     map<const char *, amf::Element *>::iterator it;
-    for (it = _variables.begin(); it != _variables.end(); it++) {
+    for (it = _properties.begin(); it != _properties.end(); it++) {
 //     const char *name = it->first;
        amf::Element *el = it->second;
        el->dump();
@@ -509,7 +550,6 @@
 
     return ping;    
 }
-
 RTMP::rtmp_ping_t *
 RTMP::decodePing(amf::Buffer *buf)
 {
@@ -576,7 +616,11 @@
     // at the minimum.
     Element *streamid = amf_obj.extractAMF(ptr, tooFar);
     if (streamid) {
-       ptr += streamid->getLength() + 2;
+       // Most onStatus messages have the stream ID, but the Data Start 
onStatus
+       // message is basically just a marker that an FLV file is coming next.
+       if (streamid->getType() == Element::NUMBER_AMF0) {
+           ptr += streamid->getLength() + 2;
+       }
     } else {
        log_error("Stream ID field of RTMP Message corrupted!");
        return 0;
@@ -585,12 +629,14 @@
     // This will need to be deleted manually later after usage, it is not
     // automatically deallocated.
     RTMPMsg *msg = new RTMPMsg;
+//    memset(msg, 0, sizeof(RTMPMsg));
 
     msg->setMethodName(name->to_string());
     double swapped = streamid->to_number();
+//     swapBytes(&swapped, amf::AMF0_NUMBER_SIZE);
     msg->setStreamID(swapped);
 
-    if ((msg->getMethodName() == "_result") || (msg->getMethodName() == 
"error")) {
+    if ((msg->getMethodName() == "_result") || (msg->getMethodName() == 
"_error") || (msg->getMethodName() == "onStatus")) {
        status = true;
     }
     
@@ -763,19 +809,19 @@
 // interval. (128 bytes for video data). Each message main contain
 // multiple packets.
 bool
-RTMP::sendMsg(amf::Buffer *buf)
+RTMP::sendMsg(amf::Buffer *data)
 {
     GNASH_REPORT_FUNCTION;
 
     size_t partial = RTMP_VIDEO_PACKET_SIZE;
     size_t nbytes = 0;
     Network::byte_t header = 0xc3;
-
-    while (nbytes <= buf->size()) {
-       if ((buf->size() - nbytes) < static_cast<signed 
int>(RTMP_VIDEO_PACKET_SIZE)) {
-           partial = buf->size() - nbytes;
+    
+    while (nbytes <= data->size()) {
+       if ((data->size() - nbytes) < static_cast<signed 
int>(RTMP_VIDEO_PACKET_SIZE)) {
+           partial = data->size() - nbytes;
        }    
-       writeNet(buf->reference() + nbytes, partial);
+       writeNet(data->reference() + nbytes, partial);
        if (partial == static_cast<signed int>(RTMP_VIDEO_PACKET_SIZE)) {
            writeNet(&header, 1);
        }
@@ -785,7 +831,7 @@
 }
     
 // Send a Msg, and expect a response back of some kind.
-amf::Element *
+RTMPMsg *
 RTMP::sendRecvMsg(int amf_index, rtmp_headersize_e head_size,
                  size_t total_size, content_types_e type,
                  RTMPMsg::rtmp_source_e routing, amf::Buffer *bufin)
@@ -794,78 +840,293 @@
 //    size_t total_size = buf2->size() - 6; // FIXME: why drop 6 bytes ?
     Buffer *head = encodeHeader(amf_index, head_size, total_size,
                                type, routing);
+//    int ret = 0;
     int ret = writeNet(head);
 //     if (netDebug()) {
-//         cerr << __FUNCTION__ << ": " <<__LINE__ << ": " << 
hexify(head->reference(), headerSize(head_size), false) << endl;
+//     head->dump();
+//     bufin->dump();
 //     }
-
+    delete head;
     ret = sendMsg(bufin);
-    if (netDebug()) {
-        cerr << __FUNCTION__ << ": " << __LINE__ << ": " << 
hexify(head->reference(), headerSize(head_size), false) << 
hexify(bufin->reference(), ret, true) << endl;
-    }
-
-    Buffer buf;
-    ret = readNet(&buf, 5);
-    if (ret < 0) {
-       log_error("Never got any data!");
+
+    RTMP::rtmp_head_t *rthead = 0;
+    RTMPMsg *msg = 0;
+    Buffer *buf = 0;
+    Network::byte_t *ptr = 0;
+
+
+    buf = recvMsg(1);  // use a 1 second timeout
+    if (buf == 0) {
        return 0;
     }
-    if ((ret == 1) && (*buf.reference() == 0xff)) {
-       log_error("Got an error from the server sending object of type %s",
-                 content_str[type]);
-       ret = readNet(&buf, 5); 
-       if (ret < 0) {
-           log_error("Never got any data!");
+    RTMP::queues_t *que = split(buf);
+//    CQue *que = split(buf);
+    while (que->size()) {
+//     ptr = que->pop();
+       cerr << "QUE SIZE: " << que->size() << endl;
+       ptr = que->front()->pop()->reference();
+       que->pop_front();
+//     ptr = buf->reference();
+       rthead = decodeHeader(ptr);
+       
+       if (rthead) {
+           if (rthead->head_size == 1) {
+               log_debug("Response header: %s", hexify(ptr, 7, false));
+           } else {
+               log_debug("Response header: %s", hexify(ptr, rthead->head_size, 
false));
+           }
+           if (rthead->type <= RTMP::FLV_DATA) {
+               log_error("Processing message of type %s!", 
content_str[rthead->type]);
+           }
+           
+           switch (rthead->type) {
+             case CHUNK_SIZE:
+                 log_debug("Got CHUNK_SIZE packet!!!");
+                 _chunksize = ntohl(*reinterpret_cast<boost::uint32_t *>(ptr + 
rthead->head_size));
+                 log_debug("Setting packet chunk size to %d.", _chunksize);
+//               decodeChunkSize();
+                 break;
+             case BYTES_READ:
+                 log_debug("Got Bytes Read packet!!!");
+//               decodeBytesRead();
+                 break;
+             case PING:
+             {
+                 RTMP::rtmp_ping_t *ping = decodePing(ptr);
+                 log_debug("FIXME: Ping type is: %d, ignored for now", 
ping->type);
+                 switch (ping->type) {
+                   case PING_CLEAR:
+                       break;
+                   case PING_PLAY:
+                       break;
+                   case PING_TIME:
+                       break;
+                   case PING_RESET:
+                       break;
+                   case PING_CLIENT:
+                       break;
+                   case PONG_CLIENT:
+                       break;
+                   default:
+                       break;
+                 };
+                 break;
+             }
+             case SERVER:
+             {
+                 log_debug("Got SERVER packet!!!");
+                 Buffer server_data(rthead->bodysize);
+                 server_data.copy(ptr + rthead->head_size, rthead->bodysize);
+//               decodeServer();
+                 break;
+             }
+             case CLIENT:
+             {
+                 log_debug("Got CLIENT packet!!!");
+                 Buffer client_data(rthead->bodysize);
+                 client_data.copy(ptr + rthead->head_size, rthead->bodysize);
+//               decodeClient();
+                 break;
+             }
+             case VIDEO_DATA:
+             {
+                 log_debug("Got VIDEO packets!!!");
+                 Buffer *frame = 0;
+                 do {
+                     frame = recvMsg(1);       // use a 1 second timeout
+                     if (frame) {
+                         _queues[rthead->channel].push(frame);
+                     }
+//                   decodeVideoData();
+                 } while (frame);
+                 _queues->dump();
+                 break;
+             }
+             case NOTIFY:
+//               decodeNotify();
+                 break;
+             case SHARED_OBJ:
+                 log_debug("Got Shared Object packet!!!");
+//               decodeSharedObj();
+                 break;
+             case INVOKE:
+                 msg = decodeMsgBody(ptr + rthead->head_size, 
rthead->bodysize);
+//               msg->dump();
+                 if (msg) {
+                     log_debug("%s: Msg status is: %d: %s, name is %s, size is 
%d", __FUNCTION__,
+                               msg->getStatus(), status_str[msg->getStatus()],
+                               msg->getMethodName(), msg->size());
+                     if (msg->getMethodName() == "onBWDone") { 
+                         log_debug("Got onBWDone packet!!!");
+                         continue;
+                     }
+                     delete buf;
+                     return msg;
+                 } else {
+                     log_error("Couldn't decode message body for type %s!",
+                               content_str[rthead->type]);
+                 }
+//               decodeInvoke();
+                 break;
+             case AUDIO_DATA:    
+//               decodeAudioData();
+                 break;
+             default:
+                 break;
+           } // end of switch
+       }
+//             if (_queues[rthead->channel] != 0) {
+//                 _queues[rthead->channel].push(chunk);
+//             }
+//     ptr += rthead->head_size + rthead->bodysize;
+    };
+    
+    return msg;
+}
+
+// Receive a message, which is a series of AMF elements, seperated
+// by a one byte header at regular byte intervals. (128 bytes for
+// video data by default). Each message main contain multiple packets.
+amf::Buffer *
+RTMP::recvMsg()
+{
+    GNASH_REPORT_FUNCTION;
+    return recvMsg(_timeout);
+}
+
+// Read big chunks of NETBUFSIZE, which is the default for a Buffer as it's
+// more efficient. As these reads may cross packet boundaries, and they may
+// also include the RTMP header every _chunksize bytes, this raw data will
+// need to be processed later on.
+amf::Buffer *
+RTMP::recvMsg(int timeout)
+{
+    GNASH_REPORT_FUNCTION;
+
+    int ret = 0;
+    bool nopacket = true;
+
+    Buffer *buf = 0;
+    buf = new Buffer;
+    while (nopacket) {
+       ret = readNet(buf, timeout);
+       if (ret <= 0) {
+           log_error("Never got any data at line %d", __LINE__);
+           delete buf;
            return 0;
        }
-       if ((ret == 1) && (*buf.reference() == 0xff)) {
-           cerr << __FUNCTION__ << ": " << __LINE__ << ": " <<
-               hexify(buf.reference(), buf.size(), false) << endl;
-           log_error("Got an error from the server sending object of type %s",
-                     content_str[type]);
-//     exit(-1);
-       }
-    }
-
-    RTMP::rtmp_head_t *rthead = decodeHeader(&buf);
-
-    RTMPMsg *msg;
-    if (rthead) {
-       if (rthead->head_size == 1) {
-           log_debug("Response header: %s", hexify(buf.reference(),
-                                                   7, false));
-       } else {
-           log_debug("Response header: %s", hexify(buf.reference(),
-                                                   rthead->head_size, false));
-       }
-       if (rthead->type == RTMP::PING) {
-           RTMP::rtmp_ping_t *ping = decodePing(buf.reference());
-           log_debug("FIXME: Ping type is: %d, ignored for now", ping->type);
-       } else if (rthead->type != RTMP::PING) {
-           msg = decodeMsgBody(buf.reference() + rthead->head_size, 
rthead->bodysize);
-           if (msg) {
-               log_debug("%s: Msg status is: %d: %s", __FUNCTION__,
-                         msg->getStatus(), status_str[msg->getStatus()]);
-           } else {
-               log_error("Couldn't decode message body for type %s!",
-                         content_str[rthead->type]);
-           }
-       } else {
-           log_error("Couldn't decode message header for type %s!",
-                     content_str[type]);
-       }
-    }
-    
-    
-//    Element *el = new Element;  
-//    el.
-    
-    if (rthead->bodysize < ret) {
-       log_debug("more bytes left to read ! %d", (rthead->bodysize < ret));
-    }
-    
-    return 0;
-}
+       if ((ret == 1) && (*(buf->reference()) == 0xff)) {
+           log_debug("Got an empty packet from the server at line %d", 
__LINE__);
+           continue;
+       }
+       nopacket = false;
+    }
+    buf->resize(ret);
+//     if (netDebug()) {
+//     buf->dump();
+//     }
+    
+    return buf;
+}
+
+
+// Split a large buffer into multiple smaller ones of the default chunksize
+// of 128 bytes. We read network data in big chunks because it's more 
efficient,
+// but RTMP uses a weird scheme of a standard header, and then every chunksize
+// bytes another 1 byte RTMP header. The header itself is not part of the byte
+// count.
+RTMP::queues_t *
+RTMP::split(Buffer *buf)
+{
+    return split(buf, _chunksize);
+}
+
+RTMP::queues_t *
+RTMP::split(Buffer *buf, size_t chunksize)
+{
+    GNASH_REPORT_FUNCTION;
+
+    if (buf == 0) {
+       log_error("Buffer pointer is invalid.");
+    }
+    
+    // split the buffer at the chunksize boundary
+    Network::byte_t *ptr = 0;
+    rtmp_head_t *rthead = 0;
+    size_t pktsize = 0;
+    size_t nbytes = 0;
+    
+    ptr = buf->reference();
+    Buffer *chunk = 0;
+    while ((ptr - buf->reference()) < buf->size()) {
+       rthead = decodeHeader(ptr);
+       // Make sure the header size is in range
+       if (rthead->head_size <= RTMP_MAX_HEADER_SIZE) {
+           // Any packet with a size greater than 1 is a new header, so create
+           // a new Buffer to hold all the data.
+           if ((rthead->head_size > 1)) {
+               // This is a queue of channels with active messages
+               _channels.push_back(&_queues[rthead->channel]);
+//             cerr << "New packet for channel #" << rthead->channel << " of 
size "
+//                  << (rthead->head_size + rthead->bodysize) << endl;
+               chunk = new Buffer(rthead->bodysize + rthead->head_size);
+               chunk->clear(); // FIXME: temporary debug only, should be 
unnecessary
+               _queues[rthead->channel].push(chunk);
+           } else {
+               // Use the existing Buffer for this pkt
+               chunk = _queues[rthead->channel].peek();
+           }
+           // Many RTMP messages are smaller than the chunksize
+           if (chunk->size() <= chunksize) {
+               // a single byte header has no length field. As these are often
+               // used as continuation packets, the body size is the same as 
the
+               // previous header with a length field.
+               if (rthead->head_size > 1) {
+                   pktsize = chunk->size();
+               } else {
+                   pktsize = rthead->head_size + rthead->bodysize - 
chunk->size();
+               }
+           } else { // this RTMP message is larger than the chunksize
+               if (rthead->head_size > 1) {
+                   pktsize = rthead->head_size + chunksize;
+               } else {
+                   pktsize = rthead->head_size + (chunk->size() - chunksize);
+               }
+           }
+           
+           // Range check the size of the packet
+           if (pktsize <= (chunksize + RTMP_MAX_HEADER_SIZE)) {
+               nbytes += pktsize;
+               // Skip the header for all but the first packet. The rest are 
just to
+               // complete all the data up to the body size from the header.
+//             cerr << _queues[rthead->channel].size() << " messages in queue 
for channel "
+//                  << rthead->channel << endl;
+               if (rthead->head_size == 1) {
+//                 cerr << "FOLLOWING PACKET!" << " for channel " << 
rthead->channel << endl;
+//                 cerr << "Space Left in buffer for channel " << 
rthead->channel << " is: "
+//                      << chunk->spaceLeft() << endl;
+                   ptr += rthead->head_size;
+                   pktsize -= rthead->head_size;
+//             } else {
+//                 cerr << "FIRST PACKET!" << " for channel " << 
rthead->channel << endl;
+               }
+               chunk->append(ptr, pktsize);
+//             cerr << "Adding data to existing packet for channel #" << 
rthead->channel
+//                  << ", read " << nbytes << " bytes." << endl;
+               ptr += pktsize;
+           } else {
+               log_error("RTMP packet size is out of range! %d", pktsize);
+               break;
+           }
+       } else {
+           log_error("RTMP header size is out of range! %d", 
rthead->head_size);
+           break;
+       }
+    }
+
+    return &_channels;
+}
+
 
 } // end of gnash namespace
 

=== modified file 'libnet/rtmp.h'
--- a/libnet/rtmp.h     2008-08-14 04:24:41 +0000
+++ b/libnet/rtmp.h     2008-08-28 01:24:04 +0000
@@ -28,6 +28,7 @@
 #include "network.h"
 #include "buffer.h"
 #include "rtmp_msg.h"
+#include "cque.h"
 
 namespace gnash
 {
@@ -74,6 +75,7 @@
 class DSOEXPORT RTMP : public Network
 {
 public:
+    typedef std::deque<CQue *> queues_t;
     typedef enum {
        RAW=0x0,
        ADPCM=0x01,
@@ -103,7 +105,8 @@
         UNKNOWN3 = 0xa,
         NOTIFY = 0x12,
         SHARED_OBJ = 0x13,
-        INVOKE = 0x14
+        INVOKE = 0x14,
+       FLV_DATA = 0x16
     } content_types_e;
 //     typedef enum {
 //         CONNECT = 0x1,
@@ -230,7 +233,7 @@
     int getPacketSize()         { return _packet_size; };
     int getMysteryWord()        { return _mystery_word; };
 
-    // Decode the an RTMP message
+    // Decode an RTMP message
     RTMPMsg *decodeMsgBody(Network::byte_t *data, size_t size);
     RTMPMsg *decodeMsgBody(amf::Buffer *buf);
     
@@ -266,27 +269,41 @@
 
     // Receive a message, which is a series of AMF elements, seperated
     // by a one byte header at regular byte intervals. (128 bytes for
-    // video data). Each message main contain multiple packets.
+    // video data by default). Each message main contain multiple packets.
     amf::Buffer *recvMsg();
+    amf::Buffer *recvMsg(int timeout);
 
     // Send a message, usually a single ActionScript object. This message
     // may be broken down into a series of packets on a regular byte
-    // interval. (128 bytes for video data). Each message main contain
-    // multiple packets.
-    bool sendMsg(amf::Buffer *buf);
+    // interval. (128 bytes for video data by default). Each message main
+    // contain multiple packets.
+    bool sendMsg(amf::Buffer *data);
     
     // Send a Msg, and expect a response back of some kind.
-    amf::Element *sendRecvMsg(int amf_index, rtmp_headersize_e head_size,
+    RTMPMsg *sendRecvMsg(int amf_index, rtmp_headersize_e head_size,
                              size_t total_size, content_types_e type,
                              RTMPMsg::rtmp_source_e routing, amf::Buffer *buf);
+    // Split a large buffer into multiple smaller ones of the default chunksize
+    // of 128 bytes. We read network data in big chunks because it's more 
efficient,
+    // but RTMP uses a weird scheme of a standard header, and then every 
chunksize
+    // bytes another 1 byte RTMP header. The header itself is not part of the 
byte
+    // count.
+    queues_t *split(amf::Buffer *buf);
+    queues_t *split(amf::Buffer *buf, size_t chunksize);
+
+    CQue &operator[] (size_t x) { return _queues[x]; }
     void dump();
   protected:
-    std::map<const char *, amf::Element *> _variables;
+    std::map<const char *, amf::Element *> _properties;
     amf::Buffer        *_handshake;
     Handler    *_handler;
     rtmp_head_t        _header;
     int         _packet_size;
     int         _mystery_word;
+    size_t     _chunksize;
+    int                _timeout;
+    CQue       _queues[MAX_AMF_INDEXES];
+    queues_t    _channels;
 };
 
 } // end of gnash namespace


reply via email to

[Prev in Thread] Current Thread [Next in Thread]