mediasoup 3.26.0 → 3.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/node/lib/DataConsumer.js +1 -1
  3. package/node/lib/Router.js +1 -1
  4. package/node/lib/Transport.js +15 -15
  5. package/node/lib/fbs/rtp-parameters/encoding-mapping.d.ts +2 -6
  6. package/node/lib/fbs/rtp-parameters/encoding-mapping.d.ts.map +1 -1
  7. package/node/lib/fbs/rtp-parameters/encoding-mapping.js +7 -19
  8. package/node/lib/fbs/rtp-parameters/rtp-encoding-parameters.d.ts +4 -4
  9. package/node/lib/fbs/rtp-parameters/rtp-encoding-parameters.js +2 -2
  10. package/node/lib/fbs/rtp-stream/bitrate-by-layer.d.ts +5 -5
  11. package/node/lib/fbs/rtp-stream/bitrate-by-layer.d.ts.map +1 -1
  12. package/node/lib/fbs/rtp-stream/bitrate-by-layer.js +3 -3
  13. package/node/lib/fbs/rtp-stream/recv-stats.d.ts +5 -5
  14. package/node/lib/fbs/rtp-stream/recv-stats.d.ts.map +1 -1
  15. package/node/lib/fbs/rtp-stream/recv-stats.js +3 -3
  16. package/node/lib/fbs/rtp-stream/send-stats.d.ts +5 -5
  17. package/node/lib/fbs/rtp-stream/send-stats.d.ts.map +1 -1
  18. package/node/lib/fbs/rtp-stream/send-stats.js +3 -3
  19. package/node/lib/fbs/transport/bwe-trace-info.d.ts +23 -23
  20. package/node/lib/fbs/transport/bwe-trace-info.d.ts.map +1 -1
  21. package/node/lib/fbs/transport/bwe-trace-info.js +15 -15
  22. package/node/lib/fbs/transport/options.d.ts +5 -5
  23. package/node/lib/fbs/transport/options.js +2 -2
  24. package/node/lib/fbs/transport/set-max-incoming-bitrate-request.d.ts +5 -5
  25. package/node/lib/fbs/transport/set-max-incoming-bitrate-request.d.ts.map +1 -1
  26. package/node/lib/fbs/transport/set-max-incoming-bitrate-request.js +3 -3
  27. package/node/lib/fbs/transport/set-max-outgoing-bitrate-request.d.ts +5 -5
  28. package/node/lib/fbs/transport/set-max-outgoing-bitrate-request.d.ts.map +1 -1
  29. package/node/lib/fbs/transport/set-max-outgoing-bitrate-request.js +3 -3
  30. package/node/lib/fbs/transport/set-min-outgoing-bitrate-request.d.ts +5 -5
  31. package/node/lib/fbs/transport/set-min-outgoing-bitrate-request.d.ts.map +1 -1
  32. package/node/lib/fbs/transport/set-min-outgoing-bitrate-request.js +3 -3
  33. package/node/lib/fbs/transport/stats.d.ts +38 -38
  34. package/node/lib/fbs/transport/stats.d.ts.map +1 -1
  35. package/node/lib/fbs/transport/stats.js +25 -25
  36. package/node/lib/ortc.d.ts +0 -1
  37. package/node/lib/ortc.d.ts.map +1 -1
  38. package/node/lib/ortc.js +1 -2
  39. package/node/lib/rtpParametersFbsUtils.d.ts.map +1 -1
  40. package/node/lib/rtpParametersFbsUtils.js +2 -2
  41. package/package.json +9 -9
  42. package/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send.cc +10 -10
  43. package/worker/deps/libwebrtc/libwebrtc/mediasoup_helpers.h +6 -6
  44. package/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/alr_detector.cc +1 -1
  45. package/worker/deps/libwebrtc/libwebrtc/modules/pacing/paced_sender.cc +7 -7
  46. package/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h +1 -1
  47. package/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc +1 -1
  48. package/worker/fbs/FBS/meson.build +25 -0
  49. package/worker/fbs/meson.build +15 -18
  50. package/worker/fbs/rtpParameters.fbs +1 -2
  51. package/worker/fbs/rtpStream.fbs +3 -3
  52. package/worker/fbs/transport.fbs +23 -23
  53. package/worker/fuzzer/include/RTC/FuzzerDtlsTransport.hpp +4 -1
  54. package/worker/fuzzer/src/FuzzerUtils.cpp +5 -3
  55. package/worker/fuzzer/src/RTC/FuzzerDtlsTransport.cpp +8 -5
  56. package/worker/fuzzer/src/RTC/FuzzerRateCalculator.cpp +3 -3
  57. package/worker/fuzzer/src/RTC/FuzzerTrendCalculator.cpp +6 -6
  58. package/worker/fuzzer/src/RTC/RTCP/FuzzerFeedbackRtpTransport.cpp +3 -3
  59. package/worker/fuzzer/src/RTC/RTP/FuzzerPacket.cpp +2 -2
  60. package/worker/fuzzer/src/RTC/RTP/FuzzerRetransmissionBuffer.cpp +5 -5
  61. package/worker/fuzzer/src/RTC/RTP/FuzzerRtpStreamSend.cpp +3 -3
  62. package/worker/fuzzer/src/fuzzer.cpp +4 -0
  63. package/worker/include/Channel/ChannelNotification.hpp +3 -3
  64. package/worker/include/Channel/ChannelRequest.hpp +1 -1
  65. package/worker/include/Channel/ChannelSocket.hpp +11 -0
  66. package/worker/include/DepLibUV.hpp +16 -33
  67. package/worker/include/RTC/ActiveSpeakerObserver.hpp +11 -11
  68. package/worker/include/RTC/AudioLevelObserver.hpp +4 -4
  69. package/worker/include/RTC/BWE/AcknowledgedBitrateEstimatorInterface.hpp +55 -0
  70. package/worker/include/RTC/BWE/AimdRateControl.hpp +190 -0
  71. package/worker/include/RTC/BWE/BweTypes.hpp +211 -0
  72. package/worker/include/RTC/BWE/DelayBasedBwe.hpp +173 -0
  73. package/worker/include/RTC/BWE/FeedbackAdapter.hpp +72 -0
  74. package/worker/include/RTC/BWE/InterArrivalDelta.hpp +106 -0
  75. package/worker/include/RTC/BWE/LinkCapacityEstimator.hpp +84 -0
  76. package/worker/include/RTC/BWE/LossBasedController.hpp +520 -0
  77. package/worker/include/RTC/BWE/RobustThroughputEstimator.hpp +94 -0
  78. package/worker/include/RTC/BWE/SendPacketHistory.hpp +137 -0
  79. package/worker/include/RTC/BWE/TargetRateController.hpp +306 -0
  80. package/worker/include/RTC/BWE/TrendlineEstimator.hpp +143 -0
  81. package/worker/include/RTC/BWE/Utils.hpp +39 -0
  82. package/worker/include/RTC/Consts.hpp +6 -6
  83. package/worker/include/RTC/Consumer.hpp +14 -12
  84. package/worker/include/RTC/DataConsumer.hpp +3 -3
  85. package/worker/include/RTC/DataProducer.hpp +3 -3
  86. package/worker/include/RTC/DtlsTransport.hpp +5 -2
  87. package/worker/include/RTC/ICE/IceCandidate.hpp +2 -2
  88. package/worker/include/RTC/ICE/IceServer.hpp +3 -3
  89. package/worker/include/RTC/KeyFrameRequestManager.hpp +3 -3
  90. package/worker/include/RTC/NEW_RTCP/packet/Packet.hpp +1 -1
  91. package/worker/include/RTC/NackGenerator.hpp +12 -12
  92. package/worker/include/RTC/PipeProducerStreamManager.hpp +3 -4
  93. package/worker/include/RTC/PipeTransport.hpp +18 -5
  94. package/worker/include/RTC/PlainTransport.hpp +18 -5
  95. package/worker/include/RTC/PortManager.hpp +4 -4
  96. package/worker/include/RTC/Producer.hpp +21 -12
  97. package/worker/include/RTC/ProducerStreamManager.hpp +12 -6
  98. package/worker/include/RTC/RTCP/Bye.hpp +2 -2
  99. package/worker/include/RTC/RTCP/FeedbackPsRemb.hpp +4 -4
  100. package/worker/include/RTC/RTCP/FeedbackRtpTmmb.hpp +3 -3
  101. package/worker/include/RTC/RTCP/FeedbackRtpTransport.hpp +54 -39
  102. package/worker/include/RTC/RTCP/Packet.hpp +3 -3
  103. package/worker/include/RTC/RTCP/ReceiverReport.hpp +3 -3
  104. package/worker/include/RTC/RTCP/Sdes.hpp +2 -2
  105. package/worker/include/RTC/RTCP/XR.hpp +2 -2
  106. package/worker/include/RTC/RTCP/XrDelaySinceLastRr.hpp +1 -1
  107. package/worker/include/RTC/RTP/Codecs/H264.hpp +1 -1
  108. package/worker/include/RTC/RTP/Codecs/Opus.hpp +2 -2
  109. package/worker/include/RTC/RTP/Codecs/PayloadDescriptorHandler.hpp +3 -3
  110. package/worker/include/RTC/RTP/Codecs/VP8.hpp +2 -2
  111. package/worker/include/RTC/RTP/Codecs/VP9.hpp +2 -2
  112. package/worker/include/RTC/RTP/HeaderExtensionIds.hpp +12 -12
  113. package/worker/include/RTC/RTP/Packet.hpp +13 -13
  114. package/worker/include/RTC/RTP/ProbationGenerator.hpp +1 -1
  115. package/worker/include/RTC/RTP/RetransmissionBuffer.hpp +7 -7
  116. package/worker/include/RTC/RTP/RtpStream.hpp +37 -51
  117. package/worker/include/RTC/RTP/RtpStreamRecv.hpp +59 -41
  118. package/worker/include/RTC/RTP/RtpStreamSend.hpp +20 -14
  119. package/worker/include/RTC/RTP/RtxStream.hpp +12 -13
  120. package/worker/include/RTC/RateCalculator.hpp +50 -44
  121. package/worker/include/RTC/RemoteCaptureTimeEstimator.hpp +5 -4
  122. package/worker/include/RTC/RemoteClockOffsetEstimator.hpp +11 -11
  123. package/worker/include/RTC/Router.hpp +6 -0
  124. package/worker/include/RTC/RtcLogger.hpp +1 -1
  125. package/worker/include/RTC/RtpDictionaries.hpp +10 -10
  126. package/worker/include/RTC/SCTP/association/Association.hpp +56 -28
  127. package/worker/include/RTC/SCTP/association/HeartbeatHandler.hpp +4 -4
  128. package/worker/include/RTC/SCTP/association/StateCookie.hpp +14 -14
  129. package/worker/include/RTC/SCTP/association/StreamResetHandler.hpp +38 -2
  130. package/worker/include/RTC/SCTP/association/TransmissionControlBlock.hpp +12 -12
  131. package/worker/include/RTC/SCTP/association/TransmissionControlBlockContextInterface.hpp +4 -4
  132. package/worker/include/RTC/SCTP/packet/TLV.hpp +1 -1
  133. package/worker/include/RTC/SCTP/packet/parameters/StateCookieParameter.hpp +3 -3
  134. package/worker/include/RTC/SCTP/public/AssociationInterface.hpp +4 -1
  135. package/worker/include/RTC/SCTP/public/AssociationMetrics.hpp +1 -1
  136. package/worker/include/RTC/SCTP/public/SctpOptions.hpp +12 -12
  137. package/worker/include/RTC/SCTP/public/SctpTypes.hpp +6 -6
  138. package/worker/include/RTC/SCTP/rx/ReassemblyQueue.hpp +10 -0
  139. package/worker/include/RTC/SCTP/tx/OutstandingData.hpp +15 -16
  140. package/worker/include/RTC/SCTP/tx/RetransmissionQueue.hpp +7 -8
  141. package/worker/include/RTC/SCTP/tx/RetransmissionTimeout.hpp +20 -16
  142. package/worker/include/RTC/SCTP/tx/RoundRobinSendQueue.hpp +5 -6
  143. package/worker/include/RTC/SCTP/tx/SendQueueInterface.hpp +2 -2
  144. package/worker/include/RTC/SCTP/tx/StreamScheduler.hpp +5 -5
  145. package/worker/include/RTC/SctpDictionaries.hpp +3 -3
  146. package/worker/include/RTC/Serializable.hpp +1 -1
  147. package/worker/include/RTC/SimpleProducerStreamManager.hpp +3 -4
  148. package/worker/include/RTC/SimulcastProducerStreamManager.hpp +6 -7
  149. package/worker/include/RTC/SvcProducerStreamManager.hpp +6 -5
  150. package/worker/include/RTC/TcpConnection.hpp +9 -3
  151. package/worker/include/RTC/TcpServer.hpp +3 -0
  152. package/worker/include/RTC/Transport.hpp +52 -45
  153. package/worker/include/RTC/TransportCongestionControlClient.hpp +30 -25
  154. package/worker/include/RTC/TransportCongestionControlServer.hpp +17 -17
  155. package/worker/include/RTC/TrendCalculator.hpp +5 -5
  156. package/worker/include/RTC/UdpSocket.hpp +11 -2
  157. package/worker/include/RTC/WebRtcServer.hpp +20 -5
  158. package/worker/include/RTC/WebRtcTransport.hpp +35 -10
  159. package/worker/include/Settings.hpp +4 -2
  160. package/worker/include/Shared.hpp +5 -20
  161. package/worker/include/SharedInterface.hpp +6 -28
  162. package/worker/include/Utils.hpp +40 -21
  163. package/worker/include/common.hpp +4 -0
  164. package/worker/include/handles/BackoffTimerHandle.hpp +4 -4
  165. package/worker/include/handles/BackoffTimerHandleInterface.hpp +5 -5
  166. package/worker/include/handles/TcpConnectionHandle.hpp +6 -6
  167. package/worker/include/handles/TcpServerHandle.hpp +1 -1
  168. package/worker/include/handles/TimerHandle.hpp +15 -9
  169. package/worker/include/handles/TimerHandleInterface.hpp +10 -4
  170. package/worker/include/handles/UdpSocketHandle.hpp +3 -3
  171. package/worker/include/handles/UnixStreamSocketHandle.hpp +2 -2
  172. package/worker/meson.build +87 -36
  173. package/worker/meson_options.txt +1 -0
  174. package/worker/mocks/include/MockShared.hpp +24 -23
  175. package/worker/mocks/include/RTC/SCTP/association/MockTransmissionControlBlockContext.hpp +51 -27
  176. package/worker/mocks/include/RTC/SCTP/tx/MockSendQueue.hpp +11 -11
  177. package/worker/mocks/include/handles/MockBackoffTimerHandle.hpp +10 -10
  178. package/worker/mocks/include/handles/MockTimerHandle.hpp +60 -22
  179. package/worker/mocks/src/MockShared.cpp +51 -5
  180. package/worker/mocks/src/handles/MockBackoffTimerHandle.cpp +29 -15
  181. package/worker/mocks/src/handles/MockTimerHandle.cpp +117 -0
  182. package/worker/scripts/clang-scripts.mjs +2 -2
  183. package/worker/src/Channel/ChannelNotification.cpp +5 -6
  184. package/worker/src/Channel/ChannelSocket.cpp +20 -2
  185. package/worker/src/DepLibUV.cpp +4 -5
  186. package/worker/src/RTC/ActiveSpeakerObserver.cpp +59 -47
  187. package/worker/src/RTC/AudioLevelObserver.cpp +7 -7
  188. package/worker/src/RTC/BWE/AimdRateControl.cpp +468 -0
  189. package/worker/src/RTC/BWE/BweTypes.cpp +61 -0
  190. package/worker/src/RTC/BWE/DelayBasedBwe.cpp +275 -0
  191. package/worker/src/RTC/BWE/FeedbackAdapter.cpp +148 -0
  192. package/worker/src/RTC/BWE/InterArrivalDelta.cpp +181 -0
  193. package/worker/src/RTC/BWE/LinkCapacityEstimator.cpp +133 -0
  194. package/worker/src/RTC/BWE/LossBasedController.cpp +1046 -0
  195. package/worker/src/RTC/BWE/RobustThroughputEstimator.cpp +245 -0
  196. package/worker/src/RTC/BWE/SendPacketHistory.cpp +184 -0
  197. package/worker/src/RTC/BWE/TargetRateController.cpp +435 -0
  198. package/worker/src/RTC/BWE/TrendlineEstimator.cpp +311 -0
  199. package/worker/src/RTC/BWE/Utils.cpp +54 -0
  200. package/worker/src/RTC/Consumer.cpp +48 -35
  201. package/worker/src/RTC/DataConsumer.cpp +4 -4
  202. package/worker/src/RTC/DataProducer.cpp +3 -3
  203. package/worker/src/RTC/DirectTransport.cpp +2 -2
  204. package/worker/src/RTC/DtlsTransport.cpp +14 -11
  205. package/worker/src/RTC/ICE/IceServer.cpp +2 -2
  206. package/worker/src/RTC/KeyFrameRequestManager.cpp +16 -12
  207. package/worker/src/RTC/NackGenerator.cpp +12 -12
  208. package/worker/src/RTC/PipeProducerStreamManager.cpp +6 -6
  209. package/worker/src/RTC/PipeTransport.cpp +16 -13
  210. package/worker/src/RTC/PlainTransport.cpp +25 -16
  211. package/worker/src/RTC/Producer.cpp +50 -36
  212. package/worker/src/RTC/RTCP/FeedbackPsRemb.cpp +13 -6
  213. package/worker/src/RTC/RTCP/FeedbackRtpTmmb.cpp +14 -5
  214. package/worker/src/RTC/RTCP/FeedbackRtpTransport.cpp +76 -50
  215. package/worker/src/RTC/RTP/Codecs/VP8.cpp +1 -1
  216. package/worker/src/RTC/RTP/Codecs/VP9.cpp +4 -4
  217. package/worker/src/RTC/RTP/Packet.cpp +9 -10
  218. package/worker/src/RTC/RTP/RetransmissionBuffer.cpp +6 -6
  219. package/worker/src/RTC/RTP/RtpStream.cpp +19 -19
  220. package/worker/src/RTC/RTP/RtpStreamRecv.cpp +146 -81
  221. package/worker/src/RTC/RTP/RtpStreamSend.cpp +49 -44
  222. package/worker/src/RTC/RTP/RtxStream.cpp +7 -10
  223. package/worker/src/RTC/RateCalculator.cpp +99 -136
  224. package/worker/src/RTC/RemoteCaptureTimeEstimator.cpp +13 -13
  225. package/worker/src/RTC/RemoteClockOffsetEstimator.cpp +18 -17
  226. package/worker/src/RTC/Router.cpp +18 -1
  227. package/worker/src/RTC/RtpDictionaries/RtpEncodingParameters.cpp +5 -2
  228. package/worker/src/RTC/SCTP/association/Association.cpp +146 -103
  229. package/worker/src/RTC/SCTP/association/AssociationListenerDeferrer.cpp +4 -4
  230. package/worker/src/RTC/SCTP/association/Capabilities.cpp +1 -1
  231. package/worker/src/RTC/SCTP/association/HeartbeatHandler.cpp +25 -18
  232. package/worker/src/RTC/SCTP/association/StateCookie.cpp +7 -6
  233. package/worker/src/RTC/SCTP/association/StreamResetHandler.cpp +122 -14
  234. package/worker/src/RTC/SCTP/association/TransmissionControlBlock.cpp +28 -26
  235. package/worker/src/RTC/SCTP/packet/chunks/SackChunk.cpp +0 -1
  236. package/worker/src/RTC/SCTP/packet/parameters/StateCookieParameter.cpp +2 -2
  237. package/worker/src/RTC/SCTP/public/AssociationMetrics.cpp +2 -2
  238. package/worker/src/RTC/SCTP/public/SctpOptions.cpp +13 -13
  239. package/worker/src/RTC/SCTP/rx/DataTracker.cpp +1 -1
  240. package/worker/src/RTC/SCTP/rx/ReassemblyQueue.cpp +5 -5
  241. package/worker/src/RTC/SCTP/tx/OutstandingData.cpp +15 -15
  242. package/worker/src/RTC/SCTP/tx/RetransmissionQueue.cpp +15 -15
  243. package/worker/src/RTC/SCTP/tx/RetransmissionTimeout.cpp +29 -26
  244. package/worker/src/RTC/SCTP/tx/RoundRobinSendQueue.cpp +12 -11
  245. package/worker/src/RTC/SCTP/tx/StreamScheduler.cpp +4 -4
  246. package/worker/src/RTC/SctpDictionaries/SctpStreamParameters.cpp +2 -2
  247. package/worker/src/RTC/SimpleProducerStreamManager.cpp +10 -10
  248. package/worker/src/RTC/SimulcastProducerStreamManager.cpp +39 -37
  249. package/worker/src/RTC/SvcProducerStreamManager.cpp +39 -25
  250. package/worker/src/RTC/TcpConnection.cpp +9 -3
  251. package/worker/src/RTC/TcpServer.cpp +7 -2
  252. package/worker/src/RTC/Transport.cpp +266 -307
  253. package/worker/src/RTC/TransportCongestionControlClient.cpp +78 -71
  254. package/worker/src/RTC/TransportCongestionControlServer.cpp +38 -40
  255. package/worker/src/RTC/TrendCalculator.cpp +3 -3
  256. package/worker/src/RTC/UdpSocket.cpp +14 -3
  257. package/worker/src/RTC/WebRtcServer.cpp +20 -14
  258. package/worker/src/RTC/WebRtcTransport.cpp +35 -30
  259. package/worker/src/Settings.cpp +10 -0
  260. package/worker/src/Shared.cpp +2 -2
  261. package/worker/src/Utils/Crypto.cpp +2 -2
  262. package/worker/src/Worker.cpp +5 -1
  263. package/worker/src/handles/BackoffTimerHandle.cpp +24 -11
  264. package/worker/src/handles/TimerHandle.cpp +74 -25
  265. package/worker/src/lib.cpp +6 -0
  266. package/worker/tasks.py +197 -45
  267. package/worker/test/include/RTC/BWE/helpers/LinkSimulator.hpp +117 -0
  268. package/worker/test/src/RTC/BWE/TestAimdRateControl.cpp +400 -0
  269. package/worker/test/src/RTC/BWE/TestDelayBasedBwe.cpp +568 -0
  270. package/worker/test/src/RTC/BWE/TestFeedbackAdapter.cpp +546 -0
  271. package/worker/test/src/RTC/BWE/TestInterArrivalDelta.cpp +301 -0
  272. package/worker/test/src/RTC/BWE/TestLinkCapacityEstimator.cpp +115 -0
  273. package/worker/test/src/RTC/BWE/TestLossBasedController.cpp +1199 -0
  274. package/worker/test/src/RTC/BWE/TestRobustThroughputEstimator.cpp +433 -0
  275. package/worker/test/src/RTC/BWE/TestSendPacketHistory.cpp +259 -0
  276. package/worker/test/src/RTC/BWE/TestTargetRateController.cpp +337 -0
  277. package/worker/test/src/RTC/BWE/TestTrendlineEstimator.cpp +182 -0
  278. package/worker/test/src/RTC/BWE/TestUtils.cpp +61 -0
  279. package/worker/test/src/RTC/BWE/helpers/LinkSimulator.cpp +171 -0
  280. package/worker/test/src/RTC/RTCP/TestFeedbackPsRemb.cpp +1 -1
  281. package/worker/test/src/RTC/RTCP/TestFeedbackRtpTmmb.cpp +1 -1
  282. package/worker/test/src/RTC/RTCP/TestFeedbackRtpTransport.cpp +246 -208
  283. package/worker/test/src/RTC/RTP/TestPacket.cpp +11 -11
  284. package/worker/test/src/RTC/RTP/TestRetransmissionBuffer.cpp +12 -12
  285. package/worker/test/src/RTC/RTP/TestRtpStreamRecv.cpp +23 -16
  286. package/worker/test/src/RTC/RTP/TestRtpStreamSend.cpp +13 -13
  287. package/worker/test/src/RTC/SCTP/association/TestAssociation.cpp +27 -22
  288. package/worker/test/src/RTC/SCTP/association/TestHeartbeatHandler.cpp +21 -15
  289. package/worker/test/src/RTC/SCTP/association/TestStateCookie.cpp +6 -6
  290. package/worker/test/src/RTC/SCTP/association/TestStreamResetHandler.cpp +128 -13
  291. package/worker/test/src/RTC/SCTP/association/TestTransmissionControlBlock.cpp +3 -3
  292. package/worker/test/src/RTC/SCTP/packet/chunks/TestForwardTsnChunk.cpp +2 -2
  293. package/worker/test/src/RTC/SCTP/packet/chunks/TestIForwardTsnChunk.cpp +23 -23
  294. package/worker/test/src/RTC/SCTP/packet/chunks/TestInitChunk.cpp +1 -1
  295. package/worker/test/src/RTC/SCTP/packet/chunks/TestSackChunk.cpp +1 -1
  296. package/worker/test/src/RTC/SCTP/packet/parameters/TestIPv6AddressParameter.cpp +1 -1
  297. package/worker/test/src/RTC/SCTP/rx/TestDataTracker.cpp +37 -37
  298. package/worker/test/src/RTC/SCTP/rx/TestInterleavedReassemblyStreams.cpp +10 -10
  299. package/worker/test/src/RTC/SCTP/rx/TestReassemblyQueue.cpp +1 -1
  300. package/worker/test/src/RTC/SCTP/tx/TestOutstandingData.cpp +93 -93
  301. package/worker/test/src/RTC/SCTP/tx/TestRetransmissionQueue.cpp +247 -247
  302. package/worker/test/src/RTC/SCTP/tx/TestRetransmissionTimeout.cpp +100 -80
  303. package/worker/test/src/RTC/SCTP/tx/TestRoundRobinSendQueue.cpp +163 -163
  304. package/worker/test/src/RTC/SCTP/tx/TestStreamScheduler.cpp +76 -77
  305. package/worker/test/src/RTC/TestConsumer.cpp +8 -3
  306. package/worker/test/src/RTC/TestKeyFrameRequestManager.cpp +3 -3
  307. package/worker/test/src/RTC/TestNackGenerator.cpp +3 -3
  308. package/worker/test/src/RTC/TestPipeProducerStreamManager.cpp +5 -5
  309. package/worker/test/src/RTC/TestRateCalculator.cpp +110 -14
  310. package/worker/test/src/RTC/TestRemoteCaptureTimeEstimator.cpp +22 -17
  311. package/worker/test/src/RTC/TestRemoteClockOffsetEstimator.cpp +87 -85
  312. package/worker/test/src/RTC/TestSimpleProducerStreamManager.cpp +54 -47
  313. package/worker/test/src/RTC/TestSimulcastProducerStreamManager.cpp +83 -69
  314. package/worker/test/src/RTC/TestSvcProducerStreamManager.cpp +76 -65
  315. package/worker/test/src/RTC/TestTransportCongestionControlServer.cpp +72 -66
  316. package/worker/test/src/RTC/TestTransportTuple.cpp +19 -4
  317. package/worker/test/src/TestDepLibUV.cpp +19 -0
  318. package/worker/test/src/Utils/TestTime.cpp +57 -26
  319. package/worker/test/src/testHelpers.cpp +1 -1
  320. package/worker/test/src/tests.cpp +6 -0
  321. package/worker/include/RTC/SenderBandwidthEstimator.hpp +0 -118
  322. package/worker/src/RTC/SenderBandwidthEstimator.cpp +0 -269
@@ -0,0 +1,1199 @@
1
+ #include "common.hpp"
2
+ #include "RTC/BWE/BweTypes.hpp"
3
+ #include "RTC/BWE/LossBasedController.hpp"
4
+ #include <array>
5
+ #include <catch2/catch_test_macros.hpp>
6
+ #include <cmath> // std::llround()
7
+ #include <vector>
8
+
9
+ SCENARIO("BWE LossBasedController", "[bwe][lossbasedcontroller]")
10
+ {
11
+ constexpr int64_t ObservationDurationLowerBoundUs{ 250 * 1000 };
12
+ constexpr int64_t PacketSizeBytes{ 15000 };
13
+
14
+ // Options that make the controller usable after a single observation, so
15
+ // that a case doesn't have to feed a whole window to prove anything.
16
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions shortObservationOptions{
17
+ .observationWindowSize = 2, .minNumObservations = 1
18
+ };
19
+
20
+ // Sequence number handed out to the packets of every case, which must not
21
+ // repeat within a same observation.
22
+ int64_t sequenceNumber{ 0 };
23
+
24
+ // Results of a feedback covering the shortest span that closes an
25
+ // observation, with the given number of its packets reported as lost.
26
+ const auto createResults = [&sequenceNumber](
27
+ int64_t firstSendTimeUs,
28
+ size_t numPackets,
29
+ size_t numLostPackets) -> std::vector<RTC::BWE::Types::PacketResult>
30
+ {
31
+ std::vector<RTC::BWE::Types::PacketResult> packetResults(numPackets);
32
+
33
+ for (size_t idx{ 0 }; idx < numPackets; ++idx)
34
+ {
35
+ auto& packetResult = packetResults[idx];
36
+
37
+ packetResult.sentPacket.sequenceNumber = sequenceNumber++;
38
+ packetResult.sentPacket.size = PacketSizeBytes;
39
+ packetResult.sentPacket.sendTimeUs =
40
+ firstSendTimeUs + (static_cast<int64_t>(idx) * ObservationDurationLowerBoundUs);
41
+
42
+ // The lost ones are the last ones, so that the span of send times is
43
+ // the same no matter how many there are.
44
+ if (idx < numPackets - numLostPackets)
45
+ {
46
+ packetResult.receiveTimeUs =
47
+ firstSendTimeUs + (static_cast<int64_t>(idx + 1) * ObservationDurationLowerBoundUs);
48
+ }
49
+ }
50
+
51
+ return packetResults;
52
+ };
53
+
54
+ // Results of a feedback whose packets are all reported as lost, sent close to
55
+ // each other so that they amount to a burst rather than to a steady rate.
56
+ const auto createLostResults = [&sequenceNumber](
57
+ int64_t firstSendTimeUs,
58
+ size_t numPackets) -> std::vector<RTC::BWE::Types::PacketResult>
59
+ {
60
+ std::vector<RTC::BWE::Types::PacketResult> packetResults(numPackets);
61
+
62
+ for (size_t idx{ 0 }; idx < numPackets; ++idx)
63
+ {
64
+ auto& packetResult = packetResults[idx];
65
+
66
+ packetResult.sentPacket.sequenceNumber = sequenceNumber++;
67
+ packetResult.sentPacket.size = PacketSizeBytes;
68
+ // The last one is what closes the observation, while the rest go right
69
+ // after each other, which is what makes this a burst.
70
+ packetResult.sentPacket.sendTimeUs =
71
+ idx == numPackets - 1 ? firstSendTimeUs + ObservationDurationLowerBoundUs
72
+ : firstSendTimeUs + (static_cast<int64_t>(idx) * 10 * 1000);
73
+ }
74
+
75
+ return packetResults;
76
+ };
77
+
78
+ SECTION("there is no estimate until one is set to start from")
79
+ {
80
+ RTC::BWE::LossBasedController lossBasedController;
81
+
82
+ lossBasedController.UpdateBitrateEstimate(
83
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0),
84
+ RTC::BWE::Types::BitrateInfinite,
85
+ /*inAlr*/ false);
86
+
87
+ REQUIRE(!lossBasedController.IsReady());
88
+ REQUIRE(lossBasedController.GetResult().bitrate == RTC::BWE::Types::BitrateInfinite);
89
+ }
90
+
91
+ SECTION("there is no estimate while no feedback covers a long enough span")
92
+ {
93
+ RTC::BWE::LossBasedController lossBasedController;
94
+
95
+ lossBasedController.SetBitrateEstimate(600000);
96
+
97
+ REQUIRE(!lossBasedController.IsReady());
98
+
99
+ // Half the shortest span an observation may cover.
100
+ std::vector<RTC::BWE::Types::PacketResult> packetResults(2);
101
+
102
+ for (size_t idx{ 0 }; idx < packetResults.size(); ++idx)
103
+ {
104
+ packetResults[idx].sentPacket.sequenceNumber = sequenceNumber++;
105
+ packetResults[idx].sentPacket.size = PacketSizeBytes;
106
+ packetResults[idx].sentPacket.sendTimeUs =
107
+ static_cast<int64_t>(idx) * (ObservationDurationLowerBoundUs / 2);
108
+ packetResults[idx].receiveTimeUs =
109
+ static_cast<int64_t>(idx + 1) * (ObservationDurationLowerBoundUs / 2);
110
+ }
111
+
112
+ lossBasedController.UpdateBitrateEstimate(
113
+ packetResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ false);
114
+
115
+ REQUIRE(!lossBasedController.IsReady());
116
+ }
117
+
118
+ SECTION("the bitrate set is what the estimate starts from")
119
+ {
120
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
121
+
122
+ lossBasedController.SetBitrateEstimate(600000);
123
+
124
+ REQUIRE(!lossBasedController.IsReady());
125
+ REQUIRE(lossBasedController.GetResult().bitrate == RTC::BWE::Types::BitrateInfinite);
126
+
127
+ lossBasedController.UpdateBitrateEstimate(
128
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0),
129
+ RTC::BWE::Types::BitrateInfinite,
130
+ /*inAlr*/ false);
131
+
132
+ // Of the three candidates, the one above the current estimate is the one
133
+ // predicting the least loss, so with no loss observed it's the most likely
134
+ // one and nothing bounds it: 600000 * 1.02.
135
+ REQUIRE(lossBasedController.IsReady());
136
+ REQUIRE(lossBasedController.GetResult().bitrate == 612000);
137
+ }
138
+
139
+ SECTION("losing every packet brings the estimate down")
140
+ {
141
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
142
+
143
+ lossBasedController.SetBitrateEstimate(600000);
144
+
145
+ lossBasedController.UpdateBitrateEstimate(
146
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 2),
147
+ RTC::BWE::Types::BitrateInfinite,
148
+ /*inAlr*/ false);
149
+
150
+ REQUIRE(lossBasedController.IsReady());
151
+ REQUIRE(lossBasedController.GetResult().bitrate < 600000);
152
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::DECREASING);
153
+ }
154
+
155
+ SECTION("the estimate doesn't go above the maximum bitrate")
156
+ {
157
+ constexpr int64_t MaxBitrate{ 700000 };
158
+
159
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
160
+
161
+ lossBasedController.SetBitrateLimits(/*minBitrate*/ 0, MaxBitrate);
162
+ lossBasedController.SetBitrateEstimate(600000);
163
+
164
+ int64_t firstSendTimeUs{ 0 };
165
+
166
+ // Feed feedback telling no loss at all for a while, which is what makes
167
+ // the estimate grow.
168
+ for (int i{ 0 }; i < 10; ++i)
169
+ {
170
+ lossBasedController.UpdateBitrateEstimate(
171
+ createResults(firstSendTimeUs, /*numPackets*/ 2, /*numLostPackets*/ 0),
172
+ RTC::BWE::Types::BitrateInfinite,
173
+ /*inAlr*/ false);
174
+
175
+ firstSendTimeUs += 2 * ObservationDurationLowerBoundUs;
176
+ }
177
+
178
+ REQUIRE(lossBasedController.GetResult().bitrate <= MaxBitrate);
179
+ }
180
+
181
+ SECTION("the estimate doesn't go below what the link is known to deliver")
182
+ {
183
+ constexpr int64_t AcknowledgedBitrate{ 500000 };
184
+
185
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
186
+
187
+ lossBasedController.SetAcknowledgedBitrate(AcknowledgedBitrate);
188
+ lossBasedController.SetBitrateEstimate(600000);
189
+
190
+ lossBasedController.UpdateBitrateEstimate(
191
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 2),
192
+ RTC::BWE::Types::BitrateInfinite,
193
+ /*inAlr*/ false);
194
+
195
+ REQUIRE(lossBasedController.GetResult().bitrate >= AcknowledgedBitrate);
196
+ }
197
+
198
+ SECTION("the delay based estimate bounds this one")
199
+ {
200
+ constexpr int64_t DelayBasedEstimate{ 400000 };
201
+
202
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
203
+
204
+ lossBasedController.SetBitrateEstimate(600000);
205
+
206
+ lossBasedController.UpdateBitrateEstimate(
207
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0),
208
+ DelayBasedEstimate,
209
+ /*inAlr*/ false);
210
+
211
+ REQUIRE(lossBasedController.GetResult().bitrate <= DelayBasedEstimate);
212
+ }
213
+
214
+ SECTION("while not filling the link the estimate doesn't fall to what it delivers")
215
+ {
216
+ constexpr int64_t AcknowledgedBitrate{ 100000 };
217
+ constexpr int64_t InitialBitrate{ 600000 };
218
+
219
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
220
+
221
+ lossBasedController.SetBitrateLimits(/*minBitrate*/ 10000, /*maxBitrate*/ 1000000000);
222
+ lossBasedController.SetBitrateEstimate(InitialBitrate);
223
+ lossBasedController.SetAcknowledgedBitrate(AcknowledgedBitrate);
224
+
225
+ lossBasedController.UpdateBitrateEstimate(
226
+ createLostResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2),
227
+ /*delayBasedEstimate*/ 5000000,
228
+ /*inAlr*/ true);
229
+
230
+ // In an application limited region what the link delivers says nothing
231
+ // about what it could deliver, so it's no candidate to fall back to.
232
+ REQUIRE(lossBasedController.GetResult().bitrate > AcknowledgedBitrate);
233
+ REQUIRE(lossBasedController.GetResult().bitrate < InitialBitrate);
234
+ }
235
+
236
+ SECTION("while filling the link the estimate falls to what it delivers")
237
+ {
238
+ constexpr int64_t AcknowledgedBitrate{ 100000 };
239
+
240
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
241
+
242
+ lossBasedController.SetBitrateLimits(/*minBitrate*/ 10000, /*maxBitrate*/ 1000000000);
243
+ lossBasedController.SetBitrateEstimate(600000);
244
+ lossBasedController.SetAcknowledgedBitrate(AcknowledgedBitrate);
245
+
246
+ lossBasedController.UpdateBitrateEstimate(
247
+ createLostResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2),
248
+ /*delayBasedEstimate*/ 5000000,
249
+ /*inAlr*/ false);
250
+
251
+ REQUIRE(lossBasedController.GetResult().bitrate == AcknowledgedBitrate);
252
+ }
253
+
254
+ SECTION("after backing off, recovering grows the estimate by the hold factor")
255
+ {
256
+ constexpr int64_t DelayBasedEstimate{ 5000000 };
257
+
258
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
259
+
260
+ lossBasedController.SetBitrateEstimate(600000);
261
+ lossBasedController.SetAcknowledgedBitrate(100000);
262
+
263
+ // Lose everything, which is what puts it in a loss limited state.
264
+ lossBasedController.UpdateBitrateEstimate(
265
+ createLostResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2),
266
+ DelayBasedEstimate,
267
+ /*inAlr*/ false);
268
+
269
+ const int64_t bitrateAtLoss = lossBasedController.GetResult().bitrate;
270
+
271
+ // Let the link recover until the estimate starts growing again.
272
+ //
273
+ // NOTE: Bounded so that a controller that never gets there fails the case
274
+ // instead of hanging.
275
+ int64_t feedbackCount{ 2 };
276
+
277
+ while (lossBasedController.GetResult().state != RTC::BWE::LossBasedController::State::INCREASING &&
278
+ feedbackCount < 100)
279
+ {
280
+ lossBasedController.UpdateBitrateEstimate(
281
+ createResults(
282
+ feedbackCount * ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 0),
283
+ DelayBasedEstimate,
284
+ /*inAlr*/ false);
285
+
286
+ ++feedbackCount;
287
+ }
288
+
289
+ // Growing out of a hold is bounded by the more conservative of the two
290
+ // rampup factors, which is 1.2. The bitrate backed off to depends on the
291
+ // whole run, so the factor is applied to it here, rounded as every bitrate
292
+ // derived from another one is.
293
+ REQUIRE(
294
+ lossBasedController.GetResult().bitrate ==
295
+ std::llround(static_cast<double>(bitrateAtLoss) * 1.2));
296
+ }
297
+
298
+ SECTION("a single observation of loss among good ones is taken as a spike")
299
+ {
300
+ constexpr int64_t DelayBasedEstimate{ 500000 };
301
+
302
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{ .observationWindowSize =
303
+ 5 };
304
+
305
+ RTC::BWE::LossBasedController lossBasedController(options);
306
+
307
+ lossBasedController.SetBitrateEstimate(DelayBasedEstimate);
308
+
309
+ // Fill the window with observations telling no loss.
310
+ for (int64_t i{ 0 }; i < 5; ++i)
311
+ {
312
+ lossBasedController.UpdateBitrateEstimate(
313
+ createResults(i * ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 0),
314
+ DelayBasedEstimate,
315
+ /*inAlr*/ false);
316
+ }
317
+
318
+ lossBasedController.UpdateBitrateEstimate(
319
+ createLostResults(5 * ObservationDurationLowerBoundUs, /*numPackets*/ 2),
320
+ DelayBasedEstimate,
321
+ /*inAlr*/ false);
322
+ lossBasedController.UpdateBitrateEstimate(
323
+ createResults(6 * ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 0),
324
+ DelayBasedEstimate,
325
+ /*inAlr*/ false);
326
+
327
+ // The worst observation of the window is left out of the average, so that
328
+ // single one doesn't count as the link being loss limited.
329
+ REQUIRE(
330
+ lossBasedController.GetResult().state ==
331
+ RTC::BWE::LossBasedController::State::DELAY_BASED_ESTIMATE);
332
+ REQUIRE(lossBasedController.GetResult().bitrate == DelayBasedEstimate);
333
+
334
+ // A second one is not a spike anymore.
335
+ lossBasedController.UpdateBitrateEstimate(
336
+ createLostResults(7 * ObservationDurationLowerBoundUs, /*numPackets*/ 2),
337
+ DelayBasedEstimate,
338
+ /*inAlr*/ false);
339
+
340
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::DECREASING);
341
+ REQUIRE(lossBasedController.GetResult().bitrate < DelayBasedEstimate);
342
+ }
343
+
344
+ SECTION("a loss below the preference threshold still lets the estimate grow")
345
+ {
346
+ // The guard that holds the estimate back while the observed loss is worse
347
+ // than the inherent one is disabled, so that nothing but the preference
348
+ // decides.
349
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
350
+ .lossThresholdOfHighBitratePreference = 0.20,
351
+ .observationWindowSize = 2,
352
+ .minNumObservations = 1,
353
+ .notIncreaseIfInherentLossLessThanAverageLoss = false
354
+ };
355
+
356
+ RTC::BWE::LossBasedController lossBasedController(options);
357
+
358
+ lossBasedController.SetBitrateEstimate(600000);
359
+
360
+ for (int64_t i{ 0 }; i < 2; ++i)
361
+ {
362
+ lossBasedController.UpdateBitrateEstimate(
363
+ createResults(i * ObservationDurationLowerBoundUs, /*numPackets*/ 10, /*numLostPackets*/ 1),
364
+ /*delayBasedEstimate*/ 5000000,
365
+ /*inAlr*/ false);
366
+ }
367
+
368
+ REQUIRE(lossBasedController.GetResult().bitrate > 600000);
369
+ }
370
+
371
+ SECTION("a feedback that closes no observation changes nothing")
372
+ {
373
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
374
+
375
+ lossBasedController.SetBitrateEstimate(600000);
376
+ lossBasedController.SetAcknowledgedBitrate(300000);
377
+
378
+ const auto packetResults =
379
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0);
380
+
381
+ lossBasedController.UpdateBitrateEstimate(
382
+ packetResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ false);
383
+
384
+ const int64_t bitrate = lossBasedController.GetResult().bitrate;
385
+
386
+ // The very same feedback again covers no new span of send times.
387
+ lossBasedController.UpdateBitrateEstimate(
388
+ packetResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ false);
389
+
390
+ REQUIRE(lossBasedController.GetResult().bitrate == bitrate);
391
+ }
392
+
393
+ SECTION("right after a decrease the estimate is bounded for a while")
394
+ {
395
+ constexpr int64_t DelayBasedEstimate{ 5000000 };
396
+ constexpr int64_t DelayedIncreaseWindowUs{ 300 * 1000 };
397
+
398
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
399
+ .observationWindowSize = 15, .minNumObservations = 1
400
+ };
401
+
402
+ RTC::BWE::LossBasedController lossBasedController(options);
403
+
404
+ lossBasedController.SetBitrateEstimate(600000);
405
+ lossBasedController.SetAcknowledgedBitrate(300000);
406
+
407
+ lossBasedController.UpdateBitrateEstimate(
408
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0),
409
+ DelayBasedEstimate,
410
+ /*inAlr*/ false);
411
+
412
+ // Raise what the link is known to deliver, so that it isn't what keeps the
413
+ // estimate low.
414
+ lossBasedController.SetAcknowledgedBitrate(5000000);
415
+
416
+ lossBasedController.UpdateBitrateEstimate(
417
+ createResults(DelayedIncreaseWindowUs - (2 * 1000), /*numPackets*/ 2, /*numLostPackets*/ 1),
418
+ DelayBasedEstimate,
419
+ /*inAlr*/ false);
420
+
421
+ const int64_t bitrateAfterDecrease = lossBasedController.GetResult().bitrate;
422
+
423
+ // Still within the window that follows the decrease.
424
+ lossBasedController.UpdateBitrateEstimate(
425
+ createResults(DelayedIncreaseWindowUs - (1 * 1000), /*numPackets*/ 2, /*numLostPackets*/ 0),
426
+ DelayBasedEstimate,
427
+ /*inAlr*/ false);
428
+
429
+ REQUIRE(lossBasedController.GetResult().bitrate == bitrateAfterDecrease);
430
+ }
431
+
432
+ SECTION("once that window is over the estimate grows again")
433
+ {
434
+ constexpr int64_t DelayBasedEstimate{ 5000000 };
435
+ constexpr int64_t DelayedIncreaseWindowUs{ 300 * 1000 };
436
+
437
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
438
+ .observationWindowSize = 15, .minNumObservations = 1
439
+ };
440
+
441
+ RTC::BWE::LossBasedController lossBasedController(options);
442
+
443
+ lossBasedController.SetBitrateEstimate(600000);
444
+ lossBasedController.SetAcknowledgedBitrate(300000);
445
+
446
+ lossBasedController.UpdateBitrateEstimate(
447
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0),
448
+ DelayBasedEstimate,
449
+ /*inAlr*/ false);
450
+
451
+ lossBasedController.SetAcknowledgedBitrate(5000000);
452
+
453
+ lossBasedController.UpdateBitrateEstimate(
454
+ createResults(DelayedIncreaseWindowUs - (1 * 1000), /*numPackets*/ 2, /*numLostPackets*/ 0),
455
+ DelayBasedEstimate,
456
+ /*inAlr*/ false);
457
+
458
+ const int64_t bitrateWithinWindow = lossBasedController.GetResult().bitrate;
459
+
460
+ lossBasedController.UpdateBitrateEstimate(
461
+ createResults(DelayedIncreaseWindowUs + (1 * 1000), /*numPackets*/ 2, /*numLostPackets*/ 0),
462
+ DelayBasedEstimate,
463
+ /*inAlr*/ false);
464
+
465
+ REQUIRE(lossBasedController.GetResult().bitrate >= bitrateWithinWindow);
466
+ }
467
+
468
+ SECTION("a loss above the preference threshold takes the estimate down")
469
+ {
470
+ // With the threshold below the loss that is about to be observed, the bias
471
+ // towards higher bitrates is gone and the lower candidate wins.
472
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
473
+ .lossThresholdOfHighBitratePreference = 0.05, .observationWindowSize = 2, .minNumObservations = 1
474
+ };
475
+
476
+ RTC::BWE::LossBasedController lossBasedController(options);
477
+
478
+ lossBasedController.SetBitrateEstimate(600000);
479
+
480
+ for (int64_t i{ 0 }; i < 2; ++i)
481
+ {
482
+ lossBasedController.UpdateBitrateEstimate(
483
+ createResults(i * ObservationDurationLowerBoundUs, /*numPackets*/ 10, /*numLostPackets*/ 1),
484
+ /*delayBasedEstimate*/ 5000000,
485
+ /*inAlr*/ false);
486
+ }
487
+
488
+ REQUIRE(lossBasedController.GetResult().bitrate < 600000);
489
+ }
490
+
491
+ SECTION("the estimate doesn't grow while the loss observed is worse than the inherent one")
492
+ {
493
+ // A single candidate above the current estimate, so that the only thing
494
+ // that can hold the estimate back is the guard being tested.
495
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
496
+ .candidateFactors = { 1.2 }, .observationWindowSize = 2, .minNumObservations = 1
497
+ };
498
+
499
+ RTC::BWE::LossBasedController lossBasedController(options);
500
+
501
+ lossBasedController.SetBitrateEstimate(600000);
502
+
503
+ for (int64_t i{ 0 }; i < 2; ++i)
504
+ {
505
+ lossBasedController.UpdateBitrateEstimate(
506
+ createResults(i * ObservationDurationLowerBoundUs, /*numPackets*/ 10, /*numLostPackets*/ 1),
507
+ RTC::BWE::Types::BitrateInfinite,
508
+ /*inAlr*/ false);
509
+ }
510
+
511
+ REQUIRE(lossBasedController.GetResult().bitrate == 600000);
512
+ }
513
+
514
+ SECTION("of two equally likely candidates the higher one is taken")
515
+ {
516
+ constexpr int64_t InitialBitrate{ 1000000 };
517
+
518
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
519
+
520
+ lossBasedController.SetBitrateEstimate(InitialBitrate);
521
+
522
+ lossBasedController.UpdateBitrateEstimate(
523
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0),
524
+ InitialBitrate,
525
+ /*inAlr*/ false);
526
+
527
+ // Just above the candidate that the factor of 1.02 builds, so that it's the
528
+ // delay based estimate the one added as a candidate and taken.
529
+ constexpr int64_t DelayBasedEstimate{ 1020008 };
530
+
531
+ lossBasedController.UpdateBitrateEstimate(
532
+ createResults(ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 0),
533
+ DelayBasedEstimate,
534
+ /*inAlr*/ false);
535
+
536
+ REQUIRE(lossBasedController.GetResult().bitrate == DelayBasedEstimate);
537
+ }
538
+
539
+ SECTION("a packet reported lost and received later doesn't take the estimate down")
540
+ {
541
+ constexpr int64_t InitialBitrate{ 2500000 };
542
+
543
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
544
+
545
+ lossBasedController.SetBitrateEstimate(InitialBitrate);
546
+
547
+ // The second packet is reported as lost, which may just mean that it was
548
+ // reordered and hasn't arrived yet.
549
+ std::vector<RTC::BWE::Types::PacketResult> firstResults(3);
550
+
551
+ for (size_t idx{ 0 }; idx < firstResults.size(); ++idx)
552
+ {
553
+ firstResults[idx].sentPacket.sequenceNumber = static_cast<int64_t>(idx) + 1;
554
+ firstResults[idx].sentPacket.size = PacketSizeBytes;
555
+ firstResults[idx].sentPacket.sendTimeUs = 0;
556
+
557
+ if (idx != 1)
558
+ {
559
+ firstResults[idx].receiveTimeUs = 10 * 1000;
560
+ }
561
+ }
562
+
563
+ // The next feedback reports it as received, and closes the observation.
564
+ std::vector<RTC::BWE::Types::PacketResult> secondResults(3);
565
+ const std::array<int64_t, 3> sequenceNumbers{ 2, 4, 5 };
566
+
567
+ for (size_t idx{ 0 }; idx < secondResults.size(); ++idx)
568
+ {
569
+ secondResults[idx].sentPacket.sequenceNumber = sequenceNumbers.at(idx);
570
+ secondResults[idx].sentPacket.size = PacketSizeBytes;
571
+ secondResults[idx].sentPacket.sendTimeUs = idx == 1 ? ObservationDurationLowerBoundUs : 0;
572
+ secondResults[idx].receiveTimeUs = secondResults[idx].sentPacket.sendTimeUs + (10 * 1000);
573
+ }
574
+
575
+ lossBasedController.UpdateBitrateEstimate(
576
+ firstResults, /*delayBasedEstimate*/ InitialBitrate, /*inAlr*/ false);
577
+ lossBasedController.UpdateBitrateEstimate(
578
+ secondResults, /*delayBasedEstimate*/ InitialBitrate, /*inAlr*/ false);
579
+
580
+ REQUIRE(lossBasedController.GetResult().bitrate == InitialBitrate);
581
+ }
582
+
583
+ SECTION("the state says the delay based path rules once the estimate reaches the maximum")
584
+ {
585
+ constexpr int64_t MaxBitrate{ 1000000 };
586
+ constexpr int64_t DelayBasedEstimate{ 2000000 };
587
+
588
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
589
+
590
+ lossBasedController.SetBitrateLimits(/*minBitrate*/ 10000, MaxBitrate);
591
+
592
+ lossBasedController.UpdateBitrateEstimate(
593
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0),
594
+ DelayBasedEstimate,
595
+ /*inAlr*/ false);
596
+
597
+ REQUIRE(
598
+ lossBasedController.GetResult().state ==
599
+ RTC::BWE::LossBasedController::State::DELAY_BASED_ESTIMATE);
600
+ REQUIRE(lossBasedController.GetResult().bitrate == MaxBitrate);
601
+
602
+ // Half of the packets lost takes it off the maximum and out of that state.
603
+ lossBasedController.UpdateBitrateEstimate(
604
+ createResults(ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 1),
605
+ DelayBasedEstimate,
606
+ /*inAlr*/ false);
607
+
608
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::DECREASING);
609
+ REQUIRE(lossBasedController.GetResult().bitrate < MaxBitrate);
610
+
611
+ // And it comes back to it once the link stops losing packets.
612
+ int64_t feedbackCount{ 2 };
613
+
614
+ // NOTE: Bounded so that a controller that never gets there fails the case
615
+ // instead of hanging.
616
+ while (lossBasedController.GetResult().state !=
617
+ RTC::BWE::LossBasedController::State::DELAY_BASED_ESTIMATE &&
618
+ feedbackCount < 100)
619
+ {
620
+ lossBasedController.UpdateBitrateEstimate(
621
+ createResults(
622
+ feedbackCount * ObservationDurationLowerBoundUs,
623
+ /*numPackets*/ 2,
624
+ /*numLostPackets*/ 0),
625
+ DelayBasedEstimate,
626
+ /*inAlr*/ false);
627
+
628
+ ++feedbackCount;
629
+ }
630
+
631
+ REQUIRE(lossBasedController.GetResult().bitrate == MaxBitrate);
632
+ }
633
+
634
+ SECTION("while holding, the bitrate held is never below what the link delivers")
635
+ {
636
+ constexpr int64_t AcknowledgedBitrate{ 1000000 };
637
+
638
+ // A hold long enough to still be in place on the next observation.
639
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
640
+ .observationWindowSize = 2,
641
+ .minNumObservations = 1,
642
+ .lowerBoundByAckedRateFactor = 1.0,
643
+ .holdDurationFactor = 10.0
644
+ };
645
+
646
+ RTC::BWE::LossBasedController lossBasedController(options);
647
+
648
+ lossBasedController.SetBitrateEstimate(2500000);
649
+
650
+ lossBasedController.UpdateBitrateEstimate(
651
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 1),
652
+ RTC::BWE::Types::BitrateInfinite,
653
+ /*inAlr*/ false);
654
+
655
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::DECREASING);
656
+
657
+ lossBasedController.SetAcknowledgedBitrate(AcknowledgedBitrate);
658
+
659
+ lossBasedController.UpdateBitrateEstimate(
660
+ createResults(ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 1),
661
+ RTC::BWE::Types::BitrateInfinite,
662
+ /*inAlr*/ false);
663
+
664
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::DECREASING);
665
+ REQUIRE(lossBasedController.GetResult().bitrate == AcknowledgedBitrate);
666
+ }
667
+
668
+ SECTION("a hold ends as soon as the delay based path works again")
669
+ {
670
+ RTC::BWE::LossBasedController lossBasedController(shortObservationOptions);
671
+
672
+ lossBasedController.SetBitrateEstimate(2500000);
673
+
674
+ lossBasedController.UpdateBitrateEstimate(
675
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 1),
676
+ RTC::BWE::Types::BitrateInfinite,
677
+ /*inAlr*/ false);
678
+
679
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::DECREASING);
680
+
681
+ const int64_t heldBitrate = lossBasedController.GetResult().bitrate;
682
+ const int64_t delayBasedEstimate = heldBitrate + 10000;
683
+
684
+ for (int64_t i{ 1 }; i <= 2; ++i)
685
+ {
686
+ lossBasedController.UpdateBitrateEstimate(
687
+ createResults(i * ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 0),
688
+ delayBasedEstimate,
689
+ /*inAlr*/ false);
690
+ }
691
+
692
+ REQUIRE(
693
+ lossBasedController.GetResult().state ==
694
+ RTC::BWE::LossBasedController::State::DELAY_BASED_ESTIMATE);
695
+ REQUIRE(lossBasedController.GetResult().bitrate == delayBasedEstimate);
696
+ }
697
+
698
+ SECTION("the estimate grows even while what the link delivers is bounding it")
699
+ {
700
+ // The preference for a high bitrate stays on no matter the loss, and no
701
+ // immediate upper bound gets in the way, so that only the bound by the
702
+ // acknowledged bitrate is left.
703
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
704
+ .bitrateRampupUpperBoundFactor = 1.2,
705
+ .lossThresholdOfHighBitratePreference = 0.99,
706
+ .observationWindowSize = 2,
707
+ .minNumObservations = 1,
708
+ .immediateUpperBoundBitrateBalance = 10000000
709
+ };
710
+
711
+ RTC::BWE::LossBasedController lossBasedController(options);
712
+
713
+ lossBasedController.SetBitrateEstimate(600000);
714
+ lossBasedController.SetAcknowledgedBitrate(300000);
715
+
716
+ lossBasedController.UpdateBitrateEstimate(
717
+ createLostResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2),
718
+ /*delayBasedEstimate*/ 5000000,
719
+ /*inAlr*/ false);
720
+
721
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::DECREASING);
722
+
723
+ const int64_t bitrateAfterLoss = lossBasedController.GetResult().bitrate;
724
+
725
+ REQUIRE(bitrateAfterLoss < 600000);
726
+
727
+ // What the link delivers is now half of the estimate, so the bound by it
728
+ // would hold the estimate still.
729
+ lossBasedController.SetAcknowledgedBitrate(bitrateAfterLoss / 2);
730
+
731
+ int64_t feedbackCount{ 1 };
732
+
733
+ // NOTE: Bounded so that a controller that never gets there fails the case
734
+ // instead of hanging.
735
+ while (lossBasedController.GetResult().state != RTC::BWE::LossBasedController::State::INCREASING &&
736
+ feedbackCount < 100)
737
+ {
738
+ lossBasedController.UpdateBitrateEstimate(
739
+ createResults(
740
+ feedbackCount * ObservationDurationLowerBoundUs,
741
+ /*numPackets*/ 2,
742
+ /*numLostPackets*/ 0),
743
+ /*delayBasedEstimate*/ 5000000,
744
+ /*inAlr*/ false);
745
+
746
+ ++feedbackCount;
747
+ }
748
+
749
+ // A single bit is added so that the state can become increasing at all.
750
+ REQUIRE(lossBasedController.GetResult().bitrate == bitrateAfterLoss + 1);
751
+ }
752
+
753
+ SECTION("the delay based estimate caps this one while the network is fine")
754
+ {
755
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
756
+ .observationWindowSize = 15, .minNumObservations = 1
757
+ };
758
+
759
+ RTC::BWE::LossBasedController lossBasedController(options);
760
+
761
+ lossBasedController.SetBitrateEstimate(600000);
762
+
763
+ lossBasedController.UpdateBitrateEstimate(
764
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0),
765
+ RTC::BWE::Types::BitrateInfinite,
766
+ /*inAlr*/ false);
767
+
768
+ // With no bound of the delay based path, nothing holds the estimate back.
769
+ REQUIRE(lossBasedController.GetResult().bitrate > 600000);
770
+
771
+ lossBasedController.UpdateBitrateEstimate(
772
+ createResults(2 * ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 0),
773
+ /*delayBasedEstimate*/ 500000,
774
+ /*inAlr*/ false);
775
+
776
+ REQUIRE(lossBasedController.GetResult().bitrate == 500000);
777
+ }
778
+
779
+ SECTION("a strong signal of overuse backs the estimate off to what the link delivers")
780
+ {
781
+ constexpr int64_t AcknowledgedBitrate{ 300000 };
782
+
783
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
784
+ .observationWindowSize = 15, .minNumObservations = 1
785
+ };
786
+
787
+ RTC::BWE::LossBasedController lossBasedController(options);
788
+
789
+ lossBasedController.SetBitrateEstimate(600000);
790
+ lossBasedController.SetAcknowledgedBitrate(AcknowledgedBitrate);
791
+
792
+ // Half of the packets lost, and then every one of them.
793
+ lossBasedController.UpdateBitrateEstimate(
794
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 1),
795
+ RTC::BWE::Types::BitrateInfinite,
796
+ /*inAlr*/ false);
797
+ lossBasedController.UpdateBitrateEstimate(
798
+ createLostResults(2 * ObservationDurationLowerBoundUs, /*numPackets*/ 2),
799
+ RTC::BWE::Types::BitrateInfinite,
800
+ /*inAlr*/ false);
801
+
802
+ REQUIRE(lossBasedController.GetResult().bitrate <= AcknowledgedBitrate);
803
+ }
804
+
805
+ SECTION("the bound the observed loss puts on the estimate makes it decreasing")
806
+ {
807
+ // A single candidate that changes nothing, so that the only thing that can
808
+ // move the estimate is that bound, brought within reach by the balance.
809
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
810
+ .candidateFactors = { 1.0 },
811
+ .observationWindowSize = 2,
812
+ .minNumObservations = 1,
813
+ .immediateUpperBoundBitrateBalance = 10000
814
+ };
815
+
816
+ RTC::BWE::LossBasedController lossBasedController(options);
817
+
818
+ lossBasedController.SetBitrateLimits(/*minBitrate*/ 10000, /*maxBitrate*/ 1000000000);
819
+ lossBasedController.SetBitrateEstimate(500000);
820
+ lossBasedController.SetAcknowledgedBitrate(100000);
821
+
822
+ lossBasedController.UpdateBitrateEstimate(
823
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 10, /*numLostPackets*/ 1),
824
+ RTC::BWE::Types::BitrateInfinite,
825
+ /*inAlr*/ false);
826
+
827
+ // 10000 / (0.1 - 0.05).
828
+ REQUIRE(lossBasedController.GetResult().bitrate == 200000);
829
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::DECREASING);
830
+ }
831
+
832
+ SECTION("the bound that what the link delivers puts on the estimate makes it increasing")
833
+ {
834
+ constexpr int64_t AcknowledgedBitrate{ 200000 };
835
+
836
+ // A single candidate that changes nothing, and a lower bound well above
837
+ // what the link delivers, so that only that bound can move the estimate.
838
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
839
+ .candidateFactors = { 1.0 },
840
+ .observationWindowSize = 2,
841
+ .minNumObservations = 1,
842
+ .lowerBoundByAckedRateFactor = 10.0
843
+ };
844
+
845
+ RTC::BWE::LossBasedController lossBasedController(options);
846
+
847
+ lossBasedController.SetBitrateLimits(/*minBitrate*/ 10000, /*maxBitrate*/ 1000000000);
848
+ lossBasedController.SetBitrateEstimate(500000);
849
+ lossBasedController.SetAcknowledgedBitrate(1000);
850
+
851
+ lossBasedController.UpdateBitrateEstimate(
852
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 1),
853
+ RTC::BWE::Types::BitrateInfinite,
854
+ /*inAlr*/ false);
855
+
856
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::DECREASING);
857
+
858
+ // The link still loses as much, but delivers a lot more.
859
+ lossBasedController.SetAcknowledgedBitrate(AcknowledgedBitrate);
860
+
861
+ lossBasedController.UpdateBitrateEstimate(
862
+ createResults(2 * ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 1),
863
+ RTC::BWE::Types::BitrateInfinite,
864
+ /*inAlr*/ false);
865
+
866
+ REQUIRE(lossBasedController.GetResult().bitrate == AcknowledgedBitrate * 10);
867
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::INCREASING);
868
+ }
869
+
870
+ SECTION("loss while sending much more than usual is not taken as a spike")
871
+ {
872
+ constexpr int64_t DelayBasedEstimate{ 500000 };
873
+
874
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{ .observationWindowSize =
875
+ 5 };
876
+
877
+ RTC::BWE::LossBasedController lossBasedController(options);
878
+
879
+ lossBasedController.SetBitrateEstimate(DelayBasedEstimate);
880
+
881
+ for (int64_t i{ 0 }; i < 5; ++i)
882
+ {
883
+ lossBasedController.UpdateBitrateEstimate(
884
+ createResults(i * ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 0),
885
+ DelayBasedEstimate,
886
+ /*inAlr*/ false);
887
+ }
888
+
889
+ // Losing everything of a burst that more than doubles the usual sending
890
+ // rate explains the loss on its own, so it's not filtered out.
891
+ lossBasedController.UpdateBitrateEstimate(
892
+ createLostResults(5 * ObservationDurationLowerBoundUs, /*numPackets*/ 5),
893
+ DelayBasedEstimate,
894
+ /*inAlr*/ false);
895
+
896
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::DECREASING);
897
+ REQUIRE(lossBasedController.GetResult().bitrate <= DelayBasedEstimate);
898
+ }
899
+
900
+ SECTION("while not filling the link the estimate grows slowly from the bound loss put on it")
901
+ {
902
+ // Coming down to that bound in one step rather than gradually leaves the
903
+ // estimate where the link already is, so what follows is a slow rampup and
904
+ // not the jump that a deeper backoff would allow.
905
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
906
+ .appendUpperBoundCandidateInAlr = true, .observationWindowSize = 2, .minNumObservations = 1
907
+ };
908
+
909
+ RTC::BWE::LossBasedController lossBasedController(options);
910
+
911
+ lossBasedController.SetBitrateEstimate(1000000);
912
+ lossBasedController.SetAcknowledgedBitrate(150000);
913
+
914
+ lossBasedController.UpdateBitrateEstimate(
915
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 1),
916
+ RTC::BWE::Types::BitrateInfinite,
917
+ /*inAlr*/ true);
918
+
919
+ REQUIRE(lossBasedController.GetResult().state == RTC::BWE::LossBasedController::State::DECREASING);
920
+
921
+ const int64_t bitrateAfterLoss = lossBasedController.GetResult().bitrate;
922
+
923
+ for (int64_t i{ 1 }; i <= 3; ++i)
924
+ {
925
+ lossBasedController.UpdateBitrateEstimate(
926
+ createResults(i * ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 0),
927
+ RTC::BWE::Types::BitrateInfinite,
928
+ /*inAlr*/ true);
929
+ }
930
+
931
+ REQUIRE(lossBasedController.GetResult().bitrate < 2 * bitrateAfterLoss);
932
+ }
933
+
934
+ SECTION("what the link delivers stops being a candidate when told so")
935
+ {
936
+ // With the acknowledged bitrate not bounding the estimate from below, the
937
+ // only way it can reach the estimate is by being a candidate of its own.
938
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions withItOptions{
939
+ .observationWindowSize = 2, .minNumObservations = 1, .lowerBoundByAckedRateFactor = 0.0
940
+ };
941
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions withoutItOptions{
942
+ .appendAcknowledgedRateCandidate = false,
943
+ .observationWindowSize = 2,
944
+ .minNumObservations = 1,
945
+ .lowerBoundByAckedRateFactor = 0.0
946
+ };
947
+
948
+ RTC::BWE::LossBasedController withIt(withItOptions);
949
+ RTC::BWE::LossBasedController withoutIt(withoutItOptions);
950
+
951
+ // The very same feedback goes to both, so the option is the only difference.
952
+ const auto packetResults =
953
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0);
954
+
955
+ withIt.SetBitrateEstimate(600000);
956
+ withIt.SetAcknowledgedBitrate(1000000);
957
+ withIt.UpdateBitrateEstimate(packetResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ false);
958
+
959
+ withoutIt.SetBitrateEstimate(600000);
960
+ withoutIt.SetAcknowledgedBitrate(1000000);
961
+ withoutIt.UpdateBitrateEstimate(packetResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ false);
962
+
963
+ // Without that candidate the estimate can only walk up by the factors:
964
+ // 600000 * 1.02.
965
+ REQUIRE(withoutIt.GetResult().bitrate == 612000);
966
+ REQUIRE(withIt.GetResult().bitrate > withoutIt.GetResult().bitrate);
967
+ }
968
+
969
+ SECTION("what the link delivers is a candidate while not filling it when told so")
970
+ {
971
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions withoutItOptions{
972
+ .observationWindowSize = 2, .minNumObservations = 1, .lowerBoundByAckedRateFactor = 0.0
973
+ };
974
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions withItOptions{
975
+ .observationWindowSize = 2,
976
+ .minNumObservations = 1,
977
+ .lowerBoundByAckedRateFactor = 0.0,
978
+ .notUseAckedRateInAlr = false
979
+ };
980
+
981
+ RTC::BWE::LossBasedController withoutIt(withoutItOptions);
982
+ RTC::BWE::LossBasedController withIt(withItOptions);
983
+
984
+ const auto packetResults =
985
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0);
986
+
987
+ withoutIt.SetBitrateEstimate(600000);
988
+ withoutIt.SetAcknowledgedBitrate(1000000);
989
+ withoutIt.UpdateBitrateEstimate(packetResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ true);
990
+
991
+ withIt.SetBitrateEstimate(600000);
992
+ withIt.SetAcknowledgedBitrate(1000000);
993
+ withIt.UpdateBitrateEstimate(packetResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ true);
994
+
995
+ REQUIRE(withoutIt.GetResult().bitrate == 612000);
996
+ REQUIRE(withIt.GetResult().bitrate > withoutIt.GetResult().bitrate);
997
+ }
998
+
999
+ SECTION("the delay based estimate stops being a candidate when told so")
1000
+ {
1001
+ constexpr int64_t DelayBasedEstimate{ 1000000 };
1002
+
1003
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions withoutItOptions{
1004
+ .appendDelayBasedEstimateCandidate = false, .observationWindowSize = 2, .minNumObservations = 1
1005
+ };
1006
+
1007
+ RTC::BWE::LossBasedController withIt(shortObservationOptions);
1008
+ RTC::BWE::LossBasedController withoutIt(withoutItOptions);
1009
+
1010
+ const auto packetResults =
1011
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0);
1012
+
1013
+ withIt.SetBitrateEstimate(600000);
1014
+ withIt.UpdateBitrateEstimate(packetResults, DelayBasedEstimate, /*inAlr*/ false);
1015
+
1016
+ withoutIt.SetBitrateEstimate(600000);
1017
+ withoutIt.UpdateBitrateEstimate(packetResults, DelayBasedEstimate, /*inAlr*/ false);
1018
+
1019
+ // The delay based estimate still bounds the estimate from above either way,
1020
+ // so the option only decides whether it can be reached in a single step.
1021
+ REQUIRE(withoutIt.GetResult().bitrate == 612000);
1022
+ REQUIRE(withIt.GetResult().bitrate == DelayBasedEstimate);
1023
+ }
1024
+
1025
+ SECTION("measuring loss by packets ignores how much each lost packet carried")
1026
+ {
1027
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions byPacketsOptions{
1028
+ .observationWindowSize = 2, .minNumObservations = 1, .useByteLossRate = false
1029
+ };
1030
+
1031
+ RTC::BWE::LossBasedController byBytes(shortObservationOptions);
1032
+ RTC::BWE::LossBasedController byPackets(byPacketsOptions);
1033
+
1034
+ // Two packets whose sizes are wildly apart with the tiny one lost: by
1035
+ // bytes next to nothing was lost, by packets half of everything was.
1036
+ std::vector<RTC::BWE::Types::PacketResult> packetResults(2);
1037
+
1038
+ packetResults[0].sentPacket.sequenceNumber = sequenceNumber++;
1039
+ packetResults[0].sentPacket.size = PacketSizeBytes;
1040
+ packetResults[0].sentPacket.sendTimeUs = 0;
1041
+ packetResults[0].receiveTimeUs = ObservationDurationLowerBoundUs;
1042
+
1043
+ packetResults[1].sentPacket.sequenceNumber = sequenceNumber++;
1044
+ packetResults[1].sentPacket.size = 50;
1045
+ packetResults[1].sentPacket.sendTimeUs = ObservationDurationLowerBoundUs;
1046
+
1047
+ byBytes.SetBitrateEstimate(600000);
1048
+ byBytes.UpdateBitrateEstimate(packetResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ false);
1049
+
1050
+ byPackets.SetBitrateEstimate(600000);
1051
+ byPackets.UpdateBitrateEstimate(packetResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ false);
1052
+
1053
+ REQUIRE(byBytes.GetResult().bitrate > byPackets.GetResult().bitrate);
1054
+ }
1055
+
1056
+ SECTION("an estimate brought down to its bounds stops describing the link")
1057
+ {
1058
+ constexpr int64_t DelayBasedEstimate{ 500000 };
1059
+
1060
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions keepingItOptions{
1061
+ .observationWindowSize = 2, .minNumObservations = 1, .boundBestCandidate = false
1062
+ };
1063
+
1064
+ RTC::BWE::LossBasedController dropping(shortObservationOptions);
1065
+ RTC::BWE::LossBasedController keeping(keepingItOptions);
1066
+
1067
+ const auto boundedResults =
1068
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0);
1069
+ const auto freeResults =
1070
+ createResults(ObservationDurationLowerBoundUs, /*numPackets*/ 2, /*numLostPackets*/ 0);
1071
+
1072
+ dropping.SetBitrateEstimate(600000);
1073
+ keeping.SetBitrateEstimate(600000);
1074
+
1075
+ // The delay based estimate brings the chosen candidate down, which both
1076
+ // report as their estimate.
1077
+ dropping.UpdateBitrateEstimate(boundedResults, DelayBasedEstimate, /*inAlr*/ false);
1078
+ keeping.UpdateBitrateEstimate(boundedResults, DelayBasedEstimate, /*inAlr*/ false);
1079
+
1080
+ REQUIRE(dropping.GetResult().bitrate == DelayBasedEstimate);
1081
+ REQUIRE(keeping.GetResult().bitrate == DelayBasedEstimate);
1082
+
1083
+ // Once nothing bounds them anymore, the one that kept the candidate as its
1084
+ // description of the link carries on from there instead of from the bound.
1085
+ dropping.UpdateBitrateEstimate(freeResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ false);
1086
+ keeping.UpdateBitrateEstimate(freeResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ false);
1087
+
1088
+ REQUIRE(dropping.GetResult().bitrate == 510000);
1089
+ REQUIRE(keeping.GetResult().bitrate == 624240);
1090
+ }
1091
+
1092
+ SECTION("the longer since the estimate was last reduced the more it may grow")
1093
+ {
1094
+ constexpr int64_t DelayBasedEstimate{ 5000000 };
1095
+
1096
+ // A single candidate above what the window that follows a decrease allows,
1097
+ // so that the only thing deciding where the estimate lands is that bound.
1098
+ // The other two candidates are left out for the same reason.
1099
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions plainOptions{
1100
+ .candidateFactors = { 1.5 },
1101
+ .appendAcknowledgedRateCandidate = false,
1102
+ .appendDelayBasedEstimateCandidate = false,
1103
+ .observationWindowSize = 2,
1104
+ .minNumObservations = 1,
1105
+ .lowerBoundByAckedRateFactor = 0.0
1106
+ };
1107
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions acceleratedOptions{
1108
+ .candidateFactors = { 1.5 },
1109
+ .rampupAccelerationMaxFactor = 0.2,
1110
+ .appendAcknowledgedRateCandidate = false,
1111
+ .appendDelayBasedEstimateCandidate = false,
1112
+ .observationWindowSize = 2,
1113
+ .minNumObservations = 1,
1114
+ .lowerBoundByAckedRateFactor = 0.0
1115
+ };
1116
+
1117
+ RTC::BWE::LossBasedController plain(plainOptions);
1118
+ RTC::BWE::LossBasedController accelerated(acceleratedOptions);
1119
+
1120
+ const auto firstResults =
1121
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0);
1122
+ // Late enough for both the hold and the window that follows a decrease to
1123
+ // be over, which is what leaves that bound as the only one in the way.
1124
+ const auto lateResults =
1125
+ createResults(/*firstSendTimeUs*/ 400 * 1000, /*numPackets*/ 2, /*numLostPackets*/ 0);
1126
+
1127
+ plain.SetBitrateEstimate(600000);
1128
+ accelerated.SetBitrateEstimate(600000);
1129
+
1130
+ plain.UpdateBitrateEstimate(firstResults, DelayBasedEstimate, /*inAlr*/ false);
1131
+ accelerated.UpdateBitrateEstimate(firstResults, DelayBasedEstimate, /*inAlr*/ false);
1132
+
1133
+ // High enough that what the link is known to deliver isn't what holds the
1134
+ // estimate back.
1135
+ plain.SetAcknowledgedBitrate(5000000);
1136
+ accelerated.SetAcknowledgedBitrate(5000000);
1137
+
1138
+ plain.UpdateBitrateEstimate(lateResults, DelayBasedEstimate, /*inAlr*/ false);
1139
+ accelerated.UpdateBitrateEstimate(lateResults, DelayBasedEstimate, /*inAlr*/ false);
1140
+
1141
+ // 900000 * 1.3, which is what that window allows on its own.
1142
+ REQUIRE(plain.GetResult().bitrate == 1170000);
1143
+ REQUIRE(accelerated.GetResult().bitrate > plain.GetResult().bitrate);
1144
+ }
1145
+
1146
+ SECTION("the estimate grows despite the observed loss when the guard is off")
1147
+ {
1148
+ // The counterpart of the case above, with the same single candidate above
1149
+ // the current estimate and the guard that holds it back disabled.
1150
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions options{
1151
+ .candidateFactors = { 1.2 },
1152
+ .observationWindowSize = 2,
1153
+ .minNumObservations = 1,
1154
+ .notIncreaseIfInherentLossLessThanAverageLoss = false
1155
+ };
1156
+
1157
+ RTC::BWE::LossBasedController lossBasedController(options);
1158
+
1159
+ lossBasedController.SetBitrateEstimate(600000);
1160
+
1161
+ for (int64_t i{ 0 }; i < 2; ++i)
1162
+ {
1163
+ lossBasedController.UpdateBitrateEstimate(
1164
+ createResults(i * ObservationDurationLowerBoundUs, /*numPackets*/ 10, /*numLostPackets*/ 1),
1165
+ RTC::BWE::Types::BitrateInfinite,
1166
+ /*inAlr*/ false);
1167
+ }
1168
+
1169
+ REQUIRE(lossBasedController.GetResult().bitrate == 720000);
1170
+ }
1171
+
1172
+ SECTION("this controller can be kept from taking over during the start phase")
1173
+ {
1174
+ const RTC::BWE::LossBasedController::LossBasedControllerOptions notInStartPhaseOptions{
1175
+ .observationWindowSize = 2, .minNumObservations = 1, .useInStartPhase = false
1176
+ };
1177
+
1178
+ RTC::BWE::LossBasedController inStartPhase(shortObservationOptions);
1179
+ RTC::BWE::LossBasedController notInStartPhase(notInStartPhaseOptions);
1180
+
1181
+ const auto packetResults =
1182
+ createResults(/*firstSendTimeUs*/ 0, /*numPackets*/ 2, /*numLostPackets*/ 0);
1183
+
1184
+ inStartPhase.SetBitrateEstimate(600000);
1185
+ inStartPhase.UpdateBitrateEstimate(
1186
+ packetResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ false);
1187
+
1188
+ notInStartPhase.SetBitrateEstimate(600000);
1189
+ notInStartPhase.UpdateBitrateEstimate(
1190
+ packetResults, RTC::BWE::Types::BitrateInfinite, /*inAlr*/ false);
1191
+
1192
+ // Both have observed enough to say something, but only one of them is
1193
+ // allowed to say it that early.
1194
+ REQUIRE(inStartPhase.IsReady());
1195
+ REQUIRE(inStartPhase.IsReadyToUseInStartPhase());
1196
+ REQUIRE(notInStartPhase.IsReady());
1197
+ REQUIRE(!notInStartPhase.IsReadyToUseInStartPhase());
1198
+ }
1199
+ }