From 6b8f5f25bbf40a89aeab1f24b698484fba5ba030 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 19 Feb 2021 10:56:00 +0100 Subject: [PATCH 1/4] [core] Added SRTO_MININPUTBW socket option --- srtcore/core.cpp | 26 ++++++++--- srtcore/core.h | 2 +- srtcore/group.cpp | 3 +- srtcore/socketconfig.cpp | 97 ++++++++++++++++++++-------------------- srtcore/socketconfig.h | 29 +++++++++--- srtcore/srt.h | 1 + 6 files changed, 97 insertions(+), 61 deletions(-) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index fa21a3dcb..a2198e9d8 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -225,6 +225,7 @@ extern const SRT_SOCKOPT srt_post_opt_list [SRT_SOCKOPT_NPOST] = { SRTO_RCVTIMEO, SRTO_MAXBW, SRTO_INPUTBW, + SRTO_MININPUTBW, SRTO_OHEADBW, SRTO_SNDDROPDELAY, SRTO_CONNTIMEO, @@ -263,6 +264,7 @@ struct SrtOptionAction flags[SRTO_TSBPDMODE] = SRTO_R_PRE; flags[SRTO_LATENCY] = SRTO_R_PRE; flags[SRTO_INPUTBW] = 0 | SRTO_POST_SPEC; + flags[SRTO_MININPUTBW] = 0 | SRTO_POST_SPEC; flags[SRTO_OHEADBW] = 0 | SRTO_POST_SPEC; flags[SRTO_PASSPHRASE] = SRTO_R_PRE; flags[SRTO_PBKEYLEN] = SRTO_R_PRE; @@ -305,7 +307,7 @@ void CUDT::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); // Restriction check - int oflags = srt_options_action.flags[optName]; + const int oflags = srt_options_action.flags[optName]; ScopedLock cg (m_ConnectionLock); ScopedLock sendguard (m_SendLock); @@ -321,7 +323,7 @@ void CUDT::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) throw CUDTException(MJ_NOTSUP, MN_ISCONNECTED, 0); // Option execution. If this returns -1, there's no such option. - int status = m_config.set(optName, optval, optlen); + const int status = m_config.set(optName, optval, optlen); if (status == -1) { LOGC(aclog.Error, log << CONID() << "OPTION: #" << optName << " UNKNOWN"); @@ -338,6 +340,7 @@ void CUDT::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) break; case SRTO_INPUTBW: + case SRTO_MININPUTBW: updateCC(TEV_INIT, EventVariant(TEV_INIT_INPUTBW)); break; @@ -433,15 +436,26 @@ void CUDT::getOpt(SRT_SOCKOPT optName, void *optval, int &optlen) break; case SRTO_MAXBW: + if (optlen < sizeof(m_config.m_llMaxBW)) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); *(int64_t *)optval = m_config.m_llMaxBW; optlen = sizeof(int64_t); break; case SRTO_INPUTBW: + if (optlen < sizeof(m_config.m_llInputBW)) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); *(int64_t*)optval = m_config.m_llInputBW; - optlen = sizeof(int64_t); + optlen = sizeof(int64_t); break; + case SRTO_MININPUTBW: + if (optlen < sizeof (m_config.m_llMinInputBW)) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + *(int64_t*)optval = m_config.m_llMinInputBW; + optlen = sizeof(int64_t); + break; + case SRTO_OHEADBW: *(int32_t *)optval = m_config.m_iOverheadBW; optlen = sizeof(int32_t); @@ -7085,7 +7099,7 @@ bool CUDT::updateCC(ETransmissionEvent evt, const EventVariant arg) } else { - // No need to calculate input reate if the bandwidth is set + // No need to calculate input rate if the bandwidth is set const bool disable_in_rate_calc = (bw != 0); m_pSndBuffer->resetInputRateSmpPeriod(disable_in_rate_calc); } @@ -7116,8 +7130,8 @@ bool CUDT::updateCC(ETransmissionEvent evt, const EventVariant arg) * and sendrate skyrockets for retransmission. * Keep previously set maximum in that case (inputbw == 0). */ - if (inputbw != 0) - m_CongCtl->updateBandwidth(0, withOverhead(inputbw)); // Bytes/sec + if (inputbw >= 0) + m_CongCtl->updateBandwidth(0, withOverhead(std::max(m_config.m_llMinInputBW, inputbw))); // Bytes/sec } } diff --git a/srtcore/core.h b/srtcore/core.h index 6ed5d02e0..ac489eac0 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -116,7 +116,7 @@ enum AckDataItem }; const size_t ACKD_FIELD_SIZE = sizeof(int32_t); -static const size_t SRT_SOCKOPT_NPOST = 12; +static const size_t SRT_SOCKOPT_NPOST = 13; extern const SRT_SOCKOPT srt_post_opt_list []; enum GroupDataItem diff --git a/srtcore/group.cpp b/srtcore/group.cpp index 9faee8126..a967b146b 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -465,7 +465,7 @@ void CUDTGroup::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) { // There's at least one socket in the group, so only // post-options are allowed. - if (!std::binary_search(srt_post_opt_list, srt_post_opt_list + SRT_SOCKOPT_NPOST, optName)) + if (!binary_search(srt_post_opt_list, srt_post_opt_list + SRT_SOCKOPT_NPOST, optName)) { LOGC(gmlog.Error, log << "setsockopt(group): Group is connected, this option can't be altered"); throw CUDTException(MJ_NOTSUP, MN_ISCONNECTED, 0); @@ -567,6 +567,7 @@ void CUDTGroup::deriveSettings(CUDT* u) // Reuseaddr: true by default and should only be true. IM(SRTO_MAXBW, m_llMaxBW); IM(SRTO_INPUTBW, m_llInputBW); + IM(SRTO_MININPUTBW, m_llMinInputBW); IM(SRTO_OHEADBW, m_iOverheadBW); IM(SRTO_IPTOS, m_iIpToS); IM(SRTO_IPTTL, m_iIpTTL); diff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp index ace07c1e2..e50bb08f5 100644 --- a/srtcore/socketconfig.cpp +++ b/srtcore/socketconfig.cpp @@ -64,58 +64,59 @@ static struct SrtConfigSetter #define DISPATCH(optname) fn[optname] = &CSrtConfigSetter::set; - DISPATCH(SRTO_MSS); - DISPATCH(SRTO_FC); - DISPATCH(SRTO_SNDBUF); - DISPATCH(SRTO_RCVBUF); - DISPATCH(SRTO_LINGER); - DISPATCH(SRTO_UDP_SNDBUF); - DISPATCH(SRTO_UDP_RCVBUF); - DISPATCH(SRTO_RENDEZVOUS); - DISPATCH(SRTO_SNDTIMEO); - DISPATCH(SRTO_RCVTIMEO); - DISPATCH(SRTO_SNDSYN); - DISPATCH(SRTO_RCVSYN); - DISPATCH(SRTO_REUSEADDR); - DISPATCH(SRTO_MAXBW); - DISPATCH(SRTO_IPTTL); - DISPATCH(SRTO_IPTOS); - DISPATCH(SRTO_BINDTODEVICE); - DISPATCH(SRTO_INPUTBW); - DISPATCH(SRTO_OHEADBW); - DISPATCH(SRTO_SENDER); - DISPATCH(SRTO_TSBPDMODE); - DISPATCH(SRTO_LATENCY); - DISPATCH(SRTO_RCVLATENCY); - DISPATCH(SRTO_PEERLATENCY); - DISPATCH(SRTO_TLPKTDROP); - DISPATCH(SRTO_SNDDROPDELAY); - DISPATCH(SRTO_PASSPHRASE); - DISPATCH(SRTO_PBKEYLEN); - DISPATCH(SRTO_NAKREPORT); - DISPATCH(SRTO_CONNTIMEO); - DISPATCH(SRTO_DRIFTTRACER); - DISPATCH(SRTO_LOSSMAXTTL); - DISPATCH(SRTO_VERSION); - DISPATCH(SRTO_MINVERSION); - DISPATCH(SRTO_STREAMID); - DISPATCH(SRTO_CONGESTION); - DISPATCH(SRTO_MESSAGEAPI); - DISPATCH(SRTO_PAYLOADSIZE); - DISPATCH(SRTO_TRANSTYPE); + DISPATCH(SRTO_MSS); + DISPATCH(SRTO_FC); + DISPATCH(SRTO_SNDBUF); + DISPATCH(SRTO_RCVBUF); + DISPATCH(SRTO_LINGER); + DISPATCH(SRTO_UDP_SNDBUF); + DISPATCH(SRTO_UDP_RCVBUF); + DISPATCH(SRTO_RENDEZVOUS); + DISPATCH(SRTO_SNDTIMEO); + DISPATCH(SRTO_RCVTIMEO); + DISPATCH(SRTO_SNDSYN); + DISPATCH(SRTO_RCVSYN); + DISPATCH(SRTO_REUSEADDR); + DISPATCH(SRTO_MAXBW); + DISPATCH(SRTO_IPTTL); + DISPATCH(SRTO_IPTOS); + DISPATCH(SRTO_BINDTODEVICE); + DISPATCH(SRTO_INPUTBW); + DISPATCH(SRTO_MININPUTBW); + DISPATCH(SRTO_OHEADBW); + DISPATCH(SRTO_SENDER); + DISPATCH(SRTO_TSBPDMODE); + DISPATCH(SRTO_LATENCY); + DISPATCH(SRTO_RCVLATENCY); + DISPATCH(SRTO_PEERLATENCY); + DISPATCH(SRTO_TLPKTDROP); + DISPATCH(SRTO_SNDDROPDELAY); + DISPATCH(SRTO_PASSPHRASE); + DISPATCH(SRTO_PBKEYLEN); + DISPATCH(SRTO_NAKREPORT); + DISPATCH(SRTO_CONNTIMEO); + DISPATCH(SRTO_DRIFTTRACER); + DISPATCH(SRTO_LOSSMAXTTL); + DISPATCH(SRTO_VERSION); + DISPATCH(SRTO_MINVERSION); + DISPATCH(SRTO_STREAMID); + DISPATCH(SRTO_CONGESTION); + DISPATCH(SRTO_MESSAGEAPI); + DISPATCH(SRTO_PAYLOADSIZE); + DISPATCH(SRTO_TRANSTYPE); #if ENABLE_EXPERIMENTAL_BONDING - DISPATCH(SRTO_GROUPCONNECT); + DISPATCH(SRTO_GROUPCONNECT); #endif - DISPATCH(SRTO_KMREFRESHRATE); - DISPATCH(SRTO_KMPREANNOUNCE); - DISPATCH(SRTO_ENFORCEDENCRYPTION); - DISPATCH(SRTO_PEERIDLETIMEO); - DISPATCH(SRTO_IPV6ONLY); - DISPATCH(SRTO_PACKETFILTER); + DISPATCH(SRTO_KMREFRESHRATE); + DISPATCH(SRTO_KMPREANNOUNCE); + DISPATCH(SRTO_ENFORCEDENCRYPTION); + DISPATCH(SRTO_PEERIDLETIMEO); + DISPATCH(SRTO_IPV6ONLY); + DISPATCH(SRTO_PACKETFILTER); #if ENABLE_EXPERIMENTAL_BONDING - DISPATCH(SRTO_GROUPSTABTIMEO); + DISPATCH(SRTO_GROUPSTABTIMEO); #endif - DISPATCH(SRTO_RETRANSMITALGO); + DISPATCH(SRTO_RETRANSMITALGO); #undef DISPATCH } diff --git a/srtcore/socketconfig.h b/srtcore/socketconfig.h index eaff48dec..c415d6ae2 100644 --- a/srtcore/socketconfig.h +++ b/srtcore/socketconfig.h @@ -247,8 +247,8 @@ struct CSrtConfig: CSrtMuxerConfig uint32_t m_uStabilityTimeout; int m_iRetransmitAlgo; - int64_t m_llInputBW; // Input stream rate (bytes/sec) - // 0: use internally estimated input bandwidth + int64_t m_llInputBW; // Input stream rate (bytes/sec). 0: use internally estimated input bandwidth + int64_t m_llMinInputBW; // Minimum input stream rate estimate (bytes/sec) int m_iOverheadBW; // Percent above input stream rate (applies if m_llMaxBW == 0) bool m_bRcvNakReport; // Enable Receiver Periodic NAK Reports int m_iMaxReorderTolerance; //< Maximum allowed value for dynamic reorder tolerance @@ -298,6 +298,7 @@ struct CSrtConfig: CSrtMuxerConfig , m_uStabilityTimeout(COMM_DEF_STABILITY_TIMEOUT_US) , m_iRetransmitAlgo(0) , m_llInputBW(0) + , m_llMinInputBW(0) , m_iOverheadBW(25) , m_bRcvNakReport(true) , m_iMaxReorderTolerance(0) // Sensible optimal value is 10, 0 preserves old behavior @@ -559,7 +560,11 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - co.m_llMaxBW = cast_optval(optval, optlen); + const int64_t val = cast_optval(optval, optlen); + if (val < -1) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.m_llMaxBW = val; } }; @@ -620,7 +625,21 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - co.m_llInputBW = cast_optval(optval, optlen); + const int64_t val = cast_optval(optval, optlen); + if (val < 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + co.m_llInputBW = val; + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int64_t val = cast_optval(optval, optlen); + if (val < 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + co.m_llMinInputBW = val; } }; template<> @@ -628,7 +647,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - int32_t val = cast_optval(optval, optlen); + const int32_t val = cast_optval(optval, optlen); if (val < 5 || val > 100) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); co.m_iOverheadBW = val; diff --git a/srtcore/srt.h b/srtcore/srt.h index db392470a..f9fa24655 100644 --- a/srtcore/srt.h +++ b/srtcore/srt.h @@ -222,6 +222,7 @@ typedef enum SRT_SOCKOPT { SRTO_PEERVERSION, // Peer SRT Version (from SRT Handshake) SRTO_CONNTIMEO = 36, // Connect timeout in msec. Caller default: 3000, rendezvous (x 10) SRTO_DRIFTTRACER = 37, // Enable or disable drift tracer + SRTO_MININPUTBW = 38, // Minimum estimate of input stream rate. // (some space left) SRTO_SNDKMSTATE = 40, // (GET) the current state of the encryption at the peer side SRTO_RCVKMSTATE, // (GET) the current state of the encryption at the agent side From ea37146e37e54790c932b9d0c0d9b0f070a709f6 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 19 Feb 2021 10:56:33 +0100 Subject: [PATCH 2/4] [apps] Added mininputbw URI query parameter --- apps/socketoptions.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/socketoptions.hpp b/apps/socketoptions.hpp index 6f6305b4c..6e26b3520 100644 --- a/apps/socketoptions.hpp +++ b/apps/socketoptions.hpp @@ -224,6 +224,7 @@ const SocketOption srt_options [] { { "ipttl", 0, SRTO_IPTTL, SocketOption::PRE, SocketOption::INT, nullptr}, { "iptos", 0, SRTO_IPTOS, SocketOption::PRE, SocketOption::INT, nullptr}, { "inputbw", 0, SRTO_INPUTBW, SocketOption::POST, SocketOption::INT64, nullptr}, + { "mininputbw", 0, SRTO_MININPUTBW, SocketOption::POST, SocketOption::INT64, nullptr}, { "oheadbw", 0, SRTO_OHEADBW, SocketOption::POST, SocketOption::INT, nullptr}, { "latency", 0, SRTO_LATENCY, SocketOption::PRE, SocketOption::INT, nullptr}, { "tsbpdmode", 0, SRTO_TSBPDMODE, SocketOption::PRE, SocketOption::BOOL, nullptr}, From bb25a02ceb392f85d0bbfa20b3ccc26f12057d97 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 19 Feb 2021 10:56:51 +0100 Subject: [PATCH 3/4] [tests] Added tests for SRTO_MININPUTBW --- test/test_socket_options.cpp | 173 ++++++++++++++++++++++++++++++----- 1 file changed, 149 insertions(+), 24 deletions(-) diff --git a/test/test_socket_options.cpp b/test/test_socket_options.cpp index 705db5a09..a94d18eec 100644 --- a/test/test_socket_options.cpp +++ b/test/test_socket_options.cpp @@ -33,6 +33,36 @@ class TestSocketOptions // cleanup any pending stuff, but no exceptions allowed } +public: + void StartListener() + { + // Specify address of the listener + sockaddr* psa = (sockaddr*)&m_sa; + ASSERT_NE(srt_bind(m_listen_sock, psa, sizeof m_sa), SRT_ERROR); + + srt_listen(m_listen_sock, 1); + } + + SRTSOCKET EstablishConnection() + { + auto accept_async = [](SRTSOCKET listen_sock) { + sockaddr_in client_address; + int length = sizeof(sockaddr_in); + const SRTSOCKET accepted_socket = srt_accept(listen_sock, (sockaddr*)&client_address, &length); + return accepted_socket; + }; + auto accept_res = async(launch::async, accept_async, m_listen_sock); + + sockaddr* psa = (sockaddr*)&m_sa; + const int connect_res = srt_connect(m_caller_sock, psa, sizeof m_sa); + EXPECT_EQ(connect_res, SRT_SUCCESS); + + const SRTSOCKET accepted_sock = accept_res.get(); + EXPECT_NE(accepted_sock, SRT_INVALID_SOCK); + + return accepted_sock; + } + protected: // SetUp() is run immediately before a test starts. void SetUp() @@ -40,6 +70,11 @@ class TestSocketOptions ASSERT_GE(srt_startup(), 0); const int yes = 1; + memset(&m_sa, 0, sizeof m_sa); + m_sa.sin_family = AF_INET; + m_sa.sin_port = htons(5200); + ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &m_sa.sin_addr), 1); + m_caller_sock = srt_create_socket(); ASSERT_NE(m_caller_sock, SRT_INVALID_SOCK); ASSERT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_RCVSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect @@ -63,6 +98,7 @@ class TestSocketOptions protected: // put in any custom data members that you need + sockaddr_in m_sa; SRTSOCKET m_caller_sock = SRT_INVALID_SOCK; SRTSOCKET m_listen_sock = SRT_INVALID_SOCK; @@ -78,30 +114,8 @@ TEST_F(TestSocketOptions, LossMaxTTL) const int loss_max_ttl = 5; ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_LOSSMAXTTL, &loss_max_ttl, sizeof loss_max_ttl), SRT_SUCCESS); - // Specify address - sockaddr_in sa; - memset(&sa, 0, sizeof sa); - sa.sin_family = AF_INET; - sa.sin_port = htons(5200); - ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr), 1); - sockaddr* psa = (sockaddr*)&sa; - ASSERT_NE(srt_bind(m_listen_sock, psa, sizeof sa), SRT_ERROR); - - srt_listen(m_listen_sock, 1); - - auto accept_async = [](SRTSOCKET listen_sock) { - sockaddr_in client_address; - int length = sizeof(sockaddr_in); - const SRTSOCKET accepted_socket = srt_accept(listen_sock, (sockaddr*)&client_address, &length); - return accepted_socket; - }; - auto accept_res = async(launch::async, accept_async, m_listen_sock); - - const int connect_res = srt_connect(m_caller_sock, psa, sizeof sa); - EXPECT_EQ(connect_res, SRT_SUCCESS); - - const SRTSOCKET accepted_sock = accept_res.get(); - ASSERT_NE(accepted_sock, SRT_INVALID_SOCK); + StartListener(); + const SRTSOCKET accepted_sock = EstablishConnection(); int opt_val = 0; int opt_len = 0; @@ -121,3 +135,114 @@ TEST_F(TestSocketOptions, LossMaxTTL) } +// Try to set/get SRTO_MININPUTBW with wrong optlen +TEST_F(TestSocketOptions, MinInputBWWrongLen) +{ + int64_t mininputbw = 0; + int optlen = (int)(sizeof mininputbw) - 1; + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_ERROR); + EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM); + optlen += 2; + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_SUCCESS) << "Bigger storage is allowed"; + EXPECT_EQ(optlen, (int)(sizeof mininputbw)); + + EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, sizeof mininputbw - 1), SRT_ERROR); + EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM); + EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, sizeof mininputbw + 1), SRT_ERROR); + EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM); +} + +// Check the default SRTO_MININPUTBW is SRT_PACING_MAXBW_DEFAULT +TEST_F(TestSocketOptions, MinInputBWDefault) +{ + const int mininputbw_expected = 0; + int64_t mininputbw = 1; + int optlen = (int)(sizeof mininputbw); + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_SUCCESS); + EXPECT_EQ(optlen, (int)(sizeof mininputbw)); + EXPECT_EQ(mininputbw, mininputbw_expected); + + StartListener(); + const SRTSOCKET accepted_sock = EstablishConnection(); + + // Check both listener and accepted socket have default values + for (SRTSOCKET sock : { m_listen_sock, accepted_sock }) + { + optlen = (int)(sizeof mininputbw); + EXPECT_EQ(srt_getsockopt(sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_SUCCESS); + EXPECT_EQ(optlen, (int)(sizeof mininputbw)); + EXPECT_EQ(mininputbw, mininputbw_expected); + } + + ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); +} + +// Check setting and getting SRT_MININPUTBW +TEST_F(TestSocketOptions, MinInputBWSet) +{ + const int64_t mininputbw_dflt = 0; + const int64_t mininputbw = 50000000; + int optlen = (int)(sizeof mininputbw); + + int64_t bw = -100; + EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_ERROR) << "Has to be a non-negative number"; + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, mininputbw_dflt); + + bw = mininputbw; + EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_SUCCESS); + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, mininputbw); + + StartListener(); + const SRTSOCKET accepted_sock = EstablishConnection(); + + // Check accepted socket inherits values + for (SRTSOCKET sock : { m_listen_sock, accepted_sock }) + { + optlen = (int)(sizeof bw); + EXPECT_EQ(srt_getsockopt(sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(optlen, (int)(sizeof bw)); + EXPECT_EQ(bw, mininputbw); + } + + ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); +} + +// Check setting and getting SRTO_MININPUTBW in runtime +TEST_F(TestSocketOptions, MinInputBWRuntime) +{ + const int64_t mininputbw = 50000000; + + // Establish a connection + StartListener(); + const SRTSOCKET accepted_sock = EstablishConnection(); + + // Test a connected socket + int64_t bw = mininputbw; + int optlen = (int)(sizeof bw); + EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_SUCCESS); + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, mininputbw); + + bw = 0; + EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_INPUTBW, &bw, sizeof bw), SRT_SUCCESS); + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_INPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, 0); + + EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_MAXBW, &bw, sizeof bw), SRT_SUCCESS); + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MAXBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, 0); + + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, mininputbw); + + const int64_t new_mininputbw = 20000000; + bw = new_mininputbw; + EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_SUCCESS); + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, new_mininputbw); + + ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); +} + From 99862bd45780ee89f1fff20281b0d2678a8198f6 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 19 Feb 2021 10:57:15 +0100 Subject: [PATCH 4/4] [docs] Added SRTO_MININPUTBW to the docs --- docs/APISocketOptions.md | 23 ++++++++++++++++++++--- docs/srt-live-transmit.md | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/APISocketOptions.md b/docs/APISocketOptions.md index aa34f4fb4..780b92228 100644 --- a/docs/APISocketOptions.md +++ b/docs/APISocketOptions.md @@ -211,6 +211,7 @@ The following table lists SRT socket options in alphabetical order. Option detai | [`SRTO_GROUPSTABTIMEO`](#SRTO_GROUPSTABTIMEO) | 1.5.0 | pre | `int32_t` | ms | 80 | 10-... | W | GSD+ | | [`SRTO_GROUPTYPE`](#SRTO_GROUPTYPE) | 1.5.0 | | `int32_t` | enum | | | R | S | | [`SRTO_INPUTBW`](#SRTO_INPUTBW) | 1.0.5 | post | `int64_t` | B/s | 0 | 0.. | RW | GSD | +| [`SRTO_MININPUTBW`](#SRTO_MININPUTBW) | 1.4.3 | post | `int64_t` | B/s | 0 | 0.. | RW | GSD | | [`SRTO_IPTOS`](#SRTO_IPTOS) | 1.0.5 | pre-bind | `int32_t` | | (system) | 0..255 | RW | GSD | | [`SRTO_IPTTL`](#SRTO_IPTTL) | 1.0.5 | pre-bind | `int32_t` | hops | (system) | 1..255 | RW | GSD | | [`SRTO_IPV6ONLY`](#SRTO_IPV6ONLY) | 1.4.0 | pre-bind | `int32_t` | | (system) | -1..1 | RW | GSD | @@ -501,12 +502,13 @@ context than inside the listener callback handler, the value is undefined. | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_INPUTBW` | 1.0.5 | post | `int64_t` | B/s | 0 | 0.. | RW | GSD | -This option is effective only if `SRTO_MAXBW` is set to 0 (relative). It -controls the maximum bandwidth together with `SRTO_OHEADBW` option according +This option is effective only if [`SRTO_MAXBW`](#SRTO_MAXBW) is set to 0 (relative). It +controls the maximum bandwidth together with [`SRTO_OHEADBW`](#SRTO_OHEADBW) option according to the formula: `MAXBW = INPUTBW * (100 + OHEADBW) / 100`. When this option is set to 0 (automatic) then the real INPUTBW value will be estimated from the rate of the input (cases when the application calls the `srt_send*` -function) during transmission. +function) during transmission. The minimum allowed estimate value is restricted +by [`SRTO_MININPUTBW`](#SRTO_MININPUTBW), meaning `INPUTBW = MAX(INPUTBW_ESTIMATE; MININPUTBW)`. *Recommended: set this option to the anticipated bitrate of your live stream and keep the default 25% value for `SRTO_OHEADBW`*. @@ -515,6 +517,21 @@ and keep the default 25% value for `SRTO_OHEADBW`*. --- +#### SRTO_MININPUTBW + +| OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | +| ----------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | +| `SRTO_MININPUTBW` | 1.4.3 | post | `int64_t` | B/s | 0 | 0.. | RW | GSD | + +This option is effective only if both `SRTO_MAXBW` and `SRTO_INPUTBW` are set to 0. +It controls the minimum allowed value of the input butrate estimate. + +See [`SRTO_INPUTBW`](#SRTO_INPUTBW). + +[Return to list](#list-of-options) + +--- + #### SRTO_IPTOS | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | diff --git a/docs/srt-live-transmit.md b/docs/srt-live-transmit.md index 0a2dfb02d..a124c631c 100644 --- a/docs/srt-live-transmit.md +++ b/docs/srt-live-transmit.md @@ -307,6 +307,7 @@ All other parameters are SRT socket options. The following have the following va | `linger` | 0.. | `SRTO_LINGER` | Link linger value | | `lossmaxttl` | 0.. | `SRTO_LOSSMAXTTL` | Packet reorder tolerance. | | `maxbw` | 0.. | `SRTO_MAXBW` | Bandwidth limit in bytes | +| `mininputbw` | 0.. | `SRTO_MININPUTBW` | Minimum allowed estimate of `SRTO_INPUTBW` | | `messageapi` | `bool` | `SRTO_MESSAGEAPI` | Enable SRT message mode. | | `minversion` | maj.min.rev | `SRTO_MINVERSION` | Minimum SRT library version of a peer. | | `mss` | 76.. | `SRTO_MSS` | MTU size |