LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/video_coding - nack_module.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 146 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include <algorithm>
      12             : #include <limits>
      13             : 
      14             : #include "webrtc/modules/video_coding/nack_module.h"
      15             : 
      16             : #include "webrtc/base/checks.h"
      17             : #include "webrtc/base/logging.h"
      18             : #include "webrtc/modules/utility/include/process_thread.h"
      19             : 
      20             : namespace webrtc {
      21             : 
      22             : namespace {
      23             : const int kMaxPacketAge = 10000;
      24             : const int kMaxNackPackets = 1000;
      25             : const int kDefaultRttMs = 100;
      26             : const int kMaxNackRetries = 10;
      27             : const int kProcessFrequency = 50;
      28             : const int kProcessIntervalMs = 1000 / kProcessFrequency;
      29             : const int kMaxReorderedPackets = 128;
      30             : const int kNumReorderingBuckets = 10;
      31             : }  // namespace
      32             : 
      33           0 : NackModule::NackInfo::NackInfo()
      34           0 :     : seq_num(0), send_at_seq_num(0), sent_at_time(-1), retries(0) {}
      35             : 
      36           0 : NackModule::NackInfo::NackInfo(uint16_t seq_num, uint16_t send_at_seq_num)
      37             :     : seq_num(seq_num),
      38             :       send_at_seq_num(send_at_seq_num),
      39             :       sent_at_time(-1),
      40           0 :       retries(0) {}
      41             : 
      42           0 : NackModule::NackModule(Clock* clock,
      43             :                        NackSender* nack_sender,
      44           0 :                        KeyFrameRequestSender* keyframe_request_sender)
      45             :     : clock_(clock),
      46             :       nack_sender_(nack_sender),
      47             :       keyframe_request_sender_(keyframe_request_sender),
      48             :       reordering_histogram_(kNumReorderingBuckets, kMaxReorderedPackets),
      49             :       running_(true),
      50             :       initialized_(false),
      51             :       rtt_ms_(kDefaultRttMs),
      52             :       newest_seq_num_(0),
      53           0 :       next_process_time_ms_(-1) {
      54           0 :   RTC_DCHECK(clock_);
      55           0 :   RTC_DCHECK(nack_sender_);
      56           0 :   RTC_DCHECK(keyframe_request_sender_);
      57           0 : }
      58             : 
      59           0 : int NackModule::OnReceivedPacket(const VCMPacket& packet) {
      60           0 :   rtc::CritScope lock(&crit_);
      61           0 :   if (!running_)
      62           0 :     return -1;
      63           0 :   uint16_t seq_num = packet.seqNum;
      64             :   // TODO(philipel): When the packet includes information whether it is
      65             :   //                 retransmitted or not, use that value instead. For
      66             :   //                 now set it to true, which will cause the reordering
      67             :   //                 statistics to never be updated.
      68           0 :   bool is_retransmitted = true;
      69             :   bool is_keyframe =
      70           0 :       packet.is_first_packet_in_frame && packet.frameType == kVideoFrameKey;
      71             : 
      72           0 :   if (!initialized_) {
      73           0 :     newest_seq_num_ = seq_num;
      74           0 :     if (is_keyframe)
      75           0 :       keyframe_list_.insert(seq_num);
      76           0 :     initialized_ = true;
      77           0 :     return 0;
      78             :   }
      79             : 
      80             :   // Since the |newest_seq_num_| is a packet we have actually received we know
      81             :   // that packet has never been Nacked.
      82           0 :   if (seq_num == newest_seq_num_)
      83           0 :     return 0;
      84             : 
      85           0 :   if (AheadOf(newest_seq_num_, seq_num)) {
      86             :     // An out of order packet has been received.
      87           0 :     auto nack_list_it = nack_list_.find(seq_num);
      88           0 :     int nacks_sent_for_packet = 0;
      89           0 :     if (nack_list_it != nack_list_.end()) {
      90           0 :       nacks_sent_for_packet = nack_list_it->second.retries;
      91           0 :       nack_list_.erase(nack_list_it);
      92             :     }
      93           0 :     if (!is_retransmitted)
      94           0 :       UpdateReorderingStatistics(seq_num);
      95           0 :     return nacks_sent_for_packet;
      96             :   }
      97           0 :   AddPacketsToNack(newest_seq_num_ + 1, seq_num);
      98           0 :   newest_seq_num_ = seq_num;
      99             : 
     100             :   // Keep track of new keyframes.
     101           0 :   if (is_keyframe)
     102           0 :     keyframe_list_.insert(seq_num);
     103             : 
     104             :   // And remove old ones so we don't accumulate keyframes.
     105           0 :   auto it = keyframe_list_.lower_bound(seq_num - kMaxPacketAge);
     106           0 :   if (it != keyframe_list_.begin())
     107           0 :     keyframe_list_.erase(keyframe_list_.begin(), it);
     108             : 
     109             :   // Are there any nacks that are waiting for this seq_num.
     110           0 :   std::vector<uint16_t> nack_batch = GetNackBatch(kSeqNumOnly);
     111           0 :   if (!nack_batch.empty())
     112           0 :     nack_sender_->SendNack(nack_batch);
     113             : 
     114           0 :   return 0;
     115             : }
     116             : 
     117           0 : void NackModule::ClearUpTo(uint16_t seq_num) {
     118           0 :   rtc::CritScope lock(&crit_);
     119           0 :   nack_list_.erase(nack_list_.begin(), nack_list_.lower_bound(seq_num));
     120             :   keyframe_list_.erase(keyframe_list_.begin(),
     121           0 :                        keyframe_list_.lower_bound(seq_num));
     122           0 : }
     123             : 
     124           0 : void NackModule::UpdateRtt(int64_t rtt_ms) {
     125           0 :   rtc::CritScope lock(&crit_);
     126           0 :   rtt_ms_ = rtt_ms;
     127           0 : }
     128             : 
     129           0 : void NackModule::Clear() {
     130           0 :   rtc::CritScope lock(&crit_);
     131           0 :   nack_list_.clear();
     132           0 :   keyframe_list_.clear();
     133           0 : }
     134             : 
     135           0 : void NackModule::Stop() {
     136           0 :   rtc::CritScope lock(&crit_);
     137           0 :   running_ = false;
     138           0 : }
     139             : 
     140           0 : int64_t NackModule::TimeUntilNextProcess() {
     141           0 :   rtc::CritScope lock(&crit_);
     142           0 :   return std::max<int64_t>(next_process_time_ms_ - clock_->TimeInMilliseconds(),
     143           0 :                            0);
     144             : }
     145             : 
     146           0 : void NackModule::Process() {
     147           0 :   rtc::CritScope lock(&crit_);
     148           0 :   if (!running_)
     149           0 :     return;
     150             : 
     151             :   // Update the next_process_time_ms_ in intervals to achieve
     152             :   // the targeted frequency over time. Also add multiple intervals
     153             :   // in case of a skip in time as to not make uneccessary
     154             :   // calls to Process in order to catch up.
     155           0 :   int64_t now_ms = clock_->TimeInMilliseconds();
     156           0 :   if (next_process_time_ms_ == -1) {
     157           0 :     next_process_time_ms_ = now_ms + kProcessIntervalMs;
     158             :   } else {
     159           0 :     next_process_time_ms_ = next_process_time_ms_ + kProcessIntervalMs +
     160           0 :                             (now_ms - next_process_time_ms_) /
     161           0 :                                 kProcessIntervalMs * kProcessIntervalMs;
     162             :   }
     163             : 
     164           0 :   std::vector<uint16_t> nack_batch = GetNackBatch(kTimeOnly);
     165           0 :   if (!nack_batch.empty() && nack_sender_ != nullptr)
     166           0 :     nack_sender_->SendNack(nack_batch);
     167             : }
     168             : 
     169           0 : bool NackModule::RemovePacketsUntilKeyFrame() {
     170           0 :   while (!keyframe_list_.empty()) {
     171           0 :     auto it = nack_list_.lower_bound(*keyframe_list_.begin());
     172             : 
     173           0 :     if (it != nack_list_.begin()) {
     174             :       // We have found a keyframe that actually is newer than at least one
     175             :       // packet in the nack list.
     176           0 :       RTC_DCHECK(it != nack_list_.end());
     177           0 :       nack_list_.erase(nack_list_.begin(), it);
     178           0 :       return true;
     179             :     }
     180             : 
     181             :     // If this keyframe is so old it does not remove any packets from the list,
     182             :     // remove it from the list of keyframes and try the next keyframe.
     183           0 :     keyframe_list_.erase(keyframe_list_.begin());
     184             :   }
     185           0 :   return false;
     186             : }
     187             : 
     188           0 : void NackModule::AddPacketsToNack(uint16_t seq_num_start,
     189             :                                   uint16_t seq_num_end) {
     190             :   // Remove old packets.
     191           0 :   auto it = nack_list_.lower_bound(seq_num_end - kMaxPacketAge);
     192           0 :   nack_list_.erase(nack_list_.begin(), it);
     193             : 
     194             :   // If the nack list is too large, remove packets from the nack list until
     195             :   // the latest first packet of a keyframe. If the list is still too large,
     196             :   // clear it and request a keyframe.
     197           0 :   uint16_t num_new_nacks = ForwardDiff(seq_num_start, seq_num_end);
     198           0 :   if (nack_list_.size() + num_new_nacks > kMaxNackPackets) {
     199           0 :     while (RemovePacketsUntilKeyFrame() &&
     200           0 :            nack_list_.size() + num_new_nacks > kMaxNackPackets) {
     201             :     }
     202             : 
     203           0 :     if (nack_list_.size() + num_new_nacks > kMaxNackPackets) {
     204           0 :       nack_list_.clear();
     205           0 :       LOG(LS_WARNING) << "NACK list full, clearing NACK"
     206           0 :                          " list and requesting keyframe.";
     207           0 :       keyframe_request_sender_->RequestKeyFrame();
     208           0 :       return;
     209             :     }
     210             :   }
     211             : 
     212           0 :   for (uint16_t seq_num = seq_num_start; seq_num != seq_num_end; ++seq_num) {
     213           0 :     NackInfo nack_info(seq_num, seq_num + WaitNumberOfPackets(0.5));
     214           0 :     RTC_DCHECK(nack_list_.find(seq_num) == nack_list_.end());
     215           0 :     nack_list_[seq_num] = nack_info;
     216             :   }
     217             : }
     218             : 
     219           0 : std::vector<uint16_t> NackModule::GetNackBatch(NackFilterOptions options) {
     220           0 :   bool consider_seq_num = options != kTimeOnly;
     221           0 :   bool consider_timestamp = options != kSeqNumOnly;
     222           0 :   int64_t now_ms = clock_->TimeInMilliseconds();
     223           0 :   std::vector<uint16_t> nack_batch;
     224           0 :   auto it = nack_list_.begin();
     225           0 :   while (it != nack_list_.end()) {
     226           0 :     if (consider_seq_num && it->second.sent_at_time == -1 &&
     227           0 :         AheadOrAt(newest_seq_num_, it->second.send_at_seq_num)) {
     228           0 :       nack_batch.emplace_back(it->second.seq_num);
     229           0 :       ++it->second.retries;
     230           0 :       it->second.sent_at_time = now_ms;
     231           0 :       if (it->second.retries >= kMaxNackRetries) {
     232           0 :         LOG(LS_WARNING) << "Sequence number " << it->second.seq_num
     233           0 :                         << " removed from NACK list due to max retries.";
     234           0 :         it = nack_list_.erase(it);
     235             :       } else {
     236           0 :         ++it;
     237             :       }
     238           0 :       continue;
     239             :     }
     240             : 
     241           0 :     if (consider_timestamp && it->second.sent_at_time + rtt_ms_ <= now_ms) {
     242           0 :       nack_batch.emplace_back(it->second.seq_num);
     243           0 :       ++it->second.retries;
     244           0 :       it->second.sent_at_time = now_ms;
     245           0 :       if (it->second.retries >= kMaxNackRetries) {
     246           0 :         LOG(LS_WARNING) << "Sequence number " << it->second.seq_num
     247           0 :                         << " removed from NACK list due to max retries.";
     248           0 :         it = nack_list_.erase(it);
     249             :       } else {
     250           0 :         ++it;
     251             :       }
     252           0 :       continue;
     253             :     }
     254           0 :     ++it;
     255             :   }
     256           0 :   return nack_batch;
     257             : }
     258             : 
     259           0 : void NackModule::UpdateReorderingStatistics(uint16_t seq_num) {
     260           0 :   RTC_DCHECK(AheadOf(newest_seq_num_, seq_num));
     261           0 :   uint16_t diff = ReverseDiff(newest_seq_num_, seq_num);
     262           0 :   reordering_histogram_.Add(diff);
     263           0 : }
     264             : 
     265           0 : int NackModule::WaitNumberOfPackets(float probability) const {
     266           0 :   if (reordering_histogram_.NumValues() == 0)
     267           0 :     return 0;
     268           0 :   return reordering_histogram_.InverseCdf(probability);
     269             : }
     270             : 
     271             : }  // namespace webrtc

Generated by: LCOV version 1.13