WebRTC的带宽利用率相当高, 在测试中, 绝大多数时间都可以在可用带宽的95%以上, 而且在高利用率的同时, 还能保持音视频的高质量, 其带宽侦测机制在其中扮演了关键的角色. 有几个关键点:
Pacing Bitrate 为allocated_bitrate_bps/1000 * kDefaultPaceMultiplier, 这里的kDefaultPaceMultiplier = 2.5
void PacedSender::SetAllocatedSendBitrate(int allocated_bitrate, int padding_bitrate) { CriticalSectionScoped cs(critsect_.get()); min_send_bitrate_kbps_ = allocated_bitrate / 1000; pacing_bitrate_kbps_ = std::max(min_send_bitrate_kbps_, estimated_bitrate_bps_ / 1000) * kDefaultPaceMultiplier; padding_budget_->set_target_rate_kbps(padding_bitrate / 1000); }
void PacedSender::InsertPacket(RtpPacketSender::Priority priority, uint32_t ssrc, uint16_t sequence_number, int64_t capture_time_ms, size_t bytes, bool retransmission) { CriticalSectionScoped cs(critsect_.get()); RTC_DCHECK(estimated_bitrate_bps_ > 0) << "SetEstimatedBitrate must be called before InsertPacket."; if (probing_enabled_ && !prober_->IsProbing()) prober_->SetEnabled(true); int64_t now_ms = clock_->TimeInMilliseconds(); prober_->OnIncomingPacket(estimated_bitrate_bps_, bytes, now_ms); if (capture_time_ms < 0) capture_time_ms = now_ms; packets_->Push(paced_sender::Packet(priority, ssrc, sequence_number, capture_time_ms, now_ms, bytes, retransmission, packet_counter_++)); }
Cluster 被清空后Probing结束.
void BitrateProber::OnIncomingPacket(uint32_t bitrate_bps, size_t packet_size, int64_t now_ms) { // Don't initialize probing unless we have something large enough to start // probing. if (packet_size < PacedSender::kMinProbePacketSize) return; if (probing_state_ != kAllowedToProbe) return; // Max number of packets used for probing. const int kMaxNumProbes = 2; const int kPacketsPerProbe = 5; const float kProbeBitrateMultipliers[kMaxNumProbes] = {3, 6}; std::stringstream bitrate_log; bitrate_log << "Start probing for bandwidth, (bitrate:packets): "; for (int i = 0; i < kMaxNumProbes; ++i) { ProbeCluster cluster; // We need one extra to get 5 deltas for the first probe, therefore (i == 0) cluster.max_probe_packets = kPacketsPerProbe + (i == 0 ? 1 : 0); cluster.probe_bitrate_bps = kProbeBitrateMultipliers[i] * bitrate_bps; cluster.id = next_cluster_id_++; bitrate_log << "(" << cluster.probe_bitrate_bps << ":"<< cluster.max_probe_packets << ") "; clusters_.push(cluster); } LOG(LS_INFO) << bitrate_log.str().c_str(); // Set last send time to current time so TimeUntilNextProbe doesn't short // circuit due to inactivity. time_last_send_ms_ = now_ms; probing_state_ = kProbing; }
void PacedSender::Process() { int64_t now_us = clock_->TimeInMicroseconds(); CriticalSectionScoped cs(critsect_.get()); int64_t elapsed_time_ms = (now_us - time_last_update_us_ + 500) / 1000; time_last_update_us_ = now_us; int target_bitrate_kbps = pacing_bitrate_kbps_; // TODO(holmer): Remove the !paused_ check when issue 5307 has been fixed. if (!paused_ && elapsed_time_ms > 0) { size_t queue_size_bytes = packets_->SizeInBytes(); if (queue_size_bytes > 0) { // Assuming equal size packets and input/output rate, the average packet // has avg_time_left_ms left to get queue_size_bytes out of the queue, if // time constraint shall be met. Determine bitrate needed for that. packets_->UpdateQueueTime(clock_->TimeInMilliseconds()); int64_t avg_time_left_ms = std::max( 1, kMaxQueueLengthMs - packets_->AverageQueueTimeMs()); int min_bitrate_needed_kbps = static_cast(queue_size_bytes * 8 / avg_time_left_ms); if (min_bitrate_needed_kbps > target_bitrate_kbps) target_bitrate_kbps = min_bitrate_needed_kbps; } media_budget_->set_target_rate_kbps(target_bitrate_kbps); int64_t delta_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms); UpdateBytesPerInterval(delta_time_ms); } while (!packets_->Empty()) { if (media_budget_->bytes_remaining() == 0 && !prober_->IsProbing()) return; // Since we need to release the lock in order to send, we first pop the // element from the priority queue but keep it in storage, so that we can // reinsert it if send fails. const paced_sender::Packet& packet = packets_->BeginPop(); int probe_cluster_id = prober_->IsProbing() ? prober_->CurrentClusterId() : -1; if (SendPacket(packet, probe_cluster_id)) { // Send succeeded, remove it from the queue. packets_->FinalizePop(packet); if (prober_->IsProbing()) return; } else { // Send failed, put it back into the queue. packets_->CancelPop(packet); return; } } // TODO(holmer): Remove the paused_ check when issue 5307 has been fixed. if (paused_ || !packets_->Empty()) return; size_t padding_needed; if (prober_->IsProbing()) { padding_needed = prober_->RecommendedPacketSize(); } else { padding_needed = padding_budget_->bytes_remaining(); } if (padding_needed > 0) SendPadding(static_cast(padding_needed)); }
尝试使用之前发送过的数据包作为Probing Packet以RTX格式发送, 如果没有,则创建Padding Packet, 发送之.
使用REMB 返回接收端的评估带宽.