正在显示
8 个修改的文件
包含
251 行增加
和
29 行删除
@@ -242,6 +242,7 @@ Supported operating systems and hardware: | @@ -242,6 +242,7 @@ Supported operating systems and hardware: | ||
242 | * 2013-10-17, Created.<br/> | 242 | * 2013-10-17, Created.<br/> |
243 | 243 | ||
244 | ## History | 244 | ## History |
245 | +* v2.0, 2014-11-08, fix [#194](https://github.com/winlinvip/simple-rtmp-server/issues/194), writev multiple msgs, support 6k+ 250kbps clients. 2.0.15. | ||
245 | * v2.0, 2014-11-08, fix [#194](https://github.com/winlinvip/simple-rtmp-server/issues/194), optmized st for timeout recv. pulse to 500ms. 2.0.14. | 246 | * v2.0, 2014-11-08, fix [#194](https://github.com/winlinvip/simple-rtmp-server/issues/194), optmized st for timeout recv. pulse to 500ms. 2.0.14. |
246 | * v2.0, 2014-11-08, fix [#195](https://github.com/winlinvip/simple-rtmp-server/issues/195), remove the confuse code st_usleep(0). 2.0.13. | 247 | * v2.0, 2014-11-08, fix [#195](https://github.com/winlinvip/simple-rtmp-server/issues/195), remove the confuse code st_usleep(0). 2.0.13. |
247 | * v2.0, 2014-11-08, fix [#191](https://github.com/winlinvip/simple-rtmp-server/issues/191), configure --export-librtmp-project and --export-librtmp-single. 2.0.11. | 248 | * v2.0, 2014-11-08, fix [#191](https://github.com/winlinvip/simple-rtmp-server/issues/191), configure --export-librtmp-project and --export-librtmp-single. 2.0.11. |
@@ -449,6 +450,7 @@ Performance benchmark history, on virtual box: | @@ -449,6 +450,7 @@ Performance benchmark history, on virtual box: | ||
449 | * 2014-11-11, SRS 1.0.5, 2700clients, 85%CPU, 66MB. (1.0 equals 2.0.12) | 450 | * 2014-11-11, SRS 1.0.5, 2700clients, 85%CPU, 66MB. (1.0 equals 2.0.12) |
450 | * 2014-11-12, SRS 2.0.14, 2700clients, 69%CPU, 59MB. | 451 | * 2014-11-12, SRS 2.0.14, 2700clients, 69%CPU, 59MB. |
451 | * 2014-11-12, SRS 2.0.14, 3500clients, 95%CPU, 78MB. | 452 | * 2014-11-12, SRS 2.0.14, 3500clients, 95%CPU, 78MB. |
453 | +* 2014-11-13, SRS 2.0.15, 6000clients, 82%CPU, 203MB. | ||
452 | 454 | ||
453 | Latest benchmark(2014-07-12): | 455 | Latest benchmark(2014-07-12): |
454 | 456 |
@@ -525,10 +525,7 @@ int SrsRtmpConn::playing(SrsSource* source) | @@ -525,10 +525,7 @@ int SrsRtmpConn::playing(SrsSource* source) | ||
525 | int64_t starttime = -1; | 525 | int64_t starttime = -1; |
526 | 526 | ||
527 | while (true) { | 527 | while (true) { |
528 | - // collect elapse for pithy print. | ||
529 | - pithy_print.elapse(); | ||
530 | - | ||
531 | - // to use isolate thread to recv, can improve about 5% performance. | 528 | + // TODO: to use isolate thread to recv, can improve about 5% performance. |
532 | // @see: https://github.com/winlinvip/simple-rtmp-server/issues/196 | 529 | // @see: https://github.com/winlinvip/simple-rtmp-server/issues/196 |
533 | // read from client. | 530 | // read from client. |
534 | if (true) { | 531 | if (true) { |
@@ -539,6 +536,7 @@ int SrsRtmpConn::playing(SrsSource* source) | @@ -539,6 +536,7 @@ int SrsRtmpConn::playing(SrsSource* source) | ||
539 | if (ret == ERROR_SOCKET_TIMEOUT) { | 536 | if (ret == ERROR_SOCKET_TIMEOUT) { |
540 | // it's ok, do nothing. | 537 | // it's ok, do nothing. |
541 | ret = ERROR_SUCCESS; | 538 | ret = ERROR_SUCCESS; |
539 | + srs_verbose("recv timeout, ignore. ret=%d", ret); | ||
542 | } else if (ret != ERROR_SUCCESS) { | 540 | } else if (ret != ERROR_SUCCESS) { |
543 | if (!srs_is_client_gracefully_close(ret)) { | 541 | if (!srs_is_client_gracefully_close(ret)) { |
544 | srs_error("recv client control message failed. ret=%d", ret); | 542 | srs_error("recv client control message failed. ret=%d", ret); |
@@ -554,6 +552,9 @@ int SrsRtmpConn::playing(SrsSource* source) | @@ -554,6 +552,9 @@ int SrsRtmpConn::playing(SrsSource* source) | ||
554 | } | 552 | } |
555 | } | 553 | } |
556 | 554 | ||
555 | + // collect elapse for pithy print. | ||
556 | + pithy_print.elapse(); | ||
557 | + | ||
557 | // get messages from consumer. | 558 | // get messages from consumer. |
558 | int count = 0; | 559 | int count = 0; |
559 | if ((ret = consumer->dump_packets(msgs.size, msgs.msgs, count)) != ERROR_SUCCESS) { | 560 | if ((ret = consumer->dump_packets(msgs.size, msgs.msgs, count)) != ERROR_SUCCESS) { |
@@ -568,22 +569,16 @@ int SrsRtmpConn::playing(SrsSource* source) | @@ -568,22 +569,16 @@ int SrsRtmpConn::playing(SrsSource* source) | ||
568 | " time=%"PRId64", msgs=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d", | 569 | " time=%"PRId64", msgs=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d", |
569 | pithy_print.age(), count, | 570 | pithy_print.age(), count, |
570 | kbps->get_send_kbps(), kbps->get_send_kbps_30s(), kbps->get_send_kbps_5m(), | 571 | kbps->get_send_kbps(), kbps->get_send_kbps_30s(), kbps->get_send_kbps_5m(), |
571 | - kbps->get_recv_kbps(), kbps->get_recv_kbps_30s(), kbps->get_recv_kbps_5m()); | 572 | + kbps->get_recv_kbps(), kbps->get_recv_kbps_30s(), kbps->get_recv_kbps_5m() |
573 | + ); | ||
572 | } | 574 | } |
573 | 575 | ||
574 | - // sendout messages | ||
575 | - // @remark, becareful, all msgs must be free explicitly, | ||
576 | - // free by send_and_free_message or srs_freep. | ||
577 | - for (int i = 0; i < count; i++) { | ||
578 | - SrsSharedPtrMessage* msg = msgs.msgs[i]; | ||
579 | - | ||
580 | - // the send_message will free the msg, | ||
581 | - // so set the msgs[i] to NULL. | ||
582 | - msgs.msgs[i] = NULL; | ||
583 | - | ||
584 | - // only when user specifies the duration, | ||
585 | - // we start to collect the durations for each message. | ||
586 | - if (user_specified_duration_to_stop) { | 576 | + // only when user specifies the duration, |
577 | + // we start to collect the durations for each message. | ||
578 | + if (user_specified_duration_to_stop) { | ||
579 | + for (int i = 0; i < count; i++) { | ||
580 | + SrsSharedPtrMessage* msg = msgs.msgs[i]; | ||
581 | + | ||
587 | // foreach msg, collect the duration. | 582 | // foreach msg, collect the duration. |
588 | // @remark: never use msg when sent it, for the protocol sdk will free it. | 583 | // @remark: never use msg when sent it, for the protocol sdk will free it. |
589 | if (starttime < 0 || starttime > msg->header.timestamp) { | 584 | if (starttime < 0 || starttime > msg->header.timestamp) { |
@@ -592,12 +587,23 @@ int SrsRtmpConn::playing(SrsSource* source) | @@ -592,12 +587,23 @@ int SrsRtmpConn::playing(SrsSource* source) | ||
592 | duration += msg->header.timestamp - starttime; | 587 | duration += msg->header.timestamp - starttime; |
593 | starttime = msg->header.timestamp; | 588 | starttime = msg->header.timestamp; |
594 | } | 589 | } |
595 | - | 590 | + } |
591 | + | ||
592 | + // sendout messages | ||
593 | + // @remark, becareful, all msgs must be free explicitly, | ||
594 | + // free by send_and_free_message or srs_freep. | ||
595 | + if (count > 0) { | ||
596 | // no need to assert msg, for the rtmp will assert it. | 596 | // no need to assert msg, for the rtmp will assert it. |
597 | - if ((ret = rtmp->send_and_free_message(msg, res->stream_id)) != ERROR_SUCCESS) { | ||
598 | - srs_error("send message to client failed. ret=%d", ret); | ||
599 | - return ret; | ||
600 | - } | 597 | + ret = rtmp->send_and_free_messages(msgs.msgs, count, res->stream_id); |
598 | + } | ||
599 | + for (int i = 0; i < count; i++) { | ||
600 | + // the send_message will free the msg, | ||
601 | + // so set the msgs[i] to NULL. | ||
602 | + msgs.msgs[i] = NULL; | ||
603 | + } | ||
604 | + if (ret != ERROR_SUCCESS) { | ||
605 | + srs_error("send messages to client failed. ret=%d", ret); | ||
606 | + return ret; | ||
601 | } | 607 | } |
602 | 608 | ||
603 | // if duration specified, and exceed it, stop play live. | 609 | // if duration specified, and exceed it, stop play live. |
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
31 | // current release version | 31 | // current release version |
32 | #define VERSION_MAJOR 2 | 32 | #define VERSION_MAJOR 2 |
33 | #define VERSION_MINOR 0 | 33 | #define VERSION_MINOR 0 |
34 | -#define VERSION_REVISION 14 | 34 | +#define VERSION_REVISION 15 |
35 | // server info. | 35 | // server info. |
36 | #define RTMP_SIG_SRS_KEY "SRS" | 36 | #define RTMP_SIG_SRS_KEY "SRS" |
37 | #define RTMP_SIG_SRS_ROLE "origin/edge server" | 37 | #define RTMP_SIG_SRS_ROLE "origin/edge server" |
@@ -97,6 +97,19 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -97,6 +97,19 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
97 | // always use fmt0 as cache. | 97 | // always use fmt0 as cache. |
98 | //#define SRS_CONSTS_RTMP_MAX_FMT3_HEADER_SIZE 5 | 98 | //#define SRS_CONSTS_RTMP_MAX_FMT3_HEADER_SIZE 5 |
99 | 99 | ||
100 | +/** | ||
101 | +* for performance issue, | ||
102 | +* the iovs cache, @see https://github.com/winlinvip/simple-rtmp-server/issues/194 | ||
103 | +* iovs cache for multiple messages for each connections. | ||
104 | +*/ | ||
105 | +#define SRS_CONSTS_IOVS_MAX 1024 | ||
106 | +/** | ||
107 | +* for performance issue, | ||
108 | +* the c0c3 cache, @see https://github.com/winlinvip/simple-rtmp-server/issues/194 | ||
109 | +* c0c3 cache for multiple messages for each connections. | ||
110 | +*/ | ||
111 | +#define SRS_CONSTS_C0C3_HEADERS_MAX 4096 | ||
112 | + | ||
100 | /////////////////////////////////////////////////////////// | 113 | /////////////////////////////////////////////////////////// |
101 | /////////////////////////////////////////////////////////// | 114 | /////////////////////////////////////////////////////////// |
102 | /////////////////////////////////////////////////////////// | 115 | /////////////////////////////////////////////////////////// |
@@ -771,6 +771,11 @@ int SrsRtmpServer::send_and_free_message(SrsMessage* msg, int stream_id) | @@ -771,6 +771,11 @@ int SrsRtmpServer::send_and_free_message(SrsMessage* msg, int stream_id) | ||
771 | return protocol->send_and_free_message(msg, stream_id); | 771 | return protocol->send_and_free_message(msg, stream_id); |
772 | } | 772 | } |
773 | 773 | ||
774 | +int SrsRtmpServer::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id) | ||
775 | +{ | ||
776 | + return protocol->send_and_free_messages(msgs, nb_msgs, stream_id); | ||
777 | +} | ||
778 | + | ||
774 | int SrsRtmpServer::send_and_free_packet(SrsPacket* packet, int stream_id) | 779 | int SrsRtmpServer::send_and_free_packet(SrsPacket* packet, int stream_id) |
775 | { | 780 | { |
776 | return protocol->send_and_free_packet(packet, stream_id); | 781 | return protocol->send_and_free_packet(packet, stream_id); |
@@ -368,6 +368,15 @@ public: | @@ -368,6 +368,15 @@ public: | ||
368 | */ | 368 | */ |
369 | virtual int send_and_free_message(SrsMessage* msg, int stream_id); | 369 | virtual int send_and_free_message(SrsMessage* msg, int stream_id); |
370 | /** | 370 | /** |
371 | + * send the RTMP message and always free it. | ||
372 | + * user must never free or use the msg after this method, | ||
373 | + * for it will always free the msg. | ||
374 | + * @param msgs, the msgs to send out, never be NULL. | ||
375 | + * @param nb_msgs, the size of msgs to send out. | ||
376 | + * @param stream_id, the stream id of packet to send over, 0 for control message. | ||
377 | + */ | ||
378 | + virtual int send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id); | ||
379 | + /** | ||
371 | * send the RTMP packet and always free it. | 380 | * send the RTMP packet and always free it. |
372 | * user must never free or use the packet after this method, | 381 | * user must never free or use the packet after this method, |
373 | * for it will always free the packet. | 382 | * for it will always free the packet. |
@@ -29,6 +29,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -29,6 +29,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
29 | #include <srs_core_autofree.hpp> | 29 | #include <srs_core_autofree.hpp> |
30 | #include <srs_kernel_utility.hpp> | 30 | #include <srs_kernel_utility.hpp> |
31 | 31 | ||
32 | +#include <stdlib.h> | ||
32 | using namespace std; | 33 | using namespace std; |
33 | 34 | ||
34 | // when got a messae header, there must be some data, | 35 | // when got a messae header, there must be some data, |
@@ -404,7 +405,15 @@ SrsProtocol::SrsProtocol(ISrsProtocolReaderWriter* io) | @@ -404,7 +405,15 @@ SrsProtocol::SrsProtocol(ISrsProtocolReaderWriter* io) | ||
404 | in_buffer = new SrsBuffer(); | 405 | in_buffer = new SrsBuffer(); |
405 | skt = io; | 406 | skt = io; |
406 | 407 | ||
407 | - in_chunk_size = out_chunk_size = SRS_CONSTS_RTMP_PROTOCOL_CHUNK_SIZE; | 408 | + in_chunk_size = SRS_CONSTS_RTMP_PROTOCOL_CHUNK_SIZE; |
409 | + out_chunk_size = SRS_CONSTS_RTMP_PROTOCOL_CHUNK_SIZE; | ||
410 | + | ||
411 | + nb_out_iovs = SRS_CONSTS_IOVS_MAX; | ||
412 | + out_iovs = (iovec*)malloc(sizeof(iovec) * nb_out_iovs); | ||
413 | + // each chunk consumers atleast 2 iovs | ||
414 | + srs_assert(nb_out_iovs >= 2); | ||
415 | + | ||
416 | + warned_c0c3_caches = false; | ||
408 | } | 417 | } |
409 | 418 | ||
410 | SrsProtocol::~SrsProtocol() | 419 | SrsProtocol::~SrsProtocol() |
@@ -421,6 +430,12 @@ SrsProtocol::~SrsProtocol() | @@ -421,6 +430,12 @@ SrsProtocol::~SrsProtocol() | ||
421 | } | 430 | } |
422 | 431 | ||
423 | srs_freep(in_buffer); | 432 | srs_freep(in_buffer); |
433 | + | ||
434 | + // alloc by malloc, use free directly. | ||
435 | + if (out_iovs) { | ||
436 | + free(out_iovs); | ||
437 | + out_iovs = NULL; | ||
438 | + } | ||
424 | } | 439 | } |
425 | 440 | ||
426 | void SrsProtocol::set_recv_timeout(int64_t timeout_us) | 441 | void SrsProtocol::set_recv_timeout(int64_t timeout_us) |
@@ -560,7 +575,7 @@ int SrsProtocol::do_send_message(SrsMessage* msg) | @@ -560,7 +575,7 @@ int SrsProtocol::do_send_message(SrsMessage* msg) | ||
560 | // always has header | 575 | // always has header |
561 | int nbh = 0; | 576 | int nbh = 0; |
562 | char* header = NULL; | 577 | char* header = NULL; |
563 | - generate_chunk_header(&msg->header, p == msg->payload, &nbh, &header); | 578 | + generate_chunk_header(out_c0c3_cache, &msg->header, p == msg->payload, &nbh, &header); |
564 | srs_assert(nbh > 0); | 579 | srs_assert(nbh > 0); |
565 | 580 | ||
566 | // header iov | 581 | // header iov |
@@ -590,10 +605,130 @@ int SrsProtocol::do_send_message(SrsMessage* msg) | @@ -590,10 +605,130 @@ int SrsProtocol::do_send_message(SrsMessage* msg) | ||
590 | return ret; | 605 | return ret; |
591 | } | 606 | } |
592 | 607 | ||
593 | -void SrsProtocol::generate_chunk_header(SrsMessageHeader* mh, bool c0, int* pnbh, char** ph) | 608 | +int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) |
594 | { | 609 | { |
595 | - char* cache = out_c0c3_cache; | 610 | + int ret = ERROR_SUCCESS; |
611 | + | ||
612 | + // TODO: FIXME: use cache system instead. | ||
613 | + int iov_index = 0; | ||
614 | + iovec* iov = out_iovs + iov_index; | ||
615 | + | ||
616 | + int c0c3_cache_index = 0; | ||
617 | + char* c0c3_cache = out_c0c3_caches + c0c3_cache_index; | ||
618 | + | ||
619 | + // try to send use the c0c3 header cache, | ||
620 | + // if cache is consumed, try another loop. | ||
621 | + for (int i = 0; i < nb_msgs; i++) { | ||
622 | + SrsMessage* msg = msgs[i]; | ||
623 | + | ||
624 | + // ignore empty message. | ||
625 | + if (!msg->payload || msg->size <= 0) { | ||
626 | + srs_info("ignore empty message."); | ||
627 | + continue; | ||
628 | + } | ||
629 | + | ||
630 | + // we donot use the complex basic header, | ||
631 | + // ensure the basic header is 1bytes. | ||
632 | + if (msg->header.perfer_cid < 2) { | ||
633 | + srs_warn("change the chunk_id=%d to default=%d", | ||
634 | + msg->header.perfer_cid, RTMP_CID_ProtocolControl); | ||
635 | + msg->header.perfer_cid = RTMP_CID_ProtocolControl; | ||
636 | + } | ||
637 | + | ||
638 | + // p set to current write position, | ||
639 | + // it's ok when payload is NULL and size is 0. | ||
640 | + char* p = msg->payload; | ||
641 | + char* pend = msg->payload + msg->size; | ||
642 | + | ||
643 | + // always write the header event payload is empty. | ||
644 | + while (p < pend) { | ||
645 | + // always has header | ||
646 | + int nbh = 0; | ||
647 | + char* header = NULL; | ||
648 | + generate_chunk_header(c0c3_cache, &msg->header, p == msg->payload, &nbh, &header); | ||
649 | + srs_assert(nbh > 0); | ||
650 | + | ||
651 | + // header iov | ||
652 | + iov[0].iov_base = header; | ||
653 | + iov[0].iov_len = nbh; | ||
654 | + | ||
655 | + // payload iov | ||
656 | + int payload_size = pend - p; | ||
657 | + if (payload_size > out_chunk_size) { | ||
658 | + payload_size = out_chunk_size; | ||
659 | + } | ||
660 | + iov[1].iov_base = p; | ||
661 | + iov[1].iov_len = payload_size; | ||
662 | + | ||
663 | + // consume sendout bytes. | ||
664 | + p += payload_size; | ||
665 | + | ||
666 | + // realloc the iovs if exceed, | ||
667 | + // for we donot know how many messges maybe to send entirely, | ||
668 | + // we just alloc the iovs, it's ok. | ||
669 | + if (iov_index >= nb_out_iovs - 2) { | ||
670 | + nb_out_iovs += SRS_CONSTS_IOVS_MAX; | ||
671 | + int realloc_size = sizeof(iovec) * nb_out_iovs; | ||
672 | + out_iovs = (iovec*)realloc(out_iovs, realloc_size); | ||
673 | + } | ||
674 | + | ||
675 | + // to next pair of iovs | ||
676 | + iov_index += 2; | ||
677 | + iov = out_iovs + iov_index; | ||
678 | + | ||
679 | + // to next c0c3 header cache | ||
680 | + c0c3_cache_index += nbh; | ||
681 | + c0c3_cache = out_c0c3_caches + c0c3_cache_index; | ||
682 | + | ||
683 | + // the cache header should never be realloc again, | ||
684 | + // for the ptr is set to iovs, so we just warn user to set larger | ||
685 | + // and use another loop to send again. | ||
686 | + int c0c3_left = SRS_CONSTS_C0C3_HEADERS_MAX - c0c3_cache_index; | ||
687 | + if (c0c3_left < SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE) { | ||
688 | + // only warn once for a connection. | ||
689 | + if (!warned_c0c3_caches) { | ||
690 | + srs_warn("c0c3 cache header too small, recoment to %d", | ||
691 | + SRS_CONSTS_C0C3_HEADERS_MAX + SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE); | ||
692 | + warned_c0c3_caches = true; | ||
693 | + } | ||
694 | + | ||
695 | + // when c0c3 cache dry, | ||
696 | + // sendout all messages and reset the cache, then send again. | ||
697 | + if ((ret = skt->writev(out_iovs, iov_index, NULL)) != ERROR_SUCCESS) { | ||
698 | + srs_error("send with writev failed. ret=%d", ret); | ||
699 | + return ret; | ||
700 | + } | ||
596 | 701 | ||
702 | + // reset caches, while these cache ensure | ||
703 | + // atleast we can sendout a chunk. | ||
704 | + iov_index = 0; | ||
705 | + iov = out_iovs + iov_index; | ||
706 | + | ||
707 | + c0c3_cache_index = 0; | ||
708 | + c0c3_cache = out_c0c3_caches + c0c3_cache_index; | ||
709 | + } | ||
710 | + } | ||
711 | + } | ||
712 | + | ||
713 | + // maybe the iovs already sendout when c0c3 cache dry, | ||
714 | + // so just ignore when no iovs to send. | ||
715 | + if (iov_index <= 0) { | ||
716 | + return ret; | ||
717 | + } | ||
718 | + | ||
719 | + // send by writev | ||
720 | + // sendout header and payload by writev. | ||
721 | + // decrease the sys invoke count to get higher performance. | ||
722 | + if ((ret = skt->writev(out_iovs, iov_index, NULL)) != ERROR_SUCCESS) { | ||
723 | + srs_error("send with writev failed. ret=%d", ret); | ||
724 | + return ret; | ||
725 | + } | ||
726 | + | ||
727 | + return ret; | ||
728 | +} | ||
729 | + | ||
730 | +void SrsProtocol::generate_chunk_header(char* cache, SrsMessageHeader* mh, bool c0, int* pnbh, char** ph) | ||
731 | +{ | ||
597 | // to directly set the field. | 732 | // to directly set the field. |
598 | char* pp = NULL; | 733 | char* pp = NULL; |
599 | 734 | ||
@@ -856,6 +991,34 @@ int SrsProtocol::send_and_free_message(SrsMessage* msg, int stream_id) | @@ -856,6 +991,34 @@ int SrsProtocol::send_and_free_message(SrsMessage* msg, int stream_id) | ||
856 | return ret; | 991 | return ret; |
857 | } | 992 | } |
858 | 993 | ||
994 | +int SrsProtocol::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id) | ||
995 | +{ | ||
996 | + // always not NULL msg. | ||
997 | + srs_assert(msgs); | ||
998 | + srs_assert(nb_msgs > 0); | ||
999 | + | ||
1000 | + // update the stream id in header. | ||
1001 | + for (int i = 0; i < nb_msgs; i++) { | ||
1002 | + SrsMessage* msg = msgs[i]; | ||
1003 | + // we assume that the stream_id in a group must be the same. | ||
1004 | + if (msg->header.stream_id == stream_id) { | ||
1005 | + break; | ||
1006 | + } | ||
1007 | + msg->header.stream_id = stream_id; | ||
1008 | + } | ||
1009 | + | ||
1010 | + // donot use the auto free to free the msg, | ||
1011 | + // for performance issue. | ||
1012 | + int ret = do_send_messages(msgs, nb_msgs); | ||
1013 | + | ||
1014 | + for (int i = 0; i < nb_msgs; i++) { | ||
1015 | + SrsMessage* msg = msgs[i]; | ||
1016 | + srs_freep(msg); | ||
1017 | + } | ||
1018 | + | ||
1019 | + return ret; | ||
1020 | +} | ||
1021 | + | ||
859 | int SrsProtocol::send_and_free_packet(SrsPacket* packet, int stream_id) | 1022 | int SrsProtocol::send_and_free_packet(SrsPacket* packet, int stream_id) |
860 | { | 1023 | { |
861 | int ret = ERROR_SUCCESS; | 1024 | int ret = ERROR_SUCCESS; |
@@ -47,6 +47,7 @@ class SrsAmf0Any; | @@ -47,6 +47,7 @@ class SrsAmf0Any; | ||
47 | class SrsMessageHeader; | 47 | class SrsMessageHeader; |
48 | class SrsMessage; | 48 | class SrsMessage; |
49 | class SrsChunkStream; | 49 | class SrsChunkStream; |
50 | +class SrsSharedPtrMessage; | ||
50 | 51 | ||
51 | /** | 52 | /** |
52 | * 4.1. Message Header | 53 | * 4.1. Message Header |
@@ -221,6 +222,15 @@ private: | @@ -221,6 +222,15 @@ private: | ||
221 | */ | 222 | */ |
222 | iovec out_iov[2]; | 223 | iovec out_iov[2]; |
223 | /** | 224 | /** |
225 | + * cache for multiple messages send | ||
226 | + */ | ||
227 | + iovec* out_iovs; | ||
228 | + int nb_out_iovs; | ||
229 | + // the c0c3 cache cannot be realloc. | ||
230 | + char out_c0c3_caches[SRS_CONSTS_C0C3_HEADERS_MAX]; | ||
231 | + // whether warned user to increase the c0c3 header cache. | ||
232 | + bool warned_c0c3_caches; | ||
233 | + /** | ||
224 | * output chunk size, default to 128, set by config. | 234 | * output chunk size, default to 128, set by config. |
225 | */ | 235 | */ |
226 | int32_t out_chunk_size; | 236 | int32_t out_chunk_size; |
@@ -276,6 +286,15 @@ public: | @@ -276,6 +286,15 @@ public: | ||
276 | */ | 286 | */ |
277 | virtual int send_and_free_message(SrsMessage* msg, int stream_id); | 287 | virtual int send_and_free_message(SrsMessage* msg, int stream_id); |
278 | /** | 288 | /** |
289 | + * send the RTMP message and always free it. | ||
290 | + * user must never free or use the msg after this method, | ||
291 | + * for it will always free the msg. | ||
292 | + * @param msgs, the msgs to send out, never be NULL. | ||
293 | + * @param nb_msgs, the size of msgs to send out. | ||
294 | + * @param stream_id, the stream id of packet to send over, 0 for control message. | ||
295 | + */ | ||
296 | + virtual int send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id); | ||
297 | + /** | ||
279 | * send the RTMP packet and always free it. | 298 | * send the RTMP packet and always free it. |
280 | * user must never free or use the packet after this method, | 299 | * user must never free or use the packet after this method, |
281 | * for it will always free the packet. | 300 | * for it will always free the packet. |
@@ -349,6 +368,11 @@ private: | @@ -349,6 +368,11 @@ private: | ||
349 | */ | 368 | */ |
350 | virtual int do_send_message(SrsMessage* msg); | 369 | virtual int do_send_message(SrsMessage* msg); |
351 | /** | 370 | /** |
371 | + * send out the messages, donot free it, | ||
372 | + * the caller must free the param msgs. | ||
373 | + */ | ||
374 | + virtual int do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs); | ||
375 | + /** | ||
352 | * generate the chunk header for msg. | 376 | * generate the chunk header for msg. |
353 | * @param mh, the header of msg to send. | 377 | * @param mh, the header of msg to send. |
354 | * @param c0, whether the first chunk, the c0 chunk. | 378 | * @param c0, whether the first chunk, the c0 chunk. |
@@ -356,7 +380,7 @@ private: | @@ -356,7 +380,7 @@ private: | ||
356 | * @param ph, output the header cache. | 380 | * @param ph, output the header cache. |
357 | * user should never free it, it's cached header. | 381 | * user should never free it, it's cached header. |
358 | */ | 382 | */ |
359 | - virtual void generate_chunk_header(SrsMessageHeader* mh, bool c0, int* pnbh, char** ph); | 383 | + virtual void generate_chunk_header(char* cache, SrsMessageHeader* mh, bool c0, int* pnbh, char** ph); |
360 | /** | 384 | /** |
361 | * imp for decode_message | 385 | * imp for decode_message |
362 | */ | 386 | */ |
-
请 注册 或 登录 后发表评论