{"id":913,"date":"2023-03-18T23:11:57","date_gmt":"2023-03-18T15:11:57","guid":{"rendered":"https:\/\/www.fanyamin.com\/wordpress\/?p=913"},"modified":"2023-03-19T10:23:52","modified_gmt":"2023-03-19T02:23:52","slug":"webrtc-bandwidth-allocation","status":"publish","type":"post","link":"https:\/\/www.fanyamin.com\/wordpress\/?p=913","title":{"rendered":"WebRTC Bandwidth Allocation"},"content":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/www.fanyamin.com\/wordpress\/wp-content\/uploads\/2023\/03\/image-1679151937737.png\" alt=\"file\" \/><\/p>\n<pre><code>Title Bandwidth allocation by REMB\n\nModuleRtpRtcpImpl-&gt;RTCPReceiver: IncomingPacket\nRTCPReceiver-&gt;RTCPReceiver: TriggerCallbacksFromRtcpPacket\nRTCPReceiver-&gt;RtpTransportControllerSend:OnReceivedEstimatedBitrate(bitrate)\nRtpTransportControllerSend-&gt;GoogCcNetworkController: OnRemoteBitrateReport(receiveTime, bitrate)\nGoogCcNetworkController-&gt;SendSideBandwidthEstimation: UpdateReceiverEstimate\nSendSideBandwidthEstimation-&gt;SendSideBandwidthEstimation: ApplyTargetLimits\nSendSideBandwidthEstimation-&gt;SendSideBandwidthEstimation: UpdateTargetBitrate\n#SendSideBandwidthEstimation-&gt;LinkCapacityTracker:OnRateUpdate\nGoogCcNetworkController-&gt;Call: OnTargetTransferRate\nCall-&gt;BitrateAllocator: OnNetworkEstimateChanged\nBitrateAllocator-&gt;BitrateAllocator: AllocateBitrates<\/code><\/pre>\n<h1>Snippets<\/h1>\n<ul>\n<li>AllocateBitrates \u5e26\u5bbd\u5206\u914d\u65b9\u6cd5<\/li>\n<\/ul>\n<pre><code>std::map&lt;BitrateAllocatorObserver*, int&gt; AllocateBitrates(\n    const std::vector&lt;AllocatableTrack&gt;&amp; allocatable_tracks,\n    uint32_t bitrate) {\n  if (allocatable_tracks.empty())\n    return std::map&lt;BitrateAllocatorObserver*, int&gt;();\n\n  if (bitrate == 0)\n    return ZeroRateAllocation(allocatable_tracks);\n\n  uint32_t sum_min_bitrates = 0;\n  uint32_t sum_max_bitrates = 0;\n  for (const auto&amp; observer_config : allocatable_tracks) {\n    sum_min_bitrates += observer_config.config.min_bitrate_bps;\n    sum_max_bitrates += observer_config.config.max_bitrate_bps;\n  }\n\n  \/\/ Not enough for all observers to get an allocation, allocate according to:\n  \/\/ enforced min bitrate -&gt; allocated bitrate previous round -&gt; restart paused\n  \/\/ streams.\n  if (!EnoughBitrateForAllObservers(allocatable_tracks, bitrate,\n                                    sum_min_bitrates))\n    return LowRateAllocation(allocatable_tracks, bitrate);\n\n  \/\/ All observers will get their min bitrate plus a share of the rest. This\n  \/\/ share is allocated to each observer based on its bitrate_priority.\n  if (bitrate &lt;= sum_max_bitrates)\n    return NormalRateAllocation(allocatable_tracks, bitrate, sum_min_bitrates);\n\n  \/\/ All observers will get up to transmission_max_bitrate_multiplier_ x max.\n  return MaxRateAllocation(allocatable_tracks, bitrate, sum_max_bitrates);\n}\n<\/code><\/pre>\n<ul>\n<li>\n<p>UpdateControlState<\/p>\n<pre><code>void RtpTransportControllerSend::UpdateControlState() {\nabsl::optional&lt;TargetTransferRate&gt; update = control_handler_-&gt;GetUpdate();\nif (!update)\nreturn;\nretransmission_rate_limiter_.SetMaxRate(update-&gt;target_rate.bps());\n\/\/ We won&#039;t create control_handler_ until we have an observers.\nRTC_DCHECK(observer_ != nullptr);\nobserver_-&gt;OnTargetTransferRate(*update);\n}<\/code><\/pre>\n<h3>EnoughBitrateForAllObservers \u5e26\u5bbd\u8db3\u591f\u548c\u8bdd<\/h3>\n<pre><code>bool EnoughBitrateForAllObservers(\nconst std::vector&lt;AllocatableTrack&gt;&amp; allocatable_tracks,\nuint32_t bitrate,\nuint32_t sum_min_bitrates) {\nif (bitrate &lt; sum_min_bitrates)\nreturn false;\n\nuint32_t extra_bitrate_per_observer =\n  (bitrate - sum_min_bitrates) \/\n  static_cast&lt;uint32_t&gt;(allocatable_tracks.size());\nfor (const auto&amp; observer_config : allocatable_tracks) {\nif (observer_config.config.min_bitrate_bps + extra_bitrate_per_observer &lt;\n    observer_config.MinBitrateWithHysteresis()) {\n  return false;\n}\n}\nreturn true;\n}<\/code><\/pre>\n<\/li>\n<\/ul>\n<h3>LowRateAllocation \u5e26\u5bbd\u4e0d\u591f\u7684\u5206\u6790\u7b56\u7565<\/h3>\n<pre><code>\/\/ Allocates bitrate to observers when there isn&#039;t enough to allocate the\n\/\/ minimum to all observers.\nstd::map&lt;BitrateAllocatorObserver*, int&gt; LowRateAllocation(\n    const std::vector&lt;AllocatableTrack&gt;&amp; allocatable_tracks,\n    uint32_t bitrate) {\n  std::map&lt;BitrateAllocatorObserver*, int&gt; allocation;\n  \/\/ Start by allocating bitrate to observers enforcing a min bitrate, hence\n  \/\/ remaining_bitrate might turn negative.\n  int64_t remaining_bitrate = bitrate;\n  for (const auto&amp; observer_config : allocatable_tracks) {\n    int32_t allocated_bitrate = 0;\n    if (observer_config.config.enforce_min_bitrate)\n      allocated_bitrate = observer_config.config.min_bitrate_bps;\n\n    allocation[observer_config.observer] = allocated_bitrate;\n    remaining_bitrate -= allocated_bitrate;\n  }\n\n  \/\/ Allocate bitrate to all previously active streams.\n  if (remaining_bitrate &gt; 0) {\n    for (const auto&amp; observer_config : allocatable_tracks) {\n      if (observer_config.config.enforce_min_bitrate ||\n          observer_config.LastAllocatedBitrate() == 0)\n        continue;\n\n      uint32_t required_bitrate = observer_config.MinBitrateWithHysteresis();\n      if (remaining_bitrate &gt;= required_bitrate) {\n        allocation[observer_config.observer] = required_bitrate;\n        remaining_bitrate -= required_bitrate;\n      }\n    }\n  }\n\n  \/\/ Allocate bitrate to previously paused streams.\n  if (remaining_bitrate &gt; 0) {\n    for (const auto&amp; observer_config : allocatable_tracks) {\n      if (observer_config.LastAllocatedBitrate() != 0)\n        continue;\n\n      \/\/ Add a hysteresis to avoid toggling.\n      uint32_t required_bitrate = observer_config.MinBitrateWithHysteresis();\n      if (remaining_bitrate &gt;= required_bitrate) {\n        allocation[observer_config.observer] = required_bitrate;\n        remaining_bitrate -= required_bitrate;\n      }\n    }\n  }\n\n  \/\/ Split a possible remainder evenly on all streams with an allocation.\n  if (remaining_bitrate &gt; 0)\n    DistributeBitrateEvenly(allocatable_tracks, remaining_bitrate, false, 1,\n                            &amp;allocation);\n\n  RTC_DCHECK_EQ(allocation.size(), allocatable_tracks.size());\n  return allocation;\n}\n<\/code><\/pre>\n<h3>NormalRateAllocation \u6309\u4f18\u5148\u7ea7\u7684\u5e26\u5bbd\u5206\u914d\u7b56\u7565<\/h3>\n<pre><code>\/\/ Allocates the bitrate based on the bitrate priority of each observer. This\n\/\/ bitrate priority defines the priority for bitrate to be allocated to that\n\/\/ observer in relation to other observers. For example with two observers, if\n\/\/ observer 1 had a bitrate_priority = 1.0, and observer 2 has a\n\/\/ bitrate_priority = 2.0, the expected behavior is that observer 2 will be\n\/\/ allocated twice the bitrate as observer 1 above the each observer&#039;s\n\/\/ min_bitrate_bps values, until one of the observers hits its max_bitrate_bps.\nstd::map&lt;BitrateAllocatorObserver*, int&gt; NormalRateAllocation(\n    const std::vector&lt;AllocatableTrack&gt;&amp; allocatable_tracks,\n    uint32_t bitrate,\n    uint32_t sum_min_bitrates) {\n  std::map&lt;BitrateAllocatorObserver*, int&gt; allocation;\n  std::map&lt;BitrateAllocatorObserver*, int&gt; observers_capacities;\n  for (const auto&amp; observer_config : allocatable_tracks) {\n    allocation[observer_config.observer] =\n        observer_config.config.min_bitrate_bps;\n    observers_capacities[observer_config.observer] =\n        observer_config.config.max_bitrate_bps -\n        observer_config.config.min_bitrate_bps;\n  }\n\n  bitrate -= sum_min_bitrates;\n\n  \/\/ TODO(srte): Implement fair sharing between prioritized streams, currently\n  \/\/ they are treated on a first come first serve basis.\n  for (const auto&amp; observer_config : allocatable_tracks) {\n    int64_t priority_margin = observer_config.config.priority_bitrate_bps -\n                              allocation[observer_config.observer];\n    if (priority_margin &gt; 0 &amp;&amp; bitrate &gt; 0) {\n      int64_t extra_bitrate = std::min&lt;int64_t&gt;(priority_margin, bitrate);\n      allocation[observer_config.observer] +=\n          rtc::dchecked_cast&lt;int&gt;(extra_bitrate);\n      observers_capacities[observer_config.observer] -= extra_bitrate;\n      bitrate -= extra_bitrate;\n    }\n  }\n\n  \/\/ From the remaining bitrate, allocate a proportional amount to each observer\n  \/\/ above the min bitrate already allocated.\n  if (bitrate &gt; 0)\n    DistributeBitrateRelatively(allocatable_tracks, bitrate,\n                                observers_capacities, &amp;allocation);\n\n  return allocation;\n}<\/code><\/pre>\n<h3>MaxRateAllocation \u6700\u5927\u5e26\u5bbd\u5206\u914d\u7b56\u7565<\/h3>\n<pre><code>\/\/ Allocates bitrate to observers when there is enough available bandwidth\n\/\/ for all observers to be allocated their max bitrate.\nstd::map&lt;BitrateAllocatorObserver*, int&gt; MaxRateAllocation(\n    const std::vector&lt;AllocatableTrack&gt;&amp; allocatable_tracks,\n    uint32_t bitrate,\n    uint32_t sum_max_bitrates) {\n  std::map&lt;BitrateAllocatorObserver*, int&gt; allocation;\n\n  for (const auto&amp; observer_config : allocatable_tracks) {\n    allocation[observer_config.observer] =\n        observer_config.config.max_bitrate_bps;\n    bitrate -= observer_config.config.max_bitrate_bps;\n  }\n  DistributeBitrateEvenly(allocatable_tracks, bitrate, true,\n                          kTransmissionMaxBitrateMultiplier, &amp;allocation);\n  return allocation;\n}<\/code><\/pre>\n<h3>ZeroRateAllocation \u96f6\u5e26\u5bbd\u5206\u914d\u7b56\u7565<\/h3>\n<pre><code>\/\/ Allocates zero bitrate to all observers.\nstd::map&lt;BitrateAllocatorObserver*, int&gt; ZeroRateAllocation(\n    const std::vector&lt;AllocatableTrack&gt;&amp; allocatable_tracks) {\n  std::map&lt;BitrateAllocatorObserver*, int&gt; allocation;\n  for (const auto&amp; observer_config : allocatable_tracks)\n    allocation[observer_config.observer] = 0;\n  return allocation;\n}<\/code><\/pre>\n<h1>Log keyword<\/h1>\n<ul>\n<li>\n<p>Current BWE<\/p>\n<pre><code>void BitrateAllocator::OnNetworkEstimateChanged(TargetTransferRate msg) {\n\n\/\/...\n\/\/ Periodically log the incoming BWE.\nint64_t now = msg.at_time.ms();\nif (now &gt; last_bwe_log_time_ + kBweLogIntervalMs) {\nRTC_LOG(LS_INFO) &lt;&lt; &quot;Current BWE &quot; &lt;&lt; last_target_bps_;\nlast_bwe_log_time_ = now;\n}<\/code><\/pre>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Title Bandwidth allocation by REMB ModuleRtpRtcpImpl-&gt;RTCPReceiver: IncomingPacket RTCPReceiver-&gt;RTCPReceiver: TriggerCallbacksFromRtcpPacket RTCPReceiver-&gt;RtpTransportControllerSend:OnReceivedEstimatedBitrate(bitrate) RtpTransportControllerSend-&gt;GoogCcNetworkController: OnRemoteBitrateReport(receiveTime, bitrate) GoogCcNetworkController-&gt;SendSideBandwidthEstimation: UpdateReceiverEstimate SendSideBandwidthEstimation-&gt;SendSideBandwidthEstimation: ApplyTargetLimits SendSideBandwidthEstimation-&gt;SendSideBandwidthEstimation: UpdateTargetBitrate #SendSideBandwidthEstimation-&gt;LinkCapacityTracker:OnRateUpdate GoogCcNetworkController-&gt;Call: OnTargetTransferRate Call-&gt;BitrateAllocator: OnNetworkEstimateChanged BitrateAllocator-&gt;BitrateAllocator: AllocateBitrates Snippets AllocateBitrates \u5e26\u5bbd\u5206\u914d\u65b9\u6cd5 std::map&lt;BitrateAllocatorObserver*, int&gt; AllocateBitrates( const std::vector&lt;AllocatableTrack&gt;&amp; allocatable_tracks, uint32_t bitrate) { if (allocatable_tracks.empty()) return std::map&lt;BitrateAllocatorObserver*, int&gt;(); if (bitrate == 0) return ZeroRateAllocation(allocatable_tracks); uint32_t sum_min_bitrates = 0; uint32_t sum_max_bitrates [&hellip;] <a class=\"read-more\" href=\"https:\/\/www.fanyamin.com\/wordpress\/?p=913\" title=\"Permanent Link to: WebRTC Bandwidth Allocation\">&rarr;Read&nbsp;more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-913","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/913"}],"collection":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=913"}],"version-history":[{"count":5,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/913\/revisions"}],"predecessor-version":[{"id":919,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/913\/revisions\/919"}],"wp:attachment":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=913"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=913"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=913"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}