winlin

encode packet and send out

@@ -60,30 +60,33 @@ int SrsClient::do_cycle() @@ -60,30 +60,33 @@ int SrsClient::do_cycle()
60 int ret = ERROR_SUCCESS; 60 int ret = ERROR_SUCCESS;
61 61
62 if ((ret = get_peer_ip()) != ERROR_SUCCESS) { 62 if ((ret = get_peer_ip()) != ERROR_SUCCESS) {
63 - srs_warn("get peer ip failed. ret=%d", ret); 63 + srs_error("get peer ip failed. ret=%d", ret);
64 return ret; 64 return ret;
65 } 65 }
66 srs_verbose("get peer ip success. ip=%s", ip); 66 srs_verbose("get peer ip success. ip=%s", ip);
67 67
68 if ((ret = rtmp->handshake()) != ERROR_SUCCESS) { 68 if ((ret = rtmp->handshake()) != ERROR_SUCCESS) {
69 - srs_warn("rtmp handshake failed. ret=%d", ret); 69 + srs_error("rtmp handshake failed. ret=%d", ret);
70 return ret; 70 return ret;
71 } 71 }
72 srs_verbose("rtmp handshake success"); 72 srs_verbose("rtmp handshake success");
73 73
74 if ((ret = rtmp->connect_app(req)) != ERROR_SUCCESS) { 74 if ((ret = rtmp->connect_app(req)) != ERROR_SUCCESS) {
75 - srs_warn("rtmp connect vhost/app failed. ret=%d", ret); 75 + srs_error("rtmp connect vhost/app failed. ret=%d", ret);
76 return ret; 76 return ret;
77 } 77 }
78 - srs_info("rtmp connect success. tcUrl=%s, pageUrl=%s, swfUrl=%s",  
79 - req->tcUrl.c_str(), req->pageUrl.c_str(), req->swfUrl.c_str());  
80 -  
81 - srs_trace("rtmp connect success. " 78 + srs_trace("rtmp connect app success. "
82 "tcUrl=%s, pageUrl=%s, swfUrl=%s, schema=%s, vhost=%s, port=%s, app=%s", 79 "tcUrl=%s, pageUrl=%s, swfUrl=%s, schema=%s, vhost=%s, port=%s, app=%s",
83 req->tcUrl.c_str(), req->pageUrl.c_str(), req->swfUrl.c_str(), 80 req->tcUrl.c_str(), req->pageUrl.c_str(), req->swfUrl.c_str(),
84 req->schema.c_str(), req->vhost.c_str(), req->port.c_str(), 81 req->schema.c_str(), req->vhost.c_str(), req->port.c_str(),
85 req->app.c_str()); 82 req->app.c_str());
86 83
  84 + if ((ret = rtmp->set_window_ack_size(2.5 * 1000 * 1000)) != ERROR_SUCCESS) {
  85 + srs_error("set window acknowledgement size failed. ret=%d", ret);
  86 + return ret;
  87 + }
  88 + srs_verbose("set window acknowledgement size success");
  89 +
87 return ret; 90 return ret;
88 } 91 }
89 92
@@ -55,6 +55,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -55,6 +55,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
55 #define ERROR_RTMP_AMF0_DECODE 303 55 #define ERROR_RTMP_AMF0_DECODE 303
56 #define ERROR_RTMP_AMF0_INVALID 304 56 #define ERROR_RTMP_AMF0_INVALID 304
57 #define ERROR_RTMP_REQ_CONNECT 305 57 #define ERROR_RTMP_REQ_CONNECT 305
  58 +#define ERROR_RTMP_REQ_TCURL 306
  59 +#define ERROR_RTMP_MESSAGE_DECODE 307
58 60
59 #define ERROR_SYSTEM_STREAM_INIT 400 61 #define ERROR_SYSTEM_STREAM_INIT 400
60 62
@@ -30,6 +30,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,6 +30,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include <srs_core_buffer.hpp> 30 #include <srs_core_buffer.hpp>
31 #include <srs_core_stream.hpp> 31 #include <srs_core_stream.hpp>
32 32
  33 +/****************************************************************************
  34 +*****************************************************************************
  35 +****************************************************************************/
33 /** 36 /**
34 5. Protocol Control Messages 37 5. Protocol Control Messages
35 RTMP reserves message type IDs 1-7 for protocol control messages. 38 RTMP reserves message type IDs 1-7 for protocol control messages.
@@ -124,6 +127,9 @@ messages. @@ -124,6 +127,9 @@ messages.
124 */ 127 */
125 #define RTMP_MSG_AggregateMessage 22 // 0x16 128 #define RTMP_MSG_AggregateMessage 22 // 0x16
126 129
  130 +/****************************************************************************
  131 +*****************************************************************************
  132 +****************************************************************************/
127 /** 133 /**
128 * 6.1.2. Chunk Message Header 134 * 6.1.2. Chunk Message Header
129 * There are four different formats for the chunk message header, 135 * There are four different formats for the chunk message header,
@@ -164,6 +170,9 @@ messages. @@ -164,6 +170,9 @@ messages.
164 // the same as the timestamp of Type 0 chunk. 170 // the same as the timestamp of Type 0 chunk.
165 #define RTMP_FMT_TYPE3 3 171 #define RTMP_FMT_TYPE3 3
166 172
  173 +/****************************************************************************
  174 +*****************************************************************************
  175 +****************************************************************************/
167 /** 176 /**
168 * 6. Chunking 177 * 6. Chunking
169 * The chunk size is configurable. It can be set using a control 178 * The chunk size is configurable. It can be set using a control
@@ -189,11 +198,58 @@ messages. @@ -189,11 +198,58 @@ messages.
189 */ 198 */
190 #define RTMP_EXTENDED_TIMESTAMP 0xFFFFFF 199 #define RTMP_EXTENDED_TIMESTAMP 0xFFFFFF
191 200
  201 +/****************************************************************************
  202 +*****************************************************************************
  203 +****************************************************************************/
192 /** 204 /**
193 * amf0 command message, command name: "connect" 205 * amf0 command message, command name: "connect"
194 */ 206 */
195 #define RTMP_AMF0_COMMAND_CONNECT "connect" 207 #define RTMP_AMF0_COMMAND_CONNECT "connect"
196 208
  209 +/****************************************************************************
  210 +*****************************************************************************
  211 +****************************************************************************/
  212 +/**
  213 +* the chunk stream id used for some under-layer message,
  214 +* for example, the PC(protocol control) message.
  215 +*/
  216 +#define RTMP_CID_ProtocolControl 0x02
  217 +/**
  218 +* the AMF0/AMF3 command message, invoke method and return the result, over NetConnection.
  219 +* generally use 0x03.
  220 +*/
  221 +#define RTMP_CID_OverConnection 0x03
  222 +/**
  223 +* the AMF0/AMF3 command message, invoke method and return the result, over NetConnection,
  224 +* the midst state(we guess).
  225 +* rarely used, e.g. onStatus(NetStream.Play.Reset).
  226 +*/
  227 +#define RTMP_CID_OverConnection2 0x04
  228 +/**
  229 +* the stream message(amf0/amf3), over NetStream.
  230 +* generally use 0x05.
  231 +*/
  232 +#define RTMP_CID_OverStream 0x05
  233 +/**
  234 +* the stream message(amf0/amf3), over NetStream, the midst state(we guess).
  235 +* rarely used, e.g. play("mp4:mystram.f4v")
  236 +*/
  237 +#define RTMP_CID_OverStream2 0x08
  238 +/**
  239 +* the stream message(video), over NetStream
  240 +* generally use 0x06.
  241 +*/
  242 +#define RTMP_CID_Video 0x06
  243 +/**
  244 +* the stream message(audio), over NetStream.
  245 +* generally use 0x07.
  246 +*/
  247 +#define RTMP_CID_Audio 0x07
  248 +
  249 +/****************************************************************************
  250 +*****************************************************************************
  251 +****************************************************************************/
  252 +
197 SrsProtocol::SrsProtocol(st_netfd_t client_stfd) 253 SrsProtocol::SrsProtocol(st_netfd_t client_stfd)
198 { 254 {
199 stfd = client_stfd; 255 stfd = client_stfd;
@@ -263,6 +319,118 @@ int SrsProtocol::recv_message(SrsMessage** pmsg) @@ -263,6 +319,118 @@ int SrsProtocol::recv_message(SrsMessage** pmsg)
263 return ret; 319 return ret;
264 } 320 }
265 321
  322 +int SrsProtocol::send_message(SrsMessage* msg)
  323 +{
  324 + int ret = ERROR_SUCCESS;
  325 +
  326 + if ((ret = msg->encode_packet()) != ERROR_SUCCESS) {
  327 + srs_error("encode packet to message payload failed. ret=%d", ret);
  328 + return ret;
  329 + }
  330 + srs_info("encode packet to message payload success");
  331 +
  332 + // p set to current write position,
  333 + // it's ok when payload is NULL and size is 0.
  334 + char* p = (char*)msg->payload;
  335 +
  336 + // always write the header event payload is empty.
  337 + do {
  338 + // generate the header.
  339 + char* pheader = NULL;
  340 + int header_size = 0;
  341 +
  342 + if (p == (char*)msg->payload) {
  343 + // write new chunk stream header, fmt is 0
  344 + pheader = out_header_fmt0;
  345 + *pheader++ = 0x00 | (msg->get_perfer_cid() & 0x3F);
  346 +
  347 + // chunk message header, 11 bytes
  348 + // timestamp, 3bytes, big-endian
  349 + if (msg->header.timestamp >= RTMP_EXTENDED_TIMESTAMP) {
  350 + *pheader++ = 0xFF;
  351 + *pheader++ = 0xFF;
  352 + *pheader++ = 0xFF;
  353 + } else {
  354 + pp = (char*)&msg->header.timestamp;
  355 + *pheader++ = pp[2];
  356 + *pheader++ = pp[1];
  357 + *pheader++ = pp[0];
  358 + }
  359 +
  360 + // message_length, 3bytes, big-endian
  361 + pp = (char*)&msg->header.payload_length;
  362 + *pheader++ = pp[2];
  363 + *pheader++ = pp[1];
  364 + *pheader++ = pp[0];
  365 +
  366 + // message_type, 1bytes
  367 + *pheader++ = msg->header.message_type;
  368 +
  369 + // message_length, 3bytes, little-endian
  370 + pp = (char*)&msg->header.stream_id;
  371 + *pheader++ = pp[0];
  372 + *pheader++ = pp[1];
  373 + *pheader++ = pp[2];
  374 + *pheader++ = pp[3];
  375 +
  376 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  377 + if(msg->header.timestamp >= RTMP_EXTENDED_TIMESTAMP){
  378 + pp = (char*)&msg->header.timestamp;
  379 + *pheader++ = pp[3];
  380 + *pheader++ = pp[2];
  381 + *pheader++ = pp[1];
  382 + *pheader++ = pp[0];
  383 + }
  384 +
  385 + header_size = pheader - out_header_fmt0;
  386 + pheader = out_header_fmt0;
  387 + } else {
  388 + // write no message header chunk stream, fmt is 3
  389 + pheader = out_header_fmt3;
  390 + *pheader++ = 0xC0 | (msg->get_perfer_cid() & 0x3F);
  391 +
  392 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  393 + if(msg->header.timestamp >= RTMP_EXTENDED_TIMESTAMP){
  394 + pp = (char*)&msg->header.timestamp;
  395 + *pheader++ = pp[3];
  396 + *pheader++ = pp[2];
  397 + *pheader++ = pp[1];
  398 + *pheader++ = pp[0];
  399 + }
  400 +
  401 + header_size = pheader - out_header_fmt3;
  402 + pheader = out_header_fmt3;
  403 + }
  404 +
  405 + // sendout header and payload by writev.
  406 + // decrease the sys invoke count to get higher performance.
  407 + int payload_size = msg->size - ((char*)msg->payload - p);
  408 + if (payload_size > out_chunk_size) {
  409 + payload_size = out_chunk_size;
  410 + }
  411 +
  412 + // send by writev
  413 + iovec iov[2];
  414 + iov[0].iov_base = pheader;
  415 + iov[0].iov_len = header_size;
  416 + iov[1].iov_base = p;
  417 + iov[1].iov_len = payload_size;
  418 +
  419 + ssize_t nwrite;
  420 + if ((ret = skt->writev(iov, 2, &nwrite)) != ERROR_SUCCESS) {
  421 + srs_error("send with writev failed. ret=%d", ret);
  422 + return ret;
  423 + }
  424 +
  425 + // consume sendout bytes when not empty packet.
  426 + if (msg->payload && msg->size > 0) {
  427 + p += payload_size;
  428 + }
  429 + } while (p < (char*)msg->payload + msg->size);
  430 +
  431 + return ret;
  432 +}
  433 +
266 int SrsProtocol::recv_interlaced_message(SrsMessage** pmsg) 434 int SrsProtocol::recv_interlaced_message(SrsMessage** pmsg)
267 { 435 {
268 int ret = ERROR_SUCCESS; 436 int ret = ERROR_SUCCESS;
@@ -325,7 +493,7 @@ int SrsProtocol::recv_interlaced_message(SrsMessage** pmsg) @@ -325,7 +493,7 @@ int SrsProtocol::recv_interlaced_message(SrsMessage** pmsg)
325 return ret; 493 return ret;
326 } 494 }
327 495
328 -int SrsProtocol::read_basic_header(char& fmt, int& cid, int& size) 496 +int SrsProtocol::read_basic_header(char& fmt, int& cid, int& bh_size)
329 { 497 {
330 int ret = ERROR_SUCCESS; 498 int ret = ERROR_SUCCESS;
331 499
@@ -339,10 +507,10 @@ int SrsProtocol::read_basic_header(char& fmt, int& cid, int& size) @@ -339,10 +507,10 @@ int SrsProtocol::read_basic_header(char& fmt, int& cid, int& size)
339 507
340 fmt = (*p >> 6) & 0x03; 508 fmt = (*p >> 6) & 0x03;
341 cid = *p & 0x3f; 509 cid = *p & 0x3f;
342 - size = 1; 510 + bh_size = 1;
343 511
344 if (cid > 1) { 512 if (cid > 1) {
345 - srs_verbose("%dbytes basic header parsed. fmt=%d, cid=%d", size, fmt, cid); 513 + srs_verbose("%dbytes basic header parsed. fmt=%d, cid=%d", bh_size, fmt, cid);
346 return ret; 514 return ret;
347 } 515 }
348 516
@@ -355,8 +523,8 @@ int SrsProtocol::read_basic_header(char& fmt, int& cid, int& size) @@ -355,8 +523,8 @@ int SrsProtocol::read_basic_header(char& fmt, int& cid, int& size)
355 523
356 cid = 64; 524 cid = 64;
357 cid += *(++p); 525 cid += *(++p);
358 - size = 2;  
359 - srs_verbose("%dbytes basic header parsed. fmt=%d, cid=%d", size, fmt, cid); 526 + bh_size = 2;
  527 + srs_verbose("%dbytes basic header parsed. fmt=%d, cid=%d", bh_size, fmt, cid);
360 } else if (cid == 1) { 528 } else if (cid == 1) {
361 required_size = 3; 529 required_size = 3;
362 if ((ret = buffer->ensure_buffer_bytes(skt, 3)) != ERROR_SUCCESS) { 530 if ((ret = buffer->ensure_buffer_bytes(skt, 3)) != ERROR_SUCCESS) {
@@ -367,8 +535,8 @@ int SrsProtocol::read_basic_header(char& fmt, int& cid, int& size) @@ -367,8 +535,8 @@ int SrsProtocol::read_basic_header(char& fmt, int& cid, int& size)
367 cid = 64; 535 cid = 64;
368 cid += *(++p); 536 cid += *(++p);
369 cid += *(++p) * 256; 537 cid += *(++p) * 256;
370 - size = 3;  
371 - srs_verbose("%dbytes basic header parsed. fmt=%d, cid=%d", size, fmt, cid); 538 + bh_size = 3;
  539 + srs_verbose("%dbytes basic header parsed. fmt=%d, cid=%d", bh_size, fmt, cid);
372 } else { 540 } else {
373 srs_error("invalid path, impossible basic header."); 541 srs_error("invalid path, impossible basic header.");
374 srs_assert(false); 542 srs_assert(false);
@@ -620,7 +788,7 @@ SrsMessage::SrsMessage() @@ -620,7 +788,7 @@ SrsMessage::SrsMessage()
620 size = 0; 788 size = 0;
621 stream = NULL; 789 stream = NULL;
622 payload = NULL; 790 payload = NULL;
623 - decoded_payload = NULL; 791 + packet = NULL;
624 } 792 }
625 793
626 SrsMessage::~SrsMessage() 794 SrsMessage::~SrsMessage()
@@ -630,9 +798,9 @@ SrsMessage::~SrsMessage() @@ -630,9 +798,9 @@ SrsMessage::~SrsMessage()
630 payload = NULL; 798 payload = NULL;
631 } 799 }
632 800
633 - if (decoded_payload) {  
634 - delete decoded_payload;  
635 - decoded_payload = NULL; 801 + if (packet) {
  802 + delete packet;
  803 + packet = NULL;
636 } 804 }
637 805
638 if (stream) { 806 if (stream) {
@@ -641,16 +809,6 @@ SrsMessage::~SrsMessage() @@ -641,16 +809,6 @@ SrsMessage::~SrsMessage()
641 } 809 }
642 } 810 }
643 811
644 -SrsPacket* SrsMessage::get_packet()  
645 -{  
646 - if (!decoded_payload) {  
647 - srs_error("the payload is raw/undecoded, invoke decode_packet to decode it.");  
648 - }  
649 - srs_assert(decoded_payload != NULL);  
650 -  
651 - return decoded_payload;  
652 -}  
653 -  
654 int SrsMessage::decode_packet() 812 int SrsMessage::decode_packet()
655 { 813 {
656 int ret = ERROR_SUCCESS; 814 int ret = ERROR_SUCCESS;
@@ -684,19 +842,64 @@ int SrsMessage::decode_packet() @@ -684,19 +842,64 @@ int SrsMessage::decode_packet()
684 stream->reset(); 842 stream->reset();
685 if (command == RTMP_AMF0_COMMAND_CONNECT) { 843 if (command == RTMP_AMF0_COMMAND_CONNECT) {
686 srs_info("decode the AMF0 command(connect vhost/app message)."); 844 srs_info("decode the AMF0 command(connect vhost/app message).");
687 - decoded_payload = new SrsConnectAppPacket();  
688 - return decoded_payload->decode(stream); 845 + packet = new SrsConnectAppPacket();
  846 + return packet->decode(stream);
689 } 847 }
690 848
691 // default packet to drop message. 849 // default packet to drop message.
692 srs_trace("drop the AMF0 command message, command_name=%s", command.c_str()); 850 srs_trace("drop the AMF0 command message, command_name=%s", command.c_str());
693 - decoded_payload = new SrsPacket(); 851 + packet = new SrsPacket();
694 return ret; 852 return ret;
695 } 853 }
696 854
697 // default packet to drop message. 855 // default packet to drop message.
698 srs_trace("drop the unknown message, type=%d", header.message_type); 856 srs_trace("drop the unknown message, type=%d", header.message_type);
699 - decoded_payload = new SrsPacket(); 857 + packet = new SrsPacket();
  858 +
  859 + return ret;
  860 +}
  861 +
  862 +SrsPacket* SrsMessage::get_packet()
  863 +{
  864 + if (!packet) {
  865 + srs_error("the payload is raw/undecoded, invoke decode_packet to decode it.");
  866 + }
  867 + srs_assert(packet != NULL);
  868 +
  869 + return packet;
  870 +}
  871 +
  872 +int SrsMessage::get_perfer_cid()
  873 +{
  874 + if (!packet) {
  875 + return RTMP_CID_ProtocolControl;
  876 + }
  877 +
  878 + // we donot use the complex basic header,
  879 + // ensure the basic header is 1bytes.
  880 + if (packet->get_perfer_cid() < 2) {
  881 + return packet->get_perfer_cid();
  882 + }
  883 +
  884 + return packet->get_perfer_cid();
  885 +}
  886 +
  887 +void SrsMessage::set_packet(SrsPacket* pkt)
  888 +{
  889 + if (packet) {
  890 + delete packet;
  891 + }
  892 + packet = pkt;
  893 +}
  894 +
  895 +int SrsMessage::encode_packet()
  896 +{
  897 + int ret = ERROR_SUCCESS;
  898 +
  899 + if (packet == NULL) {
  900 + srs_warn("packet is empty, send out empty message.");
  901 + return ret;
  902 + }
700 903
701 return ret; 904 return ret;
702 } 905 }
@@ -715,6 +918,11 @@ int SrsPacket::decode(SrsStream* /*stream*/) @@ -715,6 +918,11 @@ int SrsPacket::decode(SrsStream* /*stream*/)
715 return ret; 918 return ret;
716 } 919 }
717 920
  921 +int SrsPacket::get_perfer_cid()
  922 +{
  923 + return 0;
  924 +}
  925 +
718 SrsConnectAppPacket::SrsConnectAppPacket() 926 SrsConnectAppPacket::SrsConnectAppPacket()
719 { 927 {
720 command_name = RTMP_AMF0_COMMAND_CONNECT; 928 command_name = RTMP_AMF0_COMMAND_CONNECT;
@@ -771,3 +979,37 @@ int SrsConnectAppPacket::decode(SrsStream* stream) @@ -771,3 +979,37 @@ int SrsConnectAppPacket::decode(SrsStream* stream)
771 return ret; 979 return ret;
772 } 980 }
773 981
  982 +SrsSetWindowAckSizePacket::SrsSetWindowAckSizePacket()
  983 +{
  984 + ackowledgement_window_size = 0;
  985 +}
  986 +
  987 +SrsSetWindowAckSizePacket::~SrsSetWindowAckSizePacket()
  988 +{
  989 +}
  990 +
  991 +int SrsSetWindowAckSizePacket::decode(SrsStream* stream)
  992 +{
  993 + int ret = ERROR_SUCCESS;
  994 +
  995 + if ((ret = super::decode(stream)) != ERROR_SUCCESS) {
  996 + return ret;
  997 + }
  998 +
  999 + if (!stream->require(4)) {
  1000 + ret = ERROR_RTMP_MESSAGE_DECODE;
  1001 + srs_error("set window ack size failed. ret=%d", ret);
  1002 + return ret;
  1003 + }
  1004 +
  1005 + ackowledgement_window_size = stream->read_4bytes();
  1006 + srs_info("decode window ack size success. ack_size=%d", ackowledgement_window_size);
  1007 +
  1008 + return ret;
  1009 +}
  1010 +
  1011 +int SrsSetWindowAckSizePacket::get_perfer_cid()
  1012 +{
  1013 + return RTMP_CID_ProtocolControl;
  1014 +}
  1015 +
@@ -47,18 +47,42 @@ class SrsChunkStream; @@ -47,18 +47,42 @@ class SrsChunkStream;
47 class SrsAmf0Object; 47 class SrsAmf0Object;
48 48
49 /** 49 /**
  50 +* max rtmp header size:
  51 +* 1bytes basic header,
  52 +* 11bytes message header,
  53 +* 4bytes timestamp header,
  54 +* that is, 1+11+4=16bytes.
  55 +*/
  56 +#define RTMP_MAX_FMT0_HEADER_SIZE 16
  57 +/**
  58 +* max rtmp header size:
  59 +* 1bytes basic header,
  60 +* 4bytes timestamp header,
  61 +* that is, 1+4=5bytes.
  62 +*/
  63 +#define RTMP_MAX_FMT3_HEADER_SIZE 5
  64 +
  65 +/**
50 * the protocol provides the rtmp-message-protocol services, 66 * the protocol provides the rtmp-message-protocol services,
51 * to recv RTMP message from RTMP chunk stream, 67 * to recv RTMP message from RTMP chunk stream,
52 * and to send out RTMP message over RTMP chunk stream. 68 * and to send out RTMP message over RTMP chunk stream.
53 */ 69 */
54 class SrsProtocol 70 class SrsProtocol
55 { 71 {
  72 +// peer in/out
56 private: 73 private:
57 - std::map<int, SrsChunkStream*> chunk_streams;  
58 st_netfd_t stfd; 74 st_netfd_t stfd;
59 - SrsBuffer* buffer;  
60 SrsSocket* skt; 75 SrsSocket* skt;
  76 + char* pp;
  77 +// peer in
  78 +private:
  79 + std::map<int, SrsChunkStream*> chunk_streams;
  80 + SrsBuffer* buffer;
61 int32_t in_chunk_size; 81 int32_t in_chunk_size;
  82 +// peer out
  83 +private:
  84 + char out_header_fmt0[RTMP_MAX_FMT0_HEADER_SIZE];
  85 + char out_header_fmt3[RTMP_MAX_FMT3_HEADER_SIZE];
62 int32_t out_chunk_size; 86 int32_t out_chunk_size;
63 public: 87 public:
64 SrsProtocol(st_netfd_t client_stfd); 88 SrsProtocol(st_netfd_t client_stfd);
@@ -72,10 +96,38 @@ public: @@ -72,10 +96,38 @@ public:
72 * @remark, only when success, user can use and must free the pmsg. 96 * @remark, only when success, user can use and must free the pmsg.
73 */ 97 */
74 virtual int recv_message(SrsMessage** pmsg); 98 virtual int recv_message(SrsMessage** pmsg);
  99 + /**
  100 + * send out message with encoded payload to peer.
  101 + * use the message encode method to encode to payload,
  102 + * then sendout over socket.
  103 + * @msg this method will free it whatever return value.
  104 + */
  105 + virtual int send_message(SrsMessage* msg);
75 private: 106 private:
  107 + /**
  108 + * try to recv interlaced message from peer,
  109 + * return error if error occur and nerver set the pmsg,
  110 + * return success and pmsg set to NULL if no entire message got,
  111 + * return success and pmsg set to entire message if got one.
  112 + */
76 virtual int recv_interlaced_message(SrsMessage** pmsg); 113 virtual int recv_interlaced_message(SrsMessage** pmsg);
77 - virtual int read_basic_header(char& fmt, int& cid, int& size); 114 + /**
  115 + * read the chunk basic header(fmt, cid) from chunk stream.
  116 + * user can discovery a SrsChunkStream by cid.
  117 + * @bh_size return the chunk basic header size, to remove the used bytes when finished.
  118 + */
  119 + virtual int read_basic_header(char& fmt, int& cid, int& bh_size);
  120 + /**
  121 + * read the chunk message header(timestamp, payload_length, message_type, stream_id)
  122 + * from chunk stream and save to SrsChunkStream.
  123 + * @mh_size return the chunk message header size, to remove the used bytes when finished.
  124 + */
78 virtual int read_message_header(SrsChunkStream* chunk, char fmt, int bh_size, int& mh_size); 125 virtual int read_message_header(SrsChunkStream* chunk, char fmt, int bh_size, int& mh_size);
  126 + /**
  127 + * read the chunk payload, remove the used bytes in buffer,
  128 + * if got entire message, set the pmsg.
  129 + * @payload_size read size in this roundtrip, generally a chunk size or left message size.
  130 + */
79 virtual int read_message_payload(SrsChunkStream* chunk, int bh_size, int mh_size, int& payload_size, SrsMessage** pmsg); 131 virtual int read_message_payload(SrsChunkStream* chunk, int bh_size, int mh_size, int& payload_size, SrsMessage** pmsg);
80 }; 132 };
81 133
@@ -164,19 +216,35 @@ public: @@ -164,19 +216,35 @@ public:
164 // decoded message payload. 216 // decoded message payload.
165 private: 217 private:
166 SrsStream* stream; 218 SrsStream* stream;
167 - SrsPacket* decoded_payload; 219 + SrsPacket* packet;
  220 +public:
  221 + SrsMessage();
  222 + virtual ~SrsMessage();
168 public: 223 public:
169 /** 224 /**
170 - * get the decoded packet,  
171 - * not all packets need to decode, for video/audio packet,  
172 - * passthrough to peer are ok.  
173 - * @remark, user must invoke decode_packet first. 225 + * decode packet from message payload.
174 */ 226 */
175 - virtual SrsPacket* get_packet();  
176 virtual int decode_packet(); 227 virtual int decode_packet();
  228 + /**
  229 + * get the decoded packet which decoded by decode_packet().
  230 + * @remark, user never free the pkt, the message will auto free it.
  231 + */
  232 + virtual SrsPacket* get_packet();
177 public: 233 public:
178 - SrsMessage();  
179 - virtual ~SrsMessage(); 234 + /**
  235 + * get the perfered cid(chunk stream id) which sendout over.
  236 + */
  237 + virtual int get_perfer_cid();
  238 + /**
  239 + * set the encoded packet to encode_packet() to payload.
  240 + * @remark, user never free the pkt, the message will auto free it.
  241 + */
  242 + virtual void set_packet(SrsPacket* pkt);
  243 + /**
  244 + * encode the packet to message payload bytes.
  245 + * @remark there exists empty packet, so maybe the payload is NULL.
  246 + */
  247 + virtual int encode_packet();
180 }; 248 };
181 249
182 /** 250 /**
@@ -189,8 +257,15 @@ public: @@ -189,8 +257,15 @@ public:
189 virtual ~SrsPacket(); 257 virtual ~SrsPacket();
190 public: 258 public:
191 virtual int decode(SrsStream* stream); 259 virtual int decode(SrsStream* stream);
  260 +public:
  261 + virtual int get_perfer_cid();
192 }; 262 };
193 263
  264 +/**
  265 +* 4.1.1. connect
  266 +* The client sends the connect command to the server to request
  267 +* connection to a server application instance.
  268 +*/
194 class SrsConnectAppPacket : public SrsPacket 269 class SrsConnectAppPacket : public SrsPacket
195 { 270 {
196 private: 271 private:
@@ -207,6 +282,26 @@ public: @@ -207,6 +282,26 @@ public:
207 }; 282 };
208 283
209 /** 284 /**
  285 +* 5.5. Window Acknowledgement Size (5)
  286 +* The client or the server sends this message to inform the peer which
  287 +* window size to use when sending acknowledgment.
  288 +*/
  289 +class SrsSetWindowAckSizePacket : public SrsPacket
  290 +{
  291 +private:
  292 + typedef SrsPacket super;
  293 +public:
  294 + int32_t ackowledgement_window_size;
  295 +public:
  296 + SrsSetWindowAckSizePacket();
  297 + virtual ~SrsSetWindowAckSizePacket();
  298 +public:
  299 + virtual int decode(SrsStream* stream);
  300 +public:
  301 + virtual int get_perfer_cid();
  302 +};
  303 +
  304 +/**
210 * expect a specified message, drop others util got specified one. 305 * expect a specified message, drop others util got specified one.
211 * @pmsg, user must free it. NULL if not success. 306 * @pmsg, user must free it. NULL if not success.
212 * @ppacket, store in the pmsg, user must never free it. NULL if not success. 307 * @ppacket, store in the pmsg, user must never free it. NULL if not success.
@@ -30,6 +30,47 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,6 +30,47 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include <srs_core_auto_free.hpp> 30 #include <srs_core_auto_free.hpp>
31 #include <srs_core_amf0.hpp> 31 #include <srs_core_amf0.hpp>
32 32
  33 +int SrsRequest::discovery_app()
  34 +{
  35 + int ret = ERROR_SUCCESS;
  36 +
  37 + size_t pos = std::string::npos;
  38 + std::string url = tcUrl;
  39 +
  40 + if ((pos = url.find("://")) != std::string::npos) {
  41 + schema = url.substr(0, pos);
  42 + url = url.substr(schema.length() + 3);
  43 + srs_verbose("discovery schema=%s", schema.c_str());
  44 + }
  45 +
  46 + if ((pos = url.find("/")) != std::string::npos) {
  47 + vhost = url.substr(0, pos);
  48 + url = url.substr(vhost.length() + 1);
  49 + srs_verbose("discovery vhost=%s", vhost.c_str());
  50 + }
  51 +
  52 + port = "1935";
  53 + if ((pos = vhost.find(":")) != std::string::npos) {
  54 + port = vhost.substr(pos + 1);
  55 + vhost = vhost.substr(0, pos);
  56 + srs_verbose("discovery vhost=%s, port=%s", vhost.c_str(), port.c_str());
  57 + }
  58 +
  59 + app = url;
  60 + srs_info("discovery app success. schema=%s, vhost=%s, port=%s, app=%s",
  61 + schema.c_str(), vhost.c_str(), port.c_str(), app.c_str());
  62 +
  63 + if (schema.empty() || vhost.empty() || port.empty() || app.empty()) {
  64 + ret = ERROR_RTMP_REQ_TCURL;
  65 + srs_error("discovery tcUrl failed. "
  66 + "tcUrl=%s, schema=%s, vhost=%s, port=%s, app=%s, ret=%d",
  67 + tcUrl.c_str(), schema.c_str(), vhost.c_str(), port.c_str(), app.c_str(), ret);
  68 + return ret;
  69 + }
  70 +
  71 + return ret;
  72 +}
  73 +
33 SrsRtmp::SrsRtmp(st_netfd_t client_stfd) 74 SrsRtmp::SrsRtmp(st_netfd_t client_stfd)
34 { 75 {
35 protocol = new SrsProtocol(client_stfd); 76 protocol = new SrsProtocol(client_stfd);
@@ -119,6 +160,26 @@ int SrsRtmp::connect_app(SrsRequest* req) @@ -119,6 +160,26 @@ int SrsRtmp::connect_app(SrsRequest* req)
119 if ((prop = pkt->command_object->ensure_property_string("swfUrl")) != NULL) { 160 if ((prop = pkt->command_object->ensure_property_string("swfUrl")) != NULL) {
120 req->swfUrl = srs_amf0_convert<SrsAmf0String>(prop)->value; 161 req->swfUrl = srs_amf0_convert<SrsAmf0String>(prop)->value;
121 } 162 }
  163 + srs_info("get connect app message params success.");
  164 +
  165 + return req->discovery_app();
  166 +}
  167 +
  168 +int SrsRtmp::set_window_ack_size(int ack_size)
  169 +{
  170 + int ret = ERROR_SUCCESS;
  171 +
  172 + SrsMessage* msg = new SrsMessage();
  173 + SrsSetWindowAckSizePacket* pkt = new SrsSetWindowAckSizePacket();
  174 +
  175 + pkt->ackowledgement_window_size = ack_size;
  176 + msg->set_packet(pkt);
  177 +
  178 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  179 + srs_error("send ack size message failed. ret=%d", ret);
  180 + return ret;
  181 + }
  182 + srs_info("send ack size message success. ack_size=%d", ack_size);
122 183
123 return ret; 184 return ret;
124 } 185 }
@@ -50,6 +50,11 @@ struct SrsRequest @@ -50,6 +50,11 @@ struct SrsRequest
50 std::string port; 50 std::string port;
51 std::string app; 51 std::string app;
52 std::string stream; 52 std::string stream;
  53 +
  54 + /**
  55 + * disconvery vhost/app from tcUrl.
  56 + */
  57 + virtual int discovery_app();
53 }; 58 };
54 59
55 /** 60 /**
@@ -68,6 +73,7 @@ public: @@ -68,6 +73,7 @@ public:
68 public: 73 public:
69 virtual int handshake(); 74 virtual int handshake();
70 virtual int connect_app(SrsRequest* req); 75 virtual int connect_app(SrsRequest* req);
  76 + virtual int set_window_ack_size(int ack_size);
71 }; 77 };
72 78
73 #endif 79 #endif
@@ -85,3 +85,16 @@ int SrsSocket::write(const void* buf, size_t size, ssize_t* nwrite) @@ -85,3 +85,16 @@ int SrsSocket::write(const void* buf, size_t size, ssize_t* nwrite)
85 return ret; 85 return ret;
86 } 86 }
87 87
  88 +int SrsSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite)
  89 +{
  90 + int ret = ERROR_SUCCESS;
  91 +
  92 + *nwrite = st_writev(stfd, iov, iov_size, ST_UTIME_NO_TIMEOUT);
  93 +
  94 + if (*nwrite <= 0) {
  95 + ret = ERROR_SOCKET_WRITE;
  96 + }
  97 +
  98 + return ret;
  99 +}
  100 +
@@ -47,6 +47,7 @@ public: @@ -47,6 +47,7 @@ public:
47 virtual int read(const void* buf, size_t size, ssize_t* nread); 47 virtual int read(const void* buf, size_t size, ssize_t* nread);
48 virtual int read_fully(const void* buf, size_t size, ssize_t* nread); 48 virtual int read_fully(const void* buf, size_t size, ssize_t* nread);
49 virtual int write(const void* buf, size_t size, ssize_t* nwrite); 49 virtual int write(const void* buf, size_t size, ssize_t* nwrite);
  50 + virtual int writev(const iovec *iov, int iov_size, ssize_t* nwrite);
50 }; 51 };
51 52
52 #endif 53 #endif
@@ -97,6 +97,20 @@ int16_t SrsStream::read_2bytes() @@ -97,6 +97,20 @@ int16_t SrsStream::read_2bytes()
97 return value; 97 return value;
98 } 98 }
99 99
  100 +int32_t SrsStream::read_4bytes()
  101 +{
  102 + srs_assert(require(4));
  103 +
  104 + int32_t value;
  105 + pp = (char*)&value;
  106 + pp[3] = *p++;
  107 + pp[2] = *p++;
  108 + pp[1] = *p++;
  109 + pp[0] = *p++;
  110 +
  111 + return value;
  112 +}
  113 +
100 int64_t SrsStream::read_8bytes() 114 int64_t SrsStream::read_8bytes()
101 { 115 {
102 srs_assert(require(8)); 116 srs_assert(require(8));
@@ -80,6 +80,10 @@ public: @@ -80,6 +80,10 @@ public:
80 */ 80 */
81 virtual int16_t read_2bytes(); 81 virtual int16_t read_2bytes();
82 /** 82 /**
  83 + * get 4bytes int from stream.
  84 + */
  85 + virtual int32_t read_4bytes();
  86 + /**
83 * get 8bytes int from stream. 87 * get 8bytes int from stream.
84 */ 88 */
85 virtual int64_t read_8bytes(); 89 virtual int64_t read_8bytes();