• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2012 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 // This is the implementation of the PacketBuffer class. It is mostly based on
12 // an STL list. The list is kept sorted at all times so that the next packet to
13 // decode is at the beginning of the list.
14 
15 #include "modules/audio_coding/neteq/packet_buffer.h"
16 
17 #include <algorithm>
18 #include <list>
19 #include <memory>
20 #include <type_traits>
21 #include <utility>
22 
23 #include "api/audio_codecs/audio_decoder.h"
24 #include "api/neteq/tick_timer.h"
25 #include "modules/audio_coding/neteq/decoder_database.h"
26 #include "modules/audio_coding/neteq/statistics_calculator.h"
27 #include "rtc_base/checks.h"
28 #include "rtc_base/logging.h"
29 #include "rtc_base/numerics/safe_conversions.h"
30 
31 namespace webrtc {
32 namespace {
33 // Predicate used when inserting packets in the buffer list.
34 // Operator() returns true when |packet| goes before |new_packet|.
35 class NewTimestampIsLarger {
36  public:
NewTimestampIsLarger(const Packet & new_packet)37   explicit NewTimestampIsLarger(const Packet& new_packet)
38       : new_packet_(new_packet) {}
operator ()(const Packet & packet)39   bool operator()(const Packet& packet) { return (new_packet_ >= packet); }
40 
41  private:
42   const Packet& new_packet_;
43 };
44 
45 // Returns true if both payload types are known to the decoder database, and
46 // have the same sample rate.
EqualSampleRates(uint8_t pt1,uint8_t pt2,const DecoderDatabase & decoder_database)47 bool EqualSampleRates(uint8_t pt1,
48                       uint8_t pt2,
49                       const DecoderDatabase& decoder_database) {
50   auto* di1 = decoder_database.GetDecoderInfo(pt1);
51   auto* di2 = decoder_database.GetDecoderInfo(pt2);
52   return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
53 }
54 
LogPacketDiscarded(int codec_level,StatisticsCalculator * stats)55 void LogPacketDiscarded(int codec_level, StatisticsCalculator* stats) {
56   RTC_CHECK(stats);
57   if (codec_level > 0) {
58     stats->SecondaryPacketsDiscarded(1);
59   } else {
60     stats->PacketsDiscarded(1);
61   }
62 }
63 
64 }  // namespace
65 
PacketBuffer(size_t max_number_of_packets,const TickTimer * tick_timer)66 PacketBuffer::PacketBuffer(size_t max_number_of_packets,
67                            const TickTimer* tick_timer)
68     : max_number_of_packets_(max_number_of_packets), tick_timer_(tick_timer) {}
69 
70 // Destructor. All packets in the buffer will be destroyed.
~PacketBuffer()71 PacketBuffer::~PacketBuffer() {
72   Flush();
73 }
74 
75 // Flush the buffer. All packets in the buffer will be destroyed.
Flush()76 void PacketBuffer::Flush() {
77   buffer_.clear();
78 }
79 
Empty() const80 bool PacketBuffer::Empty() const {
81   return buffer_.empty();
82 }
83 
InsertPacket(Packet && packet,StatisticsCalculator * stats)84 int PacketBuffer::InsertPacket(Packet&& packet, StatisticsCalculator* stats) {
85   if (packet.empty()) {
86     RTC_LOG(LS_WARNING) << "InsertPacket invalid packet";
87     return kInvalidPacket;
88   }
89 
90   RTC_DCHECK_GE(packet.priority.codec_level, 0);
91   RTC_DCHECK_GE(packet.priority.red_level, 0);
92 
93   int return_val = kOK;
94 
95   packet.waiting_time = tick_timer_->GetNewStopwatch();
96 
97   if (buffer_.size() >= max_number_of_packets_) {
98     // Buffer is full. Flush it.
99     Flush();
100     stats->FlushedPacketBuffer();
101     RTC_LOG(LS_WARNING) << "Packet buffer flushed";
102     return_val = kFlushed;
103   }
104 
105   // Get an iterator pointing to the place in the buffer where the new packet
106   // should be inserted. The list is searched from the back, since the most
107   // likely case is that the new packet should be near the end of the list.
108   PacketList::reverse_iterator rit = std::find_if(
109       buffer_.rbegin(), buffer_.rend(), NewTimestampIsLarger(packet));
110 
111   // The new packet is to be inserted to the right of |rit|. If it has the same
112   // timestamp as |rit|, which has a higher priority, do not insert the new
113   // packet to list.
114   if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
115     LogPacketDiscarded(packet.priority.codec_level, stats);
116     return return_val;
117   }
118 
119   // The new packet is to be inserted to the left of |it|. If it has the same
120   // timestamp as |it|, which has a lower priority, replace |it| with the new
121   // packet.
122   PacketList::iterator it = rit.base();
123   if (it != buffer_.end() && packet.timestamp == it->timestamp) {
124     LogPacketDiscarded(it->priority.codec_level, stats);
125     it = buffer_.erase(it);
126   }
127   buffer_.insert(it, std::move(packet));  // Insert the packet at that position.
128 
129   return return_val;
130 }
131 
InsertPacketList(PacketList * packet_list,const DecoderDatabase & decoder_database,absl::optional<uint8_t> * current_rtp_payload_type,absl::optional<uint8_t> * current_cng_rtp_payload_type,StatisticsCalculator * stats)132 int PacketBuffer::InsertPacketList(
133     PacketList* packet_list,
134     const DecoderDatabase& decoder_database,
135     absl::optional<uint8_t>* current_rtp_payload_type,
136     absl::optional<uint8_t>* current_cng_rtp_payload_type,
137     StatisticsCalculator* stats) {
138   RTC_DCHECK(stats);
139   bool flushed = false;
140   for (auto& packet : *packet_list) {
141     if (decoder_database.IsComfortNoise(packet.payload_type)) {
142       if (*current_cng_rtp_payload_type &&
143           **current_cng_rtp_payload_type != packet.payload_type) {
144         // New CNG payload type implies new codec type.
145         *current_rtp_payload_type = absl::nullopt;
146         Flush();
147         flushed = true;
148       }
149       *current_cng_rtp_payload_type = packet.payload_type;
150     } else if (!decoder_database.IsDtmf(packet.payload_type)) {
151       // This must be speech.
152       if ((*current_rtp_payload_type &&
153            **current_rtp_payload_type != packet.payload_type) ||
154           (*current_cng_rtp_payload_type &&
155            !EqualSampleRates(packet.payload_type,
156                              **current_cng_rtp_payload_type,
157                              decoder_database))) {
158         *current_cng_rtp_payload_type = absl::nullopt;
159         Flush();
160         flushed = true;
161       }
162       *current_rtp_payload_type = packet.payload_type;
163     }
164     int return_val = InsertPacket(std::move(packet), stats);
165     if (return_val == kFlushed) {
166       // The buffer flushed, but this is not an error. We can still continue.
167       flushed = true;
168     } else if (return_val != kOK) {
169       // An error occurred. Delete remaining packets in list and return.
170       packet_list->clear();
171       return return_val;
172     }
173   }
174   packet_list->clear();
175   return flushed ? kFlushed : kOK;
176 }
177 
NextTimestamp(uint32_t * next_timestamp) const178 int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
179   if (Empty()) {
180     return kBufferEmpty;
181   }
182   if (!next_timestamp) {
183     return kInvalidPointer;
184   }
185   *next_timestamp = buffer_.front().timestamp;
186   return kOK;
187 }
188 
NextHigherTimestamp(uint32_t timestamp,uint32_t * next_timestamp) const189 int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
190                                       uint32_t* next_timestamp) const {
191   if (Empty()) {
192     return kBufferEmpty;
193   }
194   if (!next_timestamp) {
195     return kInvalidPointer;
196   }
197   PacketList::const_iterator it;
198   for (it = buffer_.begin(); it != buffer_.end(); ++it) {
199     if (it->timestamp >= timestamp) {
200       // Found a packet matching the search.
201       *next_timestamp = it->timestamp;
202       return kOK;
203     }
204   }
205   return kNotFound;
206 }
207 
PeekNextPacket() const208 const Packet* PacketBuffer::PeekNextPacket() const {
209   return buffer_.empty() ? nullptr : &buffer_.front();
210 }
211 
GetNextPacket()212 absl::optional<Packet> PacketBuffer::GetNextPacket() {
213   if (Empty()) {
214     // Buffer is empty.
215     return absl::nullopt;
216   }
217 
218   absl::optional<Packet> packet(std::move(buffer_.front()));
219   // Assert that the packet sanity checks in InsertPacket method works.
220   RTC_DCHECK(!packet->empty());
221   buffer_.pop_front();
222 
223   return packet;
224 }
225 
DiscardNextPacket(StatisticsCalculator * stats)226 int PacketBuffer::DiscardNextPacket(StatisticsCalculator* stats) {
227   if (Empty()) {
228     return kBufferEmpty;
229   }
230   // Assert that the packet sanity checks in InsertPacket method works.
231   const Packet& packet = buffer_.front();
232   RTC_DCHECK(!packet.empty());
233   LogPacketDiscarded(packet.priority.codec_level, stats);
234   buffer_.pop_front();
235   return kOK;
236 }
237 
DiscardOldPackets(uint32_t timestamp_limit,uint32_t horizon_samples,StatisticsCalculator * stats)238 void PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
239                                      uint32_t horizon_samples,
240                                      StatisticsCalculator* stats) {
241   buffer_.remove_if([timestamp_limit, horizon_samples, stats](const Packet& p) {
242     if (timestamp_limit == p.timestamp ||
243         !IsObsoleteTimestamp(p.timestamp, timestamp_limit, horizon_samples)) {
244       return false;
245     }
246     LogPacketDiscarded(p.priority.codec_level, stats);
247     return true;
248   });
249 }
250 
DiscardAllOldPackets(uint32_t timestamp_limit,StatisticsCalculator * stats)251 void PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit,
252                                         StatisticsCalculator* stats) {
253   DiscardOldPackets(timestamp_limit, 0, stats);
254 }
255 
DiscardPacketsWithPayloadType(uint8_t payload_type,StatisticsCalculator * stats)256 void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type,
257                                                  StatisticsCalculator* stats) {
258   buffer_.remove_if([payload_type, stats](const Packet& p) {
259     if (p.payload_type != payload_type) {
260       return false;
261     }
262     LogPacketDiscarded(p.priority.codec_level, stats);
263     return true;
264   });
265 }
266 
NumPacketsInBuffer() const267 size_t PacketBuffer::NumPacketsInBuffer() const {
268   return buffer_.size();
269 }
270 
NumSamplesInBuffer(size_t last_decoded_length) const271 size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
272   size_t num_samples = 0;
273   size_t last_duration = last_decoded_length;
274   for (const Packet& packet : buffer_) {
275     if (packet.frame) {
276       // TODO(hlundin): Verify that it's fine to count all packets and remove
277       // this check.
278       if (packet.priority != Packet::Priority(0, 0)) {
279         continue;
280       }
281       size_t duration = packet.frame->Duration();
282       if (duration > 0) {
283         last_duration = duration;  // Save the most up-to-date (valid) duration.
284       }
285     }
286     num_samples += last_duration;
287   }
288   return num_samples;
289 }
290 
GetSpanSamples(size_t last_decoded_length,size_t sample_rate,bool count_dtx_waiting_time) const291 size_t PacketBuffer::GetSpanSamples(size_t last_decoded_length,
292                                     size_t sample_rate,
293                                     bool count_dtx_waiting_time) const {
294   if (buffer_.size() == 0) {
295     return 0;
296   }
297 
298   size_t span = buffer_.back().timestamp - buffer_.front().timestamp;
299   if (buffer_.back().frame && buffer_.back().frame->Duration() > 0) {
300     size_t duration = buffer_.back().frame->Duration();
301     if (count_dtx_waiting_time && buffer_.back().frame->IsDtxPacket()) {
302       size_t waiting_time_samples = rtc::dchecked_cast<size_t>(
303           buffer_.back().waiting_time->ElapsedMs() * (sample_rate / 1000));
304       duration = std::max(duration, waiting_time_samples);
305     }
306     span += duration;
307   } else {
308     span += last_decoded_length;
309   }
310   return span;
311 }
312 
ContainsDtxOrCngPacket(const DecoderDatabase * decoder_database) const313 bool PacketBuffer::ContainsDtxOrCngPacket(
314     const DecoderDatabase* decoder_database) const {
315   RTC_DCHECK(decoder_database);
316   for (const Packet& packet : buffer_) {
317     if ((packet.frame && packet.frame->IsDtxPacket()) ||
318         decoder_database->IsComfortNoise(packet.payload_type)) {
319       return true;
320     }
321   }
322   return false;
323 }
324 
325 }  // namespace webrtc
326