WebRTC 中的带宽侦测

WebRTC 中的带宽侦测

WebRTC的带宽利用率相当高, 在测试中, 绝大多数时间都可以在可用带宽的95%以上, 而且在高利用率的同时, 还能保持音视频的高质量, 其带宽侦测机制在其中扮演了关键的角色. 有几个关键点:

Pacing Bitrate

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);
}

发起Probing 的时机

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_++));
}

创建 Probing Cluster, 设置状态为Probing

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;
}

数据发送和Probing 是在PacedSender::Process函数中处理的

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));
}

Create Probing Packet

尝试使用之前发送过的数据包作为Probing Packet以RTX格式发送, 如果没有,则创建Padding Packet, 发送之. 

Feedback

使用REMB 返回接收端的评估带宽.

你可能感兴趣的:(多媒体)