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 "video/send_delay_stats.h"
12 
13 #include <utility>
14 
15 #include "rtc_base/logging.h"
16 #include "system_wrappers/include/metrics.h"
17 
18 namespace webrtc {
19 namespace {
20 // Packet with a larger delay are removed and excluded from the delay stats.
21 // Set to larger than max histogram delay which is 10000.
22 const int64_t kMaxSentPacketDelayMs = 11000;
23 const size_t kMaxPacketMapSize = 2000;
24 
25 // Limit for the maximum number of streams to calculate stats for.
26 const size_t kMaxSsrcMapSize = 50;
27 const int kMinRequiredPeriodicSamples = 5;
28 }  // namespace
29 
SendDelayStats(Clock * clock)30 SendDelayStats::SendDelayStats(Clock* clock)
31     : clock_(clock), num_old_packets_(0), num_skipped_packets_(0) {}
32 
~SendDelayStats()33 SendDelayStats::~SendDelayStats() {
34   if (num_old_packets_ > 0 || num_skipped_packets_ > 0) {
35     RTC_LOG(LS_WARNING) << "Delay stats: number of old packets "
36                         << num_old_packets_ << ", skipped packets "
37                         << num_skipped_packets_ << ". Number of streams "
38                         << send_delay_counters_.size();
39   }
40   UpdateHistograms();
41 }
42 
UpdateHistograms()43 void SendDelayStats::UpdateHistograms() {
44   MutexLock lock(&mutex_);
45   for (const auto& it : send_delay_counters_) {
46     AggregatedStats stats = it.second->GetStats();
47     if (stats.num_samples >= kMinRequiredPeriodicSamples) {
48       RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.SendDelayInMs", stats.average);
49       RTC_LOG(LS_INFO) << "WebRTC.Video.SendDelayInMs, " << stats.ToString();
50     }
51   }
52 }
53 
AddSsrcs(const VideoSendStream::Config & config)54 void SendDelayStats::AddSsrcs(const VideoSendStream::Config& config) {
55   MutexLock lock(&mutex_);
56   if (ssrcs_.size() > kMaxSsrcMapSize)
57     return;
58   for (const auto& ssrc : config.rtp.ssrcs)
59     ssrcs_.insert(ssrc);
60 }
61 
GetSendDelayCounter(uint32_t ssrc)62 AvgCounter* SendDelayStats::GetSendDelayCounter(uint32_t ssrc) {
63   const auto& it = send_delay_counters_.find(ssrc);
64   if (it != send_delay_counters_.end())
65     return it->second.get();
66 
67   AvgCounter* counter = new AvgCounter(clock_, nullptr, false);
68   send_delay_counters_[ssrc].reset(counter);
69   return counter;
70 }
71 
OnSendPacket(uint16_t packet_id,int64_t capture_time_ms,uint32_t ssrc)72 void SendDelayStats::OnSendPacket(uint16_t packet_id,
73                                   int64_t capture_time_ms,
74                                   uint32_t ssrc) {
75   // Packet sent to transport.
76   MutexLock lock(&mutex_);
77   if (ssrcs_.find(ssrc) == ssrcs_.end())
78     return;
79 
80   int64_t now = clock_->TimeInMilliseconds();
81   RemoveOld(now, &packets_);
82 
83   if (packets_.size() > kMaxPacketMapSize) {
84     ++num_skipped_packets_;
85     return;
86   }
87   packets_.insert(
88       std::make_pair(packet_id, Packet(ssrc, capture_time_ms, now)));
89 }
90 
OnSentPacket(int packet_id,int64_t time_ms)91 bool SendDelayStats::OnSentPacket(int packet_id, int64_t time_ms) {
92   // Packet leaving socket.
93   if (packet_id == -1)
94     return false;
95 
96   MutexLock lock(&mutex_);
97   auto it = packets_.find(packet_id);
98   if (it == packets_.end())
99     return false;
100 
101   // TODO(asapersson): Remove SendSideDelayUpdated(), use capture -> sent.
102   // Elapsed time from send (to transport) -> sent (leaving socket).
103   int diff_ms = time_ms - it->second.send_time_ms;
104   GetSendDelayCounter(it->second.ssrc)->Add(diff_ms);
105   packets_.erase(it);
106   return true;
107 }
108 
RemoveOld(int64_t now,PacketMap * packets)109 void SendDelayStats::RemoveOld(int64_t now, PacketMap* packets) {
110   while (!packets->empty()) {
111     auto it = packets->begin();
112     if (now - it->second.capture_time_ms < kMaxSentPacketDelayMs)
113       break;
114 
115     packets->erase(it);
116     ++num_old_packets_;
117   }
118 }
119 
120 }  // namespace webrtc
121