From 6e9e0d6ce3c6543050799de00e090074d02429ed Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 10:35:38 +0800 Subject: [PATCH 01/54] Fix build script --- trunk/auto/depends.sh | 20 +++++++++++--------- trunk/auto/options.sh | 1 + trunk/src/app/srs_app_http_api.cpp | 10 +++++++++- trunk/src/app/srs_app_statistic.hpp | 3 +++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index f2d3e378c..8fd54333c 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -84,15 +84,6 @@ function Ubuntu_prepare() echo "The unzip is installed." fi - if [[ $SRS_NASM == YES ]]; then - nasm -v >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then - echo "Installing nasm." - require_sudoer "sudo apt-get install -y --force-yes nasm" - sudo apt-get install -y --force-yes nasm; ret=$?; if [[ 0 -ne $ret ]]; then return $ret; fi - echo "The nasm is installed." - fi - fi - if [[ $SRS_VALGRIND == YES ]]; then valgrind --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then echo "Installing valgrind." @@ -281,6 +272,10 @@ function OSX_prepare() echo "install unzip success" fi + pkg-config --version >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then + echo "Please install pkg-config"; exit -1; + fi + echo "OSX install tools success" return 0 } @@ -614,9 +609,16 @@ fi ##################################################################################### if [[ $SRS_EXPORT_LIBRTMP_PROJECT == NO && $SRS_RTC == YES ]]; then FFMPEG_OPTIONS="" + + # If disable nasm, disable all ASMs. if [[ $SRS_NASM == NO ]]; then FFMPEG_OPTIONS="--disable-asm --disable-x86asm --disable-inline-asm" fi + # If no nasm, we disable the x86asm. + nasm -v >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then + FFMPEG_OPTIONS="--disable-x86asm" + fi + if [[ -f ${SRS_OBJS}/${SRS_PLATFORM}/ffmpeg/lib/libavcodec.a ]]; then echo "The ffmpeg-4.2-fit is ok."; else diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index 69293fce3..f2b0cb7e6 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -569,6 +569,7 @@ function apply_user_detail_options() { # Detect whether has sendmmsg. # @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html + mkdir -p ${SRS_OBJS} && echo "#include " > ${SRS_OBJS}/_tmp_sendmmsg_detect.c echo "int main(int argc, char** argv) {" >> ${SRS_OBJS}/_tmp_sendmmsg_detect.c echo " struct mmsghdr hdr;" >> ${SRS_OBJS}/_tmp_sendmmsg_detect.c diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 6a83f7a8c..fdfbf8747 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1615,14 +1615,22 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* SrsStatistic* stat = SrsStatistic::instance(); string target = r->query_get("target"); - srs_trace("query target=%s", target.c_str()); + string reset = r->query_get("reset"); + srs_trace("query target=%s, reset=%s", target.c_str(), reset.c_str()); if (true) { SrsJsonObject* p = SrsJsonAny::object(); data->set("query", p); p->set("target", SrsJsonAny::str(target.c_str())); + p->set("reset", SrsJsonAny::str(reset.c_str())); p->set("help", SrsJsonAny::str("?target=avframes|rtc|rtp|gso|writev_iovs|sendmmsg")); + p->set("help2", SrsJsonAny::str("?reset=all")); + } + + if (!reset.empty()) { + stat->reset_perf(); + return srs_api_response(w, r, obj->dumps()); } if (target.empty() || target == "avframes") { diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index 0d9905f75..c0344989f 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -262,6 +262,9 @@ public: virtual void perf_sendmmsg_on_packets(int nb_packets); // Dumps the perf statistic data for UDP sendmmsg, for performance analysis. virtual srs_error_t dumps_perf_sendmmsg(SrsJsonObject* obj); +public: + // Reset all perf stat data. + virtual void reset_perf(); private: virtual void perf_on_packets(SrsStatisticCategory* p, int nb_msgs); virtual srs_error_t dumps_perf(SrsStatisticCategory* p, SrsJsonObject* obj); From 095e7c5a4ea08a33324a91d8daef2decc0fc5349 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 10:36:39 +0800 Subject: [PATCH 02/54] Fix build script --- trunk/auto/depends.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index 8fd54333c..c8817eb67 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -162,13 +162,6 @@ function Centos_prepare() echo "The unzip is installed." fi - nasm -v >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then - echo "Installing nasm." - require_sudoer "sudo yum install -y nasm" - sudo yum install -y nasm; ret=$?; if [[ 0 -ne $ret ]]; then return $ret; fi - echo "The nasm is installed." - fi - if [[ $SRS_VALGRIND == YES ]]; then valgrind --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then echo "Installing valgrind." From ab53c34945a1b9f00d236a761339ab03a7992486 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 10:44:26 +0800 Subject: [PATCH 03/54] For #307: Change the RTP payload to 1400 --- trunk/src/app/srs_app_rtc_conn.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index a01e6305c..973270204 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -60,6 +60,12 @@ using namespace std; #include #include +// The RTP payload max size, reserved some paddings for SRTP as such: +// kRtpPacketSize = kRtpMaxPayloadSize + paddings +// For example, if kRtpPacketSize is 1500, recommend to set kRtpMaxPayloadSize to 1400, +// which reserves 100 bytes for SRTP or paddings. +const int kRtpMaxPayloadSize = kRtpPacketSize - 100; + static bool is_stun(const uint8_t* data, const int size) { return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1); @@ -767,7 +773,6 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( continue; } - const int kRtpMaxPayloadSize = 1200; if (sample->size <= kRtpMaxPayloadSize) { if ((err = packet_single_nalu(msg, sample, &packet)) != srs_success) { return srs_error_wrap(err, "packet single nalu"); @@ -1052,7 +1057,6 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac return err; } - const int kRtpMaxPayloadSize = 1200; if (nn_bytes < kRtpMaxPayloadSize) { // Package NALUs in a single RTP packet. SrsRtpPacket2* packet = new SrsRtpPacket2(); From b5f2c842feb6778c76336a34b06ce47bf45c323f Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 10:50:56 +0800 Subject: [PATCH 04/54] Fix perf api bug --- trunk/src/app/srs_app_statistic.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 01abcd446..98c7ec8ab 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -651,6 +651,23 @@ srs_error_t SrsStatistic::dumps_perf_sendmmsg(SrsJsonObject* obj) return dumps_perf(perf_sendmmsg, obj); } +void SrsStatistic::reset_perf() +{ + srs_freep(perf_iovs); + srs_freep(perf_msgs); + srs_freep(perf_sendmmsg); + srs_freep(perf_gso); + srs_freep(perf_rtp); + srs_freep(perf_rtc); + + perf_iovs = new SrsStatisticCategory(); + perf_msgs = new SrsStatisticCategory(); + perf_sendmmsg = new SrsStatisticCategory(); + perf_gso = new SrsStatisticCategory(); + perf_rtp = new SrsStatisticCategory(); + perf_rtc = new SrsStatisticCategory(); +} + void SrsStatistic::perf_on_packets(SrsStatisticCategory* p, int nb_msgs) { // The range for stat: From bfc70d648210df0c75119a09df0fd725deb2015d Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 12:05:27 +0800 Subject: [PATCH 05/54] For #307: Change the RTP payload to 1300 --- trunk/src/app/srs_app_rtc_conn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 973270204..c890d5866 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -64,7 +64,7 @@ using namespace std; // kRtpPacketSize = kRtpMaxPayloadSize + paddings // For example, if kRtpPacketSize is 1500, recommend to set kRtpMaxPayloadSize to 1400, // which reserves 100 bytes for SRTP or paddings. -const int kRtpMaxPayloadSize = kRtpPacketSize - 100; +const int kRtpMaxPayloadSize = kRtpPacketSize - 200; static bool is_stun(const uint8_t* data, const int size) { From 6869ccca50616d76527fd8cb5e458e1af300ac9e Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 14:19:00 +0800 Subject: [PATCH 06/54] Fix RTP padding bug --- trunk/src/kernel/srs_kernel_rtp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index ae044d4a2..83dcf6071 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -97,7 +97,7 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* stream) uint8_t v = 0x80 | cc; if (padding) { - v |= 0x40; + v |= 0x20; } if (extension) { v |= 0x10; @@ -192,7 +192,7 @@ srs_error_t SrsRtpPacket2::encode(SrsBuffer* buf) if (!buf->require(padding)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", padding); } - memset(buf->data(), padding, padding); + memset(buf->data() + buf->pos(), padding, padding); buf->skip(padding); } From bbdd2d7eed9fc1e60d9d02bbd3caf5080715a5c3 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 15:58:17 +0800 Subject: [PATCH 07/54] For #307, support padding for GSO --- trunk/conf/full.conf | 4 +++ trunk/src/app/srs_app_config.cpp | 20 ++++++++++- trunk/src/app/srs_app_config.hpp | 3 ++ trunk/src/app/srs_app_rtc_conn.cpp | 55 +++++++++++++++++++++--------- trunk/src/app/srs_app_rtc_conn.hpp | 3 ++ 5 files changed, 68 insertions(+), 17 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 581e4daa3..66a8a27ab 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -443,6 +443,10 @@ rtc_server { # @remark Linux 4.18+ only, for other OS always disabled. # default: on gso on; + # Whether pad first packet for GSO for padding bytes. + # If 0, disable padding for GSO. + # default: 0 + padding 0; } vhost rtc.vhost.srs.com { diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 956bc99b0..85c70f87b 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3618,7 +3618,8 @@ srs_error_t SrsConfig::check_normal_config() for (int i = 0; conf && i < (int)conf->directives.size(); i++) { string n = conf->at(i)->name; if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa" - && n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus") { + && n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus" + && n != "padding") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", n.c_str()); } } @@ -4840,6 +4841,23 @@ bool SrsConfig::get_rtc_server_gso2() return SRS_CONF_PERFER_TRUE(conf->arg0()); } +int SrsConfig::get_rtc_server_padding() +{ + static int DEFAULT = 0; + + SrsConfDirective* conf = root->get("rtc_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("padding"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return srs_min(16, ::atoi(conf->arg0().c_str())); +} + SrsConfDirective* SrsConfig::get_rtc(string vhost) { SrsConfDirective* conf = get_vhost(vhost); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 96524c33a..8d31ef86e 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -535,6 +535,9 @@ public: virtual bool get_rtc_server_gso(); private: virtual bool get_rtc_server_gso2(); +public: + virtual int get_rtc_server_padding(); + public: SrsConfDirective* get_rtc(std::string vhost); bool get_rtc_enabled(std::string vhost); diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index c890d5866..c6e585665 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -468,6 +468,7 @@ SrsRtcPackets::SrsRtcPackets(bool gso, bool merge_nalus) nn_rtp_pkts = 0; nn_audios = nn_extras = 0; nn_videos = nn_samples = 0; + nn_paddings = 0; } SrsRtcPackets::~SrsRtcPackets() @@ -490,6 +491,7 @@ SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int sendonly_ukt = u->copy_sendonly(); gso = false; merge_nalus = false; + max_padding = 0; audio_timestamp = 0; audio_sequence = 0; @@ -519,8 +521,9 @@ srs_error_t SrsRtcSenderThread::initialize(const uint32_t& vssrc, const uint32_t gso = _srs_config->get_rtc_server_gso(); merge_nalus = _srs_config->get_rtc_server_merge_nalus(); - srs_trace("RTC sender video(ssrc=%d, pt=%d), audio(ssrc=%d, pt=%d), package(gso=%d, merge_nalus=%d)", - video_ssrc, video_payload_type, audio_ssrc, audio_payload_type, gso, merge_nalus); + max_padding = _srs_config->get_rtc_server_padding(); + srs_trace("RTC sender video(ssrc=%d, pt=%d), audio(ssrc=%d, pt=%d), package(gso=%d, merge_nalus=%d), padding=%d", + video_ssrc, video_payload_type, audio_ssrc, audio_payload_type, gso, merge_nalus, max_padding); return err; } @@ -543,6 +546,14 @@ srs_error_t SrsRtcSenderThread::on_reload_rtc_server() } } + if (true) { + bool v = _srs_config->get_rtc_server_padding(); + if (max_padding != v) { + srs_trace("Reload padding %d=>%d", max_padding, v); + max_padding = v; + } + } + return srs_success; } @@ -665,7 +676,7 @@ srs_error_t SrsRtcSenderThread::cycle() // Stat the RTP packets going into kernel. stat->perf_on_gso_packets(pkts.nn_rtp_pkts); #if defined(SRS_DEBUG) - srs_trace("RTC PLAY packets, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d bytes", + srs_trace("RTC PLAY done, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d bytes", msg_count, nn_rtc_packets, pkts.packets.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, pkts.nn_samples, pkts.nn_bytes); #endif @@ -673,9 +684,9 @@ srs_error_t SrsRtcSenderThread::cycle() pprint->elapse(); if (pprint->can_print()) { // TODO: FIXME: Print stat like frame/s, packet/s, loss_packets. - srs_trace("-> RTC PLAY %d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d bytes", + srs_trace("-> RTC PLAY %d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d bytes, %d pad", msg_count, pkts.packets.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, - pkts.nn_samples, pkts.nn_bytes); + pkts.nn_samples, pkts.nn_bytes, pkts.nn_paddings); } } } @@ -862,13 +873,28 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac int nn_packets = (int)packets.packets.size(); for (int i = 0; i < nn_packets; i++) { SrsRtpPacket2* packet = packets.packets[i]; - - // The handler to send message. - mmsghdr* mhdr = NULL; - - // Check whether we can use GSO to send it. int nn_packet = packet->nb_bytes(); + SrsRtpPacket2* next_packet = NULL; + int nn_next_packet = 0; + if (i < nn_packets - 1) { + next_packet = (i < nn_packets - 1)? packets.packets[i + 1]:NULL; + nn_next_packet = next_packet? next_packet->nb_bytes() : 0; + } + + // Padding the first packet if size is similar to the next one. + if (i == 0 && max_padding > 0 && next_packet && nn_packet < nn_next_packet && nn_next_packet - nn_packet < max_padding) { +#if defined(SRS_DEBUG) + srs_trace("Padding %d bytes %d=>%d, packets %d, max_padding %d", nn_next_packet - nn_packet, + nn_packet, nn_next_packet, nn_packets, max_padding); +#endif + packet->set_padding(nn_next_packet - nn_packet); + nn_packet = nn_next_packet; + packets.nn_paddings++; + } + + // Check whether we can use GSO to send it. + mmsghdr* mhdr = NULL; if ((gso_size && gso_size == nn_packet) || (use_gso && !gso_final)) { use_gso = true; gso_final = (gso_size && gso_size != nn_packet); @@ -893,10 +919,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac } // Change the state according to the next packet. - if (i < nn_packets - 1) { - SrsRtpPacket2* next_packet = (i < nn_packets - 1)? packets.packets[i + 1]:NULL; - int nn_next_packet = next_packet? next_packet->nb_bytes() : 0; - + if (next_packet) { // If GSO, but next is bigger than this one, we must enter the final state. if (use_gso && !gso_final) { gso_final = (nn_packet < nn_next_packet); @@ -1025,8 +1048,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac } #if defined(SRS_DEBUG) - srs_trace("RTC PLAY summary, rtp %d/%d, videos %d/%d, audios %d/%d", packets.packets.size(), - packets.nn_rtp_pkts, packets.nn_videos, packets.nn_samples, packets.nn_audios, packets.nn_extras); + srs_trace("RTC PLAY summary, rtp %d/%d, videos %d/%d, audios %d/%d, pad %d", packets.packets.size(), packets.nn_rtp_pkts, + packets.nn_videos, packets.nn_samples, packets.nn_audios, packets.nn_extras, packets.nn_paddings); #endif return err; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 2ffe75441..978681ccb 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -138,6 +138,8 @@ public: int nn_audios; // The original video messages. int nn_videos; + // The number of padded packet. + int nn_paddings; public: std::vector packets; public: @@ -166,6 +168,7 @@ public: SrsUdpMuxSocket* sendonly_ukt; bool merge_nalus; bool gso; + int max_padding; public: SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid); virtual ~SrsRtcSenderThread(); From c95a8517e73a59c73c8c20f148eaf4c38f4314c2 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 17:48:52 +0800 Subject: [PATCH 08/54] For #307, padding to next packet or GSO size --- trunk/src/app/srs_app_rtc_conn.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index c6e585665..42f448724 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -882,15 +882,25 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac nn_next_packet = next_packet? next_packet->nb_bytes() : 0; } - // Padding the first packet if size is similar to the next one. - if (i == 0 && max_padding > 0 && next_packet && nn_packet < nn_next_packet && nn_next_packet - nn_packet < max_padding) { + // Padding the packet to next or GSO size. + if (max_padding > 0 && next_packet) { + // Padding to the next packet to merge with it. + int padding = nn_next_packet - nn_packet; + + // If the next one could merge to this GSO stage, padding current to GSO size. + if (use_gso && nn_next_packet < gso_size) { + padding = gso_size - nn_packet; + } + + if (padding > 0 && padding < max_padding) { #if defined(SRS_DEBUG) - srs_trace("Padding %d bytes %d=>%d, packets %d, max_padding %d", nn_next_packet - nn_packet, - nn_packet, nn_next_packet, nn_packets, max_padding); + srs_trace("Padding %d bytes %d=>%d, packets %d, max_padding %d", padding, nn_packet + padding, + nn_next_packet, nn_packets, max_padding); #endif - packet->set_padding(nn_next_packet - nn_packet); - nn_packet = nn_next_packet; - packets.nn_paddings++; + packet->set_padding(padding); + nn_packet += padding; + packets.nn_paddings++; + } } // Check whether we can use GSO to send it. From 7c6583684e58048d4cfe5127e5e436e7e735478e Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 19:53:23 +0800 Subject: [PATCH 09/54] RTC: Reorder AV for GSO --- trunk/src/app/srs_app_rtc_conn.cpp | 111 ++++++++++++++++++++++++++++- trunk/src/app/srs_app_rtc_conn.hpp | 1 + 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 42f448724..a11706327 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -701,8 +701,17 @@ srs_error_t SrsRtcSenderThread::send_messages( } // Covert kernel messages to RTP packets. - if ((err = messages_to_packets(source, msgs, nb_msgs, packets)) != srs_success) { - return srs_error_wrap(err, "messages to packets"); + // For GSO and small amount of packets, process video then audio. + // TODO: FIXME: Magic number. + if (packets.use_gso && nb_msgs <= 6) { + if ((err = messages_to_packets_gso(source, msgs, nb_msgs, packets)) != srs_success) { + return srs_error_wrap(err, "messages to packets"); + } + } else { + // By default, we process the packets in its original sequence. + if ((err = messages_to_packets(source, msgs, nb_msgs, packets)) != srs_success) { + return srs_error_wrap(err, "messages to packets"); + } } #ifndef SRS_AUTO_OSX @@ -804,6 +813,104 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( return err; } +srs_error_t SrsRtcSenderThread::messages_to_packets_gso( + SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets +) { + srs_error_t err = srs_success; + + SrsRtpPacket2* packet = NULL; + + // For GSO, process video first. + for (int i = 0; i < nb_msgs; i++) { + SrsSharedPtrMessage* msg = msgs[i]; + + // Ignore audio when processing video. + if (msg->is_audio()) { + continue; + } + + // Update stats. + packets.nn_bytes += msg->size; + + int nn_samples = msg->nn_samples(); + packets.nn_samples += nn_samples; + + // For video, we should process all NALUs in samples. + packets.nn_videos++; + + // Well, for each IDR, we append a SPS/PPS before it, which is packaged in STAP-A. + if (msg->has_idr()) { + if ((err = packet_stap_a(source, msg, &packet)) != srs_success) { + return srs_error_wrap(err, "packet stap-a"); + } + packets.packets.push_back(packet); + } + + // If merge Nalus, we pcakges all NALUs(samples) as one NALU, in a RTP or FUA packet. + if (packets.should_merge_nalus && nn_samples > 1) { + if ((err = packet_nalus(msg, packets)) != srs_success) { + return srs_error_wrap(err, "packet stap-a"); + } + continue; + } + + // By default, we package each NALU(sample) to a RTP or FUA packet. + for (int i = 0; i < nn_samples; i++) { + SrsSample* sample = msg->samples() + i; + + // We always ignore bframe here, if config to discard bframe, + // the bframe flag will not be set. + if (sample->bframe) { + continue; + } + + if (sample->size <= kRtpMaxPayloadSize) { + if ((err = packet_single_nalu(msg, sample, &packet)) != srs_success) { + return srs_error_wrap(err, "packet single nalu"); + } + packets.packets.push_back(packet); + } else { + if ((err = packet_fu_a(msg, sample, kRtpMaxPayloadSize, packets)) != srs_success) { + return srs_error_wrap(err, "packet fu-a"); + } + } + + if (i == nn_samples - 1) { + packets.packets.back()->rtp_header.set_marker(true); + } + } + } + + // For GSO, process audio after video. + for (int i = 0; i < nb_msgs; i++) { + SrsSharedPtrMessage* msg = msgs[i]; + + // Ignore video when processing audio. + if (!msg->is_audio()) { + continue; + } + + // Update stats. + packets.nn_bytes += msg->size; + + int nn_extra_payloads = msg->nn_extra_payloads(); + packets.nn_extras += nn_extra_payloads; + + // For audio, we transcoded AAC to opus in extra payloads. + packets.nn_audios++; + + for (int i = 0; i < nn_extra_payloads; i++) { + SrsSample* sample = msg->extra_payloads() + i; + if ((err = packet_opus(sample, &packet)) != srs_success) { + return srs_error_wrap(err, "opus package"); + } + packets.packets.push_back(packet); + } + } + + return err; +} + srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets& packets) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 978681ccb..479d47624 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -190,6 +190,7 @@ public: private: srs_error_t send_messages(SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); srs_error_t messages_to_packets(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); + srs_error_t messages_to_packets_gso(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); srs_error_t send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); srs_error_t send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); private: From d692f2d9c4427fe524d3f6975dd14a301039508f Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 21:37:46 +0800 Subject: [PATCH 10/54] Fix build failed when RTC disabled. --- trunk/src/kernel/srs_kernel_flv.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index 28b2d938b..b05b3adbf 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -227,9 +227,10 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload() srs_memory_unwatch(payload); #endif srs_freepa(payload); - srs_freepa(samples); #ifdef SRS_AUTO_RTC + srs_freepa(samples); + for (int i = 0; i < nn_extra_payloads; i++) { SrsSample* p = extra_payloads + i; srs_freep(p->bytes); From c96ffd272c524793b906f39cebde6136aa07aade Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 21:59:27 +0800 Subject: [PATCH 11/54] Cache RTP packet vector --- trunk/auto/depends.sh | 5 +++-- trunk/src/app/srs_app_rtc_conn.cpp | 20 ++++++++++++++++---- trunk/src/app/srs_app_rtc_conn.hpp | 4 +++- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index c8817eb67..557de4bb3 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -214,15 +214,16 @@ function OSX_prepare() fi OS_IS_OSX=YES - echo "OSX detected, install tools if needed" # requires the osx when os if [ $OS_IS_OSX = YES ]; then if [ $SRS_OSX = NO ]; then - echo "OSX detected, must specifies the --osx" + echo "OSX detected, please use: ./configure --osx" exit 1 fi fi + echo "OSX detected, install tools if needed" + brew --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then echo "install brew" echo "ruby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\"" diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 42f448724..218e6b6d5 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -460,10 +460,10 @@ srs_error_t SrsDtlsSession::unprotect_rtcp(char* out_buf, const char* in_buf, in return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed"); } -SrsRtcPackets::SrsRtcPackets(bool gso, bool merge_nalus) +SrsRtcPackets::SrsRtcPackets() { - use_gso = gso; - should_merge_nalus = merge_nalus; + use_gso = false; + should_merge_nalus = false; nn_rtp_pkts = 0; nn_audios = nn_extras = 0; @@ -473,6 +473,14 @@ SrsRtcPackets::SrsRtcPackets(bool gso, bool merge_nalus) SrsRtcPackets::~SrsRtcPackets() { + reset(use_gso, should_merge_nalus); +} + +void SrsRtcPackets::reset(bool gso, bool merge_nalus) +{ + use_gso = gso; + should_merge_nalus = merge_nalus; + vector::iterator it; for (it = packets.begin(); it != packets.end(); ++it ) { SrsRtpPacket2* packet = *it; @@ -621,6 +629,7 @@ srs_error_t SrsRtcSenderThread::cycle() bool realtime = _srs_config->get_realtime_enabled(req->vhost, true); srs_utime_t mw_sleep = _srs_config->get_mw_sleep(req->vhost, true); + SrsRtcPackets pkts; SrsMessageArray msgs(SRS_PERF_MW_MSGS); SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_play(); @@ -656,11 +665,14 @@ srs_error_t SrsRtcSenderThread::cycle() continue; } - SrsRtcPackets pkts(gso, merge_nalus); + // Transmux and send out messages. + pkts.reset(gso, merge_nalus); + if ((err = send_messages(sendonly_ukt, source, msgs.msgs, msg_count, pkts)) != srs_success) { srs_warn("send err %s", srs_error_summary(err).c_str()); srs_error_reset(err); } + // Do cleanup messages. for (int i = 0; i < msg_count; i++) { SrsSharedPtrMessage* msg = msgs.msgs[i]; srs_freep(msg); diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 978681ccb..c2edcd625 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -143,8 +143,10 @@ public: public: std::vector packets; public: - SrsRtcPackets(bool gso, bool merge_nalus); + SrsRtcPackets(); virtual ~SrsRtcPackets(); +public: + void reset(bool gso, bool merge_nalus); }; class SrsRtcSenderThread : virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler From 7b68f55edc258ffc29759126622694440df4f99b Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 22:11:03 +0800 Subject: [PATCH 12/54] Refactor GSO mmsghdr alloc --- trunk/src/app/srs_app_rtc_conn.cpp | 23 +++++++++++++++++------ trunk/src/core/srs_core_performance.hpp | 3 +++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 218e6b6d5..e63be65dc 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -925,7 +925,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac // We need to increase the iov and cursor. int nb_iovs = mhdr->msg_hdr.msg_iovlen; if (gso_cursor >= nb_iovs - 1) { - int nn_new_iovs = nb_iovs; + int nn_new_iovs = 1; mhdr->msg_hdr.msg_iovlen = nb_iovs + nn_new_iovs; mhdr->msg_hdr.msg_iov = (iovec*)realloc(mhdr->msg_hdr.msg_iov, sizeof(iovec) * (nb_iovs + nn_new_iovs)); memset(mhdr->msg_hdr.msg_iov + nb_iovs, 0, sizeof(iovec) * nn_new_iovs); @@ -965,6 +965,10 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac // Reset the iovec, we should never change the msg_iovlen. for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { iovec* p = mhdr->msg_hdr.msg_iov + j; + + if (!p->iov_len) { + break; + } p->iov_len = 0; } @@ -1020,6 +1024,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac if (do_send) { for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { iovec* iov = mhdr->msg_hdr.msg_iov + j; + if (iov->iov_len <= 0) { break; } @@ -1815,7 +1820,7 @@ void SrsUdpMuxSender::free_mhdrs(std::vector& mhdrs) iovec* iov = hdr->msg_hdr.msg_iov + j; char* data = (char*)iov->iov_base; srs_freep(data); - srs_freep(iov); + srs_freepa(iov); } } mhdrs.clear(); @@ -1828,12 +1833,18 @@ srs_error_t SrsUdpMuxSender::fetch(mmsghdr** pphdr) mmsghdr mhdr; memset(&mhdr, 0, sizeof(mmsghdr)); - mhdr.msg_hdr.msg_iovlen = 1; - mhdr.msg_hdr.msg_iov = new iovec(); - mhdr.msg_hdr.msg_iov->iov_base = new char[kRtpPacketSize]; - mhdr.msg_hdr.msg_iov->iov_len = kRtpPacketSize; mhdr.msg_len = 0; + mhdr.msg_hdr.msg_iovlen = SRS_PERF_RTC_GSO_IOVS; + mhdr.msg_hdr.msg_iov = new iovec[mhdr.msg_hdr.msg_iovlen]; + + for (int i = 0; i < (int)mhdr.msg_hdr.msg_iovlen; i++) { + iovec* p = mhdr.msg_hdr.msg_iov + i; + + p->iov_base = new char[kRtpPacketSize]; + p->iov_len = kRtpPacketSize; + } + cache.push_back(mhdr); } diff --git a/trunk/src/core/srs_core_performance.hpp b/trunk/src/core/srs_core_performance.hpp index 7cafa055e..cbfddf1dc 100644 --- a/trunk/src/core/srs_core_performance.hpp +++ b/trunk/src/core/srs_core_performance.hpp @@ -192,5 +192,8 @@ #define SRS_PERF_GLIBC_MEMORY_CHECK #undef SRS_PERF_GLIBC_MEMORY_CHECK +// For RTC, how many iovs we alloc for each mmsghdr for GSO. +#define SRS_PERF_RTC_GSO_IOVS 4 + #endif From 1064429c7e758fd3f29e3bd4b5ea09967d0cf0f9 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 22:46:06 +0800 Subject: [PATCH 13/54] Cache RTP packets --- trunk/src/app/srs_app_rtc_conn.cpp | 123 +++++++++++++++++----------- trunk/src/app/srs_app_rtc_conn.hpp | 13 ++- trunk/src/kernel/srs_kernel_rtp.cpp | 7 ++ trunk/src/kernel/srs_kernel_rtp.hpp | 4 +- 4 files changed, 94 insertions(+), 53 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index e63be65dc..e4f57800d 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -469,6 +469,8 @@ SrsRtcPackets::SrsRtcPackets() nn_audios = nn_extras = 0; nn_videos = nn_samples = 0; nn_paddings = 0; + + cursor = 0; } SrsRtcPackets::~SrsRtcPackets() @@ -481,12 +483,38 @@ void SrsRtcPackets::reset(bool gso, bool merge_nalus) use_gso = gso; should_merge_nalus = merge_nalus; - vector::iterator it; - for (it = packets.begin(); it != packets.end(); ++it ) { - SrsRtpPacket2* packet = *it; - srs_freep(packet); + for (int i = 0; i < cursor; i++) { + SrsRtpPacket2* packet = packets[i]; + packet->reset(); } - packets.clear(); + + cursor = 0; +} + +SrsRtpPacket2* SrsRtcPackets::fetch() +{ + if (cursor >= (int)packets.size()) { + packets.push_back(new SrsRtpPacket2()); + } + + return packets[cursor++]; +} + +SrsRtpPacket2* SrsRtcPackets::back() +{ + srs_assert(cursor > 0); + return packets[cursor - 1]; +} + +int SrsRtcPackets::size() +{ + return cursor; +} + +SrsRtpPacket2* SrsRtcPackets::at(int index) +{ + srs_assert(index < cursor); + return packets[index]; } SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid) @@ -684,12 +712,12 @@ srs_error_t SrsRtcSenderThread::cycle() int nn_rtc_packets = srs_max(pkts.nn_audios, pkts.nn_extras) + pkts.nn_videos; stat->perf_on_rtc_packets(nn_rtc_packets); // Stat the RAW RTP packets, which maybe group by GSO. - stat->perf_on_rtp_packets(pkts.packets.size()); + stat->perf_on_rtp_packets(pkts.size()); // Stat the RTP packets going into kernel. stat->perf_on_gso_packets(pkts.nn_rtp_pkts); #if defined(SRS_DEBUG) srs_trace("RTC PLAY done, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d bytes", - msg_count, nn_rtc_packets, pkts.packets.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, + msg_count, nn_rtc_packets, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, pkts.nn_samples, pkts.nn_bytes); #endif @@ -697,7 +725,7 @@ srs_error_t SrsRtcSenderThread::cycle() if (pprint->can_print()) { // TODO: FIXME: Print stat like frame/s, packet/s, loss_packets. srs_trace("-> RTC PLAY %d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d bytes, %d pad", - msg_count, pkts.packets.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, + msg_count, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, pkts.nn_samples, pkts.nn_bytes, pkts.nn_paddings); } } @@ -753,16 +781,14 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( packets.nn_samples += nn_samples; // For audio, we transcoded AAC to opus in extra payloads. - SrsRtpPacket2* packet = NULL; if (msg->is_audio()) { packets.nn_audios++; for (int i = 0; i < nn_extra_payloads; i++) { SrsSample* sample = msg->extra_payloads() + i; - if ((err = packet_opus(sample, &packet)) != srs_success) { + if ((err = packet_opus(sample, packets)) != srs_success) { return srs_error_wrap(err, "opus package"); } - packets.packets.push_back(packet); } continue; } @@ -772,10 +798,9 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( // Well, for each IDR, we append a SPS/PPS before it, which is packaged in STAP-A. if (msg->has_idr()) { - if ((err = packet_stap_a(source, msg, &packet)) != srs_success) { + if ((err = packet_stap_a(source, msg, packets)) != srs_success) { return srs_error_wrap(err, "packet stap-a"); } - packets.packets.push_back(packet); } // If merge Nalus, we pcakges all NALUs(samples) as one NALU, in a RTP or FUA packet. @@ -797,10 +822,9 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( } if (sample->size <= kRtpMaxPayloadSize) { - if ((err = packet_single_nalu(msg, sample, &packet)) != srs_success) { + if ((err = packet_single_nalu(msg, sample, packets)) != srs_success) { return srs_error_wrap(err, "packet single nalu"); } - packets.packets.push_back(packet); } else { if ((err = packet_fu_a(msg, sample, kRtpMaxPayloadSize, packets)) != srs_success) { return srs_error_wrap(err, "packet fu-a"); @@ -808,7 +832,7 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( } if (i == nn_samples - 1) { - packets.packets.back()->rtp_header.set_marker(true); + packets.back()->rtp_header.set_marker(true); } } } @@ -822,9 +846,9 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets ISrsUdpSender* sender = skt->sender(); - vector::iterator it; - for (it = packets.packets.begin(); it != packets.packets.end(); ++it) { - SrsRtpPacket2* packet = *it; + int nn_packets = packets.size(); + for (int i = 0; i < nn_packets; i++) { + SrsRtpPacket2* packet = packets.at(i); // Fetch a cached message from queue. // TODO: FIXME: Maybe encrypt in async, so the state of mhdr maybe not ready. @@ -832,6 +856,17 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets if ((err = sender->fetch(&mhdr)) != srs_success) { return srs_error_wrap(err, "fetch msghdr"); } + + // Reset the iovec, we should never change the msg_iovlen. + for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { + iovec* p = mhdr->msg_hdr.msg_iov + j; + + if (!p->iov_len) { + break; + } + p->iov_len = 0; + } + char* buf = (char*)mhdr->msg_hdr.msg_iov->iov_base; int length = kRtpPacketSize; @@ -882,15 +917,15 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac bool use_gso = false; bool gso_final = false; ISrsUdpSender* sender = skt->sender(); - int nn_packets = (int)packets.packets.size(); + int nn_packets = packets.size(); for (int i = 0; i < nn_packets; i++) { - SrsRtpPacket2* packet = packets.packets[i]; + SrsRtpPacket2* packet = packets.at(i); int nn_packet = packet->nb_bytes(); SrsRtpPacket2* next_packet = NULL; int nn_next_packet = 0; if (i < nn_packets - 1) { - next_packet = (i < nn_packets - 1)? packets.packets[i + 1]:NULL; + next_packet = (i < nn_packets - 1)? packets.at(i + 1):NULL; nn_next_packet = next_packet? next_packet->nb_bytes() : 0; } @@ -1075,7 +1110,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac } #if defined(SRS_DEBUG) - srs_trace("RTC PLAY summary, rtp %d/%d, videos %d/%d, audios %d/%d, pad %d", packets.packets.size(), packets.nn_rtp_pkts, + srs_trace("RTC PLAY summary, rtp %d/%d, videos %d/%d, audios %d/%d, pad %d", packets.size(), packets.nn_rtp_pkts, packets.nn_videos, packets.nn_samples, packets.nn_audios, packets.nn_extras, packets.nn_paddings); #endif @@ -1109,13 +1144,12 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac if (nn_bytes < kRtpMaxPayloadSize) { // Package NALUs in a single RTP packet. - SrsRtpPacket2* packet = new SrsRtpPacket2(); + SrsRtpPacket2* packet = packets.fetch(); packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); packet->rtp_header.set_ssrc(video_ssrc); packet->rtp_header.set_payload_type(video_payload_type); packet->payload = raw; - packets.packets.push_back(packet); } else { SrsAutoFree(SrsRtpRawNALUs, raw); @@ -1131,15 +1165,19 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac for (int i = 0; i < num_of_packet; ++i) { int packet_size = srs_min(nb_left, fu_payload_size); - SrsRtpPacket2* packet = new SrsRtpPacket2(); - packets.packets.push_back(packet); + SrsRtpFUAPayload* fua = new SrsRtpFUAPayload(); + if ((err = raw->read_samples(fua->nalus, packet_size)) != srs_success) { + srs_freep(fua); + return srs_error_wrap(err, "read samples %d bytes, left %d, total %d", packet_size, nb_left, nn_bytes); + } + + SrsRtpPacket2* packet = packets.fetch(); packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); packet->rtp_header.set_ssrc(video_ssrc); packet->rtp_header.set_payload_type(video_payload_type); - SrsRtpFUAPayload* fua = new SrsRtpFUAPayload(); packet->payload = fua; fua->nri = (SrsAvcNaluType)header; @@ -1147,26 +1185,22 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac fua->start = bool(i == 0); fua->end = bool(i == num_of_packet - 1); - if ((err = raw->read_samples(fua->nalus, packet_size)) != srs_success) { - return srs_error_wrap(err, "read samples %d bytes, left %d, total %d", packet_size, nb_left, nn_bytes); - } - nb_left -= packet_size; } } - if (!packets.packets.empty()) { - packets.packets.back()->rtp_header.set_marker(true); + if (packets.size() > 0) { + packets.back()->rtp_header.set_marker(true); } return err; } -srs_error_t SrsRtcSenderThread::packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket) +srs_error_t SrsRtcSenderThread::packet_opus(SrsSample* sample, SrsRtcPackets& packets) { srs_error_t err = srs_success; - SrsRtpPacket2* packet = new SrsRtpPacket2(); + SrsRtpPacket2* packet = packets.fetch(); packet->rtp_header.set_marker(true); packet->rtp_header.set_timestamp(audio_timestamp); packet->rtp_header.set_sequence(audio_sequence++); @@ -1181,8 +1215,6 @@ srs_error_t SrsRtcSenderThread::packet_opus(SrsSample* sample, SrsRtpPacket2** p // TODO: FIXME: Why 960? Need Refactoring? audio_timestamp += 960; - *ppacket = packet; - return err; } @@ -1199,8 +1231,7 @@ srs_error_t SrsRtcSenderThread::packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* for (int i = 0; i < num_of_packet; ++i) { int packet_size = srs_min(nb_left, fu_payload_size); - SrsRtpPacket2* packet = new SrsRtpPacket2(); - packets.packets.push_back(packet); + SrsRtpPacket2* packet = packets.fetch(); packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); @@ -1228,11 +1259,11 @@ srs_error_t SrsRtcSenderThread::packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* } // Single NAL Unit Packet @see https://tools.ietf.org/html/rfc6184#section-5.6 -srs_error_t SrsRtcSenderThread::packet_single_nalu(SrsSharedPtrMessage* msg, SrsSample* sample, SrsRtpPacket2** ppacket) +srs_error_t SrsRtcSenderThread::packet_single_nalu(SrsSharedPtrMessage* msg, SrsSample* sample, SrsRtcPackets& packets) { srs_error_t err = srs_success; - SrsRtpPacket2* packet = new SrsRtpPacket2(); + SrsRtpPacket2* packet = packets.fetch(); packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); packet->rtp_header.set_ssrc(video_ssrc); @@ -1246,12 +1277,10 @@ srs_error_t SrsRtcSenderThread::packet_single_nalu(SrsSharedPtrMessage* msg, Srs p->size = sample->size; raw->push_back(p); - *ppacket = packet; - return err; } -srs_error_t SrsRtcSenderThread::packet_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtpPacket2** ppacket) +srs_error_t SrsRtcSenderThread::packet_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtcPackets& packets) { srs_error_t err = srs_success; @@ -1271,7 +1300,7 @@ srs_error_t SrsRtcSenderThread::packet_stap_a(SrsSource* source, SrsSharedPtrMes return srs_error_new(ERROR_RTC_RTP_MUXER, "sps/pps empty"); } - SrsRtpPacket2* packet = new SrsRtpPacket2(); + SrsRtpPacket2* packet = packets.fetch(); packet->rtp_header.set_marker(false); packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); @@ -1298,8 +1327,6 @@ srs_error_t SrsRtcSenderThread::packet_stap_a(SrsSource* source, SrsSharedPtrMes stap->nalus.push_back(sample); } - *ppacket = packet; - return err; } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index c2edcd625..7dbf8eefb 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -140,13 +140,18 @@ public: int nn_videos; // The number of padded packet. int nn_paddings; -public: +private: + int cursor; std::vector packets; public: SrsRtcPackets(); virtual ~SrsRtcPackets(); public: void reset(bool gso, bool merge_nalus); + SrsRtpPacket2* fetch(); + SrsRtpPacket2* back(); + int size(); + SrsRtpPacket2* at(int index); }; class SrsRtcSenderThread : virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler @@ -195,12 +200,12 @@ private: srs_error_t send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); srs_error_t send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); private: - srs_error_t packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket); + srs_error_t packet_opus(SrsSample* sample, SrsRtcPackets& packets); private: srs_error_t packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* sample, int fu_payload_size, SrsRtcPackets& packets); srs_error_t packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPackets& packets); - srs_error_t packet_single_nalu(SrsSharedPtrMessage* msg, SrsSample* sample, SrsRtpPacket2** ppacket); - srs_error_t packet_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtpPacket2** ppacket); + srs_error_t packet_single_nalu(SrsSharedPtrMessage* msg, SrsSample* sample, SrsRtcPackets& packets); + srs_error_t packet_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtcPackets& packets); }; class SrsRtcSession diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index 83dcf6071..ef33c057a 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -171,6 +171,13 @@ void SrsRtpPacket2::set_padding(int size) padding = size; } +void SrsRtpPacket2::reset() +{ + memset((void*)&rtp_header, 0, sizeof(SrsRtpHeader)); + padding = 0; + srs_freep(payload); +} + int SrsRtpPacket2::nb_bytes() { return rtp_header.header_size() + (payload? payload->nb_bytes():0) + padding; diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index 7733b431f..1b4fd2de6 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -88,7 +88,9 @@ public: virtual ~SrsRtpPacket2(); public: // Append size of bytes as padding. - virtual void set_padding(int size); + void set_padding(int size); + // Reset RTP packet. + void reset(); // interface ISrsEncoder public: virtual int nb_bytes(); From 7d1be87124127082f5d887cf8e91851bc041e6a9 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 08:30:57 +0800 Subject: [PATCH 14/54] Fix RTP packet cache bug --- trunk/src/app/srs_app_rtc_conn.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index e4f57800d..48fd770fe 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -475,7 +475,12 @@ SrsRtcPackets::SrsRtcPackets() SrsRtcPackets::~SrsRtcPackets() { - reset(use_gso, should_merge_nalus); + vector::iterator it; + for (it = packets.begin(); it != packets.end(); ++it) { + SrsRtpPacket2* p = *it; + srs_freep(p); + } + packets.clear(); } void SrsRtcPackets::reset(bool gso, bool merge_nalus) From a4dbf3ca8a67d84f17c84af3a08c9b1f2a8ca797 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 08:43:54 +0800 Subject: [PATCH 15/54] Fix RTP packet cache bug --- trunk/scripts/perf_gso.py | 1 + trunk/src/app/srs_app_rtc_conn.cpp | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index 707e6c6b5..2158659e0 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -43,6 +43,7 @@ obj = json.loads(s) # 2, 3, 5, 9, 16, 32, 64, 128, 256 keys = ['lt_2', 'lt_3', 'lt_5', 'lt_9', 'lt_16', 'lt_32', 'lt_64', 'lt_128', 'lt_256', 'gt_256'] +print("\n----------- 1 2 [3,4] [5,8] [9,15] [16,31] [32,63] [64,127] [128,255] [256,+)"), print "" print("AV---Frames"), diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 48fd770fe..03497c08f 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -485,13 +485,18 @@ SrsRtcPackets::~SrsRtcPackets() void SrsRtcPackets::reset(bool gso, bool merge_nalus) { - use_gso = gso; - should_merge_nalus = merge_nalus; - for (int i = 0; i < cursor; i++) { SrsRtpPacket2* packet = packets[i]; packet->reset(); } + + use_gso = gso; + should_merge_nalus = merge_nalus; + + nn_rtp_pkts = 0; + nn_audios = nn_extras = 0; + nn_videos = nn_samples = 0; + nn_paddings = 0; cursor = 0; } From ef48507e8040e12dd56b4ca7cbba78f75c83f9d9 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 09:07:42 +0800 Subject: [PATCH 16/54] Support padding max to 127 --- trunk/conf/full.conf | 1 + trunk/scripts/perf_gso.py | 2 +- trunk/src/app/srs_app_config.cpp | 2 +- trunk/src/app/srs_app_rtc_conn.cpp | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 66a8a27ab..6dfb8eca5 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -445,6 +445,7 @@ rtc_server { gso on; # Whether pad first packet for GSO for padding bytes. # If 0, disable padding for GSO. + # @remark The max padding size is 0x7f(127). # default: 0 padding 0; } diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index 2158659e0..f09014143 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -43,7 +43,7 @@ obj = json.loads(s) # 2, 3, 5, 9, 16, 32, 64, 128, 256 keys = ['lt_2', 'lt_3', 'lt_5', 'lt_9', 'lt_16', 'lt_32', 'lt_64', 'lt_128', 'lt_256', 'gt_256'] -print("\n----------- 1 2 [3,4] [5,8] [9,15] [16,31] [32,63] [64,127] [128,255] [256,+)"), +print("\n----------- 1 2 [3,4] [5,8] [9,15] [16,31] [32,63] [64,127] [128,255] [256,+) Packets"), print "" print("AV---Frames"), diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 85c70f87b..8df22fea4 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4855,7 +4855,7 @@ int SrsConfig::get_rtc_server_padding() return DEFAULT; } - return srs_min(16, ::atoi(conf->arg0().c_str())); + return srs_min(127, ::atoi(conf->arg0().c_str())); } SrsConfDirective* SrsConfig::get_rtc(string vhost) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 03497c08f..f17cd6ea6 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -489,7 +489,7 @@ void SrsRtcPackets::reset(bool gso, bool merge_nalus) SrsRtpPacket2* packet = packets[i]; packet->reset(); } - + use_gso = gso; should_merge_nalus = merge_nalus; From 56995db6a50fa48e89ef08cb62d3f902367af1bd Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 09:09:10 +0800 Subject: [PATCH 17/54] Refine debug info --- trunk/src/app/srs_app_rtc_conn.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index f17cd6ea6..913d7b245 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -951,8 +951,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac if (padding > 0 && padding < max_padding) { #if defined(SRS_DEBUG) - srs_trace("Padding %d bytes %d=>%d, packets %d, max_padding %d", padding, nn_packet + padding, - nn_next_packet, nn_packets, max_padding); + srs_trace("Padding %d bytes %d=>%d, packets %d, max_padding %d", padding, nn_packet, nn_packet + padding, nn_packets, max_padding); #endif packet->set_padding(padding); nn_packet += padding; From b7dab00f369be8f38c2c5c4bea83cb0b17ce4696 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 09:25:18 +0800 Subject: [PATCH 18/54] Add debug_id for GSO --- trunk/src/app/srs_app_rtc_conn.cpp | 23 ++++++++++++++++------- trunk/src/app/srs_app_rtc_conn.hpp | 4 ++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 913d7b245..bde3d0c04 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -462,6 +462,10 @@ srs_error_t SrsDtlsSession::unprotect_rtcp(char* out_buf, const char* in_buf, in SrsRtcPackets::SrsRtcPackets() { +#if defined(SRS_DEBUG) + debug_id = 0; +#endif + use_gso = false; should_merge_nalus = false; @@ -490,6 +494,10 @@ void SrsRtcPackets::reset(bool gso, bool merge_nalus) packet->reset(); } +#if defined(SRS_DEBUG) + debug_id++; +#endif + use_gso = gso; should_merge_nalus = merge_nalus; @@ -951,7 +959,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac if (padding > 0 && padding < max_padding) { #if defined(SRS_DEBUG) - srs_trace("Padding %d bytes %d=>%d, packets %d, max_padding %d", padding, nn_packet, nn_packet + padding, nn_packets, max_padding); + srs_trace("#%d, Padding %d bytes %d=>%d, packets %d, max_padding %d", packets.debug_id, + padding, nn_packet, nn_packet + padding, nn_packets, max_padding); #endif packet->set_padding(padding); nn_packet += padding; @@ -1063,8 +1072,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac #if defined(SRS_DEBUG) bool is_video = packet->rtp_header.get_payload_type() == video_payload_type; - srs_trace("Packet %s SSRC=%d, SN=%d, %d bytes", is_video? "Video":"Audio", packet->rtp_header.get_ssrc(), - packet->rtp_header.get_sequence(), nn_packet); + srs_trace("#%d, Packet %s SSRC=%d, SN=%d, %d bytes", packets.debug_id, is_video? "Video":"Audio", + packet->rtp_header.get_ssrc(), packet->rtp_header.get_sequence(), nn_packet); if (do_send) { for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { iovec* iov = mhdr->msg_hdr.msg_iov + j; @@ -1072,8 +1081,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac if (iov->iov_len <= 0) { break; } - srs_trace("%s #%d/%d/%d, %d bytes, size %d/%d", (use_gso? "GSO":"RAW"), j, gso_cursor + 1, - mhdr->msg_hdr.msg_iovlen, iov->iov_len, gso_size, gso_encrypt); + srs_trace("#%d, %s #%d/%d/%d, %d bytes, size %d/%d", packets.debug_id, (use_gso? "GSO":"RAW"), j, + gso_cursor + 1, mhdr->msg_hdr.msg_iovlen, iov->iov_len, gso_size, gso_encrypt); } } #endif @@ -1119,8 +1128,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac } #if defined(SRS_DEBUG) - srs_trace("RTC PLAY summary, rtp %d/%d, videos %d/%d, audios %d/%d, pad %d", packets.size(), packets.nn_rtp_pkts, - packets.nn_videos, packets.nn_samples, packets.nn_audios, packets.nn_extras, packets.nn_paddings); + srs_trace("#%d, RTC PLAY summary, rtp %d/%d, videos %d/%d, audios %d/%d, pad %d", packets.debug_id, packets.size(), + packets.nn_rtp_pkts, packets.nn_videos, packets.nn_samples, packets.nn_audios, packets.nn_extras, packets.nn_paddings); #endif return err; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 7dbf8eefb..9f3378273 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -124,6 +124,10 @@ public: bool use_gso; bool should_merge_nalus; public: +#if defined(SRS_DEBUG) + // Debug id. + uint32_t debug_id; +#endif // The total bytes of RTP packets. int nn_bytes; // The RTP packets send out by sendmmsg or sendmsg. Note that if many packets group to From 5ad99b119dcb8ca5eecef68e19ccccc5b80f4eb8 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 10:05:17 +0800 Subject: [PATCH 19/54] Stat bytes --- trunk/src/app/srs_app_http_api.cpp | 11 ++++++++++- trunk/src/app/srs_app_rtc_conn.cpp | 22 +++++++++++++--------- trunk/src/app/srs_app_rtc_conn.hpp | 4 ++++ trunk/src/app/srs_app_statistic.cpp | 26 +++++++++++++++++++++++++- trunk/src/app/srs_app_statistic.hpp | 10 ++++++---- 5 files changed, 58 insertions(+), 15 deletions(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index fdfbf8747..6c9b9fbc5 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1624,7 +1624,7 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* p->set("target", SrsJsonAny::str(target.c_str())); p->set("reset", SrsJsonAny::str(reset.c_str())); - p->set("help", SrsJsonAny::str("?target=avframes|rtc|rtp|gso|writev_iovs|sendmmsg")); + p->set("help", SrsJsonAny::str("?target=avframes|rtc|rtp|gso|writev_iovs|sendmmsg|bytes")); p->set("help2", SrsJsonAny::str("?reset=all")); } @@ -1687,6 +1687,15 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* } } + if (target.empty() || target == "bytes") { + SrsJsonObject* p = SrsJsonAny::object(); + data->set("bytes", p); + if ((err = stat->dumps_perf_bytes(p)) != srs_success) { + int code = srs_error_code(err); srs_error_reset(err); + return srs_api_response_code(w, r, code); + } + } + return srs_api_response(w, r, obj->dumps()); } diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index bde3d0c04..e4159b3aa 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -472,7 +472,7 @@ SrsRtcPackets::SrsRtcPackets() nn_rtp_pkts = 0; nn_audios = nn_extras = 0; nn_videos = nn_samples = 0; - nn_paddings = 0; + nn_padding_bytes = nn_paddings = 0; cursor = 0; } @@ -504,7 +504,7 @@ void SrsRtcPackets::reset(bool gso, bool merge_nalus) nn_rtp_pkts = 0; nn_audios = nn_extras = 0; nn_videos = nn_samples = 0; - nn_paddings = 0; + nn_padding_bytes = nn_paddings = 0; cursor = 0; } @@ -733,18 +733,20 @@ srs_error_t SrsRtcSenderThread::cycle() stat->perf_on_rtp_packets(pkts.size()); // Stat the RTP packets going into kernel. stat->perf_on_gso_packets(pkts.nn_rtp_pkts); + // Stat the bytes and paddings. + stat->perf_on_rtc_bytes(pkts.nn_bytes, pkts.nn_padding_bytes); #if defined(SRS_DEBUG) - srs_trace("RTC PLAY done, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d bytes", + srs_trace("RTC PLAY done, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d/%d bytes", msg_count, nn_rtc_packets, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, - pkts.nn_samples, pkts.nn_bytes); + pkts.nn_samples, pkts.nn_bytes, pkts.nn_padding_bytes); #endif pprint->elapse(); if (pprint->can_print()) { // TODO: FIXME: Print stat like frame/s, packet/s, loss_packets. - srs_trace("-> RTC PLAY %d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d bytes, %d pad", + srs_trace("-> RTC PLAY %d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d/%d bytes, %d pad", msg_count, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, - pkts.nn_samples, pkts.nn_bytes, pkts.nn_paddings); + pkts.nn_samples, pkts.nn_bytes, pkts.nn_padding_bytes, pkts.nn_paddings); } } } @@ -965,6 +967,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac packet->set_padding(padding); nn_packet += padding; packets.nn_paddings++; + packets.nn_padding_bytes += padding; } } @@ -1128,8 +1131,9 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac } #if defined(SRS_DEBUG) - srs_trace("#%d, RTC PLAY summary, rtp %d/%d, videos %d/%d, audios %d/%d, pad %d", packets.debug_id, packets.size(), - packets.nn_rtp_pkts, packets.nn_videos, packets.nn_samples, packets.nn_audios, packets.nn_extras, packets.nn_paddings); + srs_trace("#%d, RTC PLAY summary, rtp %d/%d, videos %d/%d, audios %d/%d, pad %d/%d", packets.debug_id, packets.size(), + packets.nn_rtp_pkts, packets.nn_videos, packets.nn_samples, packets.nn_audios, packets.nn_extras, packets.nn_paddings, + packets.nn_padding_bytes); #endif return err; @@ -1971,7 +1975,7 @@ srs_error_t SrsUdpMuxSender::cycle() srs_warn("sendmmsg %d msgs, %d done", vlen, r0); } - stat->perf_sendmmsg_on_packets(vlen); + stat->perf_on_sendmmsg_packets(vlen); } } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 9f3378273..c08446e34 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -128,8 +128,12 @@ public: // Debug id. uint32_t debug_id; #endif +public: // The total bytes of RTP packets. int nn_bytes; + // The total padded bytes. + int nn_padding_bytes; +public: // The RTP packets send out by sendmmsg or sendmsg. Note that if many packets group to // one msghdr by GSO, it's only one RTP packet, because we only send once. int nn_rtp_pkts; diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 98c7ec8ab..4bf58aa99 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -271,6 +271,7 @@ SrsStatistic::SrsStatistic() perf_gso = new SrsStatisticCategory(); perf_rtp = new SrsStatisticCategory(); perf_rtc = new SrsStatisticCategory(); + perf_bytes = new SrsStatisticCategory(); } SrsStatistic::~SrsStatistic() @@ -311,6 +312,7 @@ SrsStatistic::~SrsStatistic() srs_freep(perf_gso); srs_freep(perf_rtp); srs_freep(perf_rtc); + srs_freep(perf_bytes); } SrsStatistic* SrsStatistic::instance() @@ -641,7 +643,7 @@ srs_error_t SrsStatistic::dumps_perf_writev_iovs(SrsJsonObject* obj) return dumps_perf(perf_iovs, obj); } -void SrsStatistic::perf_sendmmsg_on_packets(int nb_packets) +void SrsStatistic::perf_on_sendmmsg_packets(int nb_packets) { perf_on_packets(perf_sendmmsg, nb_packets); } @@ -651,6 +653,26 @@ srs_error_t SrsStatistic::dumps_perf_sendmmsg(SrsJsonObject* obj) return dumps_perf(perf_sendmmsg, obj); } +void SrsStatistic::perf_on_rtc_bytes(int nn_bytes, int nn_padding) +{ + // a: RTC bytes. + // b: RTC paddings. + perf_bytes->a += nn_bytes; + perf_bytes->b += nn_padding; + + perf_bytes->nn += nn_bytes + nn_padding; +} + +srs_error_t SrsStatistic::dumps_perf_bytes(SrsJsonObject* obj) +{ + obj->set("rtc_bytes", SrsJsonAny::integer(perf_bytes->a)); + obj->set("rtc_padding", SrsJsonAny::integer(perf_bytes->b)); + + obj->set("nn", SrsJsonAny::integer(perf_bytes->nn)); + + return srs_success; +} + void SrsStatistic::reset_perf() { srs_freep(perf_iovs); @@ -659,6 +681,7 @@ void SrsStatistic::reset_perf() srs_freep(perf_gso); srs_freep(perf_rtp); srs_freep(perf_rtc); + srs_freep(perf_bytes); perf_iovs = new SrsStatisticCategory(); perf_msgs = new SrsStatisticCategory(); @@ -666,6 +689,7 @@ void SrsStatistic::reset_perf() perf_gso = new SrsStatisticCategory(); perf_rtp = new SrsStatisticCategory(); perf_rtc = new SrsStatisticCategory(); + perf_bytes = new SrsStatisticCategory(); } void SrsStatistic::perf_on_packets(SrsStatisticCategory* p, int nb_msgs) diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index c0344989f..50fbb8516 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -174,6 +174,7 @@ private: SrsStatisticCategory* perf_gso; SrsStatisticCategory* perf_rtp; SrsStatisticCategory* perf_rtc; + SrsStatisticCategory* perf_bytes; private: SrsStatistic(); virtual ~SrsStatistic(); @@ -245,13 +246,11 @@ public: // Stat for packets merged written, nb_packets is the number of RTP packets. // For example, a RTC/opus packet maybe package to three RTP packets. virtual void perf_on_rtp_packets(int nb_packets); - // Dumps the perf statistic data for RTP packets, for performance analysis. virtual srs_error_t dumps_perf_rtp_packets(SrsJsonObject* obj); public: // Stat for packets UDP GSO, nb_packets is the merged RTP packets. // For example, three RTP/audio packets maybe GSO to one msghdr. virtual void perf_on_gso_packets(int nb_packets); - // Dumps the perf statistic data for UDP GSO, for performance analysis. virtual srs_error_t dumps_perf_gso(SrsJsonObject* obj); public: // Stat for TCP writev, nb_iovs is the total number of iovec. @@ -259,9 +258,12 @@ public: virtual srs_error_t dumps_perf_writev_iovs(SrsJsonObject* obj); public: // Stat for packets UDP sendmmsg, nb_packets is the vlen for sendmmsg. - virtual void perf_sendmmsg_on_packets(int nb_packets); - // Dumps the perf statistic data for UDP sendmmsg, for performance analysis. + virtual void perf_on_sendmmsg_packets(int nb_packets); virtual srs_error_t dumps_perf_sendmmsg(SrsJsonObject* obj); +public: + // Stat for bytes, nn_bytes is the size of bytes, nb_padding is padding bytes. + virtual void perf_on_rtc_bytes(int nn_bytes, int nn_padding); + virtual srs_error_t dumps_perf_bytes(SrsJsonObject* obj); public: // Reset all perf stat data. virtual void reset_perf(); From b91e07f4754c15c55dbbf3ed7c14045c0648185e Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 10:25:12 +0800 Subject: [PATCH 20/54] For #307, change max padding to 127 for GSO. --- trunk/conf/full.conf | 4 ++-- trunk/src/app/srs_app_config.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 6dfb8eca5..646d82b2b 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -446,8 +446,8 @@ rtc_server { # Whether pad first packet for GSO for padding bytes. # If 0, disable padding for GSO. # @remark The max padding size is 0x7f(127). - # default: 0 - padding 0; + # default: 127 + padding 127; } vhost rtc.vhost.srs.com { diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 8df22fea4..fcea9fde3 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4843,7 +4843,7 @@ bool SrsConfig::get_rtc_server_gso2() int SrsConfig::get_rtc_server_padding() { - static int DEFAULT = 0; + static int DEFAULT = 127; SrsConfDirective* conf = root->get("rtc_server"); if (!conf) { From 4dced0b07781022761086a55d0afc3b9b4cb83ba Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 10:58:20 +0800 Subject: [PATCH 21/54] For #307, fix apdding algorithm bug. --- trunk/src/app/srs_app_rtc_conn.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index e4159b3aa..b754f6e5a 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -954,9 +954,14 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac // Padding to the next packet to merge with it. int padding = nn_next_packet - nn_packet; - // If the next one could merge to this GSO stage, padding current to GSO size. - if (use_gso && nn_next_packet < gso_size) { - padding = gso_size - nn_packet; + if (use_gso) { + // If the next one could merge to this GSO stage, padding current to GSO size. + if (nn_next_packet < gso_size) { + padding = gso_size - nn_packet; + } else { + // If the next one could not merge to this GSO stage, never padding. + padding = 0; + } } if (padding > 0 && padding < max_padding) { From 34fec09bc09b7876c14d70cbab37521e0d9d569c Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 11:22:25 +0800 Subject: [PATCH 22/54] Refactor padding --- trunk/src/app/srs_app_rtc_conn.cpp | 11 ++++++----- trunk/src/kernel/srs_kernel_rtp.cpp | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index b754f6e5a..ff488ec71 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -941,6 +941,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac for (int i = 0; i < nn_packets; i++) { SrsRtpPacket2* packet = packets.at(i); int nn_packet = packet->nb_bytes(); + int padding = 0; SrsRtpPacket2* next_packet = NULL; int nn_next_packet = 0; @@ -952,7 +953,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac // Padding the packet to next or GSO size. if (max_padding > 0 && next_packet) { // Padding to the next packet to merge with it. - int padding = nn_next_packet - nn_packet; + padding = nn_next_packet - nn_packet; if (use_gso) { // If the next one could merge to this GSO stage, padding current to GSO size. @@ -1080,8 +1081,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac #if defined(SRS_DEBUG) bool is_video = packet->rtp_header.get_payload_type() == video_payload_type; - srs_trace("#%d, Packet %s SSRC=%d, SN=%d, %d bytes", packets.debug_id, is_video? "Video":"Audio", - packet->rtp_header.get_ssrc(), packet->rtp_header.get_sequence(), nn_packet); + srs_trace("#%d, Packet %s SSRC=%d, SN=%d, %d/%d bytes", packets.debug_id, is_video? "Video":"Audio", + packet->rtp_header.get_ssrc(), packet->rtp_header.get_sequence(), nn_packet - padding, padding); if (do_send) { for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { iovec* iov = mhdr->msg_hdr.msg_iov + j; @@ -1089,8 +1090,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac if (iov->iov_len <= 0) { break; } - srs_trace("#%d, %s #%d/%d/%d, %d bytes, size %d/%d", packets.debug_id, (use_gso? "GSO":"RAW"), j, - gso_cursor + 1, mhdr->msg_hdr.msg_iovlen, iov->iov_len, gso_size, gso_encrypt); + srs_trace("#%d, %s #%d/%d/%d, %d/%d bytes, size %d/%d", packets.debug_id, (use_gso? "GSO":"RAW"), j, + gso_cursor + 1, mhdr->msg_hdr.msg_iovlen, iov->iov_len, padding, gso_size, gso_encrypt); } } #endif diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index ef33c057a..870b292ee 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -195,7 +195,7 @@ srs_error_t SrsRtpPacket2::encode(SrsBuffer* buf) return srs_error_wrap(err, "encode payload"); } - if (padding) { + if (padding > 0) { if (!buf->require(padding)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", padding); } From 92419f9836b44e0c9b0263133610e97a00a12cfa Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 11:57:11 +0800 Subject: [PATCH 23/54] For #307, refine GSO padding algorithm --- trunk/src/app/srs_app_rtc_conn.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index ff488ec71..15e27ca5e 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -952,20 +952,24 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac // Padding the packet to next or GSO size. if (max_padding > 0 && next_packet) { - // Padding to the next packet to merge with it. - padding = nn_next_packet - nn_packet; - - if (use_gso) { - // If the next one could merge to this GSO stage, padding current to GSO size. + if (!use_gso) { + // Padding to the next packet to merge with it. + if (nn_next_packet > nn_packet) { + padding = nn_next_packet - nn_packet; + } + } else { + // Padding to GSO size for next one to merge with us. if (nn_next_packet < gso_size) { padding = gso_size - nn_packet; - } else { - // If the next one could not merge to this GSO stage, never padding. - padding = 0; } } - if (padding > 0 && padding < max_padding) { + // Reset padding if exceed max. + if (padding > max_padding) { + padding = 0; + } + + if (padding > 0) { #if defined(SRS_DEBUG) srs_trace("#%d, Padding %d bytes %d=>%d, packets %d, max_padding %d", packets.debug_id, padding, nn_packet, nn_packet + padding, nn_packets, max_padding); From cc831be985f616e6f512ea3b2da9ba4498d7fff8 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 12:18:52 +0800 Subject: [PATCH 24/54] Refactor variable name for GSO --- trunk/src/app/srs_app_rtc_conn.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 15e27ca5e..b03a121ee 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -934,7 +934,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac // Previous handler, if has the same size, we can use GSO. mmsghdr* gso_mhdr = NULL; int gso_size = 0; int gso_encrypt = 0; int gso_cursor = 0; // GSO, N packets has same length, the final one may not. - bool use_gso = false; bool gso_final = false; + bool using_gso = false; bool gso_final = false; ISrsUdpSender* sender = skt->sender(); int nn_packets = packets.size(); @@ -952,7 +952,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac // Padding the packet to next or GSO size. if (max_padding > 0 && next_packet) { - if (!use_gso) { + if (!using_gso) { // Padding to the next packet to merge with it. if (nn_next_packet > nn_packet) { padding = nn_next_packet - nn_packet; @@ -983,8 +983,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac // Check whether we can use GSO to send it. mmsghdr* mhdr = NULL; - if ((gso_size && gso_size == nn_packet) || (use_gso && !gso_final)) { - use_gso = true; + if ((gso_size && gso_size == nn_packet) || (using_gso && !gso_final)) { + using_gso = true; gso_final = (gso_size && gso_size != nn_packet); mhdr = gso_mhdr; @@ -1009,14 +1009,14 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac // Change the state according to the next packet. if (next_packet) { // If GSO, but next is bigger than this one, we must enter the final state. - if (use_gso && !gso_final) { + if (using_gso && !gso_final) { gso_final = (nn_packet < nn_next_packet); } // If not GSO, maybe the first fresh packet, we should see whether the next packet is smaller than this one, // if smaller, we can still enter GSO. - if (!use_gso) { - use_gso = (nn_packet >= nn_next_packet); + if (!using_gso) { + using_gso = (nn_packet >= nn_next_packet); } } @@ -1039,7 +1039,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac } // Now, GSO will use this message and size. - if (use_gso) { + if (using_gso) { gso_mhdr = mhdr; gso_size = nn_packet; } @@ -1067,21 +1067,21 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac } // If GSO, they must has same size, except the final one. - if (use_gso && !gso_final && gso_encrypt && gso_encrypt != (int)iov->iov_len) { + if (using_gso && !gso_final && gso_encrypt && gso_encrypt != (int)iov->iov_len) { return srs_error_new(ERROR_RTC_RTP_MUXER, "GSO size=%d/%d, encrypt=%d/%d", gso_size, nn_packet, gso_encrypt, iov->iov_len); } - if (use_gso && !gso_final) { + if (using_gso && !gso_final) { gso_encrypt = iov->iov_len; } // If exceed the max GSO size, set to final. - if (use_gso && gso_cursor > 64) { + if (using_gso && gso_cursor > 64) { gso_final = true; } // For last message, or final gso, or determined not using GSO, send it now. - bool do_send = (i == nn_packets - 1 || gso_final || !use_gso); + bool do_send = (i == nn_packets - 1 || gso_final || !using_gso); #if defined(SRS_DEBUG) bool is_video = packet->rtp_header.get_payload_type() == video_payload_type; @@ -1094,7 +1094,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac if (iov->iov_len <= 0) { break; } - srs_trace("#%d, %s #%d/%d/%d, %d/%d bytes, size %d/%d", packets.debug_id, (use_gso? "GSO":"RAW"), j, + srs_trace("#%d, %s #%d/%d/%d, %d/%d bytes, size %d/%d", packets.debug_id, (using_gso? "GSO":"RAW"), j, gso_cursor + 1, mhdr->msg_hdr.msg_iovlen, iov->iov_len, padding, gso_size, gso_encrypt); } } @@ -1110,7 +1110,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac mhdr->msg_len = 0; #ifndef SRS_AUTO_OSX - if (use_gso) { + if (using_gso) { mhdr->msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t)); if (!mhdr->msg_hdr.msg_control) { mhdr->msg_hdr.msg_control = new char[mhdr->msg_hdr.msg_controllen]; @@ -1136,7 +1136,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac // Reset the GSO flag. gso_mhdr = NULL; gso_size = 0; gso_encrypt = 0; gso_cursor = 0; - use_gso = gso_final = false; + using_gso = gso_final = false; } } From b4a7566684c54990b90c73130211be09ba070064 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 12:35:36 +0800 Subject: [PATCH 25/54] Print the rtp packets cache capacity --- trunk/src/app/srs_app_rtc_conn.cpp | 13 +++++++++---- trunk/src/app/srs_app_rtc_conn.hpp | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index b03a121ee..b1b92abaf 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -529,6 +529,11 @@ int SrsRtcPackets::size() return cursor; } +int SrsRtcPackets::capacity() +{ + return (int)packets.size(); +} + SrsRtpPacket2* SrsRtcPackets::at(int index) { srs_assert(index < cursor); @@ -736,7 +741,7 @@ srs_error_t SrsRtcSenderThread::cycle() // Stat the bytes and paddings. stat->perf_on_rtc_bytes(pkts.nn_bytes, pkts.nn_padding_bytes); #if defined(SRS_DEBUG) - srs_trace("RTC PLAY done, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d/%d bytes", + srs_trace("RTC PLAY perf, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d/%d bytes", msg_count, nn_rtc_packets, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, pkts.nn_samples, pkts.nn_bytes, pkts.nn_padding_bytes); #endif @@ -744,9 +749,9 @@ srs_error_t SrsRtcSenderThread::cycle() pprint->elapse(); if (pprint->can_print()) { // TODO: FIXME: Print stat like frame/s, packet/s, loss_packets. - srs_trace("-> RTC PLAY %d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d/%d bytes, %d pad", - msg_count, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, - pkts.nn_samples, pkts.nn_bytes, pkts.nn_padding_bytes, pkts.nn_paddings); + srs_trace("-> RTC PLAY %d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d/%d bytes, %d pad, %d/%d cache", + msg_count, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, pkts.nn_samples, pkts.nn_bytes, + pkts.nn_padding_bytes, pkts.nn_paddings, pkts.size(), pkts.capacity()); } } } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index c08446e34..0af9d0b5e 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -159,6 +159,7 @@ public: SrsRtpPacket2* fetch(); SrsRtpPacket2* back(); int size(); + int capacity(); SrsRtpPacket2* at(int index); }; From e90f0629ed2d801eb5ad5ff0360253dc11fde455 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 13:13:02 +0800 Subject: [PATCH 26/54] Refactor RTP cache reset --- trunk/src/kernel/srs_kernel_rtp.cpp | 30 +++++++++-------------------- trunk/src/kernel/srs_kernel_rtp.hpp | 3 +-- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index 870b292ee..6f2918abb 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -55,27 +55,15 @@ SrsRtpHeader::SrsRtpHeader() extension_length = 0; } -SrsRtpHeader::SrsRtpHeader(const SrsRtpHeader& rhs) +void SrsRtpHeader::reset() { - operator=(rhs); -} - -SrsRtpHeader& SrsRtpHeader::operator=(const SrsRtpHeader& rhs) -{ - padding = rhs.padding; - extension = rhs.extension; - cc = rhs.cc; - marker = rhs.marker; - payload_type = rhs.payload_type; - sequence = rhs.sequence; - timestamp = rhs.timestamp; - ssrc = rhs.ssrc; - for (size_t i = 0; i < cc; ++i) { - csrc[i] = rhs.csrc[i]; - } - extension_length = rhs.extension_length; - - return *this; + // We only reset the optional fields, the required field such as ssrc + // will always be set by user. + padding = false; + extension = false; + cc = 0; + marker = false; + extension_length = 0; } SrsRtpHeader::~SrsRtpHeader() @@ -173,7 +161,7 @@ void SrsRtpPacket2::set_padding(int size) void SrsRtpPacket2::reset() { - memset((void*)&rtp_header, 0, sizeof(SrsRtpHeader)); + rtp_header.reset(); padding = 0; srs_freep(payload); } diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index 1b4fd2de6..57fdbd706 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -56,8 +56,7 @@ private: public: SrsRtpHeader(); virtual ~SrsRtpHeader(); - SrsRtpHeader(const SrsRtpHeader& rhs); - SrsRtpHeader& operator=(const SrsRtpHeader& rhs); + void reset(); public: srs_error_t decode(SrsBuffer* stream); srs_error_t encode(SrsBuffer* stream); From bbe4b3797d24b8f6c686d47025379488ec1134f2 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 13:49:37 +0800 Subject: [PATCH 27/54] Refactor stat logs for RTC --- trunk/src/app/srs_app_rtc_conn.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index b1b92abaf..8a4d4cc8d 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1960,7 +1960,7 @@ srs_error_t SrsUdpMuxSender::cycle() cache.swap(hotspot); cache_pos = 0; - // Collect informations for GSO + // Collect informations for GSO. if (pos > 0) { // For shared GSO cache, stat the messages. mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; @@ -1977,7 +1977,7 @@ srs_error_t SrsUdpMuxSender::cycle() } } - // Send out all messages, may GSO if shared cache. + // Send out all messages. if (pos > 0) { // Send out all messages. mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; @@ -2020,9 +2020,15 @@ srs_error_t SrsUdpMuxSender::cycle() pps_unit = "(k)"; pps_last /= 1000; pps_average /= 1000; } - srs_trace("-> RTC SEND #%d, sessions %d, udp %d/%d/%" PRId64 ", gso %d/%d/%" PRId64 ", iovs %d/%d/%" PRId64 ", pps %d/%d%s", - srs_netfd_fileno(lfd), (int)server->nn_sessions(), pos, nn_msgs_max, nn_msgs, gso_pos, nn_gso_msgs_max, nn_gso_msgs, gso_iovs, nn_gso_iovs_max, nn_gso_iovs, - pps_average, pps_last, pps_unit.c_str()); + int nn_cache = 0; + for (vector::iterator it = hotspot.begin(); it < hotspot.end(); ++it) { + mmsghdr& hdr = *it; + nn_cache += hdr.msg_hdr.msg_iovlen; + } + + srs_trace("-> RTC SEND #%d, sessions %d, udp %d/%d/%" PRId64 ", gso %d/%d/%" PRId64 ", iovs %d/%d/%" PRId64 ", pps %d/%d%s, cache %d/%d", + srs_netfd_fileno(lfd), (int)server->nn_sessions(), pos, nn_msgs_max, nn_msgs, gso_pos, nn_gso_msgs_max, nn_gso_msgs, gso_iovs, + nn_gso_iovs_max, nn_gso_iovs, pps_average, pps_last, pps_unit.c_str(), (int)hotspot.size(), nn_cache); nn_msgs_last = nn_msgs; time_last = srs_get_system_time(); nn_loop = nn_wait = nn_msgs_max = 0; nn_gso_msgs_max = 0; nn_gso_iovs_max = 0; From d906ced5c3b23e22ccb29308b1d3d34f5717efd4 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 14:13:09 +0800 Subject: [PATCH 28/54] For #307, set cache to about 1.4GB when clients is 2k --- trunk/src/core/srs_core_performance.hpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/trunk/src/core/srs_core_performance.hpp b/trunk/src/core/srs_core_performance.hpp index cbfddf1dc..6958aed4f 100644 --- a/trunk/src/core/srs_core_performance.hpp +++ b/trunk/src/core/srs_core_performance.hpp @@ -193,7 +193,15 @@ #undef SRS_PERF_GLIBC_MEMORY_CHECK // For RTC, how many iovs we alloc for each mmsghdr for GSO. -#define SRS_PERF_RTC_GSO_IOVS 4 +// Assume that there are 2400 clients, say, 60000 msgs in queue to send, the memory is: +// 2 # We have two queue, cache and hotspot. +// * 4 # We have reuseport, each have msg cache queue. +// * (64 + SRS_PERF_RTC_GSO_IOVS * 1500) # Each message size. +// * 60000 # Total messages. +// = 715MB # For SRS_PERF_RTC_GSO_IOVS = 1 +// = 1402MB # For SRS_PERF_RTC_GSO_IOVS = 2 +// = 2775MB # For SRS_PERF_RTC_GSO_IOVS = 4 +#define SRS_PERF_RTC_GSO_IOVS 2 #endif From d5c514cdcb3dd186c7cb66c983eddb6700071cda Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 14:28:59 +0800 Subject: [PATCH 29/54] For #307, reuse raw cache payload for RTP --- trunk/src/app/srs_app_rtc_conn.cpp | 3 +-- trunk/src/kernel/srs_kernel_rtp.cpp | 20 ++++++++++++++++++++ trunk/src/kernel/srs_kernel_rtp.hpp | 5 +++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 8a4d4cc8d..3c80902ce 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1244,10 +1244,9 @@ srs_error_t SrsRtcSenderThread::packet_opus(SrsSample* sample, SrsRtcPackets& pa packet->rtp_header.set_ssrc(audio_ssrc); packet->rtp_header.set_payload_type(audio_payload_type); - SrsRtpRawPayload* raw = new SrsRtpRawPayload(); + SrsRtpRawPayload* raw = packet->reuse_raw(); raw->payload = sample->bytes; raw->nn_payload = sample->size; - packet->payload = raw; // TODO: FIXME: Why 960? Need Refactoring? audio_timestamp += 960; diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index 6f2918abb..c298b9a68 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -146,11 +146,19 @@ SrsRtpPacket2::SrsRtpPacket2() { payload = NULL; padding = 0; + + cache_raw = new SrsRtpRawPayload(); } SrsRtpPacket2::~SrsRtpPacket2() { + // We may use the cache as payload. + if (payload == cache_raw) { + payload = NULL; + } + srs_freep(payload); + srs_freep(cache_raw); } void SrsRtpPacket2::set_padding(int size) @@ -163,9 +171,21 @@ void SrsRtpPacket2::reset() { rtp_header.reset(); padding = 0; + + // We may use the cache as payload. + if (payload == cache_raw) { + payload = NULL; + } + srs_freep(payload); } +SrsRtpRawPayload* SrsRtpPacket2::reuse_raw() +{ + payload = cache_raw; + return cache_raw; +} + int SrsRtpPacket2::nb_bytes() { return rtp_header.header_size() + (payload? payload->nb_bytes():0) + padding; diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index 57fdbd706..2212853eb 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -38,6 +38,7 @@ const uint8_t kRtpMarker = 0x80; const uint8_t kNalTypeMask = 0x1F; class SrsBuffer; +class SrsRtpRawPayload; class SrsRtpHeader { @@ -82,6 +83,8 @@ public: SrsRtpHeader rtp_header; ISrsEncoder* payload; int padding; +private: + SrsRtpRawPayload* cache_raw; public: SrsRtpPacket2(); virtual ~SrsRtpPacket2(); @@ -90,6 +93,8 @@ public: void set_padding(int size); // Reset RTP packet. void reset(); + // Reuse the cached raw message as payload. + SrsRtpRawPayload* reuse_raw(); // interface ISrsEncoder public: virtual int nb_bytes(); From 3bd56bb3a3bca297be51438b3a424acbb8948d81 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 14:51:36 +0800 Subject: [PATCH 30/54] For #307, reuse fua cache payload for RTP --- trunk/src/app/srs_app_rtc_conn.cpp | 27 +++++++++++---------------- trunk/src/kernel/srs_kernel_rtp.cpp | 22 ++++++++++++++++++++-- trunk/src/kernel/srs_kernel_rtp.hpp | 6 ++++++ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 3c80902ce..87f664590 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1182,10 +1182,12 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac if (nn_bytes < kRtpMaxPayloadSize) { // Package NALUs in a single RTP packet. SrsRtpPacket2* packet = packets.fetch(); + packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); packet->rtp_header.set_ssrc(video_ssrc); packet->rtp_header.set_payload_type(video_payload_type); + packet->payload = raw; } else { SrsAutoFree(SrsRtpRawNALUs, raw); @@ -1202,12 +1204,6 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac for (int i = 0; i < num_of_packet; ++i) { int packet_size = srs_min(nb_left, fu_payload_size); - SrsRtpFUAPayload* fua = new SrsRtpFUAPayload(); - if ((err = raw->read_samples(fua->nalus, packet_size)) != srs_success) { - srs_freep(fua); - return srs_error_wrap(err, "read samples %d bytes, left %d, total %d", packet_size, nb_left, nn_bytes); - } - SrsRtpPacket2* packet = packets.fetch(); packet->rtp_header.set_timestamp(msg->timestamp * 90); @@ -1215,13 +1211,17 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac packet->rtp_header.set_ssrc(video_ssrc); packet->rtp_header.set_payload_type(video_payload_type); - packet->payload = fua; + SrsRtpFUAPayload* fua = packet->reuse_fua(); fua->nri = (SrsAvcNaluType)header; fua->nalu_type = (SrsAvcNaluType)nal_type; fua->start = bool(i == 0); fua->end = bool(i == num_of_packet - 1); + if ((err = raw->read_samples(fua->nalus, packet_size)) != srs_success) { + return srs_error_wrap(err, "read samples %d bytes, left %d, total %d", packet_size, nb_left, nn_bytes); + } + nb_left -= packet_size; } } @@ -1274,8 +1274,7 @@ srs_error_t SrsRtcSenderThread::packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* packet->rtp_header.set_ssrc(video_ssrc); packet->rtp_header.set_payload_type(video_payload_type); - SrsRtpFUAPayload* fua = new SrsRtpFUAPayload(); - packet->payload = fua; + SrsRtpFUAPayload* fua = packet->reuse_fua(); fua->nri = (SrsAvcNaluType)header; fua->nalu_type = (SrsAvcNaluType)nal_type; @@ -1305,13 +1304,9 @@ srs_error_t SrsRtcSenderThread::packet_single_nalu(SrsSharedPtrMessage* msg, Srs packet->rtp_header.set_ssrc(video_ssrc); packet->rtp_header.set_payload_type(video_payload_type); - SrsRtpRawNALUs* raw = new SrsRtpRawNALUs(); - packet->payload = raw; - - SrsSample* p = new SrsSample(); - p->bytes = sample->bytes; - p->size = sample->size; - raw->push_back(p); + SrsRtpRawPayload* raw = packet->reuse_raw(); + raw->payload = sample->bytes; + raw->nn_payload = sample->size; return err; } diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index c298b9a68..c6b071de8 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -148,12 +148,13 @@ SrsRtpPacket2::SrsRtpPacket2() padding = 0; cache_raw = new SrsRtpRawPayload(); + cache_fua = new SrsRtpFUAPayload(); } SrsRtpPacket2::~SrsRtpPacket2() { // We may use the cache as payload. - if (payload == cache_raw) { + if (payload == cache_raw || payload == cache_fua) { payload = NULL; } @@ -173,7 +174,7 @@ void SrsRtpPacket2::reset() padding = 0; // We may use the cache as payload. - if (payload == cache_raw) { + if (payload == cache_raw || payload == cache_fua) { payload = NULL; } @@ -186,6 +187,13 @@ SrsRtpRawPayload* SrsRtpPacket2::reuse_raw() return cache_raw; } +SrsRtpFUAPayload* SrsRtpPacket2::reuse_fua() +{ + payload = cache_fua; + cache_fua->reset(); + return cache_fua; +} + int SrsRtpPacket2::nb_bytes() { return rtp_header.header_size() + (payload? payload->nb_bytes():0) + padding; @@ -421,6 +429,16 @@ SrsRtpFUAPayload::~SrsRtpFUAPayload() nalus.clear(); } +void SrsRtpFUAPayload::reset() +{ + vector::iterator it; + for (it = nalus.begin(); it != nalus.end(); ++it) { + SrsSample* p = *it; + srs_freep(p); + } + nalus.clear(); +} + int SrsRtpFUAPayload::nb_bytes() { int size = 2; diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index 2212853eb..f093f72bf 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -39,6 +39,7 @@ const uint8_t kNalTypeMask = 0x1F; class SrsBuffer; class SrsRtpRawPayload; +class SrsRtpFUAPayload; class SrsRtpHeader { @@ -85,6 +86,7 @@ public: int padding; private: SrsRtpRawPayload* cache_raw; + SrsRtpFUAPayload* cache_fua; public: SrsRtpPacket2(); virtual ~SrsRtpPacket2(); @@ -95,6 +97,8 @@ public: void reset(); // Reuse the cached raw message as payload. SrsRtpRawPayload* reuse_raw(); + // Reuse the cached fua message as payload. + SrsRtpFUAPayload* reuse_fua(); // interface ISrsEncoder public: virtual int nb_bytes(); @@ -172,6 +176,8 @@ public: public: SrsRtpFUAPayload(); virtual ~SrsRtpFUAPayload(); +public: + void reset(); // interface ISrsEncoder public: virtual int nb_bytes(); From 634225f92fcde8091bf2631ecc1451842a671995 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 18:04:56 +0800 Subject: [PATCH 31/54] Improve perforance of marshaling RTP header --- trunk/src/kernel/srs_kernel_rtp.cpp | 45 ++++++++++++++++++++++++----- trunk/src/kernel/srs_kernel_rtp.hpp | 2 +- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index c6b071de8..3798fe987 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -83,6 +83,12 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* stream) { srs_error_t err = srs_success; + // Encode the RTP fix header, 12bytes. + // @see https://tools.ietf.org/html/rfc1889#section-5.1 + char* op = stream->data() + stream->pos(); + char* p = op; + + // The version, padding, extension and cc, total 1 byte. uint8_t v = 0x80 | cc; if (padding) { v |= 0x20; @@ -90,25 +96,50 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* stream) if (extension) { v |= 0x10; } - stream->write_1bytes(v); + *p++ = v; + // The marker and payload type, total 1 byte. v = payload_type; if (marker) { v |= kRtpMarker; } - stream->write_1bytes(v); + *p++ = v; - stream->write_2bytes(sequence); - stream->write_4bytes(timestamp); - stream->write_4bytes(ssrc); + // The sequence number, 2 bytes. + char* pp = (char*)&sequence; + *p++ = pp[1]; + *p++ = pp[0]; + + // The timestamp, 4 bytes. + pp = (char*)×tamp; + *p++ = pp[3]; + *p++ = pp[2]; + *p++ = pp[1]; + *p++ = pp[0]; + + // The SSRC, 4 bytes. + pp = (char*)&ssrc; + *p++ = pp[3]; + *p++ = pp[2]; + *p++ = pp[1]; + *p++ = pp[0]; + + // The CSRC list: 0 to 15 items, each is 4 bytes. for (size_t i = 0; i < cc; ++i) { - stream->write_4bytes(csrc[i]); + pp = (char*)&csrc[i]; + *p++ = pp[3]; + *p++ = pp[2]; + *p++ = pp[1]; + *p++ = pp[0]; } // TODO: Write exteinsion field. if (extension) { } + // Consume the data. + stream->skip(p - op); + return err; } @@ -134,7 +165,7 @@ void SrsRtpHeader::set_sequence(uint16_t sequence) void SrsRtpHeader::set_timestamp(int64_t timestamp) { - this->timestamp = timestamp; + this->timestamp = (uint32_t)timestamp; } void SrsRtpHeader::set_ssrc(uint32_t ssrc) diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index f093f72bf..615194a3d 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -50,7 +50,7 @@ private: bool marker; uint8_t payload_type; uint16_t sequence; - int64_t timestamp; + int32_t timestamp; uint32_t ssrc; uint32_t csrc[15]; uint16_t extension_length; From 810b32138e8592d56970d4df61b9a8bb16db5268 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 18:25:11 +0800 Subject: [PATCH 32/54] Refactor code --- trunk/src/app/srs_app_rtc_conn.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 87f664590..c1804f62e 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1967,7 +1967,8 @@ srs_error_t SrsUdpMuxSender::cycle() int real_iovs = p->msg_len; p->msg_len = 0; - gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs; gso_iovs += real_iovs; + gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs; + gso_iovs += real_iovs; } } @@ -2015,9 +2016,10 @@ srs_error_t SrsUdpMuxSender::cycle() } int nn_cache = 0; - for (vector::iterator it = hotspot.begin(); it < hotspot.end(); ++it) { - mmsghdr& hdr = *it; - nn_cache += hdr.msg_hdr.msg_iovlen; + int nn_hotspot_size = (int)hotspot.size(); + for (int i = 0; i < nn_hotspot_size; i++) { + mmsghdr* hdr = &hotspot[i]; + nn_cache += hdr->msg_hdr.msg_iovlen; } srs_trace("-> RTC SEND #%d, sessions %d, udp %d/%d/%" PRId64 ", gso %d/%d/%" PRId64 ", iovs %d/%d/%" PRId64 ", pps %d/%d%s, cache %d/%d", From 1a6e055f7fbc20da9469a7984fdddca99787d72b Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 18:37:37 +0800 Subject: [PATCH 33/54] Support config to disable stat to improve performance. --- trunk/conf/full.conf | 3 +++ trunk/src/app/srs_app_config.cpp | 19 ++++++++++++++++- trunk/src/app/srs_app_config.hpp | 1 + trunk/src/app/srs_app_http_api.cpp | 3 ++- trunk/src/app/srs_app_rtc_conn.cpp | 34 ++++++++++++++++++------------ 5 files changed, 45 insertions(+), 15 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 646d82b2b..7cc2c5593 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -448,6 +448,9 @@ rtc_server { # @remark The max padding size is 0x7f(127). # default: 127 padding 127; + # Whether enable the perf stat at http://localhost:1985/api/v1/perf + # default: off + perf_stat off; } vhost rtc.vhost.srs.com { diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index fcea9fde3..66e5942e5 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3619,7 +3619,7 @@ srs_error_t SrsConfig::check_normal_config() string n = conf->at(i)->name; if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa" && n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus" - && n != "padding") { + && n != "padding" && n != "perf_stat") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", n.c_str()); } } @@ -4858,6 +4858,23 @@ int SrsConfig::get_rtc_server_padding() return srs_min(127, ::atoi(conf->arg0().c_str())); } +bool SrsConfig::get_rtc_server_perf_stat() +{ + static bool DEFAULT = false; + + SrsConfDirective* conf = root->get("rtc_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("perf_stat"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + SrsConfDirective* SrsConfig::get_rtc(string vhost) { SrsConfDirective* conf = get_vhost(vhost); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 8d31ef86e..0d2d0c4cc 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -537,6 +537,7 @@ private: virtual bool get_rtc_server_gso2(); public: virtual int get_rtc_server_padding(); + virtual bool get_rtc_server_perf_stat(); public: SrsConfDirective* get_rtc(std::string vhost); diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 6c9b9fbc5..e994b9982 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1616,7 +1616,8 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* string target = r->query_get("target"); string reset = r->query_get("reset"); - srs_trace("query target=%s, reset=%s", target.c_str(), reset.c_str()); + srs_trace("query target=%s, reset=%s, rtc_stat_enabled=%d", target.c_str(), reset.c_str(), + _srs_config->get_rtc_server_perf_stat()); if (true) { SrsJsonObject* p = SrsJsonAny::object(); diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index c1804f62e..d35290f0f 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -686,6 +686,7 @@ srs_error_t SrsRtcSenderThread::cycle() SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_play(); SrsAutoFree(SrsPithyPrint, pprint); + bool stat_enabled = _srs_config->get_rtc_server_perf_stat(); SrsStatistic* stat = SrsStatistic::instance(); while (true) { @@ -729,17 +730,20 @@ srs_error_t SrsRtcSenderThread::cycle() srs_freep(msg); } - // Stat the original RAW AV frame, maybe h264+aac. - stat->perf_on_msgs(msg_count); - // Stat the RTC packets, RAW AV frame, maybe h.264+opus. - int nn_rtc_packets = srs_max(pkts.nn_audios, pkts.nn_extras) + pkts.nn_videos; - stat->perf_on_rtc_packets(nn_rtc_packets); - // Stat the RAW RTP packets, which maybe group by GSO. - stat->perf_on_rtp_packets(pkts.size()); - // Stat the RTP packets going into kernel. - stat->perf_on_gso_packets(pkts.nn_rtp_pkts); - // Stat the bytes and paddings. - stat->perf_on_rtc_bytes(pkts.nn_bytes, pkts.nn_padding_bytes); + // Stat for performance analysis. + if (stat_enabled) { + // Stat the original RAW AV frame, maybe h264+aac. + stat->perf_on_msgs(msg_count); + // Stat the RTC packets, RAW AV frame, maybe h.264+opus. + int nn_rtc_packets = srs_max(pkts.nn_audios, pkts.nn_extras) + pkts.nn_videos; + stat->perf_on_rtc_packets(nn_rtc_packets); + // Stat the RAW RTP packets, which maybe group by GSO. + stat->perf_on_rtp_packets(pkts.size()); + // Stat the RTP packets going into kernel. + stat->perf_on_gso_packets(pkts.nn_rtp_pkts); + // Stat the bytes and paddings. + stat->perf_on_rtc_bytes(pkts.nn_bytes, pkts.nn_padding_bytes); + } #if defined(SRS_DEBUG) srs_trace("RTC PLAY perf, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d/%d bytes", msg_count, nn_rtc_packets, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, @@ -1928,6 +1932,8 @@ srs_error_t SrsUdpMuxSender::cycle() uint64_t nn_gso_msgs = 0; uint64_t nn_gso_iovs = 0; int nn_gso_msgs_max = 0; int nn_gso_iovs_max = 0; int nn_loop = 0; int nn_wait = 0; srs_utime_t time_last = srs_get_system_time(); + + bool stat_enabled = _srs_config->get_rtc_server_perf_stat(); SrsStatistic* stat = SrsStatistic::instance(); SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_send(srs_netfd_fileno(lfd)); @@ -1955,7 +1961,7 @@ srs_error_t SrsUdpMuxSender::cycle() cache_pos = 0; // Collect informations for GSO. - if (pos > 0) { + if (pos > 0 && stat_enabled) { // For shared GSO cache, stat the messages. mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; for (p = &hotspot[0]; p < end; p++) { @@ -1985,7 +1991,9 @@ srs_error_t SrsUdpMuxSender::cycle() srs_warn("sendmmsg %d msgs, %d done", vlen, r0); } - stat->perf_on_sendmmsg_packets(vlen); + if (stat_enabled) { + stat->perf_on_sendmmsg_packets(vlen); + } } } From 32f43a992091be567821cb727873903b61b6e279 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 18:52:17 +0800 Subject: [PATCH 34/54] For RTC, always try to read message first, to improve performance --- trunk/src/app/srs_app_rtc_conn.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index d35290f0f..c3232a476 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -694,26 +694,24 @@ srs_error_t SrsRtcSenderThread::cycle() return srs_error_wrap(err, "rtc sender thread"); } -#ifdef SRS_PERF_QUEUE_COND_WAIT - if (realtime) { - // for realtime, min required msgs is 0, send when got one+ msgs. - consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME, mw_sleep); - } else { - // for no-realtime, got some msgs then send. - consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC, mw_sleep); - } -#endif - int msg_count = 0; if ((err = consumer->dump_packets(&msgs, msg_count)) != srs_success) { continue; } - if (msg_count <= 0) { -#ifndef SRS_PERF_QUEUE_COND_WAIT + // For RTC, we always try to read messages, only wait when no message. + if (msg_count <= 0) { +#ifdef SRS_PERF_QUEUE_COND_WAIT + if (realtime) { + // for realtime, min required msgs is 0, send when got one+ msgs. + consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME, mw_sleep); + } else { + // for no-realtime, got some msgs then send. + consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC, mw_sleep); + } +#else srs_usleep(mw_sleep); #endif - // ignore when nothing got. continue; } From 8383f1b27a6561ff7fd837e4eace375caeb97e33 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 16 Apr 2020 19:33:10 +0800 Subject: [PATCH 35/54] Improve performance for GSO --- trunk/src/app/srs_app_rtc_conn.cpp | 45 +++++++++++++++++------------- trunk/src/app/srs_app_rtc_conn.hpp | 8 ++++-- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index c3232a476..d84ead035 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -548,6 +548,8 @@ SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int rtc_session = s; sendonly_ukt = u->copy_sendonly(); + sender = u->sender(); + gso = false; merge_nalus = false; max_padding = 0; @@ -652,6 +654,7 @@ void SrsRtcSenderThread::update_sendonly_socket(SrsUdpMuxSocket* skt) srs_freep(sendonly_ukt); sendonly_ukt = skt->copy_sendonly(); + sender = skt->sender(); } srs_error_t SrsRtcSenderThread::cycle() @@ -701,6 +704,8 @@ srs_error_t SrsRtcSenderThread::cycle() // For RTC, we always try to read messages, only wait when no message. if (msg_count <= 0) { + srs_usleep(0); + #ifdef SRS_PERF_QUEUE_COND_WAIT if (realtime) { // for realtime, min required msgs is 0, send when got one+ msgs. @@ -718,7 +723,7 @@ srs_error_t SrsRtcSenderThread::cycle() // Transmux and send out messages. pkts.reset(gso, merge_nalus); - if ((err = send_messages(sendonly_ukt, source, msgs.msgs, msg_count, pkts)) != srs_success) { + if ((err = send_messages(source, msgs.msgs, msg_count, pkts)) != srs_success) { srs_warn("send err %s", srs_error_summary(err).c_str()); srs_error_reset(err); } @@ -759,7 +764,7 @@ srs_error_t SrsRtcSenderThread::cycle() } srs_error_t SrsRtcSenderThread::send_messages( - SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets + SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets ) { srs_error_t err = srs_success; @@ -775,7 +780,7 @@ srs_error_t SrsRtcSenderThread::send_messages( #ifndef SRS_AUTO_OSX // If enabled GSO, send out some packets in a msghdr. if (packets.use_gso) { - if ((err = send_packets_gso(skt, packets)) != srs_success) { + if ((err = send_packets_gso(packets)) != srs_success) { return srs_error_wrap(err, "gso send"); } return err; @@ -783,7 +788,7 @@ srs_error_t SrsRtcSenderThread::send_messages( #endif // By default, we send packets by sendmmsg. - if ((err = send_packets(skt, packets)) != srs_success) { + if ((err = send_packets(packets)) != srs_success) { return srs_error_wrap(err, "raw send"); } @@ -867,12 +872,10 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( return err; } -srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets& packets) +srs_error_t SrsRtcSenderThread::send_packets(SrsRtcPackets& packets) { srs_error_t err = srs_success; - ISrsUdpSender* sender = skt->sender(); - int nn_packets = packets.size(); for (int i = 0; i < nn_packets; i++) { SrsRtpPacket2* packet = packets.at(i); @@ -913,8 +916,8 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets } } - sockaddr_in* addr = (sockaddr_in*)skt->peer_addr(); - socklen_t addrlen = (socklen_t)skt->peer_addrlen(); + sockaddr_in* addr = (sockaddr_in*)sendonly_ukt->peer_addr(); + socklen_t addrlen = (socklen_t)sendonly_ukt->peer_addrlen(); mhdr->msg_hdr.msg_name = (sockaddr_in*)addr; mhdr->msg_hdr.msg_namelen = (socklen_t)addrlen; @@ -934,7 +937,7 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets } // TODO: FIXME: We can gather and pad audios, because they have similar size. -srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPackets& packets) +srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) { srs_error_t err = srs_success; @@ -943,7 +946,6 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac // GSO, N packets has same length, the final one may not. bool using_gso = false; bool gso_final = false; - ISrsUdpSender* sender = skt->sender(); int nn_packets = packets.size(); for (int i = 0; i < nn_packets; i++) { SrsRtpPacket2* packet = packets.at(i); @@ -1108,8 +1110,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac #endif if (do_send) { - sockaddr_in* addr = (sockaddr_in*)skt->peer_addr(); - socklen_t addrlen = (socklen_t)skt->peer_addrlen(); + sockaddr_in* addr = (sockaddr_in*)sendonly_ukt->peer_addr(); + socklen_t addrlen = (socklen_t)sendonly_ukt->peer_addrlen(); mhdr->msg_hdr.msg_name = (sockaddr_in*)addr; mhdr->msg_hdr.msg_namelen = (socklen_t)addrlen; @@ -1945,13 +1947,17 @@ srs_error_t SrsUdpMuxSender::cycle() nn_loop++; int pos = cache_pos; - int gso_pos = 0; int gso_iovs = 0; - if (pos <= 0 && gso_pos == 0) { - waiting_msgs = true; - nn_wait++; - srs_cond_wait(cond); - continue; + if (pos <= 0) { + srs_usleep(0); + if (pos <= 0) { + waiting_msgs = true; + nn_wait++; + srs_cond_wait(cond); + } + if (pos <= 0) { + continue; + } } // We are working on hotspot now. @@ -1959,6 +1965,7 @@ srs_error_t SrsUdpMuxSender::cycle() cache_pos = 0; // Collect informations for GSO. + int gso_pos = 0; if (pos > 0 && stat_enabled) { // For shared GSO cache, stat the messages. mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 0af9d0b5e..a1fe62514 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -50,6 +50,7 @@ class SrsRtcSession; class SrsSharedPtrMessage; class SrsSource; class SrsRtpPacket2; +class ISrsUdpSender; const uint8_t kSR = 200; const uint8_t kRR = 201; @@ -182,6 +183,7 @@ private: uint16_t video_sequence; public: SrsUdpMuxSocket* sendonly_ukt; + ISrsUdpSender* sender; bool merge_nalus; bool gso; int max_padding; @@ -204,10 +206,10 @@ public: public: virtual srs_error_t cycle(); private: - srs_error_t send_messages(SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); + srs_error_t send_messages(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); srs_error_t messages_to_packets(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); - srs_error_t send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); - srs_error_t send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); + srs_error_t send_packets(SrsRtcPackets& packets); + srs_error_t send_packets_gso(SrsRtcPackets& packets); private: srs_error_t packet_opus(SrsSample* sample, SrsRtcPackets& packets); private: From f0015a7cc1caf6b0c63c0917bc34d0f11f943731 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 17 Apr 2020 07:10:16 +0800 Subject: [PATCH 36/54] For #307, refine GSO performance, alloc iovs --- trunk/src/app/srs_app_rtc_conn.cpp | 130 +++++++++--------------- trunk/src/core/srs_core_performance.hpp | 9 +- trunk/src/service/srs_service_st.cpp | 2 + 3 files changed, 58 insertions(+), 83 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index d84ead035..d18602ed5 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -704,8 +704,6 @@ srs_error_t SrsRtcSenderThread::cycle() // For RTC, we always try to read messages, only wait when no message. if (msg_count <= 0) { - srs_usleep(0); - #ifdef SRS_PERF_QUEUE_COND_WAIT if (realtime) { // for realtime, min required msgs is 0, send when got one+ msgs. @@ -887,43 +885,40 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsRtcPackets& packets) return srs_error_wrap(err, "fetch msghdr"); } - // Reset the iovec, we should never change the msg_iovlen. - for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { - iovec* p = mhdr->msg_hdr.msg_iov + j; + // For this message, select the first iovec. + iovec* iov = mhdr->msg_hdr.msg_iov; + mhdr->msg_hdr.msg_iovlen = 1; - if (!p->iov_len) { - break; - } - p->iov_len = 0; + if (!iov->iov_base) { + iov->iov_base = new char[kRtpPacketSize]; } + iov->iov_len = kRtpPacketSize; - char* buf = (char*)mhdr->msg_hdr.msg_iov->iov_base; - int length = kRtpPacketSize; - - // Marshal packet to bytes. + // Marshal packet to bytes in iovec. if (true) { - SrsBuffer stream(buf, length); + SrsBuffer stream((char*)iov->iov_base, iov->iov_len); if ((err = packet->encode(&stream)) != srs_success) { return srs_error_wrap(err, "encode packet"); } - length = stream.pos(); + iov->iov_len = stream.pos(); } // Whether encrypt the RTP bytes. if (rtc_session->encrypt) { - if ((err = rtc_session->dtls_session->protect_rtp2(buf, &length)) != srs_success) { + int nn_encrypt = (int)iov->iov_len; + if ((err = rtc_session->dtls_session->protect_rtp2(iov->iov_base, &nn_encrypt)) != srs_success) { return srs_error_wrap(err, "srtp protect"); } + iov->iov_len = (size_t)nn_encrypt; } + // Set the address and control information. sockaddr_in* addr = (sockaddr_in*)sendonly_ukt->peer_addr(); socklen_t addrlen = (socklen_t)sendonly_ukt->peer_addrlen(); mhdr->msg_hdr.msg_name = (sockaddr_in*)addr; mhdr->msg_hdr.msg_namelen = (socklen_t)addrlen; - mhdr->msg_hdr.msg_iov->iov_len = length; mhdr->msg_hdr.msg_controllen = 0; - mhdr->msg_len = 0; // When we send out a packet, we commit a RTP packet. packets.nn_rtp_pkts++; @@ -996,23 +991,6 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) using_gso = true; gso_final = (gso_size && gso_size != nn_packet); mhdr = gso_mhdr; - - // We need to increase the iov and cursor. - int nb_iovs = mhdr->msg_hdr.msg_iovlen; - if (gso_cursor >= nb_iovs - 1) { - int nn_new_iovs = 1; - mhdr->msg_hdr.msg_iovlen = nb_iovs + nn_new_iovs; - mhdr->msg_hdr.msg_iov = (iovec*)realloc(mhdr->msg_hdr.msg_iov, sizeof(iovec) * (nb_iovs + nn_new_iovs)); - memset(mhdr->msg_hdr.msg_iov + nb_iovs, 0, sizeof(iovec) * nn_new_iovs); - } - gso_cursor++; - - // Create payload cache for RTP packet. - iovec* p = mhdr->msg_hdr.msg_iov + gso_cursor; - if (!p->iov_base) { - p->iov_base = new char[kRtpPacketSize]; - p->iov_len = kRtpPacketSize; - } } // Change the state according to the next packet. @@ -1037,16 +1015,6 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) return srs_error_wrap(err, "fetch msghdr"); } - // Reset the iovec, we should never change the msg_iovlen. - for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { - iovec* p = mhdr->msg_hdr.msg_iov + j; - - if (!p->iov_len) { - break; - } - p->iov_len = 0; - } - // Now, GSO will use this message and size. if (using_gso) { gso_mhdr = mhdr; @@ -1054,10 +1022,17 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) } } - // Marshal packet to bytes. + // For this message, select a new iovec. iovec* iov = mhdr->msg_hdr.msg_iov + gso_cursor; + mhdr->msg_hdr.msg_iovlen = gso_cursor + 1; + gso_cursor++; + + if (!iov->iov_base) { + iov->iov_base = new char[kRtpPacketSize]; + } iov->iov_len = kRtpPacketSize; + // Marshal packet to bytes in iovec. if (true) { SrsBuffer stream((char*)iov->iov_base, iov->iov_len); if ((err = packet->encode(&stream)) != srs_success) { @@ -1085,7 +1060,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) } // If exceed the max GSO size, set to final. - if (using_gso && gso_cursor > 64) { + if (using_gso && gso_cursor + 1 >= SRS_PERF_RTC_GSO_MAX) { gso_final = true; } @@ -1099,10 +1074,6 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) if (do_send) { for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { iovec* iov = mhdr->msg_hdr.msg_iov + j; - - if (iov->iov_len <= 0) { - break; - } srs_trace("#%d, %s #%d/%d/%d, %d/%d bytes, size %d/%d", packets.debug_id, (using_gso? "GSO":"RAW"), j, gso_cursor + 1, mhdr->msg_hdr.msg_iovlen, iov->iov_len, padding, gso_size, gso_encrypt); } @@ -1110,13 +1081,13 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) #endif if (do_send) { + // Set the address and control information. sockaddr_in* addr = (sockaddr_in*)sendonly_ukt->peer_addr(); socklen_t addrlen = (socklen_t)sendonly_ukt->peer_addrlen(); mhdr->msg_hdr.msg_name = (sockaddr_in*)addr; mhdr->msg_hdr.msg_namelen = (socklen_t)addrlen; mhdr->msg_hdr.msg_controllen = 0; - mhdr->msg_len = 0; #ifndef SRS_AUTO_OSX if (using_gso) { @@ -1130,9 +1101,6 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) cm->cmsg_type = UDP_SEGMENT; cm->cmsg_len = CMSG_LEN(sizeof(uint16_t)); *((uint16_t*)CMSG_DATA(cm)) = gso_encrypt; - - // Private message, use it to store the cursor. - mhdr->msg_len = gso_cursor + 1; } #endif @@ -1870,18 +1838,21 @@ srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd) void SrsUdpMuxSender::free_mhdrs(std::vector& mhdrs) { - for (int i = 0; i < (int)mhdrs.size(); i++) { + int nn_mhdrs = (int)mhdrs.size(); + for (int i = 0; i < nn_mhdrs; i++) { + // @see https://linux.die.net/man/2/sendmmsg + // @see https://linux.die.net/man/2/sendmsg mmsghdr* hdr = &mhdrs[i]; // Free control for GSO. char* msg_control = (char*)hdr->msg_hdr.msg_control; - srs_freep(msg_control); + srs_freepa(msg_control); // Free iovec. - for (int j = (int)hdr->msg_hdr.msg_iovlen - 1; j >= 0 ; j--) { + for (int j = SRS_PERF_RTC_GSO_MAX - 1; j >= 0 ; j--) { iovec* iov = hdr->msg_hdr.msg_iov + j; char* data = (char*)iov->iov_base; - srs_freep(data); + srs_freepa(data); srs_freepa(iov); } } @@ -1892,19 +1863,21 @@ srs_error_t SrsUdpMuxSender::fetch(mmsghdr** pphdr) { // TODO: FIXME: Maybe need to shrink? if (cache_pos >= (int)cache.size()) { + // @see https://linux.die.net/man/2/sendmmsg + // @see https://linux.die.net/man/2/sendmsg mmsghdr mhdr; - memset(&mhdr, 0, sizeof(mmsghdr)); mhdr.msg_len = 0; + mhdr.msg_hdr.msg_flags = 0; + mhdr.msg_hdr.msg_control = NULL; - mhdr.msg_hdr.msg_iovlen = SRS_PERF_RTC_GSO_IOVS; + mhdr.msg_hdr.msg_iovlen = SRS_PERF_RTC_GSO_MAX; mhdr.msg_hdr.msg_iov = new iovec[mhdr.msg_hdr.msg_iovlen]; + memset((void*)mhdr.msg_hdr.msg_iov, 0, sizeof(iovec) * mhdr.msg_hdr.msg_iovlen); - for (int i = 0; i < (int)mhdr.msg_hdr.msg_iovlen; i++) { + for (int i = 0; i < SRS_PERF_RTC_GSO_IOVS; i++) { iovec* p = mhdr.msg_hdr.msg_iov + i; - p->iov_base = new char[kRtpPacketSize]; - p->iov_len = kRtpPacketSize; } cache.push_back(mhdr); @@ -1949,15 +1922,10 @@ srs_error_t SrsUdpMuxSender::cycle() int pos = cache_pos; int gso_iovs = 0; if (pos <= 0) { - srs_usleep(0); - if (pos <= 0) { - waiting_msgs = true; - nn_wait++; - srs_cond_wait(cond); - } - if (pos <= 0) { - continue; - } + waiting_msgs = true; + nn_wait++; + srs_cond_wait(cond); + continue; } // We are working on hotspot now. @@ -1968,16 +1936,12 @@ srs_error_t SrsUdpMuxSender::cycle() int gso_pos = 0; if (pos > 0 && stat_enabled) { // For shared GSO cache, stat the messages. - mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; - for (p = &hotspot[0]; p < end; p++) { - if (!p->msg_len) { - continue; - } - - // Private message, use it to store the cursor. - int real_iovs = p->msg_len; - p->msg_len = 0; + // @see https://linux.die.net/man/2/sendmmsg + // @see https://linux.die.net/man/2/sendmsg + for (int i = 0; i < pos; i++) { + mmsghdr* mhdr = &hotspot[i]; + int real_iovs = mhdr->msg_hdr.msg_iovlen; gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs; gso_iovs += real_iovs; } @@ -1986,6 +1950,8 @@ srs_error_t SrsUdpMuxSender::cycle() // Send out all messages. if (pos > 0) { // Send out all messages. + // @see https://linux.die.net/man/2/sendmmsg + // @see https://linux.die.net/man/2/sendmsg mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; for (p = &hotspot[0]; p < end; p += max_sendmmsg) { int vlen = (int)(end - p); diff --git a/trunk/src/core/srs_core_performance.hpp b/trunk/src/core/srs_core_performance.hpp index 6958aed4f..01c6138f7 100644 --- a/trunk/src/core/srs_core_performance.hpp +++ b/trunk/src/core/srs_core_performance.hpp @@ -201,7 +201,14 @@ // = 715MB # For SRS_PERF_RTC_GSO_IOVS = 1 // = 1402MB # For SRS_PERF_RTC_GSO_IOVS = 2 // = 2775MB # For SRS_PERF_RTC_GSO_IOVS = 4 -#define SRS_PERF_RTC_GSO_IOVS 2 +#if defined(__linux__) + #define SRS_PERF_RTC_GSO_IOVS 2 +#else + #define SRS_PERF_RTC_GSO_IOVS 1 +#endif + +// For RTC, the max iovs in msghdr, the max packets sent in a msghdr. +#define SRS_PERF_RTC_GSO_MAX 64 #endif diff --git a/trunk/src/service/srs_service_st.cpp b/trunk/src/service/srs_service_st.cpp index 4e1e1bc01..da54a5dae 100644 --- a/trunk/src/service/srs_service_st.cpp +++ b/trunk/src/service/srs_service_st.cpp @@ -436,6 +436,8 @@ int srs_sendmmsg(srs_netfd_t stfd, struct mmsghdr *msgvec, unsigned int vlen, in } msgvec->msg_len = r0; #else + msgvec->msg_len = 0; + int tolen = (int)msgvec->msg_hdr.msg_namelen; const struct sockaddr* to = (const struct sockaddr*)msgvec->msg_hdr.msg_name; for (int i = 0; i < (int)msgvec->msg_hdr.msg_iovlen; i++) { From 21ede1f08417502eca564fe8b2e61988c539a553 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 17 Apr 2020 07:57:52 +0800 Subject: [PATCH 37/54] Enable perf stat by default --- trunk/conf/full.conf | 4 ++-- trunk/src/app/srs_app_config.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 7cc2c5593..643c364c8 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -449,8 +449,8 @@ rtc_server { # default: 127 padding 127; # Whether enable the perf stat at http://localhost:1985/api/v1/perf - # default: off - perf_stat off; + # default: on + perf_stat on; } vhost rtc.vhost.srs.com { diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 66e5942e5..d2fae574d 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4860,7 +4860,7 @@ int SrsConfig::get_rtc_server_padding() bool SrsConfig::get_rtc_server_perf_stat() { - static bool DEFAULT = false; + static bool DEFAULT = true; SrsConfDirective* conf = root->get("rtc_server"); if (!conf) { @@ -4872,7 +4872,7 @@ bool SrsConfig::get_rtc_server_perf_stat() return DEFAULT; } - return SRS_CONF_PERFER_FALSE(conf->arg0()); + return SRS_CONF_PERFER_TRUE(conf->arg0()); } SrsConfDirective* SrsConfig::get_rtc(string vhost) From acc471b0a9acae80f464f5d378b27f720158f9e6 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 17 Apr 2020 07:58:11 +0800 Subject: [PATCH 38/54] For #307, refine the GSO for performance --- trunk/src/app/srs_app_rtc_conn.cpp | 41 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index d18602ed5..5b802684a 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -940,6 +940,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) mmsghdr* gso_mhdr = NULL; int gso_size = 0; int gso_encrypt = 0; int gso_cursor = 0; // GSO, N packets has same length, the final one may not. bool using_gso = false; bool gso_final = false; + // The message will marshal in iovec. + iovec* iov = NULL; int nn_packets = packets.size(); for (int i = 0; i < nn_packets; i++) { @@ -986,28 +988,25 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) } // Check whether we can use GSO to send it. - mmsghdr* mhdr = NULL; - if ((gso_size && gso_size == nn_packet) || (using_gso && !gso_final)) { - using_gso = true; - gso_final = (gso_size && gso_size != nn_packet); - mhdr = gso_mhdr; + if (using_gso && !gso_final) { + gso_final = (gso_size != nn_packet); } - // Change the state according to the next packet. if (next_packet) { - // If GSO, but next is bigger than this one, we must enter the final state. - if (using_gso && !gso_final) { - gso_final = (nn_packet < nn_next_packet); - } - // If not GSO, maybe the first fresh packet, we should see whether the next packet is smaller than this one, // if smaller, we can still enter GSO. if (!using_gso) { using_gso = (nn_packet >= nn_next_packet); } + + // If GSO, but next is bigger than this one, we must enter the final state. + if (using_gso && !gso_final) { + gso_final = (nn_packet < nn_next_packet); + } } - // Now, we fetch the msg from cache. + // For GSO, reuse mhdr if possible. + mmsghdr* mhdr = gso_mhdr; if (!mhdr) { // Fetch a cached message from queue. // TODO: FIXME: Maybe encrypt in async, so the state of mhdr maybe not ready. @@ -1016,18 +1015,20 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) } // Now, GSO will use this message and size. - if (using_gso) { - gso_mhdr = mhdr; - gso_size = nn_packet; - } + gso_mhdr = mhdr; + gso_size = nn_packet; } // For this message, select a new iovec. - iovec* iov = mhdr->msg_hdr.msg_iov + gso_cursor; - mhdr->msg_hdr.msg_iovlen = gso_cursor + 1; + if (!iov) { + iov = mhdr->msg_hdr.msg_iov; + } else { + iov++; + } gso_cursor++; + mhdr->msg_hdr.msg_iovlen = gso_cursor; - if (!iov->iov_base) { + if (gso_cursor > SRS_PERF_RTC_GSO_IOVS && !iov->iov_base) { iov->iov_base = new char[kRtpPacketSize]; } iov->iov_len = kRtpPacketSize; @@ -1113,7 +1114,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) // Reset the GSO flag. gso_mhdr = NULL; gso_size = 0; gso_encrypt = 0; gso_cursor = 0; - using_gso = gso_final = false; + using_gso = gso_final = false; iov = NULL; } } From 606f8873b322c9f3e18c0c5cbe4ecd612555ebc0 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 17 Apr 2020 10:42:04 +0800 Subject: [PATCH 39/54] Refactor code --- trunk/src/app/srs_app_rtc_conn.cpp | 60 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 5b802684a..239909c59 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -951,39 +951,41 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) SrsRtpPacket2* next_packet = NULL; int nn_next_packet = 0; - if (i < nn_packets - 1) { - next_packet = (i < nn_packets - 1)? packets.at(i + 1):NULL; - nn_next_packet = next_packet? next_packet->nb_bytes() : 0; - } - - // Padding the packet to next or GSO size. - if (max_padding > 0 && next_packet) { - if (!using_gso) { - // Padding to the next packet to merge with it. - if (nn_next_packet > nn_packet) { - padding = nn_next_packet - nn_packet; - } - } else { - // Padding to GSO size for next one to merge with us. - if (nn_next_packet < gso_size) { - padding = gso_size - nn_packet; - } + if (max_padding > 0) { + if (i < nn_packets - 1) { + next_packet = (i < nn_packets - 1)? packets.at(i + 1):NULL; + nn_next_packet = next_packet? next_packet->nb_bytes() : 0; } - // Reset padding if exceed max. - if (padding > max_padding) { - padding = 0; - } + // Padding the packet to next or GSO size. + if (next_packet) { + if (!using_gso) { + // Padding to the next packet to merge with it. + if (nn_next_packet > nn_packet) { + padding = nn_next_packet - nn_packet; + } + } else { + // Padding to GSO size for next one to merge with us. + if (nn_next_packet < gso_size) { + padding = gso_size - nn_packet; + } + } - if (padding > 0) { + // Reset padding if exceed max. + if (padding > max_padding) { + padding = 0; + } + + if (padding > 0) { #if defined(SRS_DEBUG) - srs_trace("#%d, Padding %d bytes %d=>%d, packets %d, max_padding %d", packets.debug_id, - padding, nn_packet, nn_packet + padding, nn_packets, max_padding); + srs_trace("#%d, Padding %d bytes %d=>%d, packets %d, max_padding %d", packets.debug_id, + padding, nn_packet, nn_packet + padding, nn_packets, max_padding); #endif - packet->set_padding(padding); - nn_packet += padding; - packets.nn_paddings++; - packets.nn_padding_bytes += padding; + packet->set_padding(padding); + nn_packet += padding; + packets.nn_paddings++; + packets.nn_padding_bytes += padding; + } } } @@ -1970,7 +1972,7 @@ srs_error_t SrsUdpMuxSender::cycle() } // Increase total messages. - nn_msgs += pos; + nn_msgs += pos + gso_iovs; nn_msgs_max = srs_max(pos, nn_msgs_max); nn_gso_msgs_max = srs_max(gso_pos, nn_gso_msgs_max); nn_gso_iovs_max = srs_max(gso_iovs, nn_gso_iovs_max); From 14e3ec2fe82c5ee7e6c3c114b73f166ea0b53175 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 17 Apr 2020 12:30:53 +0800 Subject: [PATCH 40/54] For #307, drop frame when VBR too high --- trunk/conf/full.conf | 7 +++++++ trunk/scripts/perf_gso.py | 4 ++++ trunk/src/app/srs_app_config.cpp | 19 +++++++++++++++++- trunk/src/app/srs_app_config.hpp | 1 + trunk/src/app/srs_app_http_api.cpp | 11 ++++++++++- trunk/src/app/srs_app_listener.hpp | 2 ++ trunk/src/app/srs_app_rtc_conn.cpp | 30 ++++++++++++++++++++++++----- trunk/src/app/srs_app_rtc_conn.hpp | 7 ++++++- trunk/src/app/srs_app_statistic.cpp | 27 ++++++++++++++++++++++++++ trunk/src/app/srs_app_statistic.hpp | 5 +++++ 10 files changed, 105 insertions(+), 8 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 643c364c8..98a8792dc 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -451,6 +451,13 @@ rtc_server { # Whether enable the perf stat at http://localhost:1985/api/v1/perf # default: on perf_stat on; + # The queue length, in number of mmsghdr, in messages. + # For example, 30 means we will cache 30K messages at most. + # If exceed, we will drop messages. + # @remark Each reuseport use a dedicated queue, if queue is 2000, reuseport is 4, + # then system queue is 2000*4 = 8k, user can incrase reuseport to incrase the queue. + # default: 2000 + queue_length 2000; } vhost rtc.vhost.srs.com { diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index f09014143..7180c7e4b 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -41,6 +41,10 @@ print "Repsonse %s"%(s) obj = json.loads(s) +print "" +p = obj['data']['dropped'] +print('RTC Frame Dropped: %s'%(100.0 * p['rtc_dropeed'] / p['rtc_frames'])) + # 2, 3, 5, 9, 16, 32, 64, 128, 256 keys = ['lt_2', 'lt_3', 'lt_5', 'lt_9', 'lt_16', 'lt_32', 'lt_64', 'lt_128', 'lt_256', 'gt_256'] print("\n----------- 1 2 [3,4] [5,8] [9,15] [16,31] [32,63] [64,127] [128,255] [256,+) Packets"), diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index d2fae574d..eef0a325c 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3619,7 +3619,7 @@ srs_error_t SrsConfig::check_normal_config() string n = conf->at(i)->name; if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa" && n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus" - && n != "padding" && n != "perf_stat") { + && n != "padding" && n != "perf_stat" && n != "queue_length") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", n.c_str()); } } @@ -4875,6 +4875,23 @@ bool SrsConfig::get_rtc_server_perf_stat() return SRS_CONF_PERFER_TRUE(conf->arg0()); } +int SrsConfig::get_rtc_server_queue_length() +{ + static int DEFAULT = 2000; + + SrsConfDirective* conf = root->get("rtc_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("queue_length"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return ::atoi(conf->arg0().c_str()); +} + SrsConfDirective* SrsConfig::get_rtc(string vhost) { SrsConfDirective* conf = get_vhost(vhost); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 0d2d0c4cc..bc9417d76 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -538,6 +538,7 @@ private: public: virtual int get_rtc_server_padding(); virtual bool get_rtc_server_perf_stat(); + virtual int get_rtc_server_queue_length(); public: SrsConfDirective* get_rtc(std::string vhost); diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index e994b9982..fa0a7d9f5 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1625,7 +1625,7 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* p->set("target", SrsJsonAny::str(target.c_str())); p->set("reset", SrsJsonAny::str(reset.c_str())); - p->set("help", SrsJsonAny::str("?target=avframes|rtc|rtp|gso|writev_iovs|sendmmsg|bytes")); + p->set("help", SrsJsonAny::str("?target=avframes|rtc|rtp|gso|writev_iovs|sendmmsg|bytes|dropped")); p->set("help2", SrsJsonAny::str("?reset=all")); } @@ -1697,6 +1697,15 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* } } + if (target.empty() || target == "dropped") { + SrsJsonObject* p = SrsJsonAny::object(); + data->set("dropped", p); + if ((err = stat->dumps_perf_dropped(p)) != srs_success) { + int code = srs_error_code(err); srs_error_reset(err); + return srs_api_response_code(w, r, code); + } + } + return srs_api_response(w, r, obj->dumps()); } diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index 8ef384dd9..d096e5910 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -141,6 +141,8 @@ public: virtual srs_error_t fetch(mmsghdr** pphdr) = 0; // Notify the sender to send out the msg. virtual srs_error_t sendmmsg(mmsghdr* hdr) = 0; + // Whether sender exceed the max queue, that is, overflow. + virtual bool overflow() = 0; }; class SrsUdpMuxSocket diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 239909c59..ad87e622e 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -473,6 +473,7 @@ SrsRtcPackets::SrsRtcPackets() nn_audios = nn_extras = 0; nn_videos = nn_samples = 0; nn_padding_bytes = nn_paddings = 0; + nn_dropped = 0; cursor = 0; } @@ -505,6 +506,7 @@ void SrsRtcPackets::reset(bool gso, bool merge_nalus) nn_audios = nn_extras = 0; nn_videos = nn_samples = 0; nn_padding_bytes = nn_paddings = 0; + nn_dropped = 0; cursor = 0; } @@ -744,6 +746,8 @@ srs_error_t SrsRtcSenderThread::cycle() stat->perf_on_gso_packets(pkts.nn_rtp_pkts); // Stat the bytes and paddings. stat->perf_on_rtc_bytes(pkts.nn_bytes, pkts.nn_padding_bytes); + // Stat the messages and dropped count. + stat->perf_on_dropped(msg_count, nn_rtc_packets, pkts.nn_dropped); } #if defined(SRS_DEBUG) srs_trace("RTC PLAY perf, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d/%d bytes", @@ -754,8 +758,8 @@ srs_error_t SrsRtcSenderThread::cycle() pprint->elapse(); if (pprint->can_print()) { // TODO: FIXME: Print stat like frame/s, packet/s, loss_packets. - srs_trace("-> RTC PLAY %d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d/%d bytes, %d pad, %d/%d cache", - msg_count, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, pkts.nn_samples, pkts.nn_bytes, + srs_trace("-> RTC PLAY %d/%d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d/%d bytes, %d pad, %d/%d cache", + msg_count, pkts.nn_dropped, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, pkts.nn_samples, pkts.nn_bytes, pkts.nn_padding_bytes, pkts.nn_paddings, pkts.size(), pkts.capacity()); } } @@ -766,6 +770,7 @@ srs_error_t SrsRtcSenderThread::send_messages( ) { srs_error_t err = srs_success; + // If DTLS is not OK, drop all messages. if (!rtc_session->dtls_session) { return err; } @@ -801,6 +806,12 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( for (int i = 0; i < nb_msgs; i++) { SrsSharedPtrMessage* msg = msgs[i]; + // If overflow, drop all messages. + if (sender->overflow()) { + packets.nn_dropped += nb_msgs - i; + return err; + } + // Update stats. packets.nn_bytes += msg->size; @@ -1802,6 +1813,8 @@ SrsUdpMuxSender::SrsUdpMuxSender(SrsRtcServer* s) trd = new SrsDummyCoroutine(); cache_pos = 0; + max_sendmmsg = 0; + queue_length = 0; _srs_config->subscribe(this); } @@ -1820,7 +1833,7 @@ SrsUdpMuxSender::~SrsUdpMuxSender() cache.clear(); } -srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd) +srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd, int senders) { srs_error_t err = srs_success; @@ -1834,7 +1847,9 @@ srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd) max_sendmmsg = _srs_config->get_rtc_server_sendmmsg(); bool gso = _srs_config->get_rtc_server_gso(); - srs_trace("UDP sender #%d init ok, max_sendmmsg=%d, gso=%d", srs_netfd_fileno(fd), max_sendmmsg, gso); + queue_length = srs_max(128, _srs_config->get_rtc_server_queue_length()); + srs_trace("UDP sender #%d init ok, max_sendmmsg=%d, gso=%d, queue_max=%dx%d", srs_netfd_fileno(fd), + max_sendmmsg, gso, queue_length, senders); return err; } @@ -1890,6 +1905,11 @@ srs_error_t SrsUdpMuxSender::fetch(mmsghdr** pphdr) return srs_success; } +bool SrsUdpMuxSender::overflow() +{ + return cache_pos > queue_length; +} + srs_error_t SrsUdpMuxSender::sendmmsg(mmsghdr* hdr) { if (waiting_msgs) { @@ -2098,7 +2118,7 @@ srs_error_t SrsRtcServer::listen_udp() return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); } - if ((err = sender->initialize(listener->stfd())) != srs_success) { + if ((err = sender->initialize(listener->stfd(), nn_listeners)) != srs_success) { return srs_error_wrap(err, "init sender"); } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index a1fe62514..9f771028f 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -149,6 +149,8 @@ public: int nn_videos; // The number of padded packet. int nn_paddings; + // The number of dropped messages. + int nn_dropped; private: int cursor; std::vector packets; @@ -303,16 +305,19 @@ private: int cache_pos; // The max number of messages for sendmmsg. If 1, we use sendmsg to send. int max_sendmmsg; + // The total queue length, share with all senders. + int queue_length; public: SrsUdpMuxSender(SrsRtcServer* s); virtual ~SrsUdpMuxSender(); public: - virtual srs_error_t initialize(srs_netfd_t fd); + virtual srs_error_t initialize(srs_netfd_t fd, int senders); private: void free_mhdrs(std::vector& mhdrs); public: virtual srs_error_t fetch(mmsghdr** pphdr); virtual srs_error_t sendmmsg(mmsghdr* hdr); + virtual bool overflow(); virtual srs_error_t cycle(); // interface ISrsReloadHandler public: diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 4bf58aa99..6116c9f50 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -272,6 +272,7 @@ SrsStatistic::SrsStatistic() perf_rtp = new SrsStatisticCategory(); perf_rtc = new SrsStatisticCategory(); perf_bytes = new SrsStatisticCategory(); + perf_dropped = new SrsStatisticCategory(); } SrsStatistic::~SrsStatistic() @@ -313,6 +314,7 @@ SrsStatistic::~SrsStatistic() srs_freep(perf_rtp); srs_freep(perf_rtc); srs_freep(perf_bytes); + srs_freep(perf_dropped); } SrsStatistic* SrsStatistic::instance() @@ -673,6 +675,29 @@ srs_error_t SrsStatistic::dumps_perf_bytes(SrsJsonObject* obj) return srs_success; } +void SrsStatistic::perf_on_dropped(int nn_msgs, int nn_rtc, int nn_dropped) +{ + // a: System AVFrames. + // b: RTC frames. + // c: Dropped frames. + perf_dropped->a += nn_msgs; + perf_dropped->b += nn_rtc; + perf_dropped->c += nn_dropped; + + perf_dropped->nn += nn_dropped; +} + +srs_error_t SrsStatistic::dumps_perf_dropped(SrsJsonObject* obj) +{ + obj->set("avframes", SrsJsonAny::integer(perf_dropped->a)); + obj->set("rtc_frames", SrsJsonAny::integer(perf_dropped->b)); + obj->set("rtc_dropeed", SrsJsonAny::integer(perf_dropped->c)); + + obj->set("nn", SrsJsonAny::integer(perf_dropped->nn)); + + return srs_success; +} + void SrsStatistic::reset_perf() { srs_freep(perf_iovs); @@ -682,6 +707,7 @@ void SrsStatistic::reset_perf() srs_freep(perf_rtp); srs_freep(perf_rtc); srs_freep(perf_bytes); + srs_freep(perf_dropped); perf_iovs = new SrsStatisticCategory(); perf_msgs = new SrsStatisticCategory(); @@ -690,6 +716,7 @@ void SrsStatistic::reset_perf() perf_rtp = new SrsStatisticCategory(); perf_rtc = new SrsStatisticCategory(); perf_bytes = new SrsStatisticCategory(); + perf_dropped = new SrsStatisticCategory(); } void SrsStatistic::perf_on_packets(SrsStatisticCategory* p, int nb_msgs) diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index 50fbb8516..919322098 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -175,6 +175,7 @@ private: SrsStatisticCategory* perf_rtp; SrsStatisticCategory* perf_rtc; SrsStatisticCategory* perf_bytes; + SrsStatisticCategory* perf_dropped; private: SrsStatistic(); virtual ~SrsStatistic(); @@ -264,6 +265,10 @@ public: // Stat for bytes, nn_bytes is the size of bytes, nb_padding is padding bytes. virtual void perf_on_rtc_bytes(int nn_bytes, int nn_padding); virtual srs_error_t dumps_perf_bytes(SrsJsonObject* obj); +public: + // Stat for rtc messages, nn_rtc is rtc messages, nn_dropped is dropped messages. + virtual void perf_on_dropped(int nn_msgs, int nn_rtc, int nn_dropped); + virtual srs_error_t dumps_perf_dropped(SrsJsonObject* obj); public: // Reset all perf stat data. virtual void reset_perf(); From cac5bbddf6e13b01f8f8e064f773df279c0fc09b Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 17 Apr 2020 12:48:05 +0800 Subject: [PATCH 41/54] Refine comments --- trunk/scripts/perf_gso.py | 2 +- trunk/src/app/srs_app_rtc_conn.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index 7180c7e4b..4d817f8bc 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -43,7 +43,7 @@ obj = json.loads(s) print "" p = obj['data']['dropped'] -print('RTC Frame Dropped: %s'%(100.0 * p['rtc_dropeed'] / p['rtc_frames'])) +print('RTC Frame Dropped: %s%s'%(10000.0 * p['rtc_dropeed'] / p['rtc_frames'], '%%')) # 2, 3, 5, 9, 16, 32, 64, 128, 256 keys = ['lt_2', 'lt_3', 'lt_5', 'lt_9', 'lt_16', 'lt_32', 'lt_64', 'lt_128', 'lt_256', 'gt_256'] diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 9f771028f..158b1e02f 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -305,7 +305,7 @@ private: int cache_pos; // The max number of messages for sendmmsg. If 1, we use sendmsg to send. int max_sendmmsg; - // The total queue length, share with all senders. + // The total queue length, for each sender. int queue_length; public: SrsUdpMuxSender(SrsRtcServer* s); From 54b6a9faa7447f3b2188064c5a27c6bba8bb93c4 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 17 Apr 2020 13:02:54 +0800 Subject: [PATCH 42/54] Refactor for performance --- trunk/src/app/srs_app_rtc_conn.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index ad87e622e..daf5317b9 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -885,6 +885,9 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsRtcPackets& packets) { srs_error_t err = srs_success; + // Cache the encrypt flag. + bool encrypt = rtc_session->encrypt; + int nn_packets = packets.size(); for (int i = 0; i < nn_packets; i++) { SrsRtpPacket2* packet = packets.at(i); @@ -915,7 +918,7 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsRtcPackets& packets) } // Whether encrypt the RTP bytes. - if (rtc_session->encrypt) { + if (encrypt) { int nn_encrypt = (int)iov->iov_len; if ((err = rtc_session->dtls_session->protect_rtp2(iov->iov_base, &nn_encrypt)) != srs_success) { return srs_error_wrap(err, "srtp protect"); @@ -947,6 +950,9 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) { srs_error_t err = srs_success; + // Cache the encrypt flag. + bool encrypt = rtc_session->encrypt; + // Previous handler, if has the same size, we can use GSO. mmsghdr* gso_mhdr = NULL; int gso_size = 0; int gso_encrypt = 0; int gso_cursor = 0; // GSO, N packets has same length, the final one may not. @@ -1056,7 +1062,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) } // Whether encrypt the RTP bytes. - if (rtc_session->encrypt) { + if (encrypt) { int nn_encrypt = (int)iov->iov_len; if ((err = rtc_session->dtls_session->protect_rtp2(iov->iov_base, &nn_encrypt)) != srs_success) { return srs_error_wrap(err, "srtp protect"); From 36d06edab3940497936ff22d85a992ada535f269 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 17 Apr 2020 14:24:24 +0800 Subject: [PATCH 43/54] Refine performance --- trunk/src/app/srs_app_rtc_conn.cpp | 6 ++++++ trunk/src/app/srs_app_rtc_conn.hpp | 3 +++ trunk/src/kernel/srs_kernel_error.hpp | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index daf5317b9..41033f0d0 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1854,6 +1854,12 @@ srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd, int senders) max_sendmmsg = _srs_config->get_rtc_server_sendmmsg(); bool gso = _srs_config->get_rtc_server_gso(); queue_length = srs_max(128, _srs_config->get_rtc_server_queue_length()); + + // For no GSO, we need larger queue. + if (!gso) { + queue_length *= 2; + } + srs_trace("UDP sender #%d init ok, max_sendmmsg=%d, gso=%d, queue_max=%dx%d", srs_netfd_fileno(fd), max_sendmmsg, gso, queue_length, senders); diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 158b1e02f..51b4c00b6 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -185,10 +185,13 @@ private: uint16_t video_sequence; public: SrsUdpMuxSocket* sendonly_ukt; +private: ISrsUdpSender* sender; +private: bool merge_nalus; bool gso; int max_padding; + public: SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid); virtual ~SrsRtcSenderThread(); diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index 5a6b8c6e5..c5421d640 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -422,7 +422,7 @@ public: }; // Error helpers, should use these functions to new or wrap an error. -#define srs_success SrsCplxError::success() +#define srs_success 0 // SrsCplxError::success() #define srs_error_new(ret, fmt, ...) SrsCplxError::create(__FUNCTION__, __FILE__, __LINE__, ret, fmt, ##__VA_ARGS__) #define srs_error_wrap(err, fmt, ...) SrsCplxError::wrap(__FUNCTION__, __FILE__, __LINE__, err, fmt, ##__VA_ARGS__) #define srs_error_copy(err) SrsCplxError::copy(err) From e4eb501c57f5340e6367fdf39d4f73fe46ef20bf Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 17 Apr 2020 16:36:56 +0800 Subject: [PATCH 44/54] Fix the perf stat bytes bug --- trunk/scripts/perf_gso.py | 4 +++- trunk/src/app/srs_app_rtc_conn.cpp | 25 ++++++++++++++++--------- trunk/src/app/srs_app_rtc_conn.hpp | 4 +++- trunk/src/app/srs_app_statistic.cpp | 17 ++++++++++------- trunk/src/app/srs_app_statistic.hpp | 2 +- 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index 4d817f8bc..3e20e5a05 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -43,7 +43,9 @@ obj = json.loads(s) print "" p = obj['data']['dropped'] -print('RTC Frame Dropped: %s%s'%(10000.0 * p['rtc_dropeed'] / p['rtc_frames'], '%%')) +print('RTC Frame Dropped: %.4f%s'%(10000.0 * p['rtc_dropeed'] / p['rtc_frames'], '%%')) +p = obj['data']['bytes'] +print('Padding Overload: %.4f%s %.2fMB'%(10000.0 * p['rtc_padding'] / p['rtc_bytes'], '%%', p['rtc_padding']/1024/1024)) # 2, 3, 5, 9, 16, 32, 64, 128, 256 keys = ['lt_2', 'lt_3', 'lt_5', 'lt_9', 'lt_16', 'lt_32', 'lt_64', 'lt_128', 'lt_256', 'gt_256'] diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 41033f0d0..0b5ce34ae 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -472,6 +472,7 @@ SrsRtcPackets::SrsRtcPackets() nn_rtp_pkts = 0; nn_audios = nn_extras = 0; nn_videos = nn_samples = 0; + nn_bytes = nn_rtp_bytes = 0; nn_padding_bytes = nn_paddings = 0; nn_dropped = 0; @@ -505,6 +506,7 @@ void SrsRtcPackets::reset(bool gso, bool merge_nalus) nn_rtp_pkts = 0; nn_audios = nn_extras = 0; nn_videos = nn_samples = 0; + nn_bytes = nn_rtp_bytes = 0; nn_padding_bytes = nn_paddings = 0; nn_dropped = 0; @@ -745,22 +747,23 @@ srs_error_t SrsRtcSenderThread::cycle() // Stat the RTP packets going into kernel. stat->perf_on_gso_packets(pkts.nn_rtp_pkts); // Stat the bytes and paddings. - stat->perf_on_rtc_bytes(pkts.nn_bytes, pkts.nn_padding_bytes); + stat->perf_on_rtc_bytes(pkts.nn_bytes, pkts.nn_rtp_bytes, pkts.nn_padding_bytes); // Stat the messages and dropped count. stat->perf_on_dropped(msg_count, nn_rtc_packets, pkts.nn_dropped); - } + #if defined(SRS_DEBUG) - srs_trace("RTC PLAY perf, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d/%d bytes", - msg_count, nn_rtc_packets, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, - pkts.nn_samples, pkts.nn_bytes, pkts.nn_padding_bytes); + srs_trace("RTC PLAY perf, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d/%d/%d bytes", + msg_count, nn_rtc_packets, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, + pkts.nn_samples, pkts.nn_bytes, pkts.nn_rtp_bytes, pkts.nn_padding_bytes); #endif + } pprint->elapse(); if (pprint->can_print()) { // TODO: FIXME: Print stat like frame/s, packet/s, loss_packets. - srs_trace("-> RTC PLAY %d/%d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d/%d bytes, %d pad, %d/%d cache", + srs_trace("-> RTC PLAY %d/%d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d/%d/%d bytes, %d pad, %d/%d cache", msg_count, pkts.nn_dropped, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, pkts.nn_samples, pkts.nn_bytes, - pkts.nn_padding_bytes, pkts.nn_paddings, pkts.size(), pkts.capacity()); + pkts.nn_rtp_bytes, pkts.nn_padding_bytes, pkts.nn_paddings, pkts.size(), pkts.capacity()); } } } @@ -926,6 +929,8 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsRtcPackets& packets) iov->iov_len = (size_t)nn_encrypt; } + packets.nn_rtp_bytes += (int)iov->iov_len; + // Set the address and control information. sockaddr_in* addr = (sockaddr_in*)sendonly_ukt->peer_addr(); socklen_t addrlen = (socklen_t)sendonly_ukt->peer_addrlen(); @@ -1070,6 +1075,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) iov->iov_len = (size_t)nn_encrypt; } + packets.nn_rtp_bytes += (int)iov->iov_len; + // If GSO, they must has same size, except the final one. if (using_gso && !gso_final && gso_encrypt && gso_encrypt != (int)iov->iov_len) { return srs_error_new(ERROR_RTC_RTP_MUXER, "GSO size=%d/%d, encrypt=%d/%d", gso_size, nn_packet, gso_encrypt, iov->iov_len); @@ -1138,9 +1145,9 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) } #if defined(SRS_DEBUG) - srs_trace("#%d, RTC PLAY summary, rtp %d/%d, videos %d/%d, audios %d/%d, pad %d/%d", packets.debug_id, packets.size(), + srs_trace("#%d, RTC PLAY summary, rtp %d/%d, videos %d/%d, audios %d/%d, pad %d/%d/%d", packets.debug_id, packets.size(), packets.nn_rtp_pkts, packets.nn_videos, packets.nn_samples, packets.nn_audios, packets.nn_extras, packets.nn_paddings, - packets.nn_padding_bytes); + packets.nn_padding_bytes, packets.nn_rtp_bytes); #endif return err; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 51b4c00b6..40c341fdf 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -130,8 +130,10 @@ public: uint32_t debug_id; #endif public: - // The total bytes of RTP packets. + // The total bytes of AVFrame packets. int nn_bytes; + // The total bytes of RTP packets. + int nn_rtp_bytes; // The total padded bytes. int nn_padding_bytes; public: diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 6116c9f50..890e43746 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -655,20 +655,23 @@ srs_error_t SrsStatistic::dumps_perf_sendmmsg(SrsJsonObject* obj) return dumps_perf(perf_sendmmsg, obj); } -void SrsStatistic::perf_on_rtc_bytes(int nn_bytes, int nn_padding) +void SrsStatistic::perf_on_rtc_bytes(int nn_bytes, int nn_rtp_bytes, int nn_padding) { - // a: RTC bytes. - // b: RTC paddings. + // a: AVFrame bytes. + // b: RTC bytes. + // c: RTC paddings. perf_bytes->a += nn_bytes; - perf_bytes->b += nn_padding; + perf_bytes->b += nn_rtp_bytes; + perf_bytes->c += nn_padding; - perf_bytes->nn += nn_bytes + nn_padding; + perf_bytes->nn += nn_rtp_bytes; } srs_error_t SrsStatistic::dumps_perf_bytes(SrsJsonObject* obj) { - obj->set("rtc_bytes", SrsJsonAny::integer(perf_bytes->a)); - obj->set("rtc_padding", SrsJsonAny::integer(perf_bytes->b)); + obj->set("avframe_bytes", SrsJsonAny::integer(perf_bytes->a)); + obj->set("rtc_bytes", SrsJsonAny::integer(perf_bytes->b)); + obj->set("rtc_padding", SrsJsonAny::integer(perf_bytes->c)); obj->set("nn", SrsJsonAny::integer(perf_bytes->nn)); diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index 919322098..81ed9e27d 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -263,7 +263,7 @@ public: virtual srs_error_t dumps_perf_sendmmsg(SrsJsonObject* obj); public: // Stat for bytes, nn_bytes is the size of bytes, nb_padding is padding bytes. - virtual void perf_on_rtc_bytes(int nn_bytes, int nn_padding); + virtual void perf_on_rtc_bytes(int nn_bytes, int nn_rtp_bytes, int nn_padding); virtual srs_error_t dumps_perf_bytes(SrsJsonObject* obj); public: // Stat for rtc messages, nn_rtc is rtc messages, nn_dropped is dropped messages. From cf52390cf277eff93f41f317735d2b3b3ebda31c Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 17 Apr 2020 18:04:52 +0800 Subject: [PATCH 45/54] Support fast padding --- trunk/src/app/srs_app_rtc.cpp | 4 ++++ trunk/src/app/srs_app_rtc_conn.cpp | 18 +++++++++++++++--- trunk/src/app/srs_app_rtc_conn.hpp | 3 +-- trunk/src/kernel/srs_kernel_flv.cpp | 1 + trunk/src/kernel/srs_kernel_flv.hpp | 7 +++++++ trunk/src/kernel/srs_kernel_rtp.cpp | 6 ++++++ trunk/src/kernel/srs_kernel_rtp.hpp | 4 +++- 7 files changed, 37 insertions(+), 6 deletions(-) diff --git a/trunk/src/app/srs_app_rtc.cpp b/trunk/src/app/srs_app_rtc.cpp index 7d2d44e82..95cfea597 100644 --- a/trunk/src/app/srs_app_rtc.cpp +++ b/trunk/src/app/srs_app_rtc.cpp @@ -195,15 +195,19 @@ srs_error_t SrsRtpOpusMuxer::transcode(SrsSharedPtrMessage* shared_audio, char* return err; } + int nn_max_extra_payload = 0; SrsSample samples[nn_opus_packets]; for (int i = 0; i < nn_opus_packets; i++) { SrsSample* p = samples + i; p->size = opus_sizes[i]; p->bytes = new char[p->size]; memcpy(p->bytes, opus_payloads[i], p->size); + + nn_max_extra_payload = srs_max(nn_max_extra_payload, p->size); } shared_audio->set_extra_payloads(samples, nn_opus_packets); + shared_audio->set_max_extra_payload(nn_max_extra_payload); return err; } diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 0b5ce34ae..24c19663c 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -830,7 +830,7 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( for (int i = 0; i < nn_extra_payloads; i++) { SrsSample* sample = msg->extra_payloads() + i; - if ((err = packet_opus(sample, packets)) != srs_success) { + if ((err = packet_opus(sample, packets, msg->nn_max_extra_payloads())) != srs_success) { return srs_error_wrap(err, "opus package"); } } @@ -1003,7 +1003,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsRtcPackets& packets) srs_trace("#%d, Padding %d bytes %d=>%d, packets %d, max_padding %d", packets.debug_id, padding, nn_packet, nn_packet + padding, nn_packets, max_padding); #endif - packet->set_padding(padding); + packet->add_padding(padding); nn_packet += padding; packets.nn_paddings++; packets.nn_padding_bytes += padding; @@ -1232,7 +1232,7 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac return err; } -srs_error_t SrsRtcSenderThread::packet_opus(SrsSample* sample, SrsRtcPackets& packets) +srs_error_t SrsRtcSenderThread::packet_opus(SrsSample* sample, SrsRtcPackets& packets, int nn_max_payload) { srs_error_t err = srs_success; @@ -1247,6 +1247,18 @@ srs_error_t SrsRtcSenderThread::packet_opus(SrsSample* sample, SrsRtcPackets& pa raw->payload = sample->bytes; raw->nn_payload = sample->size; + if (max_padding > 0) { + if (sample->size < nn_max_payload && nn_max_payload - sample->size < max_padding) { + int padding = nn_max_payload - sample->size; + packet->set_padding(padding); + +#if defined(SRS_DEBUG) + srs_trace("#%d, Fast Padding %d bytes %d=>%d, SN=%d, max_payload %d, max_padding %d", packets.debug_id, + padding, sample->size, sample->size + padding, packet->rtp_header.get_sequence(), nn_max_payload, max_padding); +#endif + } + } + // TODO: FIXME: Why 960? Need Refactoring? audio_timestamp += 960; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 40c341fdf..a563a4e2a 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -193,7 +193,6 @@ private: bool merge_nalus; bool gso; int max_padding; - public: SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid); virtual ~SrsRtcSenderThread(); @@ -218,7 +217,7 @@ private: srs_error_t send_packets(SrsRtcPackets& packets); srs_error_t send_packets_gso(SrsRtcPackets& packets); private: - srs_error_t packet_opus(SrsSample* sample, SrsRtcPackets& packets); + srs_error_t packet_opus(SrsSample* sample, SrsRtcPackets& packets, int nn_max_payload); private: srs_error_t packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* sample, int fu_payload_size, SrsRtcPackets& packets); srs_error_t packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPackets& packets); diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index b05b3adbf..eead02374 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -218,6 +218,7 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::SrsSharedPtrPayload() extra_payloads = NULL; nn_extra_payloads = 0; + nn_max_extra_payloads = 0; #endif } diff --git a/trunk/src/kernel/srs_kernel_flv.hpp b/trunk/src/kernel/srs_kernel_flv.hpp index 84d7d34d9..8cfda3557 100644 --- a/trunk/src/kernel/srs_kernel_flv.hpp +++ b/trunk/src/kernel/srs_kernel_flv.hpp @@ -310,10 +310,14 @@ private: int nn_samples; // For RTC video, whether NALUs has IDR. bool has_idr; + public: // For RTC audio, we may need to transcode AAC to opus, // so there must be an extra payloads, which is transformed from payload. SrsSample* extra_payloads; int nn_extra_payloads; + // The max size payload in extras. + // @remark For GSO to fast guess the best padding. + int nn_max_extra_payloads; #endif public: SrsSharedPtrPayload(); @@ -363,6 +367,9 @@ public: void set_extra_payloads(SrsSample* payloads, int nn_payloads); int nn_extra_payloads() { return ptr->nn_extra_payloads; } SrsSample* extra_payloads() { return ptr->extra_payloads; } + // The max extra payload size. + void set_max_extra_payload(int v) { ptr->nn_max_extra_payloads = v; } + int nn_max_extra_payloads() { return ptr->nn_max_extra_payloads; } // Whether samples has idr. bool has_idr() { return ptr->has_idr; } void set_has_idr(bool v) { ptr->has_idr = v; } diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index 3798fe987..b9659174e 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -199,6 +199,12 @@ void SrsRtpPacket2::set_padding(int size) padding = size; } +void SrsRtpPacket2::add_padding(int size) +{ + rtp_header.set_padding(padding + size > 0); + padding += size; +} + void SrsRtpPacket2::reset() { rtp_header.reset(); diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index 615194a3d..973de2205 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -91,8 +91,10 @@ public: SrsRtpPacket2(); virtual ~SrsRtpPacket2(); public: - // Append size of bytes as padding. + // Set the padding of RTP packet. void set_padding(int size); + // Increase the padding of RTP packet. + void add_padding(int size); // Reset RTP packet. void reset(); // Reuse the cached raw message as payload. From 170b7453f4480cdfd68cec56dab7be0075a0c796 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 18 Apr 2020 08:10:28 +0800 Subject: [PATCH 46/54] Refine for performance --- trunk/src/core/srs_core_performance.hpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/trunk/src/core/srs_core_performance.hpp b/trunk/src/core/srs_core_performance.hpp index 01c6138f7..08b006c10 100644 --- a/trunk/src/core/srs_core_performance.hpp +++ b/trunk/src/core/srs_core_performance.hpp @@ -193,16 +193,17 @@ #undef SRS_PERF_GLIBC_MEMORY_CHECK // For RTC, how many iovs we alloc for each mmsghdr for GSO. -// Assume that there are 2400 clients, say, 60000 msgs in queue to send, the memory is: +// Assume that there are 3300 clients, say, 10000 msgs in queue to send, the memory is: // 2 # We have two queue, cache and hotspot. // * 4 # We have reuseport, each have msg cache queue. -// * (64 + SRS_PERF_RTC_GSO_IOVS * 1500) # Each message size. -// * 60000 # Total messages. -// = 715MB # For SRS_PERF_RTC_GSO_IOVS = 1 -// = 1402MB # For SRS_PERF_RTC_GSO_IOVS = 2 -// = 2775MB # For SRS_PERF_RTC_GSO_IOVS = 4 +// * (64 + 16*SRS_PERF_RTC_GSO_MAX + SRS_PERF_RTC_GSO_IOVS * 1500) # Each message size. +// * 10000 # Total messages. +// = 197MB # For SRS_PERF_RTC_GSO_IOVS = 1 +// = 311MB # For SRS_PERF_RTC_GSO_IOVS = 2 +// = 540MB # For SRS_PERF_RTC_GSO_IOVS = 4 +// = 998MB # For SRS_PERF_RTC_GSO_IOVS = 8 #if defined(__linux__) - #define SRS_PERF_RTC_GSO_IOVS 2 + #define SRS_PERF_RTC_GSO_IOVS 4 #else #define SRS_PERF_RTC_GSO_IOVS 1 #endif From b0566d51ef38cd1b36198385e8b74359bc4f2f6c Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 18 Apr 2020 08:33:35 +0800 Subject: [PATCH 47/54] Refine play consume message for RTC --- trunk/src/app/srs_app_rtc_conn.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 24c19663c..a2d7c9c7a 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -701,22 +701,25 @@ srs_error_t SrsRtcSenderThread::cycle() return srs_error_wrap(err, "rtc sender thread"); } +#ifdef SRS_PERF_QUEUE_COND_WAIT + // Wait for amount of messages or a duration. + if (realtime) { + // for realtime, min required msgs is 0, send when got one+ msgs. + consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME, mw_sleep); + } else { + // for no-realtime, got some msgs then send. + consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC, mw_sleep); + } +#endif + + // Try to read some messages. int msg_count = 0; if ((err = consumer->dump_packets(&msgs, msg_count)) != srs_success) { continue; } - // For RTC, we always try to read messages, only wait when no message. if (msg_count <= 0) { -#ifdef SRS_PERF_QUEUE_COND_WAIT - if (realtime) { - // for realtime, min required msgs is 0, send when got one+ msgs. - consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME, mw_sleep); - } else { - // for no-realtime, got some msgs then send. - consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC, mw_sleep); - } -#else +#ifndef SRS_PERF_QUEUE_COND_WAIT srs_usleep(mw_sleep); #endif continue; From 08312ddc42808e03ec9389f348d82e9c352b71f9 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 18 Apr 2020 10:04:45 +0800 Subject: [PATCH 48/54] Support config the mw_sleep and mw_msgs --- trunk/conf/full.conf | 21 ++++++-- trunk/src/app/srs_app_config.cpp | 37 ++++++++++++- trunk/src/app/srs_app_config.hpp | 4 ++ trunk/src/app/srs_app_http_api.cpp | 8 +++ trunk/src/app/srs_app_http_stream.cpp | 3 +- trunk/src/app/srs_app_rtc_conn.cpp | 71 +++++++++++++------------ trunk/src/app/srs_app_rtc_conn.hpp | 6 +++ trunk/src/app/srs_app_rtmp_conn.cpp | 43 +++++++-------- trunk/src/app/srs_app_rtmp_conn.hpp | 4 +- trunk/src/core/srs_core_performance.hpp | 6 +-- 10 files changed, 132 insertions(+), 71 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 98a8792dc..39f02bd7f 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -484,12 +484,16 @@ vhost rtc.vhost.srs.com { stun_strict_check on; } # whether enable min delay mode for vhost. - # For RTC, we recommend to set to on. + # default: on, for RTC. min_latency on; play { # set the MW(merged-write) latency in ms. - # For RTC, we recommend lower value, such as 0. + # default: 0 (For WebRTC) mw_latency 0; + # Set the MW(merged-write) min messages. + # default: 0 (For Real-Time, min_latency on) + # default: 1 (For WebRTC, min_latency off) + mw_msgs 0; } } @@ -716,10 +720,16 @@ vhost play.srs.com { # SRS always set mw on, so we just set the latency value. # the latency of stream >= mw_latency + mr_latency # the value recomment is [300, 1800] - # default: 350 (for RTMP/HTTP-FLV) - # default: 0 (for WebRTC) + # default: 350 (For RTMP/HTTP-FLV) + # default: 0 (For WebRTC) mw_latency 350; + # Set the MW(merged-write) min messages. + # default: 0 (For Real-Time, min_latency on) + # default: 1 (For WebRTC, min_latency off) + # default: 8 (For RTMP/HTTP-FLV, min_latency off). + mw_msgs 8; + # the minimal packets send interval in ms, # used to control the ndiff of stream by srs_rtmp_dump, # for example, some device can only accept some stream which @@ -776,6 +786,7 @@ vhost mrw.srs.com { # @see play.srs.com play { mw_latency 350; + mw_msgs 8; } # @see publish.srs.com @@ -795,6 +806,7 @@ vhost min.delay.com { # @see play.srs.com play { mw_latency 100; + mw_msgs 4; gop_cache off; queue_length 10; } @@ -823,6 +835,7 @@ vhost stream.control.com { # @see play.srs.com play { mw_latency 100; + mw_msgs 4; queue_length 10; send_min_interval 10.0; reduce_sequence_header on; diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index eef0a325c..e9b89a346 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3785,7 +3785,8 @@ srs_error_t SrsConfig::check_normal_config() for (int j = 0; j < (int)conf->directives.size(); j++) { string m = conf->at(j)->name; if (m != "time_jitter" && m != "mix_correct" && m != "atc" && m != "atc_auto" && m != "mw_latency" - && m != "gop_cache" && m != "queue_length" && m != "send_min_interval" && m != "reduce_sequence_header") { + && m != "gop_cache" && m != "queue_length" && m != "send_min_interval" && m != "reduce_sequence_header" + && m != "mw_msgs") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.play.%s of %s", m.c_str(), vhost->arg0().c_str()); } } @@ -5423,6 +5424,40 @@ srs_utime_t SrsConfig::get_mw_sleep(string vhost, bool is_rtc) return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_MILLISECONDS); } +int SrsConfig::get_mw_msgs(string vhost, bool is_realtime, bool is_rtc) +{ + int DEFAULT = SRS_PERF_MW_MIN_MSGS; + if (is_rtc) { + DEFAULT = SRS_PERF_MW_MIN_MSGS_FOR_RTC; + } + if (is_realtime) { + DEFAULT = SRS_PERF_MW_MIN_MSGS_REALTIME; + } + + SrsConfDirective* conf = get_vhost(vhost); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("play"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("mw_msgs"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + int v = ::atoi(conf->arg0().c_str()); + if (v > SRS_PERF_MW_MSGS) { + srs_warn("reset mw_msgs %d to max %d", v, SRS_PERF_MW_MSGS); + v = SRS_PERF_MW_MSGS; + } + + return v; +} + bool SrsConfig::get_realtime_enabled(string vhost, bool is_rtc) { static bool SYS_DEFAULT = SRS_PERF_MIN_LATENCY_ENABLED; diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index bc9417d76..a905949b1 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -630,6 +630,10 @@ public: // @param vhost, the vhost to get the mw sleep time. // TODO: FIXME: add utest for mw config. virtual srs_utime_t get_mw_sleep(std::string vhost, bool is_rtc = false); + // Get the mw_msgs, mw wait time in packets for vhost. + // @param vhost, the vhost to get the mw sleep msgs. + // TODO: FIXME: add utest for mw config. + virtual int get_mw_msgs(std::string vhost, bool is_realtime, bool is_rtc = false); // Whether min latency mode enabled. // @param vhost, the vhost to get the min_latency. // TODO: FIXME: add utest for min_latency. diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index fa0a7d9f5..61552def2 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -869,6 +869,7 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe api = prop->to_str(); } + // TODO: FIXME: Parse vhost. // Parse app and stream from streamurl. string app; string stream_name; @@ -909,6 +910,13 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe request.app = app; request.stream = stream_name; + // TODO: FIXME: Parse vhost. + // discovery vhost, resolve the vhost from config + SrsConfDirective* parsed_vhost = _srs_config->get_vhost(""); + if (parsed_vhost) { + request.vhost = parsed_vhost->arg0(); + } + // TODO: FIXME: Maybe need a better name? // TODO: FIXME: When server enabled, but vhost disabled, should report error. SrsRtcSession* rtc_session = rtc_server->create_rtc_session(request, remote_sdp, local_sdp, eip); diff --git a/trunk/src/app/srs_app_http_stream.cpp b/trunk/src/app/srs_app_http_stream.cpp index 95c1f03fd..95a67c21a 100755 --- a/trunk/src/app/srs_app_http_stream.cpp +++ b/trunk/src/app/srs_app_http_stream.cpp @@ -660,7 +660,8 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess if ((err = consumer->dump_packets(&msgs, count)) != srs_success) { return srs_error_wrap(err, "consumer dump packets"); } - + + // TODO: FIXME: Support merged-write wait. if (count <= 0) { // Directly use sleep, donot use consumer wait, because we couldn't awake consumer. srs_usleep(mw_sleep); diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index a2d7c9c7a..890540c1c 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -563,6 +563,10 @@ SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int video_sequence = 0; + mw_sleep = 0; + mw_msgs = 0; + realtime = true; + _srs_config->subscribe(this); } @@ -595,33 +599,37 @@ srs_error_t SrsRtcSenderThread::initialize(const uint32_t& vssrc, const uint32_t srs_error_t SrsRtcSenderThread::on_reload_rtc_server() { - if (true) { - bool v = _srs_config->get_rtc_server_gso(); - if (gso != v) { - srs_trace("Reload gso %d=>%d", gso, v); - gso = v; - } - } + gso = _srs_config->get_rtc_server_gso(); + merge_nalus = _srs_config->get_rtc_server_merge_nalus(); + max_padding = _srs_config->get_rtc_server_padding(); - if (true) { - bool v = _srs_config->get_rtc_server_merge_nalus(); - if (merge_nalus != v) { - srs_trace("Reload merge_nalus %d=>%d", merge_nalus, v); - merge_nalus = v; - } - } - - if (true) { - bool v = _srs_config->get_rtc_server_padding(); - if (max_padding != v) { - srs_trace("Reload padding %d=>%d", max_padding, v); - max_padding = v; - } - } + srs_trace("Reload rtc_server gso=%d, merge_nalus=%d, max_padding=%d", gso, merge_nalus, max_padding); return srs_success; } +srs_error_t SrsRtcSenderThread::on_reload_vhost_play(string vhost) +{ + SrsRequest* req = &rtc_session->request; + + if (req->vhost != vhost) { + return srs_success; + } + + realtime = _srs_config->get_realtime_enabled(req->vhost, true); + mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime, true); + mw_sleep = _srs_config->get_mw_sleep(req->vhost, true); + + srs_trace("Reload play realtime=%d, mw_msgs=%d, mw_sleep=%d", realtime, mw_msgs, mw_sleep); + + return srs_success; +} + +srs_error_t SrsRtcSenderThread::on_reload_vhost_realtime(string vhost) +{ + return on_reload_vhost_play(vhost); +} + int SrsRtcSenderThread::cid() { return trd->cid(); @@ -673,9 +681,6 @@ srs_error_t SrsRtcSenderThread::cycle() return srs_error_wrap(err, "rtc fetch source failed"); } - srs_trace("source url=%s, source_id=[%d][%d], encrypt=%d", - rtc_session->request.get_stream_url().c_str(), ::getpid(), source->source_id(), rtc_session->encrypt); - SrsConsumer* consumer = NULL; SrsAutoFree(SrsConsumer, consumer); if ((err = source->create_consumer(NULL, consumer)) != srs_success) { @@ -684,8 +689,12 @@ srs_error_t SrsRtcSenderThread::cycle() // TODO: FIXME: Support reload. SrsRequest* req = &rtc_session->request; - bool realtime = _srs_config->get_realtime_enabled(req->vhost, true); - srs_utime_t mw_sleep = _srs_config->get_mw_sleep(req->vhost, true); + realtime = _srs_config->get_realtime_enabled(req->vhost, true); + mw_sleep = _srs_config->get_mw_sleep(req->vhost, true); + mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime, true); + + srs_trace("RTC source url=%s, source_id=[%d][%d], encrypt=%d, realtime=%d, mw_sleep=%dms, mw_msgs=%d", rtc_session->request.get_stream_url().c_str(), + ::getpid(), source->source_id(), rtc_session->encrypt, realtime, srsu2msi(mw_sleep), mw_msgs); SrsRtcPackets pkts; SrsMessageArray msgs(SRS_PERF_MW_MSGS); @@ -703,13 +712,7 @@ srs_error_t SrsRtcSenderThread::cycle() #ifdef SRS_PERF_QUEUE_COND_WAIT // Wait for amount of messages or a duration. - if (realtime) { - // for realtime, min required msgs is 0, send when got one+ msgs. - consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME, mw_sleep); - } else { - // for no-realtime, got some msgs then send. - consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC, mw_sleep); - } + consumer->wait(mw_msgs, mw_sleep); #endif // Try to read some messages. diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index a563a4e2a..4cf19d727 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -193,6 +193,10 @@ private: bool merge_nalus; bool gso; int max_padding; +private: + srs_utime_t mw_sleep; + int mw_msgs; + bool realtime; public: SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid); virtual ~SrsRtcSenderThread(); @@ -201,6 +205,8 @@ public: // interface ISrsReloadHandler public: virtual srs_error_t on_reload_rtc_server(); + virtual srs_error_t on_reload_vhost_play(std::string vhost); + virtual srs_error_t on_reload_vhost_realtime(std::string vhost); public: virtual int cid(); public: diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index d06d79a42..0f8b1012a 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -116,7 +116,7 @@ SrsRtmpConn::SrsRtmpConn(SrsServer* svr, srs_netfd_t c, string cip) : SrsConnect wakable = NULL; mw_sleep = SRS_PERF_MW_SLEEP; - mw_enabled = false; + mw_msgs = 0; realtime = SRS_PERF_MIN_LATENCY_ENABLED; send_min_interval = 0; tcp_nodelay = false; @@ -264,6 +264,10 @@ srs_error_t SrsRtmpConn::on_reload_vhost_play(string vhost) send_min_interval = v; } } + + mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime); + mw_sleep = _srs_config->get_mw_sleep(req->vhost); + set_socket_buffer(mw_sleep); return err; } @@ -298,6 +302,10 @@ srs_error_t SrsRtmpConn::on_reload_vhost_realtime(string vhost) srs_trace("realtime changed %d=>%d", realtime, realtime_enabled); realtime = realtime_enabled; } + + mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime); + mw_sleep = _srs_config->get_mw_sleep(req->vhost); + set_socket_buffer(mw_sleep); return err; } @@ -689,18 +697,19 @@ srs_error_t SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, Sr SrsMessageArray msgs(SRS_PERF_MW_MSGS); bool user_specified_duration_to_stop = (req->duration > 0); int64_t starttime = -1; - + // setup the realtime. realtime = _srs_config->get_realtime_enabled(req->vhost); // setup the mw config. // when mw_sleep changed, resize the socket send buffer. - mw_enabled = true; - change_mw_sleep(_srs_config->get_mw_sleep(req->vhost)); + mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime); + mw_sleep = _srs_config->get_mw_sleep(req->vhost); + set_socket_buffer(mw_sleep); // initialize the send_min_interval send_min_interval = _srs_config->get_send_min_interval(req->vhost); - srs_trace("start play smi=%dms, mw_sleep=%d, mw_enabled=%d, realtime=%d, tcp_nodelay=%d", - srsu2msi(send_min_interval), srsu2msi(mw_sleep), mw_enabled, realtime, tcp_nodelay); + srs_trace("start play smi=%dms, mw_sleep=%d, mw_msgs=%d, realtime=%d, tcp_nodelay=%d", + srsu2msi(send_min_interval), srsu2msi(mw_sleep), mw_msgs, realtime, tcp_nodelay); while (true) { // when source is set to expired, disconnect it. @@ -730,13 +739,7 @@ srs_error_t SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, Sr // wait for message to incoming. // @see https://github.com/ossrs/srs/issues/251 // @see https://github.com/ossrs/srs/issues/257 - if (realtime) { - // for realtime, min required msgs is 0, send when got one+ msgs. - consumer->wait(SRS_PERF_MW_MIN_MSGS_REALTIME, mw_sleep); - } else { - // for no-realtime, got some msgs then send. - consumer->wait(SRS_PERF_MW_MIN_MSGS, mw_sleep); - } + consumer->wait(mw_msgs, mw_sleep); #endif // get messages from consumer. @@ -750,9 +753,9 @@ srs_error_t SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, Sr // reportable if (pprint->can_print()) { kbps->sample(); - srs_trace("-> " SRS_CONSTS_LOG_PLAY " time=%d, msgs=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d, mw=%d", + srs_trace("-> " SRS_CONSTS_LOG_PLAY " time=%d, msgs=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d, mw=%d/%d", (int)pprint->age(), count, kbps->get_send_kbps(), kbps->get_send_kbps_30s(), kbps->get_send_kbps_5m(), - kbps->get_recv_kbps(), kbps->get_recv_kbps_30s(), kbps->get_recv_kbps_5m(), srsu2msi(mw_sleep)); + kbps->get_recv_kbps(), kbps->get_recv_kbps_30s(), kbps->get_recv_kbps_5m(), srsu2msi(mw_sleep), mw_msgs); } if (count <= 0) { @@ -1114,16 +1117,6 @@ srs_error_t SrsRtmpConn::process_play_control_msg(SrsConsumer* consumer, SrsComm return err; } -void SrsRtmpConn::change_mw_sleep(srs_utime_t sleep_v) -{ - if (!mw_enabled) { - return; - } - - set_socket_buffer(sleep_v); - mw_sleep = sleep_v; -} - void SrsRtmpConn::set_sock_options() { SrsRequest* req = info->req; diff --git a/trunk/src/app/srs_app_rtmp_conn.hpp b/trunk/src/app/srs_app_rtmp_conn.hpp index ac4b7efb9..c58111f04 100644 --- a/trunk/src/app/srs_app_rtmp_conn.hpp +++ b/trunk/src/app/srs_app_rtmp_conn.hpp @@ -102,8 +102,7 @@ private: srs_utime_t duration; // The MR(merged-write) sleep time in srs_utime_t. srs_utime_t mw_sleep; - // The MR(merged-write) only enabled for play. - int mw_enabled; + int mw_msgs; // For realtime // @see https://github.com/ossrs/srs/issues/257 bool realtime; @@ -149,7 +148,6 @@ private: virtual srs_error_t handle_publish_message(SrsSource* source, SrsCommonMessage* msg); virtual srs_error_t process_publish_message(SrsSource* source, SrsCommonMessage* msg); virtual srs_error_t process_play_control_msg(SrsConsumer* consumer, SrsCommonMessage* msg); - virtual void change_mw_sleep(srs_utime_t sleep_v); virtual void set_sock_options(); private: virtual srs_error_t check_edge_token_traverse_auth(); diff --git a/trunk/src/core/srs_core_performance.hpp b/trunk/src/core/srs_core_performance.hpp index 08b006c10..4d71ccdf8 100644 --- a/trunk/src/core/srs_core_performance.hpp +++ b/trunk/src/core/srs_core_performance.hpp @@ -129,10 +129,10 @@ #ifdef SRS_PERF_QUEUE_COND_WAIT // For RTMP, use larger wait queue. #define SRS_PERF_MW_MIN_MSGS 8 - #define SRS_PERF_MW_MIN_MSGS_REALTIME 0 // For RTC, use smaller wait queue. - #define SRS_PERF_MW_MIN_MSGS_FOR_RTC 2 - #define SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME 0 + #define SRS_PERF_MW_MIN_MSGS_FOR_RTC 1 + // For Real-Time, never wait messages. + #define SRS_PERF_MW_MIN_MSGS_REALTIME 0 #endif /** * the default value of vhost for From c1464f5aeee0545a86cf3e45cd570362a8798433 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 18 Apr 2020 10:35:30 +0800 Subject: [PATCH 49/54] Use extra queue when set mw_msgs --- trunk/src/app/srs_app_listener.hpp | 3 +++ trunk/src/app/srs_app_rtc_conn.cpp | 43 +++++++++++++++++++++++------- trunk/src/app/srs_app_rtc_conn.hpp | 8 ++++++ 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index d096e5910..cc20cc756 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -143,6 +143,9 @@ public: virtual srs_error_t sendmmsg(mmsghdr* hdr) = 0; // Whether sender exceed the max queue, that is, overflow. virtual bool overflow() = 0; + // Set the queue extra ratio, for example, when mw_msgs > 0, we need larger queue. + // For r, 100 means x1, 200 means x2. + virtual void set_extra_ratio(int r) = 0; }; class SrsUdpMuxSocket diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 890540c1c..9414741ab 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -674,26 +674,32 @@ srs_error_t SrsRtcSenderThread::cycle() srs_error_t err = srs_success; SrsSource* source = NULL; + SrsRequest* req = &rtc_session->request; // TODO: FIXME: Should refactor it, directly use http server as handler. ISrsSourceHandler* handler = _srs_hybrid->srs()->instance(); - if ((err = _srs_sources->fetch_or_create(&rtc_session->request, handler, &source)) != srs_success) { + if ((err = _srs_sources->fetch_or_create(req, handler, &source)) != srs_success) { return srs_error_wrap(err, "rtc fetch source failed"); } SrsConsumer* consumer = NULL; SrsAutoFree(SrsConsumer, consumer); if ((err = source->create_consumer(NULL, consumer)) != srs_success) { - return srs_error_wrap(err, "rtc create consumer, source url=%s", rtc_session->request.get_stream_url().c_str()); + return srs_error_wrap(err, "rtc create consumer, source url=%s", req->get_stream_url().c_str()); } - // TODO: FIXME: Support reload. - SrsRequest* req = &rtc_session->request; realtime = _srs_config->get_realtime_enabled(req->vhost, true); mw_sleep = _srs_config->get_mw_sleep(req->vhost, true); mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime, true); - srs_trace("RTC source url=%s, source_id=[%d][%d], encrypt=%d, realtime=%d, mw_sleep=%dms, mw_msgs=%d", rtc_session->request.get_stream_url().c_str(), + // We merged write more messages, so we need larger queue. + if (mw_msgs > 2) { + sender->set_extra_ratio(150); + } else if (mw_msgs > 0) { + sender->set_extra_ratio(80); + } + + srs_trace("RTC source url=%s, source_id=[%d][%d], encrypt=%d, realtime=%d, mw_sleep=%dms, mw_msgs=%d", req->get_stream_url().c_str(), ::getpid(), source->source_id(), rtc_session->encrypt, realtime, srsu2msi(mw_sleep), mw_msgs); SrsRtcPackets pkts; @@ -1846,6 +1852,10 @@ SrsUdpMuxSender::SrsUdpMuxSender(SrsRtcServer* s) cache_pos = 0; max_sendmmsg = 0; queue_length = 0; + extra_ratio = 0; + extra_queue = 0; + gso = false; + nn_senders = 0; _srs_config->subscribe(this); } @@ -1877,16 +1887,17 @@ srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd, int senders) } max_sendmmsg = _srs_config->get_rtc_server_sendmmsg(); - bool gso = _srs_config->get_rtc_server_gso(); + gso = _srs_config->get_rtc_server_gso(); queue_length = srs_max(128, _srs_config->get_rtc_server_queue_length()); + nn_senders = senders; // For no GSO, we need larger queue. if (!gso) { queue_length *= 2; } - srs_trace("UDP sender #%d init ok, max_sendmmsg=%d, gso=%d, queue_max=%dx%d", srs_netfd_fileno(fd), - max_sendmmsg, gso, queue_length, senders); + srs_trace("RTC sender #%d init ok, max_sendmmsg=%d, gso=%d, queue_max=%dx%d, extra_ratio=%d/%d", srs_netfd_fileno(fd), + max_sendmmsg, gso, queue_length, nn_senders, extra_ratio, extra_queue); return err; } @@ -1944,7 +1955,21 @@ srs_error_t SrsUdpMuxSender::fetch(mmsghdr** pphdr) bool SrsUdpMuxSender::overflow() { - return cache_pos > queue_length; + return cache_pos > queue_length + extra_queue; +} + +void SrsUdpMuxSender::set_extra_ratio(int r) +{ + // We use the larger extra ratio, because all vhosts shares the senders. + if (extra_ratio > r) { + return; + } + + extra_ratio = r; + extra_queue = queue_length * r / 100; + + srs_trace("RTC sender #%d extra queue, max_sendmmsg=%d, gso=%d, queue_max=%dx%d, extra_ratio=%d/%d, cache=%d/%d/%d", srs_netfd_fileno(lfd), + max_sendmmsg, gso, queue_length, nn_senders, extra_ratio, extra_queue, cache_pos, (int)cache.size(), (int)hotspot.size()); } srs_error_t SrsUdpMuxSender::sendmmsg(mmsghdr* hdr) diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 4cf19d727..3ad6a1072 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -307,6 +307,9 @@ private: private: srs_cond_t cond; bool waiting_msgs; + bool gso; + int nn_senders; +private: // Hotspot msgs, we are working on it. // @remark We will wait util all messages are ready. std::vector hotspot; @@ -317,6 +320,9 @@ private: int max_sendmmsg; // The total queue length, for each sender. int queue_length; + // The extra queue ratio. + int extra_ratio; + int extra_queue; public: SrsUdpMuxSender(SrsRtcServer* s); virtual ~SrsUdpMuxSender(); @@ -328,6 +334,8 @@ public: virtual srs_error_t fetch(mmsghdr** pphdr); virtual srs_error_t sendmmsg(mmsghdr* hdr); virtual bool overflow(); + virtual void set_extra_ratio(int r); +public: virtual srs_error_t cycle(); // interface ISrsReloadHandler public: From c93cd86ce4684a53b70c141e12c204d219c8c631 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 18 Apr 2020 20:37:08 +0800 Subject: [PATCH 50/54] For #307, refine performance --- trunk/conf/full.conf | 2 + trunk/src/app/srs_app_config.cpp | 8 +- trunk/src/app/srs_app_rtc_conn.cpp | 139 +++++++++------- trunk/src/app/srs_app_rtc_conn.hpp | 5 +- trunk/src/app/srs_app_source.cpp | 53 ++++-- trunk/src/app/srs_app_source.hpp | 12 +- trunk/src/core/srs_core_performance.hpp | 3 + trunk/src/kernel/srs_kernel_buffer.cpp | 5 - trunk/src/kernel/srs_kernel_buffer.hpp | 3 +- trunk/src/kernel/srs_kernel_rtp.cpp | 210 ++++++++++++++---------- trunk/src/kernel/srs_kernel_rtp.hpp | 58 +++++-- 11 files changed, 323 insertions(+), 175 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 39f02bd7f..2c1089665 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -488,6 +488,7 @@ vhost rtc.vhost.srs.com { min_latency on; play { # set the MW(merged-write) latency in ms. + # @remark For WebRTC, we enable pass-timestamp mode, so we ignore this config. # default: 0 (For WebRTC) mw_latency 0; # Set the MW(merged-write) min messages. @@ -720,6 +721,7 @@ vhost play.srs.com { # SRS always set mw on, so we just set the latency value. # the latency of stream >= mw_latency + mr_latency # the value recomment is [300, 1800] + # @remark For WebRTC, we enable pass-timestamp mode, so we ignore this config. # default: 350 (For RTMP/HTTP-FLV) # default: 0 (For WebRTC) mw_latency 350; diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index e9b89a346..2a8454633 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -5420,8 +5420,14 @@ srs_utime_t SrsConfig::get_mw_sleep(string vhost, bool is_rtc) if (!conf || conf->arg0().empty()) { return DEFAULT; } + + int v = ::atoi(conf->arg0().c_str()); + if (is_rtc && v > 0) { + srs_warn("For RTC, we ignore mw_latency"); + return 0; + } - return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_MILLISECONDS); + return (srs_utime_t)(v * SRS_UTIME_MILLISECONDS); } int SrsConfig::get_mw_msgs(string vhost, bool is_realtime, bool is_rtc) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 9414741ab..230ea2e49 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -460,7 +460,7 @@ srs_error_t SrsDtlsSession::unprotect_rtcp(char* out_buf, const char* in_buf, in return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed"); } -SrsRtcPackets::SrsRtcPackets() +SrsRtcPackets::SrsRtcPackets(int nn_cache_max) { #if defined(SRS_DEBUG) debug_id = 0; @@ -477,22 +477,20 @@ SrsRtcPackets::SrsRtcPackets() nn_dropped = 0; cursor = 0; + nn_cache = nn_cache_max; + cache = new SrsRtpPacket2[nn_cache]; } SrsRtcPackets::~SrsRtcPackets() { - vector::iterator it; - for (it = packets.begin(); it != packets.end(); ++it) { - SrsRtpPacket2* p = *it; - srs_freep(p); - } - packets.clear(); + srs_freepa(cache); + nn_cache = 0; } void SrsRtcPackets::reset(bool gso, bool merge_nalus) { for (int i = 0; i < cursor; i++) { - SrsRtpPacket2* packet = packets[i]; + SrsRtpPacket2* packet = cache + i; packet->reset(); } @@ -515,17 +513,16 @@ void SrsRtcPackets::reset(bool gso, bool merge_nalus) SrsRtpPacket2* SrsRtcPackets::fetch() { - if (cursor >= (int)packets.size()) { - packets.push_back(new SrsRtpPacket2()); + if (cursor >= nn_cache) { + return NULL; } - - return packets[cursor++]; + return cache + (cursor++); } SrsRtpPacket2* SrsRtcPackets::back() { srs_assert(cursor > 0); - return packets[cursor - 1]; + return cache + cursor - 1; } int SrsRtcPackets::size() @@ -535,13 +532,13 @@ int SrsRtcPackets::size() int SrsRtcPackets::capacity() { - return (int)packets.size(); + return nn_cache; } SrsRtpPacket2* SrsRtcPackets::at(int index) { srs_assert(index < cursor); - return packets[index]; + return cache + index; } SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid) @@ -688,6 +685,13 @@ srs_error_t SrsRtcSenderThread::cycle() return srs_error_wrap(err, "rtc create consumer, source url=%s", req->get_stream_url().c_str()); } + // For RTC, we enable pass-timestamp mode, ignore the timestamp in queue, never depends on the duration, + // because RTC allows the audio and video has its own timebase, that is the audio timestamp and video timestamp + // maybe not monotonically increase. + // In this mode, we use mw_msgs to set the delay. We never shrink the consumer queue, instead, we dumps the + // messages and drop them if the shared sender queue is full. + consumer->enable_pass_timestamp(); + realtime = _srs_config->get_realtime_enabled(req->vhost, true); mw_sleep = _srs_config->get_mw_sleep(req->vhost, true); mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime, true); @@ -702,8 +706,8 @@ srs_error_t SrsRtcSenderThread::cycle() srs_trace("RTC source url=%s, source_id=[%d][%d], encrypt=%d, realtime=%d, mw_sleep=%dms, mw_msgs=%d", req->get_stream_url().c_str(), ::getpid(), source->source_id(), rtc_session->encrypt, realtime, srsu2msi(mw_sleep), mw_msgs); - SrsRtcPackets pkts; SrsMessageArray msgs(SRS_PERF_MW_MSGS); + SrsRtcPackets pkts(SRS_PERF_RTC_RTP_PACKETS); SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_play(); SrsAutoFree(SrsPithyPrint, pprint); @@ -748,27 +752,29 @@ srs_error_t SrsRtcSenderThread::cycle() } // Stat for performance analysis. - if (stat_enabled) { - // Stat the original RAW AV frame, maybe h264+aac. - stat->perf_on_msgs(msg_count); - // Stat the RTC packets, RAW AV frame, maybe h.264+opus. - int nn_rtc_packets = srs_max(pkts.nn_audios, pkts.nn_extras) + pkts.nn_videos; - stat->perf_on_rtc_packets(nn_rtc_packets); - // Stat the RAW RTP packets, which maybe group by GSO. - stat->perf_on_rtp_packets(pkts.size()); - // Stat the RTP packets going into kernel. - stat->perf_on_gso_packets(pkts.nn_rtp_pkts); - // Stat the bytes and paddings. - stat->perf_on_rtc_bytes(pkts.nn_bytes, pkts.nn_rtp_bytes, pkts.nn_padding_bytes); - // Stat the messages and dropped count. - stat->perf_on_dropped(msg_count, nn_rtc_packets, pkts.nn_dropped); + if (!stat_enabled) { + continue; + } + + // Stat the original RAW AV frame, maybe h264+aac. + stat->perf_on_msgs(msg_count); + // Stat the RTC packets, RAW AV frame, maybe h.264+opus. + int nn_rtc_packets = srs_max(pkts.nn_audios, pkts.nn_extras) + pkts.nn_videos; + stat->perf_on_rtc_packets(nn_rtc_packets); + // Stat the RAW RTP packets, which maybe group by GSO. + stat->perf_on_rtp_packets(pkts.size()); + // Stat the RTP packets going into kernel. + stat->perf_on_gso_packets(pkts.nn_rtp_pkts); + // Stat the bytes and paddings. + stat->perf_on_rtc_bytes(pkts.nn_bytes, pkts.nn_rtp_bytes, pkts.nn_padding_bytes); + // Stat the messages and dropped count. + stat->perf_on_dropped(msg_count, nn_rtc_packets, pkts.nn_dropped); #if defined(SRS_DEBUG) - srs_trace("RTC PLAY perf, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d/%d/%d bytes", - msg_count, nn_rtc_packets, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, - pkts.nn_samples, pkts.nn_bytes, pkts.nn_rtp_bytes, pkts.nn_padding_bytes); + srs_trace("RTC PLAY perf, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d/%d/%d bytes", + msg_count, nn_rtc_packets, pkts.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, + pkts.nn_samples, pkts.nn_bytes, pkts.nn_rtp_bytes, pkts.nn_padding_bytes); #endif - } pprint->elapse(); if (pprint->can_print()) { @@ -1193,6 +1199,10 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac if (nn_bytes < kRtpMaxPayloadSize) { // Package NALUs in a single RTP packet. SrsRtpPacket2* packet = packets.fetch(); + if (!packet) { + srs_freep(raw); + return srs_error_new(ERROR_RTC_RTP_MUXER, "cache empty"); + } packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); @@ -1216,13 +1226,19 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac int packet_size = srs_min(nb_left, fu_payload_size); SrsRtpPacket2* packet = packets.fetch(); + if (!packet) { + srs_freep(raw); + return srs_error_new(ERROR_RTC_RTP_MUXER, "cache empty"); + } + packet->extra_payload = raw; packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); packet->rtp_header.set_ssrc(video_ssrc); packet->rtp_header.set_payload_type(video_payload_type); - SrsRtpFUAPayload* fua = packet->reuse_fua(); + SrsRtpFUAPayload* fua = new SrsRtpFUAPayload(); + packet->payload = fua; fua->nri = (SrsAvcNaluType)header; fua->nalu_type = (SrsAvcNaluType)nal_type; @@ -1249,6 +1265,9 @@ srs_error_t SrsRtcSenderThread::packet_opus(SrsSample* sample, SrsRtcPackets& pa srs_error_t err = srs_success; SrsRtpPacket2* packet = packets.fetch(); + if (!packet) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "cache empty"); + } packet->rtp_header.set_marker(true); packet->rtp_header.set_timestamp(audio_timestamp); packet->rtp_header.set_sequence(audio_sequence++); @@ -1291,23 +1310,24 @@ srs_error_t SrsRtcSenderThread::packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* int packet_size = srs_min(nb_left, fu_payload_size); SrsRtpPacket2* packet = packets.fetch(); + if (!packet) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "cache empty"); + } packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); packet->rtp_header.set_ssrc(video_ssrc); packet->rtp_header.set_payload_type(video_payload_type); - SrsRtpFUAPayload* fua = packet->reuse_fua(); + SrsRtpFUAPayload2* fua = packet->reuse_fua(); fua->nri = (SrsAvcNaluType)header; fua->nalu_type = (SrsAvcNaluType)nal_type; fua->start = bool(i == 0); fua->end = bool(i == num_of_packet - 1); - SrsSample* fragment_sample = new SrsSample(); - fragment_sample->bytes = p; - fragment_sample->size = packet_size; - fua->nalus.push_back(fragment_sample); + fua->payload = p; + fua->size = packet_size; p += packet_size; nb_left -= packet_size; @@ -1322,6 +1342,9 @@ srs_error_t SrsRtcSenderThread::packet_single_nalu(SrsSharedPtrMessage* msg, Srs srs_error_t err = srs_success; SrsRtpPacket2* packet = packets.fetch(); + if (!packet) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "cache empty"); + } packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); packet->rtp_header.set_ssrc(video_ssrc); @@ -1355,6 +1378,9 @@ srs_error_t SrsRtcSenderThread::packet_stap_a(SrsSource* source, SrsSharedPtrMes } SrsRtpPacket2* packet = packets.fetch(); + if (!packet) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "cache empty"); + } packet->rtp_header.set_marker(false); packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); @@ -2017,23 +2043,22 @@ srs_error_t SrsUdpMuxSender::cycle() cache.swap(hotspot); cache_pos = 0; - // Collect informations for GSO. int gso_pos = 0; - if (pos > 0 && stat_enabled) { - // For shared GSO cache, stat the messages. - // @see https://linux.die.net/man/2/sendmmsg - // @see https://linux.die.net/man/2/sendmsg - for (int i = 0; i < pos; i++) { - mmsghdr* mhdr = &hotspot[i]; - - int real_iovs = mhdr->msg_hdr.msg_iovlen; - gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs; - gso_iovs += real_iovs; - } - } - - // Send out all messages. if (pos > 0) { + // Collect informations for GSO. + if (stat_enabled) { + // For shared GSO cache, stat the messages. + // @see https://linux.die.net/man/2/sendmmsg + // @see https://linux.die.net/man/2/sendmsg + for (int i = 0; i < pos; i++) { + mmsghdr* mhdr = &hotspot[i]; + + int real_iovs = mhdr->msg_hdr.msg_iovlen; + gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs; + gso_iovs += real_iovs; + } + } + // Send out all messages. // @see https://linux.die.net/man/2/sendmmsg // @see https://linux.die.net/man/2/sendmsg @@ -2053,6 +2078,10 @@ srs_error_t SrsUdpMuxSender::cycle() } } + if (!stat_enabled) { + continue; + } + // Increase total messages. nn_msgs += pos + gso_iovs; nn_msgs_max = srs_max(pos, nn_msgs_max); diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 3ad6a1072..c3796c711 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -155,9 +155,10 @@ public: int nn_dropped; private: int cursor; - std::vector packets; + int nn_cache; + SrsRtpPacket2* cache; public: - SrsRtcPackets(); + SrsRtcPackets(int nn_cache_max); virtual ~SrsRtcPackets(); public: void reset(bool gso, bool merge_nalus); diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index fcf3b071e..c0548708f 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -269,9 +269,17 @@ void SrsMessageQueue::set_queue_size(srs_utime_t queue_size) max_queue_size = queue_size; } -srs_error_t SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg, bool* is_overflow) +srs_error_t SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg, bool* is_overflow, bool pass_timestamp) { srs_error_t err = srs_success; + + msgs.push_back(msg); + + // For RTC, we never care about the timestamp and duration, so we never shrink queue here, + // but we will drop messages in each consumer coroutine. + if (pass_timestamp) { + return err; + } if (msg->is_av()) { if (av_start_time == -1) { @@ -281,8 +289,6 @@ srs_error_t SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg, bool* is_overflow av_end_time = srs_utime_t(msg->timestamp * SRS_UTIME_MILLISECONDS); } - msgs.push_back(msg); - while (av_end_time - av_start_time > max_queue_size) { // notice the caller queue already overflow and shrinked. if (is_overflow) { @@ -295,7 +301,7 @@ srs_error_t SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg, bool* is_overflow return err; } -srs_error_t SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, int& count) +srs_error_t SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, int& count, bool pass_timestamp) { srs_error_t err = srs_success; @@ -308,13 +314,15 @@ srs_error_t SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** p count = srs_min(max_count, nb_msgs); SrsSharedPtrMessage** omsgs = msgs.data(); - for (int i = 0; i < count; i++) { - pmsgs[i] = omsgs[i]; + memcpy(pmsgs, omsgs, count * sizeof(SrsSharedPtrMessage*)); + + // For RTC, we enable pass_timestamp mode, which never care about the timestamp and duration, + // so we do not have to update the start time here. + if (!pass_timestamp) { + SrsSharedPtrMessage* last = omsgs[count - 1]; + av_start_time = srs_utime_t(last->timestamp * SRS_UTIME_MILLISECONDS); } - SrsSharedPtrMessage* last = omsgs[count - 1]; - av_start_time = srs_utime_t(last->timestamp * SRS_UTIME_MILLISECONDS); - if (count >= nb_msgs) { // the pmsgs is big enough and clear msgs at most time. msgs.clear(); @@ -433,6 +441,8 @@ SrsConsumer::SrsConsumer(SrsSource* s, SrsConnection* c) mw_duration = 0; mw_waiting = false; #endif + + pass_timestamp = false; } SrsConsumer::~SrsConsumer() @@ -466,20 +476,35 @@ srs_error_t SrsConsumer::enqueue(SrsSharedPtrMessage* shared_msg, bool atc, SrsR srs_error_t err = srs_success; SrsSharedPtrMessage* msg = shared_msg->copy(); - - if (!atc) { + + // For RTC, we enable pass_timestamp mode, which never correct or depends on monotonic increasing of + // timestamp. And in RTC, the audio and video timebase can be different, so we ignore time_jitter here. + if (!pass_timestamp && !atc) { if ((err = jitter->correct(msg, ag)) != srs_success) { return srs_error_wrap(err, "consume message"); } } - - if ((err = queue->enqueue(msg, NULL)) != srs_success) { + + // Put message in queue, here we may enable pass_timestamp mode. + if ((err = queue->enqueue(msg, NULL, pass_timestamp)) != srs_success) { return srs_error_wrap(err, "enqueue message"); } #ifdef SRS_PERF_QUEUE_COND_WAIT // fire the mw when msgs is enough. if (mw_waiting) { + // For RTC, we use pass_timestamp mode, we don't care about the timestamp in queue, + // so we only check the messages in queue. + if (pass_timestamp) { + if (queue->size() > mw_min_msgs) { + srs_cond_signal(mw_wait); + mw_waiting = false; + return err; + } + return err; + } + + // For RTMP, we wait for messages and duration. srs_utime_t duration = queue->duration(); bool match_min_msgs = queue->size() > mw_min_msgs; @@ -529,7 +554,7 @@ srs_error_t SrsConsumer::dump_packets(SrsMessageArray* msgs, int& count) } // pump msgs from queue. - if ((err = queue->dump_packets(max, msgs->msgs, count)) != srs_success) { + if ((err = queue->dump_packets(max, msgs->msgs, count, pass_timestamp)) != srs_success) { return srs_error_wrap(err, "dump packets"); } diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 6e64e9b21..fdfe9c789 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -151,12 +151,13 @@ public: // Enqueue the message, the timestamp always monotonically. // @param msg, the msg to enqueue, user never free it whatever the return code. // @param is_overflow, whether overflow and shrinked. NULL to ignore. - virtual srs_error_t enqueue(SrsSharedPtrMessage* msg, bool* is_overflow = NULL); + // @remark If pass_timestamp, we never shrink and never care about the timestamp or duration. + virtual srs_error_t enqueue(SrsSharedPtrMessage* msg, bool* is_overflow = NULL, bool pass_timestamp = false); // Get packets in consumer queue. // @pmsgs SrsSharedPtrMessage*[], used to store the msgs, user must alloc it. // @count the count in array, output param. // @max_count the max count to dequeue, must be positive. - virtual srs_error_t dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, int& count); + virtual srs_error_t dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, int& count, bool pass_timestamp = false); // Dumps packets to consumer, use specified args. // @remark the atc/tba/tbv/ag are same to SrsConsumer.enqueue(). virtual srs_error_t dump_packets(SrsConsumer* consumer, bool atc, SrsRtmpJitterAlgorithm ag); @@ -203,10 +204,17 @@ private: int mw_min_msgs; srs_utime_t mw_duration; #endif +private: + // For RTC, we never use jitter to correct timestamp. + // But we should not change the atc or time_jitter for source or RTMP. + // @remark In this mode, we also never check the queue by timstamp, but only by count. + bool pass_timestamp; public: SrsConsumer(SrsSource* s, SrsConnection* c); virtual ~SrsConsumer(); public: + // Use pass timestamp mode. + void enable_pass_timestamp() { pass_timestamp = true; } // Set the size of queue. virtual void set_queue_size(srs_utime_t queue_size); // when source id changed, notice client to print. diff --git a/trunk/src/core/srs_core_performance.hpp b/trunk/src/core/srs_core_performance.hpp index 4d71ccdf8..39493646a 100644 --- a/trunk/src/core/srs_core_performance.hpp +++ b/trunk/src/core/srs_core_performance.hpp @@ -211,5 +211,8 @@ // For RTC, the max iovs in msghdr, the max packets sent in a msghdr. #define SRS_PERF_RTC_GSO_MAX 64 +// For RTC, the max count of RTP packets we process in one loop. +#define SRS_PERF_RTC_RTP_PACKETS 1024 + #endif diff --git a/trunk/src/kernel/srs_kernel_buffer.cpp b/trunk/src/kernel/srs_kernel_buffer.cpp index 73c6cafe1..be94d0bcb 100644 --- a/trunk/src/kernel/srs_kernel_buffer.cpp +++ b/trunk/src/kernel/srs_kernel_buffer.cpp @@ -67,11 +67,6 @@ SrsBuffer::~SrsBuffer() { } -char* SrsBuffer::data() -{ - return bytes; -} - int SrsBuffer::size() { return nb_bytes; diff --git a/trunk/src/kernel/srs_kernel_buffer.hpp b/trunk/src/kernel/srs_kernel_buffer.hpp index 870da9ef8..532375f8d 100644 --- a/trunk/src/kernel/srs_kernel_buffer.hpp +++ b/trunk/src/kernel/srs_kernel_buffer.hpp @@ -113,7 +113,8 @@ public: * get data of stream, set by initialize. * current bytes = data() + pos() */ - virtual char* data(); + inline char* data() { return bytes; } + inline char* head() { return p; } /** * the total stream size, set by initialize. * left bytes = size() - pos(). diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index b9659174e..fa98c5957 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -85,7 +85,7 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* stream) // Encode the RTP fix header, 12bytes. // @see https://tools.ietf.org/html/rfc1889#section-5.1 - char* op = stream->data() + stream->pos(); + char* op = stream->head(); char* p = op; // The version, padding, extension and cc, total 1 byte. @@ -148,60 +148,45 @@ size_t SrsRtpHeader::header_size() return kRtpHeaderFixedSize + cc * 4 + (extension ? (extension_length + 1) * 4 : 0); } -void SrsRtpHeader::set_marker(bool marker) -{ - this->marker = marker; -} - -void SrsRtpHeader::set_payload_type(uint8_t payload_type) -{ - this->payload_type = payload_type; -} - -void SrsRtpHeader::set_sequence(uint16_t sequence) -{ - this->sequence = sequence; -} - -void SrsRtpHeader::set_timestamp(int64_t timestamp) -{ - this->timestamp = (uint32_t)timestamp; -} - -void SrsRtpHeader::set_ssrc(uint32_t ssrc) -{ - this->ssrc = ssrc; -} - SrsRtpPacket2::SrsRtpPacket2() { payload = NULL; + extra_payload = NULL; padding = 0; cache_raw = new SrsRtpRawPayload(); - cache_fua = new SrsRtpFUAPayload(); + cache_fua = new SrsRtpFUAPayload2(); + cache_payload = 0; + using_cache = false; } SrsRtpPacket2::~SrsRtpPacket2() { // We may use the cache as payload. - if (payload == cache_raw || payload == cache_fua) { + if (using_cache) { payload = NULL; } srs_freep(payload); + srs_freep(extra_payload); srs_freep(cache_raw); } void SrsRtpPacket2::set_padding(int size) { rtp_header.set_padding(size > 0); + if (cache_payload) { + cache_payload += size - padding; + } padding = size; } void SrsRtpPacket2::add_padding(int size) { rtp_header.set_padding(padding + size > 0); + if (cache_payload) { + cache_payload += size; + } padding += size; } @@ -209,31 +194,39 @@ void SrsRtpPacket2::reset() { rtp_header.reset(); padding = 0; + cache_payload = 0; + srs_freep(extra_payload); // We may use the cache as payload. - if (payload == cache_raw || payload == cache_fua) { + if (using_cache) { payload = NULL; + } else { + srs_freep(payload); } - srs_freep(payload); + using_cache = false; } SrsRtpRawPayload* SrsRtpPacket2::reuse_raw() { + using_cache = true; payload = cache_raw; return cache_raw; } -SrsRtpFUAPayload* SrsRtpPacket2::reuse_fua() +SrsRtpFUAPayload2* SrsRtpPacket2::reuse_fua() { + using_cache = true; payload = cache_fua; - cache_fua->reset(); return cache_fua; } int SrsRtpPacket2::nb_bytes() { - return rtp_header.header_size() + (payload? payload->nb_bytes():0) + padding; + if (!cache_payload) { + cache_payload = rtp_header.header_size() + (payload? payload->nb_bytes():0) + padding; + } + return cache_payload; } srs_error_t SrsRtpPacket2::encode(SrsBuffer* buf) @@ -297,12 +290,20 @@ SrsRtpRawNALUs::SrsRtpRawNALUs() SrsRtpRawNALUs::~SrsRtpRawNALUs() { - vector::iterator it; - for (it = nalus.begin(); it != nalus.end(); ++it) { - SrsSample* p = *it; - srs_freep(p); + if (true) { + int nn_nalus = (int)nalus.size(); + for (int i = 0; i < nn_nalus; i++) { + SrsSample* p = nalus[i]; + srs_freep(p); + } + } + if (true) { + int nn_nalus = (int)extra_nalus.size(); + for (int i = 0; i < nn_nalus; i++) { + SrsSample* p = extra_nalus[i]; + srs_freep(p); + } } - nalus.clear(); } void SrsRtpRawNALUs::push_back(SrsSample* sample) @@ -330,19 +331,19 @@ uint8_t SrsRtpRawNALUs::skip_first_byte() return uint8_t(nalus[0]->bytes[0]); } -srs_error_t SrsRtpRawNALUs::read_samples(vector& samples, int size) +srs_error_t SrsRtpRawNALUs::read_samples(vector& samples, int packet_size) { - if (cursor + size < 0 || cursor + size > nn_bytes) { - return srs_error_new(ERROR_RTC_RTP_MUXER, "cursor=%d, max=%d, size=%d", cursor, nn_bytes, size); + if (cursor + packet_size < 0 || cursor + packet_size > nn_bytes) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "cursor=%d, max=%d, size=%d", cursor, nn_bytes, packet_size); } int pos = cursor; - cursor += size; - int left = size; + cursor += packet_size; + int left = packet_size; - vector::iterator it; - for (it = nalus.begin(); it != nalus.end() && left > 0; ++it) { - SrsSample* p = *it; + int nn_nalus = (int)nalus.size(); + for (int i = 0; i < nn_nalus; i++) { + SrsSample* p = nalus[i]; // Ignore previous consumed samples. if (pos && pos - p->size >= 0) { @@ -355,9 +356,11 @@ srs_error_t SrsRtpRawNALUs::read_samples(vector& samples, int size) srs_assert(nn > 0); SrsSample* sample = new SrsSample(); + extra_nalus.push_back(sample); + samples.push_back(sample); + sample->bytes = p->bytes + pos; sample->size = nn; - samples.push_back(sample); left -= nn; pos = 0; @@ -370,9 +373,9 @@ int SrsRtpRawNALUs::nb_bytes() { int size = 0; - vector::iterator it; - for (it = nalus.begin(); it != nalus.end(); ++it) { - SrsSample* p = *it; + int nn_nalus = (int)nalus.size(); + for (int i = 0; i < nn_nalus; i++) { + SrsSample* p = nalus[i]; size += p->size; } @@ -381,9 +384,9 @@ int SrsRtpRawNALUs::nb_bytes() srs_error_t SrsRtpRawNALUs::encode(SrsBuffer* buf) { - vector::iterator it; - for (it = nalus.begin(); it != nalus.end(); ++it) { - SrsSample* p = *it; + int nn_nalus = (int)nalus.size(); + for (int i = 0; i < nn_nalus; i++) { + SrsSample* p = nalus[i]; if (!buf->require(p->size)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", p->size); @@ -402,21 +405,20 @@ SrsRtpSTAPPayload::SrsRtpSTAPPayload() SrsRtpSTAPPayload::~SrsRtpSTAPPayload() { - vector::iterator it; - for (it = nalus.begin(); it != nalus.end(); ++it) { - SrsSample* p = *it; + int nn_nalus = (int)nalus.size(); + for (int i = 0; i < nn_nalus; i++) { + SrsSample* p = nalus[i]; srs_freep(p); } - nalus.clear(); } int SrsRtpSTAPPayload::nb_bytes() { int size = 1; - vector::iterator it; - for (it = nalus.begin(); it != nalus.end(); ++it) { - SrsSample* p = *it; + int nn_nalus = (int)nalus.size(); + for (int i = 0; i < nn_nalus; i++) { + SrsSample* p = nalus[i]; size += 2 + p->size; } @@ -436,9 +438,10 @@ srs_error_t SrsRtpSTAPPayload::encode(SrsBuffer* buf) buf->write_1bytes(v); // NALUs. - vector::iterator it; - for (it = nalus.begin(); it != nalus.end(); ++it) { - SrsSample* p = *it; + int nn_nalus = (int)nalus.size(); + for (int i = 0; i < nn_nalus; i++) { + SrsSample* p = nalus[i]; + if (!buf->require(2 + p->size)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2 + p->size); } @@ -458,31 +461,20 @@ SrsRtpFUAPayload::SrsRtpFUAPayload() SrsRtpFUAPayload::~SrsRtpFUAPayload() { - vector::iterator it; - for (it = nalus.begin(); it != nalus.end(); ++it) { - SrsSample* p = *it; + int nn_nalus = (int)nalus.size(); + for (int i = 0; i < nn_nalus; i++) { + SrsSample* p = nalus[i]; srs_freep(p); } - nalus.clear(); -} - -void SrsRtpFUAPayload::reset() -{ - vector::iterator it; - for (it = nalus.begin(); it != nalus.end(); ++it) { - SrsSample* p = *it; - srs_freep(p); - } - nalus.clear(); } int SrsRtpFUAPayload::nb_bytes() { int size = 2; - vector::iterator it; - for (it = nalus.begin(); it != nalus.end(); ++it) { - SrsSample* p = *it; + int nn_nalus = (int)nalus.size(); + for (int i = 0; i < nn_nalus; i++) { + SrsSample* p = nalus[i]; size += p->size; } @@ -511,9 +503,10 @@ srs_error_t SrsRtpFUAPayload::encode(SrsBuffer* buf) buf->write_1bytes(fu_header); // FU payload, @see https://tools.ietf.org/html/rfc6184#section-5.8 - vector::iterator it; - for (it = nalus.begin(); it != nalus.end(); ++it) { - SrsSample* p = *it; + int nn_nalus = (int)nalus.size(); + for (int i = 0; i < nn_nalus; i++) { + SrsSample* p = nalus[i]; + if (!buf->require(p->size)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", p->size); } @@ -524,6 +517,57 @@ srs_error_t SrsRtpFUAPayload::encode(SrsBuffer* buf) return srs_success; } +SrsRtpFUAPayload2::SrsRtpFUAPayload2() +{ + start = end = false; + nri = nalu_type = (SrsAvcNaluType)0; + + payload = NULL; + size = 0; +} + +SrsRtpFUAPayload2::~SrsRtpFUAPayload2() +{ +} + +int SrsRtpFUAPayload2::nb_bytes() +{ + return 2 + size; +} + +srs_error_t SrsRtpFUAPayload2::encode(SrsBuffer* buf) +{ + if (!buf->require(2 + size)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); + } + + // Fast encoding. + char* p = buf->head(); + + // FU indicator, @see https://tools.ietf.org/html/rfc6184#section-5.8 + uint8_t fu_indicate = kFuA; + fu_indicate |= (nri & (~kNalTypeMask)); + *p++ = fu_indicate; + + // FU header, @see https://tools.ietf.org/html/rfc6184#section-5.8 + uint8_t fu_header = nalu_type; + if (start) { + fu_header |= kStart; + } + if (end) { + fu_header |= kEnd; + } + *p++ = fu_header; + + // FU payload, @see https://tools.ietf.org/html/rfc6184#section-5.8 + memcpy(p, payload, size); + + // Consume bytes. + buf->skip(2 + size); + + return srs_success; +} + SrsRtpSharedPacket::SrsRtpSharedPacketPayload::SrsRtpSharedPacketPayload() { payload = NULL; diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index 973de2205..53601d126 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -39,7 +39,7 @@ const uint8_t kNalTypeMask = 0x1F; class SrsBuffer; class SrsRtpRawPayload; -class SrsRtpFUAPayload; +class SrsRtpFUAPayload2; class SrsRtpHeader { @@ -65,17 +65,17 @@ public: public: size_t header_size(); public: - void set_marker(bool marker); + inline void set_marker(bool v) { marker = v; } bool get_marker() const { return marker; } - void set_payload_type(uint8_t payload_type); + inline void set_payload_type(uint8_t v) { payload_type = v; } uint8_t get_payload_type() const { return payload_type; } - void set_sequence(uint16_t sequence); + inline void set_sequence(uint16_t v) { sequence = v; } uint16_t get_sequence() const { return sequence; } - void set_timestamp(int64_t timestamp); + inline void set_timestamp(int64_t v) { timestamp = (uint32_t)v; } int64_t get_timestamp() const { return timestamp; } - void set_ssrc(uint32_t ssrc); + inline void set_ssrc(uint32_t v) { ssrc = v; } uint32_t get_ssrc() const { return ssrc; } - void set_padding(bool v) { padding = v; } + inline void set_padding(bool v) { padding = v; } }; class SrsRtpPacket2 @@ -84,9 +84,16 @@ public: SrsRtpHeader rtp_header; ISrsEncoder* payload; int padding; +public: + // User can set an extra payload, we will free it. + // For example, when reassemble NALUs by SrsRtpRawNALUs, we can set the extra payload to + // SrsRtpRawNALUs, then we can use SrsRtpFUAPayload which never free samples. + ISrsEncoder* extra_payload; private: SrsRtpRawPayload* cache_raw; - SrsRtpFUAPayload* cache_fua; + SrsRtpFUAPayload2* cache_fua; + bool using_cache; + int cache_payload; public: SrsRtpPacket2(); virtual ~SrsRtpPacket2(); @@ -100,7 +107,7 @@ public: // Reuse the cached raw message as payload. SrsRtpRawPayload* reuse_raw(); // Reuse the cached fua message as payload. - SrsRtpFUAPayload* reuse_fua(); + SrsRtpFUAPayload2* reuse_fua(); // interface ISrsEncoder public: virtual int nb_bytes(); @@ -111,7 +118,8 @@ public: class SrsRtpRawPayload : public ISrsEncoder { public: - // @remark We only refer to the memory, user must free it. + // The RAW payload, directly point to the shared memory. + // @remark We only refer to the memory, user must free its bytes. char* payload; int nn_payload; public: @@ -127,6 +135,9 @@ public: class SrsRtpRawNALUs : public ISrsEncoder { private: + // The returned samples. + std::vector extra_nalus; + // We will manage the samples, but the sample itself point to the shared memory. std::vector nalus; int nn_bytes; int cursor; @@ -137,7 +148,8 @@ public: void push_back(SrsSample* sample); public: uint8_t skip_first_byte(); - srs_error_t read_samples(std::vector& samples, int size); + // We will manage the returned samples, if user want to manage it, please copy it. + srs_error_t read_samples(std::vector& samples, int packet_size); // interface ISrsEncoder public: virtual int nb_bytes(); @@ -163,6 +175,7 @@ public: }; // FU-A, for one NALU with multiple fragments. +// With more than one payload. class SrsRtpFUAPayload : public ISrsEncoder { public: @@ -178,8 +191,29 @@ public: public: SrsRtpFUAPayload(); virtual ~SrsRtpFUAPayload(); +// interface ISrsEncoder public: - void reset(); + virtual int nb_bytes(); + virtual srs_error_t encode(SrsBuffer* buf); +}; + +// FU-A, for one NALU with multiple fragments. +// With only one payload. +class SrsRtpFUAPayload2 : public ISrsEncoder +{ +public: + // The NRI in NALU type. + SrsAvcNaluType nri; + // The FUA header. + bool start; + bool end; + SrsAvcNaluType nalu_type; + // The payload and size, + char* payload; + int size; +public: + SrsRtpFUAPayload2(); + virtual ~SrsRtpFUAPayload2(); // interface ISrsEncoder public: virtual int nb_bytes(); From ce36a970ff075d631c221fca66b1affa41faaf38 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 18 Apr 2020 22:55:38 +0800 Subject: [PATCH 51/54] Refine perf stat --- trunk/3rdparty/st-srs/README.md | 8 ++++++ trunk/src/app/srs_app_rtc_conn.cpp | 39 ++++++++++++++++++------------ 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/trunk/3rdparty/st-srs/README.md b/trunk/3rdparty/st-srs/README.md index 60fc1a651..522d3c761 100644 --- a/trunk/3rdparty/st-srs/README.md +++ b/trunk/3rdparty/st-srs/README.md @@ -22,6 +22,8 @@ The branch [srs](https://github.com/ossrs/state-threads/tree/srs) will be patche - [x] Patch [st.osx10.14.build.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/6.st.osx10.14.build.patch), for osx 10.14 build. - [x] Support macro `MD_ST_NO_ASM` to disable ASM, [#8](https://github.com/ossrs/state-threads/issues/8). - [x] Merge patch [srs#1282](https://github.com/ossrs/srs/issues/1282#issuecomment-445539513) to support aarch64, [#9](https://github.com/ossrs/state-threads/issues/9). +- [x] Support OSX for Apple Darwin, macOS, [#11](https://github.com/ossrs/state-threads/issues/11). +- [x] Support sendmmsg for UDP, [#12](https://github.com/ossrs/state-threads/issues/12). ## Docs @@ -85,4 +87,10 @@ Important cli options: 1. `--track-origins= [default: no]`, Controls whether Memcheck tracks the origin of uninitialised values. By default, it does not, which means that although it can tell you that an uninitialised value is being used in a dangerous way, it cannot tell you where the uninitialised value came from. This often makes it difficult to track down the root problem. 1. `--show-reachable= , --show-possibly-lost=`, to show the using memory. +## Analysis + +1. About setjmp and longjmp, read [setjmp](https://gitee.com/winlinvip/srs-wiki/raw/master/images/st-setjmp.jpg). +1. About the stack structure, read [stack](https://gitee.com/winlinvip/srs-wiki/raw/master/images/st-stack.jpg) +1. About asm code comments, read [#91d530e](https://github.com/ossrs/state-threads/commit/91d530e#diff-ed9428b14ff6afda0e9ab04cc91d4445R25). + Winlin 2016 diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 230ea2e49..5b79be9ca 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -2013,6 +2013,7 @@ srs_error_t SrsUdpMuxSender::cycle() srs_error_t err = srs_success; uint64_t nn_msgs = 0; uint64_t nn_msgs_last = 0; int nn_msgs_max = 0; + uint64_t nn_bytes = 0; int nn_bytes_max = 0; uint64_t nn_gso_msgs = 0; uint64_t nn_gso_iovs = 0; int nn_gso_msgs_max = 0; int nn_gso_iovs_max = 0; int nn_loop = 0; int nn_wait = 0; srs_utime_t time_last = srs_get_system_time(); @@ -2044,21 +2045,8 @@ srs_error_t SrsUdpMuxSender::cycle() cache_pos = 0; int gso_pos = 0; + int nn_writen = 0; if (pos > 0) { - // Collect informations for GSO. - if (stat_enabled) { - // For shared GSO cache, stat the messages. - // @see https://linux.die.net/man/2/sendmmsg - // @see https://linux.die.net/man/2/sendmsg - for (int i = 0; i < pos; i++) { - mmsghdr* mhdr = &hotspot[i]; - - int real_iovs = mhdr->msg_hdr.msg_iovlen; - gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs; - gso_iovs += real_iovs; - } - } - // Send out all messages. // @see https://linux.die.net/man/2/sendmmsg // @see https://linux.die.net/man/2/sendmsg @@ -2076,6 +2064,22 @@ srs_error_t SrsUdpMuxSender::cycle() stat->perf_on_sendmmsg_packets(vlen); } } + + // Collect informations for GSO. + if (stat_enabled) { + // Stat the messages, iovs and bytes. + // @see https://linux.die.net/man/2/sendmmsg + // @see https://linux.die.net/man/2/sendmsg + for (int i = 0; i < pos; i++) { + mmsghdr* mhdr = &hotspot[i]; + + nn_writen += (int)mhdr->msg_len; + + int real_iovs = mhdr->msg_hdr.msg_iovlen; + gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs; + gso_iovs += real_iovs; + } + } } if (!stat_enabled) { @@ -2085,6 +2089,8 @@ srs_error_t SrsUdpMuxSender::cycle() // Increase total messages. nn_msgs += pos + gso_iovs; nn_msgs_max = srs_max(pos, nn_msgs_max); + nn_bytes += nn_writen; + nn_bytes_max = srs_max(nn_bytes_max, nn_writen); nn_gso_msgs_max = srs_max(gso_pos, nn_gso_msgs_max); nn_gso_iovs_max = srs_max(gso_iovs, nn_gso_iovs_max); @@ -2115,12 +2121,13 @@ srs_error_t SrsUdpMuxSender::cycle() nn_cache += hdr->msg_hdr.msg_iovlen; } - srs_trace("-> RTC SEND #%d, sessions %d, udp %d/%d/%" PRId64 ", gso %d/%d/%" PRId64 ", iovs %d/%d/%" PRId64 ", pps %d/%d%s, cache %d/%d", + srs_trace("-> RTC SEND #%d, sessions %d, udp %d/%d/%" PRId64 ", gso %d/%d/%" PRId64 ", iovs %d/%d/%" PRId64 ", pps %d/%d%s, cache %d/%d, bytes %d/%" PRId64, srs_netfd_fileno(lfd), (int)server->nn_sessions(), pos, nn_msgs_max, nn_msgs, gso_pos, nn_gso_msgs_max, nn_gso_msgs, gso_iovs, - nn_gso_iovs_max, nn_gso_iovs, pps_average, pps_last, pps_unit.c_str(), (int)hotspot.size(), nn_cache); + nn_gso_iovs_max, nn_gso_iovs, pps_average, pps_last, pps_unit.c_str(), (int)hotspot.size(), nn_cache, nn_bytes_max, nn_bytes); nn_msgs_last = nn_msgs; time_last = srs_get_system_time(); nn_loop = nn_wait = nn_msgs_max = 0; nn_gso_msgs_max = 0; nn_gso_iovs_max = 0; + nn_bytes_max = 0; } } From b1df04cb09205fbd7a87c09a62a95451e101d18d Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 19 Apr 2020 09:32:09 +0800 Subject: [PATCH 52/54] Fix double free bug for RTP --- trunk/src/app/srs_app_rtc_conn.cpp | 1 + trunk/src/kernel/srs_kernel_rtp.cpp | 8 -------- trunk/src/kernel/srs_kernel_rtp.hpp | 6 ++---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 5b79be9ca..401ecc01f 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -478,6 +478,7 @@ SrsRtcPackets::SrsRtcPackets(int nn_cache_max) cursor = 0; nn_cache = nn_cache_max; + // TODO: FIXME: We should allocate a smaller cache, and increase it when exhausted. cache = new SrsRtpPacket2[nn_cache]; } diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index fa98c5957..0215cb1a6 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -297,13 +297,6 @@ SrsRtpRawNALUs::~SrsRtpRawNALUs() srs_freep(p); } } - if (true) { - int nn_nalus = (int)extra_nalus.size(); - for (int i = 0; i < nn_nalus; i++) { - SrsSample* p = extra_nalus[i]; - srs_freep(p); - } - } } void SrsRtpRawNALUs::push_back(SrsSample* sample) @@ -356,7 +349,6 @@ srs_error_t SrsRtpRawNALUs::read_samples(vector& samples, int packet srs_assert(nn > 0); SrsSample* sample = new SrsSample(); - extra_nalus.push_back(sample); samples.push_back(sample); sample->bytes = p->bytes + pos; diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index 53601d126..eb811ee29 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -135,8 +135,6 @@ public: class SrsRtpRawNALUs : public ISrsEncoder { private: - // The returned samples. - std::vector extra_nalus; // We will manage the samples, but the sample itself point to the shared memory. std::vector nalus; int nn_bytes; @@ -162,7 +160,7 @@ class SrsRtpSTAPPayload : public ISrsEncoder public: // The NRI in NALU type. SrsAvcNaluType nri; - // The NALU samples. + // The NALU samples, we will manage the samples. // @remark We only refer to the memory, user must free its bytes. std::vector nalus; public: @@ -185,7 +183,7 @@ public: bool start; bool end; SrsAvcNaluType nalu_type; - // The NALU samples. + // The NALU samples, we manage the samples. // @remark We only refer to the memory, user must free its bytes. std::vector nalus; public: From 6a4e0433498ef783ed7fca4168ea2b5d6d0d6791 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 19 Apr 2020 11:22:18 +0800 Subject: [PATCH 53/54] Fix the double free bug --- trunk/src/app/srs_app_rtc_conn.cpp | 2 -- trunk/src/kernel/srs_kernel_rtp.cpp | 13 ++++--------- trunk/src/kernel/srs_kernel_rtp.hpp | 1 - 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 401ecc01f..ffab0f6e5 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1212,8 +1212,6 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac packet->payload = raw; } else { - SrsAutoFree(SrsRtpRawNALUs, raw); - // Package NALUs in FU-A RTP packets. int fu_payload_size = kRtpMaxPayloadSize; diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index 0215cb1a6..a61b360a3 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -157,19 +157,19 @@ SrsRtpPacket2::SrsRtpPacket2() cache_raw = new SrsRtpRawPayload(); cache_fua = new SrsRtpFUAPayload2(); cache_payload = 0; - using_cache = false; } SrsRtpPacket2::~SrsRtpPacket2() { // We may use the cache as payload. - if (using_cache) { + if (payload == cache_raw || payload == cache_fua) { payload = NULL; } srs_freep(payload); srs_freep(extra_payload); srs_freep(cache_raw); + srs_freep(cache_fua); } void SrsRtpPacket2::set_padding(int size) @@ -198,25 +198,20 @@ void SrsRtpPacket2::reset() srs_freep(extra_payload); // We may use the cache as payload. - if (using_cache) { + if (payload == cache_raw || payload == cache_fua) { payload = NULL; - } else { - srs_freep(payload); } - - using_cache = false; + srs_freep(payload); } SrsRtpRawPayload* SrsRtpPacket2::reuse_raw() { - using_cache = true; payload = cache_raw; return cache_raw; } SrsRtpFUAPayload2* SrsRtpPacket2::reuse_fua() { - using_cache = true; payload = cache_fua; return cache_fua; } diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index eb811ee29..31b59ec85 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -92,7 +92,6 @@ public: private: SrsRtpRawPayload* cache_raw; SrsRtpFUAPayload2* cache_fua; - bool using_cache; int cache_payload; public: SrsRtpPacket2(); From 32879eaf477cbd01b6d397c1281e91f456e70939 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 19 Apr 2020 13:16:48 +0800 Subject: [PATCH 54/54] Fix double free bug for RTP --- trunk/src/app/srs_app_rtc_conn.cpp | 5 ++++- trunk/src/kernel/srs_kernel_rtp.cpp | 5 +---- trunk/src/kernel/srs_kernel_rtp.hpp | 5 ----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index ffab0f6e5..dd9a791b2 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1212,6 +1212,10 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac packet->payload = raw; } else { + // We must free it, should never use RTP packets to free it, + // because more than one RTP packet will refer to it. + SrsAutoFree(SrsRtpRawNALUs, raw); + // Package NALUs in FU-A RTP packets. int fu_payload_size = kRtpMaxPayloadSize; @@ -1229,7 +1233,6 @@ srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPac srs_freep(raw); return srs_error_new(ERROR_RTC_RTP_MUXER, "cache empty"); } - packet->extra_payload = raw; packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index a61b360a3..5c23cbd34 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -151,7 +151,6 @@ size_t SrsRtpHeader::header_size() SrsRtpPacket2::SrsRtpPacket2() { payload = NULL; - extra_payload = NULL; padding = 0; cache_raw = new SrsRtpRawPayload(); @@ -167,7 +166,6 @@ SrsRtpPacket2::~SrsRtpPacket2() } srs_freep(payload); - srs_freep(extra_payload); srs_freep(cache_raw); srs_freep(cache_fua); } @@ -195,7 +193,6 @@ void SrsRtpPacket2::reset() rtp_header.reset(); padding = 0; cache_payload = 0; - srs_freep(extra_payload); // We may use the cache as payload. if (payload == cache_raw || payload == cache_fua) { @@ -330,7 +327,7 @@ srs_error_t SrsRtpRawNALUs::read_samples(vector& samples, int packet int left = packet_size; int nn_nalus = (int)nalus.size(); - for (int i = 0; i < nn_nalus; i++) { + for (int i = 0; left > 0 && i < nn_nalus; i++) { SrsSample* p = nalus[i]; // Ignore previous consumed samples. diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index 31b59ec85..349c388a5 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -84,11 +84,6 @@ public: SrsRtpHeader rtp_header; ISrsEncoder* payload; int padding; -public: - // User can set an extra payload, we will free it. - // For example, when reassemble NALUs by SrsRtpRawNALUs, we can set the extra payload to - // SrsRtpRawNALUs, then we can use SrsRtpFUAPayload which never free samples. - ISrsEncoder* extra_payload; private: SrsRtpRawPayload* cache_raw; SrsRtpFUAPayload2* cache_fua;