正在显示
2 个修改的文件
包含
148 行增加
和
114 行删除
@@ -532,137 +532,149 @@ int SrsProtocol::decode_message(SrsMessage* msg, SrsPacket** ppacket) | @@ -532,137 +532,149 @@ int SrsProtocol::decode_message(SrsMessage* msg, SrsPacket** ppacket) | ||
532 | return ret; | 532 | return ret; |
533 | } | 533 | } |
534 | 534 | ||
535 | -int SrsProtocol::do_send_message(SrsMessage* msg, SrsPacket* packet) | 535 | +int SrsProtocol::do_send_message(SrsMessage* msg) |
536 | { | 536 | { |
537 | int ret = ERROR_SUCCESS; | 537 | int ret = ERROR_SUCCESS; |
538 | 538 | ||
539 | - // always not NULL msg. | ||
540 | - srs_assert(msg); | 539 | + // ignore empty message. |
540 | + if (!msg->payload || msg->size <= 0) { | ||
541 | + srs_info("ignore empty message."); | ||
542 | + return ret; | ||
543 | + } | ||
541 | 544 | ||
542 | // we donot use the complex basic header, | 545 | // we donot use the complex basic header, |
543 | // ensure the basic header is 1bytes. | 546 | // ensure the basic header is 1bytes. |
544 | if (msg->header.perfer_cid < 2) { | 547 | if (msg->header.perfer_cid < 2) { |
545 | - srs_warn("change the chunk_id=%d to default=%d", msg->header.perfer_cid, RTMP_CID_ProtocolControl); | 548 | + srs_warn("change the chunk_id=%d to default=%d", |
549 | + msg->header.perfer_cid, RTMP_CID_ProtocolControl); | ||
546 | msg->header.perfer_cid = RTMP_CID_ProtocolControl; | 550 | msg->header.perfer_cid = RTMP_CID_ProtocolControl; |
547 | } | 551 | } |
548 | 552 | ||
549 | // p set to current write position, | 553 | // p set to current write position, |
550 | // it's ok when payload is NULL and size is 0. | 554 | // it's ok when payload is NULL and size is 0. |
551 | char* p = msg->payload; | 555 | char* p = msg->payload; |
552 | - // to directly set the field. | ||
553 | - char* pp = NULL; | 556 | + char* pend = msg->payload + msg->size; |
554 | 557 | ||
555 | // always write the header event payload is empty. | 558 | // always write the header event payload is empty. |
556 | - do { | ||
557 | - // generate the header. | ||
558 | - char* pheader = out_header_cache; | 559 | + while (p < pend) { |
560 | + // always has header | ||
561 | + int nbh = 0; | ||
562 | + char* header = NULL; | ||
563 | + generate_chunk_header(&msg->header, p == msg->payload, &nbh, &header); | ||
564 | + srs_assert(nbh > 0); | ||
559 | 565 | ||
560 | - if (p == msg->payload) { | ||
561 | - // write new chunk stream header, fmt is 0 | ||
562 | - *pheader++ = 0x00 | (msg->header.perfer_cid & 0x3F); | ||
563 | - | ||
564 | - // chunk message header, 11 bytes | ||
565 | - // timestamp, 3bytes, big-endian | ||
566 | - u_int32_t timestamp = (u_int32_t)msg->header.timestamp; | ||
567 | - if (timestamp < RTMP_EXTENDED_TIMESTAMP) { | ||
568 | - pp = (char*)×tamp; | ||
569 | - *pheader++ = pp[2]; | ||
570 | - *pheader++ = pp[1]; | ||
571 | - *pheader++ = pp[0]; | ||
572 | - } else { | ||
573 | - *pheader++ = 0xFF; | ||
574 | - *pheader++ = 0xFF; | ||
575 | - *pheader++ = 0xFF; | ||
576 | - } | ||
577 | - | ||
578 | - // message_length, 3bytes, big-endian | ||
579 | - pp = (char*)&msg->header.payload_length; | ||
580 | - *pheader++ = pp[2]; | ||
581 | - *pheader++ = pp[1]; | ||
582 | - *pheader++ = pp[0]; | ||
583 | - | ||
584 | - // message_type, 1bytes | ||
585 | - *pheader++ = msg->header.message_type; | ||
586 | - | ||
587 | - // message_length, 3bytes, little-endian | ||
588 | - pp = (char*)&msg->header.stream_id; | ||
589 | - *pheader++ = pp[0]; | ||
590 | - *pheader++ = pp[1]; | ||
591 | - *pheader++ = pp[2]; | ||
592 | - *pheader++ = pp[3]; | ||
593 | - | ||
594 | - // chunk extended timestamp header, 0 or 4 bytes, big-endian | ||
595 | - if(timestamp >= RTMP_EXTENDED_TIMESTAMP) { | ||
596 | - pp = (char*)×tamp; | ||
597 | - *pheader++ = pp[3]; | ||
598 | - *pheader++ = pp[2]; | ||
599 | - *pheader++ = pp[1]; | ||
600 | - *pheader++ = pp[0]; | ||
601 | - } | ||
602 | - } else { | ||
603 | - // write no message header chunk stream, fmt is 3 | ||
604 | - // @remark, if perfer_cid > 0x3F, that is, use 2B/3B chunk header, | ||
605 | - // SRS will rollback to 1B chunk header. | ||
606 | - *pheader++ = 0xC0 | (msg->header.perfer_cid & 0x3F); | ||
607 | - | ||
608 | - // chunk extended timestamp header, 0 or 4 bytes, big-endian | ||
609 | - // 6.1.3. Extended Timestamp | ||
610 | - // This field is transmitted only when the normal time stamp in the | ||
611 | - // chunk message header is set to 0x00ffffff. If normal time stamp is | ||
612 | - // set to any value less than 0x00ffffff, this field MUST NOT be | ||
613 | - // present. This field MUST NOT be present if the timestamp field is not | ||
614 | - // present. Type 3 chunks MUST NOT have this field. | ||
615 | - // adobe changed for Type3 chunk: | ||
616 | - // FMLE always sendout the extended-timestamp, | ||
617 | - // must send the extended-timestamp to FMS, | ||
618 | - // must send the extended-timestamp to flash-player. | ||
619 | - // @see: ngx_rtmp_prepare_message | ||
620 | - // @see: http://blog.csdn.net/win_lin/article/details/13363699 | ||
621 | - u_int32_t timestamp = (u_int32_t)msg->header.timestamp; | ||
622 | - if (timestamp >= RTMP_EXTENDED_TIMESTAMP) { | ||
623 | - pp = (char*)×tamp; | ||
624 | - *pheader++ = pp[3]; | ||
625 | - *pheader++ = pp[2]; | ||
626 | - *pheader++ = pp[1]; | ||
627 | - *pheader++ = pp[0]; | ||
628 | - } | 566 | + // header iov |
567 | + iov[0].iov_base = header; | ||
568 | + iov[0].iov_len = nbh; | ||
569 | + | ||
570 | + // payload iov | ||
571 | + int payload_size = pend - p; | ||
572 | + if (payload_size > out_chunk_size) { | ||
573 | + payload_size = out_chunk_size; | ||
629 | } | 574 | } |
575 | + iov[1].iov_base = p; | ||
576 | + iov[1].iov_len = payload_size; | ||
630 | 577 | ||
578 | + // send by writev | ||
631 | // sendout header and payload by writev. | 579 | // sendout header and payload by writev. |
632 | // decrease the sys invoke count to get higher performance. | 580 | // decrease the sys invoke count to get higher performance. |
633 | - int payload_size = msg->size - (p - msg->payload); | ||
634 | - payload_size = srs_min(payload_size, out_chunk_size); | 581 | + if ((ret = skt->writev(iov, 2, NULL)) != ERROR_SUCCESS) { |
582 | + srs_error("send with writev failed. ret=%d", ret); | ||
583 | + return ret; | ||
584 | + } | ||
635 | 585 | ||
636 | - // always has header | ||
637 | - int header_size = pheader - out_header_cache; | ||
638 | - srs_assert(header_size > 0); | 586 | + // consume sendout bytes. |
587 | + p += payload_size; | ||
588 | + } | ||
589 | + | ||
590 | + return ret; | ||
591 | +} | ||
592 | + | ||
593 | +void SrsProtocol::generate_chunk_header(SrsMessageHeader* mh, bool c0, int* pnbh, char** ph) | ||
594 | +{ | ||
595 | + char* cache = out_c0_cache; | ||
596 | + | ||
597 | + // to directly set the field. | ||
598 | + char* pp = NULL; | ||
599 | + | ||
600 | + // generate the header. | ||
601 | + char* p = cache; | ||
602 | + | ||
603 | + if (c0) { | ||
604 | + // write new chunk stream header, fmt is 0 | ||
605 | + *p++ = 0x00 | (mh->perfer_cid & 0x3F); | ||
639 | 606 | ||
640 | - // send by writev | ||
641 | - iovec iov[2]; | ||
642 | - iov[0].iov_base = out_header_cache; | ||
643 | - iov[0].iov_len = header_size; | ||
644 | - iov[1].iov_base = p; | ||
645 | - iov[1].iov_len = payload_size; | 607 | + // chunk message header, 11 bytes |
608 | + // timestamp, 3bytes, big-endian | ||
609 | + u_int32_t timestamp = (u_int32_t)mh->timestamp; | ||
610 | + if (timestamp < RTMP_EXTENDED_TIMESTAMP) { | ||
611 | + pp = (char*)×tamp; | ||
612 | + *p++ = pp[2]; | ||
613 | + *p++ = pp[1]; | ||
614 | + *p++ = pp[0]; | ||
615 | + } else { | ||
616 | + *p++ = 0xFF; | ||
617 | + *p++ = 0xFF; | ||
618 | + *p++ = 0xFF; | ||
619 | + } | ||
646 | 620 | ||
647 | - ssize_t nwrite; | ||
648 | - if ((ret = skt->writev(iov, 2, &nwrite)) != ERROR_SUCCESS) { | ||
649 | - srs_error("send with writev failed. ret=%d", ret); | ||
650 | - return ret; | 621 | + // message_length, 3bytes, big-endian |
622 | + pp = (char*)&mh->payload_length; | ||
623 | + *p++ = pp[2]; | ||
624 | + *p++ = pp[1]; | ||
625 | + *p++ = pp[0]; | ||
626 | + | ||
627 | + // message_type, 1bytes | ||
628 | + *p++ = mh->message_type; | ||
629 | + | ||
630 | + // message_length, 3bytes, little-endian | ||
631 | + pp = (char*)&mh->stream_id; | ||
632 | + *p++ = pp[0]; | ||
633 | + *p++ = pp[1]; | ||
634 | + *p++ = pp[2]; | ||
635 | + *p++ = pp[3]; | ||
636 | + | ||
637 | + // chunk extended timestamp header, 0 or 4 bytes, big-endian | ||
638 | + if(timestamp >= RTMP_EXTENDED_TIMESTAMP) { | ||
639 | + pp = (char*)×tamp; | ||
640 | + *p++ = pp[3]; | ||
641 | + *p++ = pp[2]; | ||
642 | + *p++ = pp[1]; | ||
643 | + *p++ = pp[0]; | ||
651 | } | 644 | } |
645 | + } else { | ||
646 | + // write no message header chunk stream, fmt is 3 | ||
647 | + // @remark, if perfer_cid > 0x3F, that is, use 2B/3B chunk header, | ||
648 | + // SRS will rollback to 1B chunk header. | ||
649 | + *p++ = 0xC0 | (mh->perfer_cid & 0x3F); | ||
652 | 650 | ||
653 | - // consume sendout bytes when not empty packet. | ||
654 | - if (msg->payload && msg->size > 0) { | ||
655 | - p += payload_size; | 651 | + // chunk extended timestamp header, 0 or 4 bytes, big-endian |
652 | + // 6.1.3. Extended Timestamp | ||
653 | + // This field is transmitted only when the normal time stamp in the | ||
654 | + // chunk message header is set to 0x00ffffff. If normal time stamp is | ||
655 | + // set to any value less than 0x00ffffff, this field MUST NOT be | ||
656 | + // present. This field MUST NOT be present if the timestamp field is not | ||
657 | + // present. Type 3 chunks MUST NOT have this field. | ||
658 | + // adobe changed for Type3 chunk: | ||
659 | + // FMLE always sendout the extended-timestamp, | ||
660 | + // must send the extended-timestamp to FMS, | ||
661 | + // must send the extended-timestamp to flash-player. | ||
662 | + // @see: ngx_rtmp_prepare_message | ||
663 | + // @see: http://blog.csdn.net/win_lin/article/details/13363699 | ||
664 | + // TODO: FIXME: extract to outer. | ||
665 | + u_int32_t timestamp = (u_int32_t)mh->timestamp; | ||
666 | + if (timestamp >= RTMP_EXTENDED_TIMESTAMP) { | ||
667 | + pp = (char*)×tamp; | ||
668 | + *p++ = pp[3]; | ||
669 | + *p++ = pp[2]; | ||
670 | + *p++ = pp[1]; | ||
671 | + *p++ = pp[0]; | ||
656 | } | 672 | } |
657 | - } while (p < msg->payload + msg->size); | ||
658 | - | ||
659 | - // only process the callback event when with packet | ||
660 | - if (packet && (ret = on_send_packet(msg, packet)) != ERROR_SUCCESS) { | ||
661 | - srs_error("hook the send message failed. ret=%d", ret); | ||
662 | - return ret; | ||
663 | } | 673 | } |
664 | 674 | ||
665 | - return ret; | 675 | + // always has header |
676 | + *pnbh = p - cache; | ||
677 | + *ph = cache; | ||
666 | } | 678 | } |
667 | 679 | ||
668 | int SrsProtocol::do_decode_message(SrsMessageHeader& header, SrsStream* stream, SrsPacket** ppacket) | 680 | int SrsProtocol::do_decode_message(SrsMessageHeader& header, SrsStream* stream, SrsPacket** ppacket) |
@@ -834,14 +846,17 @@ int SrsProtocol::do_decode_message(SrsMessageHeader& header, SrsStream* stream, | @@ -834,14 +846,17 @@ int SrsProtocol::do_decode_message(SrsMessageHeader& header, SrsStream* stream, | ||
834 | 846 | ||
835 | int SrsProtocol::send_and_free_message(SrsMessage* msg, int stream_id) | 847 | int SrsProtocol::send_and_free_message(SrsMessage* msg, int stream_id) |
836 | { | 848 | { |
837 | - if (msg) { | ||
838 | - msg->header.stream_id = stream_id; | ||
839 | - } | 849 | + // always not NULL msg. |
850 | + srs_assert(msg); | ||
851 | + | ||
852 | + // update the stream id in header. | ||
853 | + msg->header.stream_id = stream_id; | ||
840 | 854 | ||
841 | // donot use the auto free to free the msg, | 855 | // donot use the auto free to free the msg, |
842 | // for performance issue. | 856 | // for performance issue. |
843 | - int ret = do_send_message(msg, NULL); | 857 | + int ret = do_send_message(msg); |
844 | srs_freep(msg); | 858 | srs_freep(msg); |
859 | + | ||
845 | return ret; | 860 | return ret; |
846 | } | 861 | } |
847 | 862 | ||
@@ -878,7 +893,10 @@ int SrsProtocol::send_and_free_packet(SrsPacket* packet, int stream_id) | @@ -878,7 +893,10 @@ int SrsProtocol::send_and_free_packet(SrsPacket* packet, int stream_id) | ||
878 | 893 | ||
879 | // donot use the auto free to free the msg, | 894 | // donot use the auto free to free the msg, |
880 | // for performance issue. | 895 | // for performance issue. |
881 | - ret = do_send_message(msg, packet); | 896 | + ret = do_send_message(msg); |
897 | + if (ret == ERROR_SUCCESS) { | ||
898 | + ret = on_send_packet(msg, packet); | ||
899 | + } | ||
882 | srs_freep(msg); | 900 | srs_freep(msg); |
883 | 901 | ||
884 | return ret; | 902 | return ret; |
@@ -1535,8 +1553,10 @@ int SrsProtocol::on_send_packet(SrsMessage* msg, SrsPacket* packet) | @@ -1535,8 +1553,10 @@ int SrsProtocol::on_send_packet(SrsMessage* msg, SrsPacket* packet) | ||
1535 | { | 1553 | { |
1536 | int ret = ERROR_SUCCESS; | 1554 | int ret = ERROR_SUCCESS; |
1537 | 1555 | ||
1538 | - // should never be raw bytes oriented RTMP message. | ||
1539 | - srs_assert(packet); | 1556 | + // ignore raw bytes oriented RTMP message. |
1557 | + if (packet == NULL) { | ||
1558 | + return ret; | ||
1559 | + } | ||
1540 | 1560 | ||
1541 | switch (msg->header.message_type) { | 1561 | switch (msg->header.message_type) { |
1542 | case RTMP_MSG_SetChunkSize: { | 1562 | case RTMP_MSG_SetChunkSize: { |
@@ -32,6 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -32,6 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
32 | 32 | ||
33 | #include <map> | 33 | #include <map> |
34 | #include <string> | 34 | #include <string> |
35 | +#include <sys/uio.h> | ||
35 | 36 | ||
36 | #include <srs_kernel_log.hpp> | 37 | #include <srs_kernel_log.hpp> |
37 | #include <srs_kernel_error.hpp> | 38 | #include <srs_kernel_error.hpp> |
@@ -214,7 +215,11 @@ private: | @@ -214,7 +215,11 @@ private: | ||
214 | * used for type0, 11bytes(or 15bytes with extended timestamp) header. | 215 | * used for type0, 11bytes(or 15bytes with extended timestamp) header. |
215 | * or for type3, 1bytes(or 5bytes with extended timestamp) header. | 216 | * or for type3, 1bytes(or 5bytes with extended timestamp) header. |
216 | */ | 217 | */ |
217 | - char out_header_cache[SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE]; | 218 | + char out_c0_cache[SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE]; |
219 | + /** | ||
220 | + * output iovec cache. | ||
221 | + */ | ||
222 | + iovec iov[2]; | ||
218 | /** | 223 | /** |
219 | * output chunk size, default to 128, set by config. | 224 | * output chunk size, default to 128, set by config. |
220 | */ | 225 | */ |
@@ -339,10 +344,19 @@ public: | @@ -339,10 +344,19 @@ public: | ||
339 | } | 344 | } |
340 | private: | 345 | private: |
341 | /** | 346 | /** |
342 | - * send out the message, donot free it, the caller must free the param msg. | ||
343 | - * @param packet the packet of message, NULL for raw message. | 347 | + * send out the message, donot free it, |
348 | + * the caller must free the param msg. | ||
349 | + */ | ||
350 | + virtual int do_send_message(SrsMessage* msg); | ||
351 | + /** | ||
352 | + * generate the chunk header for msg. | ||
353 | + * @param mh, the header of msg to send. | ||
354 | + * @param c0, whether the first chunk, the c0 chunk. | ||
355 | + * @param pnbh, output the size of header. | ||
356 | + * @param ph, output the header cache. | ||
357 | + * user should never free it, it's cached header. | ||
344 | */ | 358 | */ |
345 | - virtual int do_send_message(SrsMessage* msg, SrsPacket* packet); | 359 | + virtual void generate_chunk_header(SrsMessageHeader* mh, bool c0, int* pnbh, char** ph); |
346 | /** | 360 | /** |
347 | * imp for decode_message | 361 | * imp for decode_message |
348 | */ | 362 | */ |
-
请 注册 或 登录 后发表评论