blob: 059308f7fe2a8294a69849cb9e59e251e086a540 [file] [log] [blame]
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "modules/audio_coding/neteq/packet_buffer.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000016
Yves Gerey988cc082018-10-23 12:03:01 +020017#include <algorithm>
18#include <list>
19#include <memory>
20#include <type_traits>
21#include <utility>
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000022
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "api/audio_codecs/audio_decoder.h"
Ivo Creusen3ce44a32019-10-31 14:38:11 +010024#include "api/neteq/tick_timer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "modules/audio_coding/neteq/decoder_database.h"
26#include "modules/audio_coding/neteq/statistics_calculator.h"
Yves Gerey988cc082018-10-23 12:03:01 +020027#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "rtc_base/logging.h"
Jakob Ivarsson46dda832019-07-03 16:00:30 +020029#include "rtc_base/numerics/safe_conversions.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000030
31namespace webrtc {
henrik.lundin067d8552016-09-01 23:19:05 -070032namespace {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000033// Predicate used when inserting packets in the buffer list.
34// Operator() returns true when |packet| goes before |new_packet|.
35class NewTimestampIsLarger {
36 public:
ossua73f6c92016-10-24 08:25:28 -070037 explicit NewTimestampIsLarger(const Packet& new_packet)
Yves Gerey665174f2018-06-19 15:03:05 +020038 : new_packet_(new_packet) {}
39 bool operator()(const Packet& packet) { return (new_packet_ >= packet); }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000040
41 private:
ossua73f6c92016-10-24 08:25:28 -070042 const Packet& new_packet_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000043};
44
henrik.lundin067d8552016-09-01 23:19:05 -070045// Returns true if both payload types are known to the decoder database, and
46// have the same sample rate.
47bool EqualSampleRates(uint8_t pt1,
48 uint8_t pt2,
49 const DecoderDatabase& decoder_database) {
kjellander7c856582017-02-26 19:53:40 -080050 auto* di1 = decoder_database.GetDecoderInfo(pt1);
51 auto* di2 = decoder_database.GetDecoderInfo(pt2);
henrik.lundin067d8552016-09-01 23:19:05 -070052 return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
53}
minyue-webrtc0c3ca752017-08-23 15:59:38 +020054
55void 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
henrik.lundin067d8552016-09-01 23:19:05 -070064} // namespace
65
henrik.lundin84f8cd62016-04-26 07:45:16 -070066PacketBuffer::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) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000069
70// Destructor. All packets in the buffer will be destroyed.
71PacketBuffer::~PacketBuffer() {
72 Flush();
73}
74
75// Flush the buffer. All packets in the buffer will be destroyed.
76void PacketBuffer::Flush() {
ossua73f6c92016-10-24 08:25:28 -070077 buffer_.clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000078}
79
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020080bool PacketBuffer::Empty() const {
81 return buffer_.empty();
82}
83
minyue-webrtc12d30842017-07-19 11:44:06 +020084int PacketBuffer::InsertPacket(Packet&& packet, StatisticsCalculator* stats) {
ossua73f6c92016-10-24 08:25:28 -070085 if (packet.empty()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010086 RTC_LOG(LS_WARNING) << "InsertPacket invalid packet";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000087 return kInvalidPacket;
88 }
89
ossua73f6c92016-10-24 08:25:28 -070090 RTC_DCHECK_GE(packet.priority.codec_level, 0);
91 RTC_DCHECK_GE(packet.priority.red_level, 0);
ossua70695a2016-09-22 02:06:28 -070092
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000093 int return_val = kOK;
94
ossua73f6c92016-10-24 08:25:28 -070095 packet.waiting_time = tick_timer_->GetNewStopwatch();
henrik.lundin84f8cd62016-04-26 07:45:16 -070096
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000097 if (buffer_.size() >= max_number_of_packets_) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000098 // Buffer is full. Flush it.
99 Flush();
Ivo Creusendc6d5532018-09-27 11:43:42 +0200100 stats->FlushedPacketBuffer();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100101 RTC_LOG(LS_WARNING) << "Packet buffer flushed";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000102 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000103 }
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(
Yves Gerey665174f2018-06-19 15:03:05 +0200109 buffer_.rbegin(), buffer_.rend(), NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000110
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.
ossua73f6c92016-10-24 08:25:28 -0700114 if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200115 LogPacketDiscarded(packet.priority.codec_level, stats);
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000116 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();
ossua73f6c92016-10-24 08:25:28 -0700123 if (it != buffer_.end() && packet.timestamp == it->timestamp) {
Peng Yub90e63c62018-06-07 19:20:55 +0800124 LogPacketDiscarded(it->priority.codec_level, stats);
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000125 it = buffer_.erase(it);
126 }
ossua73f6c92016-10-24 08:25:28 -0700127 buffer_.insert(it, std::move(packet)); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000128
129 return return_val;
130}
131
henrik.lundinda8bbf62016-08-31 03:14:11 -0700132int PacketBuffer::InsertPacketList(
133 PacketList* packet_list,
134 const DecoderDatabase& decoder_database,
Danil Chapovalovb6021232018-06-19 13:26:36 +0200135 absl::optional<uint8_t>* current_rtp_payload_type,
136 absl::optional<uint8_t>* current_cng_rtp_payload_type,
minyue-webrtc12d30842017-07-19 11:44:06 +0200137 StatisticsCalculator* stats) {
138 RTC_DCHECK(stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000139 bool flushed = false;
ossua73f6c92016-10-24 08:25:28 -0700140 for (auto& packet : *packet_list) {
141 if (decoder_database.IsComfortNoise(packet.payload_type)) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700142 if (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700143 **current_cng_rtp_payload_type != packet.payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000144 // New CNG payload type implies new codec type.
Danil Chapovalovb6021232018-06-19 13:26:36 +0200145 *current_rtp_payload_type = absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000146 Flush();
147 flushed = true;
148 }
Oskar Sundbom12ab00b2017-11-16 15:31:38 +0100149 *current_cng_rtp_payload_type = packet.payload_type;
ossua73f6c92016-10-24 08:25:28 -0700150 } else if (!decoder_database.IsDtmf(packet.payload_type)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000151 // This must be speech.
henrik.lundin067d8552016-09-01 23:19:05 -0700152 if ((*current_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700153 **current_rtp_payload_type != packet.payload_type) ||
henrik.lundin067d8552016-09-01 23:19:05 -0700154 (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700155 !EqualSampleRates(packet.payload_type,
henrik.lundin067d8552016-09-01 23:19:05 -0700156 **current_cng_rtp_payload_type,
157 decoder_database))) {
Danil Chapovalovb6021232018-06-19 13:26:36 +0200158 *current_cng_rtp_payload_type = absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000159 Flush();
160 flushed = true;
161 }
Oskar Sundbom12ab00b2017-11-16 15:31:38 +0100162 *current_rtp_payload_type = packet.payload_type;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000163 }
minyue-webrtc12d30842017-07-19 11:44:06 +0200164 int return_val = InsertPacket(std::move(packet), stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000165 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.
ossua73f6c92016-10-24 08:25:28 -0700170 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000171 return return_val;
172 }
173 }
ossua73f6c92016-10-24 08:25:28 -0700174 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000175 return flushed ? kFlushed : kOK;
176}
177
178int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
179 if (Empty()) {
180 return kBufferEmpty;
181 }
182 if (!next_timestamp) {
183 return kInvalidPointer;
184 }
ossua73f6c92016-10-24 08:25:28 -0700185 *next_timestamp = buffer_.front().timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000186 return kOK;
187}
188
189int 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) {
ossua73f6c92016-10-24 08:25:28 -0700199 if (it->timestamp >= timestamp) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000200 // Found a packet matching the search.
ossua73f6c92016-10-24 08:25:28 -0700201 *next_timestamp = it->timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000202 return kOK;
203 }
204 }
205 return kNotFound;
206}
207
ossu7a377612016-10-18 04:06:13 -0700208const Packet* PacketBuffer::PeekNextPacket() const {
ossua73f6c92016-10-24 08:25:28 -0700209 return buffer_.empty() ? nullptr : &buffer_.front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000210}
211
Danil Chapovalovb6021232018-06-19 13:26:36 +0200212absl::optional<Packet> PacketBuffer::GetNextPacket() {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000213 if (Empty()) {
214 // Buffer is empty.
Danil Chapovalovb6021232018-06-19 13:26:36 +0200215 return absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000216 }
217
Danil Chapovalovb6021232018-06-19 13:26:36 +0200218 absl::optional<Packet> packet(std::move(buffer_.front()));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000219 // Assert that the packet sanity checks in InsertPacket method works.
ossua73f6c92016-10-24 08:25:28 -0700220 RTC_DCHECK(!packet->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000221 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000222
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000223 return packet;
224}
225
minyue-webrtcfae474c2017-07-05 11:17:40 +0200226int PacketBuffer::DiscardNextPacket(StatisticsCalculator* stats) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000227 if (Empty()) {
228 return kBufferEmpty;
229 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000230 // Assert that the packet sanity checks in InsertPacket method works.
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200231 const Packet& packet = buffer_.front();
232 RTC_DCHECK(!packet.empty());
233 LogPacketDiscarded(packet.priority.codec_level, stats);
ossua73f6c92016-10-24 08:25:28 -0700234 buffer_.pop_front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000235 return kOK;
236}
237
minyue-webrtcfae474c2017-07-05 11:17:40 +0200238void PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
239 uint32_t horizon_samples,
240 StatisticsCalculator* stats) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200241 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;
henrik.lundin63d146b2017-07-05 07:03:34 -0700248 });
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000249}
250
minyue-webrtcfae474c2017-07-05 11:17:40 +0200251void PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit,
252 StatisticsCalculator* stats) {
253 DiscardOldPackets(timestamp_limit, 0, stats);
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200254}
255
minyue-webrtcfae474c2017-07-05 11:17:40 +0200256void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type,
257 StatisticsCalculator* stats) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200258 buffer_.remove_if([payload_type, stats](const Packet& p) {
259 if (p.payload_type != payload_type) {
260 return false;
ossu61a208b2016-09-20 01:38:00 -0700261 }
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200262 LogPacketDiscarded(p.priority.codec_level, stats);
263 return true;
264 });
ossu61a208b2016-09-20 01:38:00 -0700265}
266
Peter Kastingdce40cf2015-08-24 14:52:23 -0700267size_t PacketBuffer::NumPacketsInBuffer() const {
268 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200269}
270
ossu61a208b2016-09-20 01:38:00 -0700271size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700272 size_t num_samples = 0;
273 size_t last_duration = last_decoded_length;
ossua73f6c92016-10-24 08:25:28 -0700274 for (const Packet& packet : buffer_) {
275 if (packet.frame) {
ossua70695a2016-09-22 02:06:28 -0700276 // TODO(hlundin): Verify that it's fine to count all packets and remove
277 // this check.
ossua73f6c92016-10-24 08:25:28 -0700278 if (packet.priority != Packet::Priority(0, 0)) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000279 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000280 }
ossua73f6c92016-10-24 08:25:28 -0700281 size_t duration = packet.frame->Duration();
ossu61a208b2016-09-20 01:38:00 -0700282 if (duration > 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000283 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000284 }
285 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000286 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000287 }
288 return num_samples;
289}
290
Jakob Ivarsson46dda832019-07-03 16:00:30 +0200291size_t PacketBuffer::GetSpanSamples(size_t last_decoded_length,
292 size_t sample_rate,
293 bool count_dtx_waiting_time) const {
Jakob Ivarsson1b4254a2019-03-12 15:12:08 +0100294 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) {
Jakob Ivarsson46dda832019-07-03 16:00:30 +0200300 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;
Jakob Ivarsson1b4254a2019-03-12 15:12:08 +0100307 } else {
308 span += last_decoded_length;
309 }
310 return span;
311}
312
Ivo Creusenc7f09ad2018-05-22 13:21:01 +0200313bool 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
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000325} // namespace webrtc