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();