正在显示
10 个修改的文件
包含
484 行增加
和
43 行删除
@@ -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(); |
-
请 注册 或 登录 后发表评论