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,1046 @@
1
+ #define MS_CLASS "RTC::BWE::LossBasedController"
2
+ // #define MS_LOG_DEV_LEVEL 3
3
+
4
+ #include "RTC/BWE/LossBasedController.hpp"
5
+ #include "Logger.hpp"
6
+ #include "RTC/BWE/Utils.hpp"
7
+ #include <cmath>
8
+ #include <limits>
9
+
10
+ namespace RTC
11
+ {
12
+ namespace BWE
13
+ {
14
+ /* Static. */
15
+
16
+ // How long the first hold lasts, each following one lasting longer.
17
+ static constexpr int64_t InitHoldDurationUs{ 300 * 1000 };
18
+ // How long a hold may last no matter how many have piled up.
19
+ static constexpr int64_t MaxHoldDurationUs{ 60 * 1000 * 1000 };
20
+ // Lowest bitrate any congestion controller may produce.
21
+ static constexpr int64_t CongestionControllerMinBitrate{ 5000 };
22
+
23
+ /**
24
+ * Loss to expect from a link described by the given pair of values while
25
+ * sending at the given rate: its inherent loss, plus the share of the traffic
26
+ * that doesn't fit while sending above its capacity.
27
+ */
28
+ static double getLossProbability(double inherentLoss, int64_t lossLimitedBitrate, int64_t sendingRate)
29
+ {
30
+ MS_TRACE();
31
+
32
+ // NOTE: Clamped rather than asserted because a candidate refined by
33
+ // Newton's method can land outside before being brought back.
34
+ inherentLoss = std::clamp(inherentLoss, 0.0, 1.0);
35
+
36
+ double lossProbability{ inherentLoss };
37
+
38
+ if (sendingRate > 0 && lossLimitedBitrate > 0 && sendingRate > lossLimitedBitrate)
39
+ {
40
+ lossProbability += (1 - inherentLoss) *
41
+ static_cast<double>(sendingRate - lossLimitedBitrate) /
42
+ static_cast<double>(sendingRate);
43
+ }
44
+
45
+ // Leave room on both ends, since the likelihood takes the logarithm of
46
+ // this value and of its complement.
47
+ return std::clamp(lossProbability, 1.0e-6, 1.0 - 1.0e-6);
48
+ }
49
+
50
+ /**
51
+ * Size in kilobytes, which is the unit the likelihood is computed in so that
52
+ * its terms stay in a sane range.
53
+ */
54
+ static double toKiloBytes(int64_t bytes)
55
+ {
56
+ MS_TRACE();
57
+
58
+ return static_cast<double>(bytes) / 1000.0;
59
+ }
60
+
61
+ /* Instance methods. */
62
+
63
+ LossBasedController::LossBasedController() : LossBasedController(LossBasedControllerOptions{})
64
+ {
65
+ MS_TRACE();
66
+ }
67
+
68
+ LossBasedController::LossBasedController(LossBasedControllerOptions options)
69
+ : options(std::move(options))
70
+ {
71
+ MS_TRACE();
72
+
73
+ // NOTE: The window is what every observation is indexed modulo, so an
74
+ // empty one would divide by zero. These options are ours, so this can only
75
+ // fail out of a programming error.
76
+ MS_ASSERT(this->options.observationWindowSize > 0, "observation window size must be positive");
77
+
78
+ this->currentBestEstimate.inherentLoss = this->options.initialInherentLossEstimate;
79
+
80
+ this->observations.resize(this->options.observationWindowSize);
81
+ this->temporalWeights.resize(this->options.observationWindowSize);
82
+ this->immediateUpperBoundTemporalWeights.resize(this->options.observationWindowSize);
83
+
84
+ CalculateTemporalWeights();
85
+
86
+ this->lastHoldInfo.durationUs = InitHoldDurationUs;
87
+ }
88
+
89
+ bool LossBasedController::IsReady() const
90
+ {
91
+ MS_TRACE();
92
+
93
+ return this->currentBestEstimate.lossLimitedBitrate > 0 &&
94
+ this->numObservations >= this->options.minNumObservations;
95
+ }
96
+
97
+ bool LossBasedController::IsReadyToUseInStartPhase() const
98
+ {
99
+ MS_TRACE();
100
+
101
+ return IsReady() && this->options.useInStartPhase;
102
+ }
103
+
104
+ void LossBasedController::Reset()
105
+ {
106
+ MS_TRACE();
107
+
108
+ // Everything the constructor leaves behind, since what was observed
109
+ // describes a link that is not the one being used anymore. The temporal
110
+ // weights are left alone because they only depend on the options.
111
+ this->observations.assign(this->options.observationWindowSize, Observation{});
112
+ this->partialObservation = {};
113
+
114
+ this->currentBestEstimate = {};
115
+ this->currentBestEstimate.inherentLoss = this->options.initialInherentLossEstimate;
116
+
117
+ this->lastHoldInfo = {};
118
+ this->lastHoldInfo.durationUs = InitHoldDurationUs;
119
+
120
+ this->result = {};
121
+ this->numObservations = 0;
122
+ this->lastSendTimeOfLatestObservationUs.reset();
123
+ this->averageReportedLossRatio = 0.0;
124
+ this->acknowledgedBitrate = Types::BitrateInfinite;
125
+ this->delayBasedEstimate = Types::BitrateInfinite;
126
+ this->minBitrate = 0;
127
+ this->maxBitrate = Types::BitrateInfinite;
128
+ this->immediateUpperBoundBitrate.reset();
129
+ this->immediateLowerBoundBitrate.reset();
130
+ this->bitrateLimitInCurrentWindow = Types::BitrateInfinite;
131
+ this->recoveringAfterLossAtUs.reset();
132
+ this->lastBitrateReducedAtUs.reset();
133
+ }
134
+
135
+ LossBasedController::Result LossBasedController::GetResult() const
136
+ {
137
+ MS_TRACE();
138
+
139
+ if (!IsReady())
140
+ {
141
+ return { .bitrate = this->delayBasedEstimate, .state = State::DELAY_BASED_ESTIMATE };
142
+ }
143
+
144
+ return this->result;
145
+ }
146
+
147
+ void LossBasedController::SetAcknowledgedBitrate(int64_t acknowledgedBitrate)
148
+ {
149
+ MS_TRACE();
150
+
151
+ this->acknowledgedBitrate = acknowledgedBitrate;
152
+
153
+ CalculateImmediateLowerBoundBitrate();
154
+ }
155
+
156
+ void LossBasedController::SetBitrateLimits(int64_t minBitrate, int64_t maxBitrate)
157
+ {
158
+ MS_TRACE();
159
+
160
+ this->minBitrate = minBitrate;
161
+ this->maxBitrate = maxBitrate;
162
+
163
+ CalculateImmediateLowerBoundBitrate();
164
+ }
165
+
166
+ void LossBasedController::SetBitrateEstimate(int64_t bitrate)
167
+ {
168
+ MS_TRACE();
169
+
170
+ this->currentBestEstimate.lossLimitedBitrate = bitrate;
171
+ this->result = { .bitrate = bitrate, .state = State::DELAY_BASED_ESTIMATE };
172
+ }
173
+
174
+ void LossBasedController::UpdateBitrateEstimate(
175
+ const std::vector<Types::PacketResult>& packetResults, int64_t delayBasedEstimate, bool inAlr)
176
+ {
177
+ MS_TRACE();
178
+
179
+ this->delayBasedEstimate = delayBasedEstimate;
180
+
181
+ if (!PushBackObservation(packetResults) || !this->lastSendTimeOfLatestObservationUs.has_value())
182
+ {
183
+ return;
184
+ }
185
+
186
+ const int64_t lastSendTimeUs = this->lastSendTimeOfLatestObservationUs.value();
187
+
188
+ // Nothing has been estimated yet, so the delay based path is the only
189
+ // thing that can say where to start from.
190
+ if (this->currentBestEstimate.lossLimitedBitrate == 0)
191
+ {
192
+ if (delayBasedEstimate == Types::BitrateInfinite)
193
+ {
194
+ MS_WARN_TAG(bwe, "no delay based estimate to start the loss based one from");
195
+
196
+ return;
197
+ }
198
+
199
+ this->currentBestEstimate.lossLimitedBitrate = delayBasedEstimate;
200
+ this->result = { .bitrate = delayBasedEstimate, .state = State::DELAY_BASED_ESTIMATE };
201
+ }
202
+
203
+ // Take the candidate whose pair of values makes the observed losses most
204
+ // likely, preferring the higher bitrate when two are equally likely.
205
+ ChannelParameters bestCandidate = this->currentBestEstimate;
206
+ double maxObjective{ std::numeric_limits<double>::lowest() };
207
+
208
+ for (ChannelParameters candidate : GetCandidates(inAlr))
209
+ {
210
+ ApplyNewtonsMethod(candidate);
211
+
212
+ const double candidateObjective = GetObjective(candidate);
213
+
214
+ if (
215
+ candidateObjective > maxObjective ||
216
+ (candidateObjective == maxObjective &&
217
+ candidate.lossLimitedBitrate > bestCandidate.lossLimitedBitrate))
218
+ {
219
+ maxObjective = candidateObjective;
220
+ bestCandidate = candidate;
221
+ }
222
+ }
223
+
224
+ if (bestCandidate.lossLimitedBitrate < this->currentBestEstimate.lossLimitedBitrate)
225
+ {
226
+ this->lastBitrateReducedAtUs = lastSendTimeUs;
227
+ }
228
+
229
+ // Don't increase the estimate while the loss observed is worse than the
230
+ // one the chosen candidate says the link has by itself, since then the
231
+ // excess is ours to fix.
232
+ if (
233
+ this->averageReportedLossRatio > bestCandidate.inherentLoss &&
234
+ this->options.notIncreaseIfInherentLossLessThanAverageLoss &&
235
+ this->currentBestEstimate.lossLimitedBitrate < bestCandidate.lossLimitedBitrate)
236
+ {
237
+ bestCandidate.lossLimitedBitrate = this->currentBestEstimate.lossLimitedBitrate;
238
+ }
239
+
240
+ if (IsInLossLimitedState())
241
+ {
242
+ // Right after a decrease the estimate may not grow past what that
243
+ // decrease allowed, so that it doesn't jump straight back to the bitrate
244
+ // that caused the loss.
245
+ if (
246
+ this->recoveringAfterLossAtUs.has_value() &&
247
+ this->recoveringAfterLossAtUs.value() + this->options.delayedIncreaseWindowUs >
248
+ lastSendTimeUs &&
249
+ bestCandidate.lossLimitedBitrate > this->bitrateLimitInCurrentWindow)
250
+ {
251
+ bestCandidate.lossLimitedBitrate = this->bitrateLimitInCurrentWindow;
252
+ }
253
+
254
+ const bool increasingWhenLossLimited = IsEstimateIncreasingWhenLossLimited(
255
+ this->currentBestEstimate.lossLimitedBitrate, bestCandidate.lossLimitedBitrate);
256
+
257
+ // While loss limited, growing beyond what the link is known to be
258
+ // delivering is a guess, so it's bounded by the acknowledged bitrate.
259
+ if (increasingWhenLossLimited && this->acknowledgedBitrate != Types::BitrateInfinite)
260
+ {
261
+ double rampupFactor{ this->options.bitrateRampupUpperBoundFactor };
262
+
263
+ if (
264
+ this->lastHoldInfo.bitrate != Types::BitrateInfinite &&
265
+ this->acknowledgedBitrate <
266
+ this->options.bitrateRampupHoldThreshold * this->lastHoldInfo.bitrate)
267
+ {
268
+ rampupFactor = this->options.bitrateRampupUpperBoundFactorInHold;
269
+ }
270
+
271
+ bestCandidate.lossLimitedBitrate = std::max(
272
+ this->currentBestEstimate.lossLimitedBitrate,
273
+ std::min(
274
+ bestCandidate.lossLimitedBitrate,
275
+ Utils::ApplyBitrateFactor(this->acknowledgedBitrate, rampupFactor)));
276
+
277
+ // Growing by a single bit is what lets the state stop being
278
+ // decreasing. Without it, a bound that leaves the estimate untouched
279
+ // keeps it decreasing for good.
280
+ if (
281
+ this->result.state == State::DECREASING &&
282
+ bestCandidate.lossLimitedBitrate == this->currentBestEstimate.lossLimitedBitrate)
283
+ {
284
+ bestCandidate.lossLimitedBitrate =
285
+ Utils::AddBitrates(this->currentBestEstimate.lossLimitedBitrate, 1);
286
+ }
287
+ }
288
+ }
289
+
290
+ const int64_t boundedBitrate = std::max(
291
+ GetImmediateLowerBoundBitrate(),
292
+ std::min(
293
+ { bestCandidate.lossLimitedBitrate,
294
+ GetImmediateUpperBoundBitrate(),
295
+ this->delayBasedEstimate }));
296
+
297
+ // A bitrate that had to be brought down to its bounds is not an estimate
298
+ // of the link anymore, so the pair of values is not kept as such.
299
+ if (this->options.boundBestCandidate && boundedBitrate < bestCandidate.lossLimitedBitrate)
300
+ {
301
+ this->currentBestEstimate.lossLimitedBitrate = boundedBitrate;
302
+ this->currentBestEstimate.inherentLoss = 0;
303
+ }
304
+ else
305
+ {
306
+ this->currentBestEstimate = bestCandidate;
307
+
308
+ // A link is never worth describing as delivering less than what it is
309
+ // known to be delivering, unless that bound has been turned off.
310
+ if (this->options.lowerBoundByAckedRateFactor > 0.0)
311
+ {
312
+ this->currentBestEstimate.lossLimitedBitrate =
313
+ std::max(this->currentBestEstimate.lossLimitedBitrate, GetImmediateLowerBoundBitrate());
314
+ }
315
+ }
316
+
317
+ // While holding, the estimate may not grow above the bitrate being held,
318
+ // which is the whole point of holding.
319
+ if (
320
+ this->result.state == State::DECREASING && this->lastHoldInfo.atUs > lastSendTimeUs &&
321
+ boundedBitrate < this->delayBasedEstimate)
322
+ {
323
+ // A link is never worth holding below what it is known to be
324
+ // delivering, unless that bound has been turned off.
325
+ if (this->options.lowerBoundByAckedRateFactor > 0.0)
326
+ {
327
+ this->lastHoldInfo.bitrate =
328
+ std::max(GetImmediateLowerBoundBitrate(), this->lastHoldInfo.bitrate);
329
+ }
330
+
331
+ this->result.bitrate = std::min(this->lastHoldInfo.bitrate, boundedBitrate);
332
+
333
+ return;
334
+ }
335
+
336
+ if (
337
+ IsEstimateIncreasingWhenLossLimited(this->result.bitrate, boundedBitrate) &&
338
+ boundedBitrate < this->delayBasedEstimate && boundedBitrate < this->maxBitrate)
339
+ {
340
+ this->result.state = State::INCREASING;
341
+ }
342
+ else if (boundedBitrate < this->delayBasedEstimate && boundedBitrate < this->maxBitrate)
343
+ {
344
+ // A factor of zero means that no hold is ever entered, since each hold
345
+ // would last no time at all.
346
+ if (this->result.state != State::DECREASING && this->options.holdDurationFactor > 0.0)
347
+ {
348
+ MS_DEBUG_DEV(
349
+ "switching to hold [bitrate:%" PRIi64 ", durationMs:%" PRIi64 ", averageLoss:%f]",
350
+ boundedBitrate,
351
+ this->lastHoldInfo.durationUs / 1000,
352
+ this->averageReportedLossRatio);
353
+
354
+ this->lastHoldInfo = { .atUs = lastSendTimeUs + this->lastHoldInfo.durationUs,
355
+ .durationUs = std::min<int64_t>(
356
+ MaxHoldDurationUs,
357
+ std::llround(
358
+ static_cast<double>(this->lastHoldInfo.durationUs) *
359
+ this->options.holdDurationFactor)),
360
+ .bitrate = boundedBitrate };
361
+ }
362
+
363
+ this->result.state = State::DECREASING;
364
+ }
365
+ else
366
+ {
367
+ // The delay based path is what limits us, so any hold that was in place
368
+ // would only keep the estimate low for no reason.
369
+ this->lastHoldInfo = { .atUs = 0,
370
+ .durationUs = InitHoldDurationUs,
371
+ .bitrate = Types::BitrateInfinite };
372
+
373
+ this->result.state = State::DELAY_BASED_ESTIMATE;
374
+ }
375
+
376
+ this->result.bitrate = boundedBitrate;
377
+
378
+ // Open a new window in which the estimate is not allowed to grow freely,
379
+ // so that a link that keeps losing packets is approached gradually.
380
+ if (
381
+ IsInLossLimitedState() &&
382
+ (!this->recoveringAfterLossAtUs.has_value() ||
383
+ this->recoveringAfterLossAtUs.value() + this->options.delayedIncreaseWindowUs <
384
+ lastSendTimeUs))
385
+ {
386
+ this->bitrateLimitInCurrentWindow = std::max<int64_t>(
387
+ CongestionControllerMinBitrate,
388
+ Utils::ApplyBitrateFactor(
389
+ this->currentBestEstimate.lossLimitedBitrate, this->options.maxIncreaseFactor));
390
+
391
+ this->recoveringAfterLossAtUs = lastSendTimeUs;
392
+ }
393
+ }
394
+
395
+ bool LossBasedController::PushBackObservation(const std::vector<Types::PacketResult>& packetResults)
396
+ {
397
+ MS_TRACE();
398
+
399
+ if (packetResults.empty())
400
+ {
401
+ return false;
402
+ }
403
+
404
+ int64_t firstSendTimeUs{ Types::TimeUsInfinite };
405
+ int64_t lastSendTimeUs{ 0 };
406
+ bool anySendTime{ false };
407
+
408
+ for (const auto& packetResult : packetResults)
409
+ {
410
+ const auto sendTimeUs = packetResult.sentPacket.sendTimeUs;
411
+
412
+ // A packet with no send time belongs to no span of send times, and its
413
+ // bytes cannot be counted either: the duration of the observation comes
414
+ // from the instants of the other packets, so adding its size would
415
+ // inflate the sending rate attributed to them.
416
+ if (sendTimeUs == Types::TimeUsInfinite)
417
+ {
418
+ continue;
419
+ }
420
+
421
+ if (packetResult.IsReceived())
422
+ {
423
+ this->partialObservation.lostPackets.erase(packetResult.sentPacket.sequenceNumber);
424
+ }
425
+ else
426
+ {
427
+ this->partialObservation.lostPackets.emplace(
428
+ packetResult.sentPacket.sequenceNumber,
429
+ static_cast<int64_t>(packetResult.sentPacket.size));
430
+ }
431
+
432
+ this->partialObservation.numPackets += 1;
433
+ this->partialObservation.sizeBytes += static_cast<int64_t>(packetResult.sentPacket.size);
434
+
435
+ firstSendTimeUs = std::min(firstSendTimeUs, sendTimeUs);
436
+ lastSendTimeUs = std::max(lastSendTimeUs, sendTimeUs);
437
+ anySendTime = true;
438
+ }
439
+
440
+ if (!anySendTime)
441
+ {
442
+ return false;
443
+ }
444
+
445
+ // This is the first feedback ever received.
446
+ if (!this->lastSendTimeOfLatestObservationUs.has_value())
447
+ {
448
+ this->lastSendTimeOfLatestObservationUs = firstSendTimeUs;
449
+ }
450
+
451
+ const int64_t observationDurationUs =
452
+ lastSendTimeUs - this->lastSendTimeOfLatestObservationUs.value();
453
+
454
+ // Too short a span to tell anything.
455
+ if (observationDurationUs <= 0 || observationDurationUs < this->options.observationDurationLowerBoundUs)
456
+ {
457
+ return false;
458
+ }
459
+
460
+ this->lastSendTimeOfLatestObservationUs = lastSendTimeUs;
461
+
462
+ int64_t lostSizeBytes{ 0 };
463
+
464
+ for (const auto& kv : this->partialObservation.lostPackets)
465
+ {
466
+ lostSizeBytes += kv.second;
467
+ }
468
+
469
+ Observation observation;
470
+
471
+ observation.numPackets = this->partialObservation.numPackets;
472
+ observation.numLostPackets = static_cast<int64_t>(this->partialObservation.lostPackets.size());
473
+ observation.numReceivedPackets = observation.numPackets - observation.numLostPackets;
474
+ observation.sizeBytes = this->partialObservation.sizeBytes;
475
+ observation.lostSizeBytes = lostSizeBytes;
476
+ observation.sendingRate =
477
+ GetSendingRate((this->partialObservation.sizeBytes * 8 * 1000000) / observationDurationUs);
478
+ observation.id = this->numObservations++;
479
+
480
+ this->observations[observation.id % this->options.observationWindowSize] = observation;
481
+
482
+ this->partialObservation = PartialObservation();
483
+
484
+ UpdateAverageReportedLossRatio();
485
+ CalculateImmediateUpperBoundBitrate();
486
+
487
+ return true;
488
+ }
489
+
490
+ std::vector<LossBasedController::ChannelParameters> LossBasedController::GetCandidates(bool inAlr) const
491
+ {
492
+ MS_TRACE();
493
+
494
+ std::vector<int64_t> bitrates;
495
+
496
+ // The factors plus the acknowledged bitrate, the delay based estimate and
497
+ // the bound that the observed loss puts on the estimate.
498
+ bitrates.reserve(this->options.candidateFactors.size() + 3);
499
+
500
+ for (const double candidateFactor : this->options.candidateFactors)
501
+ {
502
+ bitrates.push_back(
503
+ Utils::ApplyBitrateFactor(this->currentBestEstimate.lossLimitedBitrate, candidateFactor));
504
+ }
505
+
506
+ // While not sending enough to fill the link, what it delivers says nothing
507
+ // about what it could deliver, so it's no candidate.
508
+ if (
509
+ this->acknowledgedBitrate != Types::BitrateInfinite &&
510
+ this->options.appendAcknowledgedRateCandidate &&
511
+ !(this->options.notUseAckedRateInAlr && inAlr))
512
+ {
513
+ bitrates.push_back(
514
+ Utils::ApplyBitrateFactor(
515
+ this->acknowledgedBitrate, this->options.bitrateBackoffLowerBoundFactor));
516
+ }
517
+
518
+ if (
519
+ this->delayBasedEstimate != Types::BitrateInfinite &&
520
+ this->options.appendDelayBasedEstimateCandidate &&
521
+ this->delayBasedEstimate > this->currentBestEstimate.lossLimitedBitrate)
522
+ {
523
+ bitrates.push_back(this->delayBasedEstimate);
524
+ }
525
+
526
+ // Coming all the way down to that bound in one step rather than gradually
527
+ // only makes sense while not filling the link, since then the loss is not
528
+ // ours to fix by sending less.
529
+ if (
530
+ inAlr && this->options.appendUpperBoundCandidateInAlr &&
531
+ this->currentBestEstimate.lossLimitedBitrate > GetImmediateUpperBoundBitrate())
532
+ {
533
+ bitrates.push_back(GetImmediateUpperBoundBitrate());
534
+ }
535
+
536
+ const int64_t candidateBitrateUpperBound = GetCandidateBitrateUpperBound();
537
+
538
+ std::vector<ChannelParameters> candidates;
539
+
540
+ candidates.reserve(bitrates.size());
541
+
542
+ for (const int64_t bitrate : bitrates)
543
+ {
544
+ ChannelParameters candidate = this->currentBestEstimate;
545
+
546
+ candidate.lossLimitedBitrate = std::min(
547
+ bitrate,
548
+ std::max(this->currentBestEstimate.lossLimitedBitrate, candidateBitrateUpperBound));
549
+ candidate.inherentLoss = GetFeasibleInherentLoss(candidate);
550
+
551
+ candidates.push_back(candidate);
552
+ }
553
+
554
+ return candidates;
555
+ }
556
+
557
+ int64_t LossBasedController::GetCandidateBitrateUpperBound() const
558
+ {
559
+ MS_TRACE();
560
+
561
+ int64_t candidateBitrateUpperBound{ this->maxBitrate };
562
+
563
+ if (IsInLossLimitedState() && this->bitrateLimitInCurrentWindow != Types::BitrateInfinite)
564
+ {
565
+ candidateBitrateUpperBound = this->bitrateLimitInCurrentWindow;
566
+ }
567
+
568
+ if (this->acknowledgedBitrate == Types::BitrateInfinite)
569
+ {
570
+ return candidateBitrateUpperBound;
571
+ }
572
+
573
+ // The longer it's been since the estimate was last reduced, the more it is
574
+ // allowed to grow beyond its usual bound.
575
+ if (this->options.rampupAccelerationMaxFactor > 0.0)
576
+ {
577
+ // Never having been reduced counts as the longest time possible, which
578
+ // is what gives the fullest acceleration.
579
+ const int64_t sinceBitrateReducedUs =
580
+ this->lastBitrateReducedAtUs.has_value() &&
581
+ this->lastSendTimeOfLatestObservationUs.has_value()
582
+ ? std::min(
583
+ this->options.rampupAccelerationMaxoutTimeUs,
584
+ std::max<int64_t>(
585
+ this->lastSendTimeOfLatestObservationUs.value() -
586
+ this->lastBitrateReducedAtUs.value(),
587
+ 0))
588
+ : this->options.rampupAccelerationMaxoutTimeUs;
589
+ const double rampupAcceleration =
590
+ this->options.rampupAccelerationMaxFactor * static_cast<double>(sinceBitrateReducedUs) /
591
+ static_cast<double>(this->options.rampupAccelerationMaxoutTimeUs);
592
+
593
+ candidateBitrateUpperBound = Utils::AddBitrates(
594
+ candidateBitrateUpperBound,
595
+ Utils::ApplyBitrateFactor(this->acknowledgedBitrate, rampupAcceleration));
596
+ }
597
+
598
+ return candidateBitrateUpperBound;
599
+ }
600
+
601
+ double LossBasedController::GetObjective(const ChannelParameters& channelParameters) const
602
+ {
603
+ MS_TRACE();
604
+
605
+ double objective{ 0.0 };
606
+
607
+ const double highBitrateBias = GetHighBitrateBias(channelParameters.lossLimitedBitrate);
608
+
609
+ for (const auto& observation : this->observations)
610
+ {
611
+ if (!observation.IsInitialized())
612
+ {
613
+ continue;
614
+ }
615
+
616
+ const double lossProbability = getLossProbability(
617
+ channelParameters.inherentLoss,
618
+ channelParameters.lossLimitedBitrate,
619
+ observation.sendingRate);
620
+
621
+ const double temporalWeight =
622
+ this->temporalWeights[(this->numObservations - 1) - observation.id];
623
+
624
+ if (this->options.useByteLossRate)
625
+ {
626
+ objective +=
627
+ temporalWeight * ((toKiloBytes(observation.lostSizeBytes) * std::log(lossProbability)) +
628
+ (toKiloBytes(observation.sizeBytes - observation.lostSizeBytes) *
629
+ std::log(1.0 - lossProbability)));
630
+ objective += temporalWeight * highBitrateBias * toKiloBytes(observation.sizeBytes);
631
+ }
632
+ else
633
+ {
634
+ objective +=
635
+ temporalWeight *
636
+ ((static_cast<double>(observation.numLostPackets) * std::log(lossProbability)) +
637
+ (static_cast<double>(observation.numReceivedPackets) * std::log(1.0 - lossProbability)));
638
+ objective += temporalWeight * highBitrateBias * static_cast<double>(observation.numPackets);
639
+ }
640
+ }
641
+
642
+ return objective;
643
+ }
644
+
645
+ LossBasedController::Derivatives LossBasedController::GetDerivatives(
646
+ const ChannelParameters& channelParameters) const
647
+ {
648
+ MS_TRACE();
649
+
650
+ Derivatives derivatives;
651
+
652
+ for (const auto& observation : this->observations)
653
+ {
654
+ if (!observation.IsInitialized())
655
+ {
656
+ continue;
657
+ }
658
+
659
+ const double lossProbability = getLossProbability(
660
+ channelParameters.inherentLoss,
661
+ channelParameters.lossLimitedBitrate,
662
+ observation.sendingRate);
663
+
664
+ const double temporalWeight =
665
+ this->temporalWeights[(this->numObservations - 1) - observation.id];
666
+
667
+ if (this->options.useByteLossRate)
668
+ {
669
+ derivatives.first +=
670
+ temporalWeight * ((toKiloBytes(observation.lostSizeBytes) / lossProbability) -
671
+ (toKiloBytes(observation.sizeBytes - observation.lostSizeBytes) /
672
+ (1.0 - lossProbability)));
673
+ derivatives.second -=
674
+ temporalWeight * ((toKiloBytes(observation.lostSizeBytes) / std::pow(lossProbability, 2)) +
675
+ (toKiloBytes(observation.sizeBytes - observation.lostSizeBytes) /
676
+ std::pow(1.0 - lossProbability, 2)));
677
+ }
678
+ else
679
+ {
680
+ derivatives.first +=
681
+ temporalWeight *
682
+ ((static_cast<double>(observation.numLostPackets) / lossProbability) -
683
+ (static_cast<double>(observation.numReceivedPackets) / (1.0 - lossProbability)));
684
+ derivatives.second -=
685
+ temporalWeight *
686
+ ((static_cast<double>(observation.numLostPackets) / std::pow(lossProbability, 2)) +
687
+ (static_cast<double>(observation.numReceivedPackets) /
688
+ std::pow(1.0 - lossProbability, 2)));
689
+ }
690
+ }
691
+
692
+ // NOTE: The second derivative is negative by construction, so a value of
693
+ // zero can only come from rounding and would make the step below divide by
694
+ // zero.
695
+ if (derivatives.second >= 0.0)
696
+ {
697
+ derivatives.second = -1.0e-6;
698
+ }
699
+
700
+ return derivatives;
701
+ }
702
+
703
+ void LossBasedController::ApplyNewtonsMethod(ChannelParameters& channelParameters) const
704
+ {
705
+ MS_TRACE();
706
+
707
+ if (this->numObservations <= 0)
708
+ {
709
+ return;
710
+ }
711
+
712
+ for (int64_t i{ 0 }; i < this->options.newtonIterations; ++i)
713
+ {
714
+ const Derivatives derivatives = GetDerivatives(channelParameters);
715
+
716
+ channelParameters.inherentLoss -=
717
+ this->options.newtonStepSize * derivatives.first / derivatives.second;
718
+ channelParameters.inherentLoss = GetFeasibleInherentLoss(channelParameters);
719
+ }
720
+ }
721
+
722
+ double LossBasedController::GetFeasibleInherentLoss(const ChannelParameters& channelParameters) const
723
+ {
724
+ MS_TRACE();
725
+
726
+ return std::min(
727
+ std::max(channelParameters.inherentLoss, this->options.inherentLossLowerBound),
728
+ GetInherentLossUpperBound(channelParameters.lossLimitedBitrate));
729
+ }
730
+
731
+ double LossBasedController::GetInherentLossUpperBound(int64_t bitrate) const
732
+ {
733
+ MS_TRACE();
734
+
735
+ if (bitrate == 0)
736
+ {
737
+ return 1.0;
738
+ }
739
+
740
+ // The lower the bitrate, the more loss a link is allowed to be said to
741
+ // have by itself, since at a low enough bitrate the traffic cannot be the
742
+ // cause.
743
+ const double inherentLossUpperBound =
744
+ this->options.inherentLossUpperBoundOffset +
745
+ (static_cast<double>(this->options.inherentLossUpperBoundBitrateBalance) /
746
+ static_cast<double>(bitrate));
747
+
748
+ return std::min(inherentLossUpperBound, 1.0);
749
+ }
750
+
751
+ double LossBasedController::AdjustBiasFactor(double lossRate, double biasFactor) const
752
+ {
753
+ MS_TRACE();
754
+
755
+ return biasFactor * (this->options.lossThresholdOfHighBitratePreference - lossRate) /
756
+ (this->options.bitratePreferenceSmoothingFactor +
757
+ std::abs(this->options.lossThresholdOfHighBitratePreference - lossRate));
758
+ }
759
+
760
+ double LossBasedController::GetHighBitrateBias(int64_t bitrate) const
761
+ {
762
+ MS_TRACE();
763
+
764
+ if (bitrate <= 0)
765
+ {
766
+ return 0.0;
767
+ }
768
+
769
+ const double bitrateKbps = static_cast<double>(bitrate) / 1000.0;
770
+
771
+ return (AdjustBiasFactor(this->averageReportedLossRatio, this->options.higherBitrateBiasFactor) *
772
+ bitrateKbps) +
773
+ (AdjustBiasFactor(
774
+ this->averageReportedLossRatio, this->options.higherLogBitrateBiasFactor) *
775
+ std::log(1.0 + bitrateKbps));
776
+ }
777
+
778
+ int64_t LossBasedController::GetSendingRate(int64_t instantSendingRate) const
779
+ {
780
+ MS_TRACE();
781
+
782
+ if (this->numObservations <= 0)
783
+ {
784
+ return instantSendingRate;
785
+ }
786
+
787
+ const int64_t latestObservationIdx =
788
+ (this->numObservations - 1) % this->options.observationWindowSize;
789
+ const int64_t previousSendingRate = this->observations[latestObservationIdx].sendingRate;
790
+
791
+ // Each share is rounded on its own before they are added, so that the
792
+ // smoothed rate doesn't depend on how the two of them happen to split.
793
+ return Utils::AddBitrates(
794
+ Utils::ApplyBitrateFactor(previousSendingRate, this->options.sendingRateSmoothingFactor),
795
+ Utils::ApplyBitrateFactor(instantSendingRate, 1.0 - this->options.sendingRateSmoothingFactor));
796
+ }
797
+
798
+ void LossBasedController::UpdateAverageReportedLossRatio()
799
+ {
800
+ MS_TRACE();
801
+
802
+ this->averageReportedLossRatio = this->options.useByteLossRate
803
+ ? CalculateAverageReportedByteLossRatio()
804
+ : CalculateAverageReportedPacketLossRatio();
805
+ }
806
+
807
+ double LossBasedController::CalculateAverageReportedPacketLossRatio() const
808
+ {
809
+ MS_TRACE();
810
+
811
+ if (this->numObservations <= 0)
812
+ {
813
+ return 0.0;
814
+ }
815
+
816
+ double numPackets{ 0.0 };
817
+ double numLostPackets{ 0.0 };
818
+
819
+ for (const auto& observation : this->observations)
820
+ {
821
+ if (!observation.IsInitialized())
822
+ {
823
+ continue;
824
+ }
825
+
826
+ const double temporalWeight =
827
+ this->immediateUpperBoundTemporalWeights[(this->numObservations - 1) - observation.id];
828
+
829
+ numPackets += temporalWeight * static_cast<double>(observation.numPackets);
830
+ numLostPackets += temporalWeight * static_cast<double>(observation.numLostPackets);
831
+ }
832
+
833
+ // NOTE: Nothing was sent at all, so there is no loss to tell. Without this
834
+ // the division would give a NaN, which makes every comparison it takes
835
+ // part in false and silently freezes the estimate for good.
836
+ if (numPackets == 0.0)
837
+ {
838
+ return 0.0;
839
+ }
840
+
841
+ return numLostPackets / numPackets;
842
+ }
843
+
844
+ double LossBasedController::CalculateAverageReportedByteLossRatio() const
845
+ {
846
+ MS_TRACE();
847
+
848
+ if (this->numObservations <= 0)
849
+ {
850
+ return 0.0;
851
+ }
852
+
853
+ double totalBytes{ 0.0 };
854
+ double lostBytes{ 0.0 };
855
+ double minLossRate{ 1.0 };
856
+ double maxLossRate{ 0.0 };
857
+ double minLostBytes{ 0.0 };
858
+ double maxLostBytes{ 0.0 };
859
+ double minBytesReceived{ 0.0 };
860
+ double maxBytesReceived{ 0.0 };
861
+ int64_t sendingRateOfMaxLossObservation{ 0 };
862
+
863
+ for (const auto& observation : this->observations)
864
+ {
865
+ if (!observation.IsInitialized())
866
+ {
867
+ continue;
868
+ }
869
+
870
+ const double temporalWeight =
871
+ this->immediateUpperBoundTemporalWeights[(this->numObservations - 1) - observation.id];
872
+
873
+ totalBytes += temporalWeight * static_cast<double>(observation.sizeBytes);
874
+ lostBytes += temporalWeight * static_cast<double>(observation.lostSizeBytes);
875
+
876
+ const double lossRate = observation.sizeBytes != 0
877
+ ? static_cast<double>(observation.lostSizeBytes) /
878
+ static_cast<double>(observation.sizeBytes)
879
+ : 0.0;
880
+
881
+ // The highest and the lowest are left out only once there are enough
882
+ // observations for that to still leave something.
883
+ if (this->numObservations <= 3)
884
+ {
885
+ continue;
886
+ }
887
+
888
+ if (lossRate > maxLossRate)
889
+ {
890
+ maxLossRate = lossRate;
891
+ maxLostBytes = temporalWeight * static_cast<double>(observation.lostSizeBytes);
892
+ maxBytesReceived = temporalWeight * static_cast<double>(observation.sizeBytes);
893
+ sendingRateOfMaxLossObservation = observation.sendingRate;
894
+ }
895
+
896
+ if (lossRate < minLossRate)
897
+ {
898
+ minLossRate = lossRate;
899
+ minLostBytes = temporalWeight * static_cast<double>(observation.lostSizeBytes);
900
+ minBytesReceived = temporalWeight * static_cast<double>(observation.sizeBytes);
901
+ }
902
+ }
903
+
904
+ // NOTE: Nothing was sent at all, so there is no loss to tell. Without this
905
+ // the division below would give a NaN, which makes every comparison it
906
+ // takes part in false and silently freezes the estimate for good.
907
+ if (totalBytes == 0.0)
908
+ {
909
+ return 0.0;
910
+ }
911
+
912
+ // A sudden jump of the sending rate explains the loss of that observation
913
+ // on its own, so it's not a spike to be filtered out.
914
+ if (GetMedianSendingRate() * this->options.medianSendingRateFactor <= sendingRateOfMaxLossObservation)
915
+ {
916
+ return lostBytes / totalBytes;
917
+ }
918
+
919
+ // It could happen if the window was of two observations.
920
+ if (totalBytes == maxBytesReceived + minBytesReceived)
921
+ {
922
+ return lostBytes / totalBytes;
923
+ }
924
+
925
+ return (lostBytes - minLostBytes - maxLostBytes) /
926
+ (totalBytes - maxBytesReceived - minBytesReceived);
927
+ }
928
+
929
+ int64_t LossBasedController::GetMedianSendingRate() const
930
+ {
931
+ MS_TRACE();
932
+
933
+ std::vector<int64_t> sendingRates;
934
+
935
+ sendingRates.reserve(this->observations.size());
936
+
937
+ for (const auto& observation : this->observations)
938
+ {
939
+ if (!observation.IsInitialized() || observation.sendingRate == 0)
940
+ {
941
+ continue;
942
+ }
943
+
944
+ sendingRates.push_back(observation.sendingRate);
945
+ }
946
+
947
+ if (sendingRates.empty())
948
+ {
949
+ return 0;
950
+ }
951
+
952
+ std::ranges::sort(sendingRates);
953
+
954
+ if (sendingRates.size() % 2 == 0)
955
+ {
956
+ return (sendingRates[(sendingRates.size() / 2) - 1] + sendingRates[sendingRates.size() / 2]) /
957
+ 2;
958
+ }
959
+
960
+ return sendingRates[sendingRates.size() / 2];
961
+ }
962
+
963
+ int64_t LossBasedController::GetImmediateUpperBoundBitrate() const
964
+ {
965
+ MS_TRACE();
966
+
967
+ return this->immediateUpperBoundBitrate.value_or(this->maxBitrate);
968
+ }
969
+
970
+ void LossBasedController::CalculateImmediateUpperBoundBitrate()
971
+ {
972
+ MS_TRACE();
973
+
974
+ int64_t bitrate{ this->maxBitrate };
975
+
976
+ // Beyond a bit of loss, the more is observed the less the link is allowed
977
+ // to be told to carry, without waiting for the estimate to converge.
978
+ if (this->averageReportedLossRatio > this->options.immediateUpperBoundLossOffset)
979
+ {
980
+ const double boundBitrate =
981
+ static_cast<double>(this->options.immediateUpperBoundBitrateBalance) /
982
+ (this->averageReportedLossRatio - this->options.immediateUpperBoundLossOffset);
983
+
984
+ // NOTE: A loss barely above the offset gives a bound beyond what an
985
+ // int64_t can hold, and converting such a value is undefined behaviour.
986
+ // It bounds nothing anyway once it's over the maximum bitrate.
987
+ bitrate = boundBitrate >= static_cast<double>(this->maxBitrate) ? this->maxBitrate
988
+ : std::llround(boundBitrate);
989
+ }
990
+
991
+ this->immediateUpperBoundBitrate = bitrate;
992
+ }
993
+
994
+ int64_t LossBasedController::GetImmediateLowerBoundBitrate() const
995
+ {
996
+ MS_TRACE();
997
+
998
+ return this->immediateLowerBoundBitrate.value_or(0);
999
+ }
1000
+
1001
+ void LossBasedController::CalculateImmediateLowerBoundBitrate()
1002
+ {
1003
+ MS_TRACE();
1004
+
1005
+ int64_t bitrate{ 0 };
1006
+
1007
+ // What the link is known to be delivering is never worth going below.
1008
+ if (this->acknowledgedBitrate != Types::BitrateInfinite)
1009
+ {
1010
+ bitrate = Utils::ApplyBitrateFactor(
1011
+ this->acknowledgedBitrate, this->options.lowerBoundByAckedRateFactor);
1012
+ }
1013
+
1014
+ this->immediateLowerBoundBitrate = std::max(bitrate, this->minBitrate);
1015
+ }
1016
+
1017
+ void LossBasedController::CalculateTemporalWeights()
1018
+ {
1019
+ MS_TRACE();
1020
+
1021
+ for (int64_t i{ 0 }; i < this->options.observationWindowSize; ++i)
1022
+ {
1023
+ this->temporalWeights[i] = std::pow(this->options.temporalWeightFactor, i);
1024
+ this->immediateUpperBoundTemporalWeights[i] =
1025
+ std::pow(this->options.immediateUpperBoundTemporalWeightFactor, i);
1026
+ }
1027
+ }
1028
+
1029
+ bool LossBasedController::IsInLossLimitedState() const
1030
+ {
1031
+ MS_TRACE();
1032
+
1033
+ return this->result.state != State::DELAY_BASED_ESTIMATE;
1034
+ }
1035
+
1036
+ bool LossBasedController::IsEstimateIncreasingWhenLossLimited(
1037
+ int64_t oldEstimate, int64_t newEstimate) const
1038
+ {
1039
+ MS_TRACE();
1040
+
1041
+ return (oldEstimate < newEstimate ||
1042
+ (oldEstimate == newEstimate && this->result.state == State::INCREASING)) &&
1043
+ IsInLossLimitedState();
1044
+ }
1045
+ } // namespace BWE
1046
+ } // namespace RTC