winlin

Merge branch 'srs.master'

@@ -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, 576 // only when user specifies the duration,
585 // we start to collect the durations for each message. 577 // we start to collect the durations for each message.
586 if (user_specified_duration_to_stop) { 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 }
  590 + }
595 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; 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;
600 } 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 + }
  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 + }
596 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 */