WebRTC研究:audio 丢包判断

当收到一个包时,丢包判断原理:

  • 当前收包序列号:sequence_number 从丢包集合 nack_list_ 中剔除;

  • sequence_number最近收到的新包:sequence_num_last_received_rtp_ 对比,判断当前包是否为重传或乱序包。如若是的话,直接终止判断,否则继续;

  • 对比 当前包最新收到的包 的序列号与时间戳,更新每个包的样本数:samples_per_packet_;

  • 更新 nack_list_ 中部分包的丢包状态:is_missing = true,这些包我们之前认为后续再考虑,现在需要把它们当做丢包。这些包满足:序列号 在 sequence_number - nack_threshold_packets_ 之前(nack_threshold_packets_ = 2);

  • 如果 最新收到的包当前包 不连续,则区间内的包都要被放到 nack_list_,其中那些太旧的包(判断标准同上一步)会被直接认为丢包,剩下的包当后续包达到时,会在上一步中再明确是否为丢包;

  • 最近收到的新包 的序列号: sequence_num_last_received_rtp_ 与时间戳更新为 当前包 的序列号与时间戳;

  • 丢弃掉集合 nack_list_ 中不能重传的包信息,同时保证集合容量不超过限制(最大容量 max_nack_list_size_ = 500,即对于单位长度为 20ms 的帧,保留 10s 长度)。不能重传的包满足序列号在 最新收到的包序列号 - static_cast(max_nack_list_size_) - 1 之前。

一、判断当前收包是否为重传或乱序包:

/*
sequence_number:当前收到的包的序列号
timestamp:当前收到的包的时间戳
*/
void NackTracker::UpdateLastReceivedPacket(uint16_t sequence_number, uint32_t timestamp)
{
  /*
  如果这是第一个包
  any_rtp_received_ = true,表示收到了任意包
  */
  if (!any_rtp_received_) 
  {
	/* 第一个包仅仅记录序列号与时间戳 */
    sequence_num_last_received_rtp_ = sequence_number;
    timestamp_last_received_rtp_ = timestamp;
    any_rtp_received_ = true;

    // If no packet is decoded, to have a reasonable estimate of time-to-play
    // use the given values.
    if (!any_rtp_decoded_) 
	{
      sequence_num_last_decoded_rtp_ = sequence_number;
      timestamp_last_decoded_rtp_ = timestamp;
    }

    return;
  }

  /* 如果是上一个包, */
  if (sequence_number == sequence_num_last_received_rtp_)
    return;

  /* nack_list_:丢包集合 */
  nack_list_.erase(sequence_number);

  /*
  将当前包 与 最近收到的新包 对比,判断当前包是否为重传或乱序包
  是的话,直接返回
  */
  if (IsNewerSequenceNumber(sequence_num_last_received_rtp_, sequence_number))
    return;

  /* 对比 当前包 与 最新收到的包 的序列号与时间戳,更新每个包的样本数:samples_per_packet_ */
  UpdateSamplesPerPacket(sequence_number, timestamp);

  /* 更新丢包集合:nack_list_ */
  UpdateList(sequence_number);

  /* 更新最新收包的序列号与时间戳 */
  sequence_num_last_received_rtp_ = sequence_number;
  timestamp_last_received_rtp_ = timestamp;

  /* 丢弃掉集合 nack_list_ 中不能重传的包信息,同时保证集合容量不超过限制 */
  LimitNackListSize();
}

二、更新丢包集合:nack_list_:

void NackTracker::UpdateList(uint16_t sequence_number_current_received_rtp) 
{
  /*
  更新 nack_list_ 中部分包的丢包状态:is_missing = true,
  这些包我们之前认为后续再考虑,现在需要把它们当做丢包
  */
  ChangeFromLateToMissing(sequence_number_current_received_rtp);

  /*
  如果当前收到的包 比 sequence_num_last_received_rtp_ + 1 新,
  即:最近收到的新包 与 当前收到的包 不连续
  */
  if (IsNewerSequenceNumber(sequence_number_current_received_rtp,
                            sequence_num_last_received_rtp_ + 1))
    AddToList(sequence_number_current_received_rtp);
}

三、更新 nack_list_ 中部分包的丢包状态:is_missing = true,这些包我们之前认为后续再考虑,现在需要把它们当做丢包:

void NackTracker::ChangeFromLateToMissing(uint16_t sequence_number_current_received_rtp) 
{
  /*
  nack_threshold_packets_ = 2,表示:
  当序列号为 N 的包到达时,序列号在 ( , N - |nack_threshold_packets_| ) 区间、所有未到达的包,都会被认为丢失
  而对于序列号在 [ N - |nack_threshold_packets_| , N-1 ] 区间、所有未达到的包,后面再考虑
  */

  /* 查找 大于等于 N - |nack_threshold_packets_| 的第一个元素 */
  NackList::const_iterator lower_bound =
      nack_list_.lower_bound(static_cast<uint16_t>(
          sequence_number_current_received_rtp - nack_threshold_packets_));

  for (NackList::iterator it = nack_list_.begin(); it != lower_bound; ++it)
    it->second.is_missing = true;
}

四、最新收到的包 与 当前包 之间的所有包都要被添加到 nack_list_,其中那些太旧的包会被直接认为丢包,剩下的包当后续包达到时,会在上一步中再明确是否为丢包:

void NackTracker::AddToList(uint16_t sequence_number_current_received_rtp) 
{
  assert(!any_rtp_decoded_ ||
         IsNewerSequenceNumber(sequence_number_current_received_rtp,
                               sequence_num_last_decoded_rtp_));

  /*
  序列号在 upper_bound_missing 之前的包(不包括 upper_bound_missing),都认为是丢包,添加到 nack_list_
  upper_bound_missing 以及之后的包,一并添加到 nack_list_,但后面再考虑
  */
  uint16_t upper_bound_missing =
      sequence_number_current_received_rtp - nack_threshold_packets_;

  /*
  最近收到的新包 到 当前收到的包 区间内的包,都可能是丢包,都会被添加到 nack_list_
  但只有在 upper_bound_missing 之前的包,才直接认为丢包
  */
  for (uint16_t n = sequence_num_last_received_rtp_ + 1;
       IsNewerSequenceNumber(sequence_number_current_received_rtp, n); ++n) 
  {
    bool is_missing = IsNewerSequenceNumber(upper_bound_missing, n);
    uint32_t timestamp = EstimateTimestamp(n);
    NackElement nack_element(TimeToPlay(timestamp), timestamp, is_missing);
    nack_list_.insert(nack_list_.end(), std::make_pair(n, nack_element));
  }
}

五、丢弃掉集合 nack_list_ 中不能重传的包信息,同时保证集合容量不超过限制:

void NackTracker::LimitNackListSize() 
{
  /* max_nack_list_size_ = 500 */
  uint16_t limit = sequence_num_last_received_rtp_ - static_cast<uint16_t>(max_nack_list_size_) - 1;

  /* 删除 [ start, end ) 区间内的节点 */
  nack_list_.erase(nack_list_.begin(), nack_list_.upper_bound(limit));
}

你可能感兴趣的:(webrtc)