1 /*
2  *  Copyright (c) 2015 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 "modules/rtp_rtcp/source/packet_loss_stats.h"
12 
13 #include <cstdint>
14 #include <iterator>
15 #include <vector>
16 
17 #include "rtc_base/checks.h"
18 
19 // After this many packets are added, adding additional packets will cause the
20 // oldest packets to be pruned from the buffer.
21 static const int kBufferSize = 100;
22 
23 namespace webrtc {
24 
PacketLossStats()25 PacketLossStats::PacketLossStats()
26     : single_loss_historic_count_(0),
27       multiple_loss_historic_event_count_(0),
28       multiple_loss_historic_packet_count_(0) {}
29 
30 PacketLossStats::~PacketLossStats() = default;
31 
AddLostPacket(uint16_t sequence_number)32 void PacketLossStats::AddLostPacket(uint16_t sequence_number) {
33   // Detect sequence number wrap around.
34   if (!lost_packets_buffer_.empty() &&
35       static_cast<int>(*(lost_packets_buffer_.rbegin())) - sequence_number >
36           0x8000) {
37     // The buffer contains large numbers and this is a small number.
38     lost_packets_wrapped_buffer_.insert(sequence_number);
39   } else {
40     lost_packets_buffer_.insert(sequence_number);
41   }
42   if (lost_packets_wrapped_buffer_.size() + lost_packets_buffer_.size() >
43           kBufferSize ||
44       (!lost_packets_wrapped_buffer_.empty() &&
45        *(lost_packets_wrapped_buffer_.rbegin()) > 0x4000)) {
46     PruneBuffer();
47   }
48 }
49 
GetSingleLossCount() const50 int PacketLossStats::GetSingleLossCount() const {
51   int single_loss_count, unused1, unused2;
52   ComputeLossCounts(&single_loss_count, &unused1, &unused2);
53   return single_loss_count;
54 }
55 
GetMultipleLossEventCount() const56 int PacketLossStats::GetMultipleLossEventCount() const {
57   int event_count, unused1, unused2;
58   ComputeLossCounts(&unused1, &event_count, &unused2);
59   return event_count;
60 }
61 
GetMultipleLossPacketCount() const62 int PacketLossStats::GetMultipleLossPacketCount() const {
63   int packet_count, unused1, unused2;
64   ComputeLossCounts(&unused1, &unused2, &packet_count);
65   return packet_count;
66 }
67 
ComputeLossCounts(int * out_single_loss_count,int * out_multiple_loss_event_count,int * out_multiple_loss_packet_count) const68 void PacketLossStats::ComputeLossCounts(
69     int* out_single_loss_count,
70     int* out_multiple_loss_event_count,
71     int* out_multiple_loss_packet_count) const {
72   *out_single_loss_count = single_loss_historic_count_;
73   *out_multiple_loss_event_count = multiple_loss_historic_event_count_;
74   *out_multiple_loss_packet_count = multiple_loss_historic_packet_count_;
75   if (lost_packets_buffer_.empty()) {
76     RTC_DCHECK(lost_packets_wrapped_buffer_.empty());
77     return;
78   }
79   uint16_t last_num = 0;
80   int sequential_count = 0;
81   std::vector<const std::set<uint16_t>*> buffers;
82   buffers.push_back(&lost_packets_buffer_);
83   buffers.push_back(&lost_packets_wrapped_buffer_);
84   for (const auto* buffer : buffers) {
85     for (auto it = buffer->begin(); it != buffer->end(); ++it) {
86       uint16_t current_num = *it;
87       if (sequential_count > 0 && current_num != ((last_num + 1) & 0xFFFF)) {
88         if (sequential_count == 1) {
89           (*out_single_loss_count)++;
90         } else {
91           (*out_multiple_loss_event_count)++;
92           *out_multiple_loss_packet_count += sequential_count;
93         }
94         sequential_count = 0;
95       }
96       sequential_count++;
97       last_num = current_num;
98     }
99   }
100   if (sequential_count == 1) {
101     (*out_single_loss_count)++;
102   } else if (sequential_count > 1) {
103     (*out_multiple_loss_event_count)++;
104     *out_multiple_loss_packet_count += sequential_count;
105   }
106 }
107 
PruneBuffer()108 void PacketLossStats::PruneBuffer() {
109   // Remove the oldest lost packet and any contiguous packets and move them
110   // into the historic counts.
111   auto it = lost_packets_buffer_.begin();
112   uint16_t last_removed = 0;
113   int remove_count = 0;
114   // Count adjacent packets and continue counting if it is wrap around by
115   // swapping in the wrapped buffer and letting our value wrap as well.
116   while (remove_count == 0 || (!lost_packets_buffer_.empty() &&
117                                *it == ((last_removed + 1) & 0xFFFF))) {
118     last_removed = *it;
119     remove_count++;
120     auto to_erase = it++;
121     lost_packets_buffer_.erase(to_erase);
122     if (lost_packets_buffer_.empty()) {
123       lost_packets_buffer_.swap(lost_packets_wrapped_buffer_);
124       it = lost_packets_buffer_.begin();
125     }
126   }
127   if (remove_count > 1) {
128     multiple_loss_historic_event_count_++;
129     multiple_loss_historic_packet_count_ += remove_count;
130   } else {
131     single_loss_historic_count_++;
132   }
133   // Continue pruning if the wrapped buffer is beyond a threshold and there are
134   // things left in the pre-wrapped buffer.
135   if (!lost_packets_wrapped_buffer_.empty() &&
136       *(lost_packets_wrapped_buffer_.rbegin()) > 0x4000) {
137     PruneBuffer();
138   }
139 }
140 
141 }  // namespace webrtc
142