blob: 7b70dee019617dad0c324c9f029ebbb4b41a6d0b [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"
24#include "modules/audio_coding/neteq/decoder_database.h"
25#include "modules/audio_coding/neteq/statistics_calculator.h"
26#include "modules/audio_coding/neteq/tick_timer.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"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000029
30namespace webrtc {
henrik.lundin067d8552016-09-01 23:19:05 -070031namespace {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000032// Predicate used when inserting packets in the buffer list.
33// Operator() returns true when |packet| goes before |new_packet|.
34class NewTimestampIsLarger {
35 public:
ossua73f6c92016-10-24 08:25:28 -070036 explicit NewTimestampIsLarger(const Packet& new_packet)
Yves Gerey665174f2018-06-19 15:03:05 +020037 : new_packet_(new_packet) {}
38 bool operator()(const Packet& packet) { return (new_packet_ >= packet); }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000039
40 private:
ossua73f6c92016-10-24 08:25:28 -070041 const Packet& new_packet_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000042};
43
henrik.lundin067d8552016-09-01 23:19:05 -070044// Returns true if both payload types are known to the decoder database, and
45// have the same sample rate.
46bool EqualSampleRates(uint8_t pt1,
47 uint8_t pt2,
48 const DecoderDatabase& decoder_database) {
kjellander7c856582017-02-26 19:53:40 -080049 auto* di1 = decoder_database.GetDecoderInfo(pt1);
50 auto* di2 = decoder_database.GetDecoderInfo(pt2);
henrik.lundin067d8552016-09-01 23:19:05 -070051 return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
52}
minyue-webrtc0c3ca752017-08-23 15:59:38 +020053
54void LogPacketDiscarded(int codec_level, StatisticsCalculator* stats) {
55 RTC_CHECK(stats);
56 if (codec_level > 0) {
57 stats->SecondaryPacketsDiscarded(1);
58 } else {
59 stats->PacketsDiscarded(1);
60 }
61}
62
henrik.lundin067d8552016-09-01 23:19:05 -070063} // namespace
64
henrik.lundin84f8cd62016-04-26 07:45:16 -070065PacketBuffer::PacketBuffer(size_t max_number_of_packets,
66 const TickTimer* tick_timer)
67 : max_number_of_packets_(max_number_of_packets), tick_timer_(tick_timer) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000068
69// Destructor. All packets in the buffer will be destroyed.
70PacketBuffer::~PacketBuffer() {
71 Flush();
72}
73
74// Flush the buffer. All packets in the buffer will be destroyed.
75void PacketBuffer::Flush() {
ossua73f6c92016-10-24 08:25:28 -070076 buffer_.clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000077}
78
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020079bool PacketBuffer::Empty() const {
80 return buffer_.empty();
81}
82
minyue-webrtc12d30842017-07-19 11:44:06 +020083int PacketBuffer::InsertPacket(Packet&& packet, StatisticsCalculator* stats) {
ossua73f6c92016-10-24 08:25:28 -070084 if (packet.empty()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010085 RTC_LOG(LS_WARNING) << "InsertPacket invalid packet";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000086 return kInvalidPacket;
87 }
88
ossua73f6c92016-10-24 08:25:28 -070089 RTC_DCHECK_GE(packet.priority.codec_level, 0);
90 RTC_DCHECK_GE(packet.priority.red_level, 0);
ossua70695a2016-09-22 02:06:28 -070091
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000092 int return_val = kOK;
93
ossua73f6c92016-10-24 08:25:28 -070094 packet.waiting_time = tick_timer_->GetNewStopwatch();
henrik.lundin84f8cd62016-04-26 07:45:16 -070095
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000096 if (buffer_.size() >= max_number_of_packets_) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000097 // Buffer is full. Flush it.
98 Flush();
Ivo Creusendc6d5532018-09-27 11:43:42 +020099 stats->FlushedPacketBuffer();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100100 RTC_LOG(LS_WARNING) << "Packet buffer flushed";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000101 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000102 }
103
104 // Get an iterator pointing to the place in the buffer where the new packet
105 // should be inserted. The list is searched from the back, since the most
106 // likely case is that the new packet should be near the end of the list.
107 PacketList::reverse_iterator rit = std::find_if(
Yves Gerey665174f2018-06-19 15:03:05 +0200108 buffer_.rbegin(), buffer_.rend(), NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000109
110 // The new packet is to be inserted to the right of |rit|. If it has the same
111 // timestamp as |rit|, which has a higher priority, do not insert the new
112 // packet to list.
ossua73f6c92016-10-24 08:25:28 -0700113 if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200114 LogPacketDiscarded(packet.priority.codec_level, stats);
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000115 return return_val;
116 }
117
118 // The new packet is to be inserted to the left of |it|. If it has the same
119 // timestamp as |it|, which has a lower priority, replace |it| with the new
120 // packet.
121 PacketList::iterator it = rit.base();
ossua73f6c92016-10-24 08:25:28 -0700122 if (it != buffer_.end() && packet.timestamp == it->timestamp) {
Peng Yub90e63c62018-06-07 19:20:55 +0800123 LogPacketDiscarded(it->priority.codec_level, stats);
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000124 it = buffer_.erase(it);
125 }
ossua73f6c92016-10-24 08:25:28 -0700126 buffer_.insert(it, std::move(packet)); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000127
128 return return_val;
129}
130
henrik.lundinda8bbf62016-08-31 03:14:11 -0700131int PacketBuffer::InsertPacketList(
132 PacketList* packet_list,
133 const DecoderDatabase& decoder_database,
Danil Chapovalovb6021232018-06-19 13:26:36 +0200134 absl::optional<uint8_t>* current_rtp_payload_type,
135 absl::optional<uint8_t>* current_cng_rtp_payload_type,
minyue-webrtc12d30842017-07-19 11:44:06 +0200136 StatisticsCalculator* stats) {
137 RTC_DCHECK(stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000138 bool flushed = false;
ossua73f6c92016-10-24 08:25:28 -0700139 for (auto& packet : *packet_list) {
140 if (decoder_database.IsComfortNoise(packet.payload_type)) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700141 if (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700142 **current_cng_rtp_payload_type != packet.payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000143 // New CNG payload type implies new codec type.
Danil Chapovalovb6021232018-06-19 13:26:36 +0200144 *current_rtp_payload_type = absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000145 Flush();
146 flushed = true;
147 }
Oskar Sundbom12ab00b2017-11-16 15:31:38 +0100148 *current_cng_rtp_payload_type = packet.payload_type;
ossua73f6c92016-10-24 08:25:28 -0700149 } else if (!decoder_database.IsDtmf(packet.payload_type)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000150 // This must be speech.
henrik.lundin067d8552016-09-01 23:19:05 -0700151 if ((*current_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700152 **current_rtp_payload_type != packet.payload_type) ||
henrik.lundin067d8552016-09-01 23:19:05 -0700153 (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700154 !EqualSampleRates(packet.payload_type,
henrik.lundin067d8552016-09-01 23:19:05 -0700155 **current_cng_rtp_payload_type,
156 decoder_database))) {
Danil Chapovalovb6021232018-06-19 13:26:36 +0200157 *current_cng_rtp_payload_type = absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000158 Flush();
159 flushed = true;
160 }
Oskar Sundbom12ab00b2017-11-16 15:31:38 +0100161 *current_rtp_payload_type = packet.payload_type;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000162 }
minyue-webrtc12d30842017-07-19 11:44:06 +0200163 int return_val = InsertPacket(std::move(packet), stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000164 if (return_val == kFlushed) {
165 // The buffer flushed, but this is not an error. We can still continue.
166 flushed = true;
167 } else if (return_val != kOK) {
168 // An error occurred. Delete remaining packets in list and return.
ossua73f6c92016-10-24 08:25:28 -0700169 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000170 return return_val;
171 }
172 }
ossua73f6c92016-10-24 08:25:28 -0700173 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000174 return flushed ? kFlushed : kOK;
175}
176
177int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
178 if (Empty()) {
179 return kBufferEmpty;
180 }
181 if (!next_timestamp) {
182 return kInvalidPointer;
183 }
ossua73f6c92016-10-24 08:25:28 -0700184 *next_timestamp = buffer_.front().timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000185 return kOK;
186}
187
188int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
189 uint32_t* next_timestamp) const {
190 if (Empty()) {
191 return kBufferEmpty;
192 }
193 if (!next_timestamp) {
194 return kInvalidPointer;
195 }
196 PacketList::const_iterator it;
197 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
ossua73f6c92016-10-24 08:25:28 -0700198 if (it->timestamp >= timestamp) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000199 // Found a packet matching the search.
ossua73f6c92016-10-24 08:25:28 -0700200 *next_timestamp = it->timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000201 return kOK;
202 }
203 }
204 return kNotFound;
205}
206
ossu7a377612016-10-18 04:06:13 -0700207const Packet* PacketBuffer::PeekNextPacket() const {
ossua73f6c92016-10-24 08:25:28 -0700208 return buffer_.empty() ? nullptr : &buffer_.front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000209}
210
Danil Chapovalovb6021232018-06-19 13:26:36 +0200211absl::optional<Packet> PacketBuffer::GetNextPacket() {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000212 if (Empty()) {
213 // Buffer is empty.
Danil Chapovalovb6021232018-06-19 13:26:36 +0200214 return absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000215 }
216
Danil Chapovalovb6021232018-06-19 13:26:36 +0200217 absl::optional<Packet> packet(std::move(buffer_.front()));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000218 // Assert that the packet sanity checks in InsertPacket method works.
ossua73f6c92016-10-24 08:25:28 -0700219 RTC_DCHECK(!packet->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000220 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000221
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000222 return packet;
223}
224
minyue-webrtcfae474c2017-07-05 11:17:40 +0200225int PacketBuffer::DiscardNextPacket(StatisticsCalculator* stats) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000226 if (Empty()) {
227 return kBufferEmpty;
228 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000229 // Assert that the packet sanity checks in InsertPacket method works.
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200230 const Packet& packet = buffer_.front();
231 RTC_DCHECK(!packet.empty());
232 LogPacketDiscarded(packet.priority.codec_level, stats);
ossua73f6c92016-10-24 08:25:28 -0700233 buffer_.pop_front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000234 return kOK;
235}
236
minyue-webrtcfae474c2017-07-05 11:17:40 +0200237void PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
238 uint32_t horizon_samples,
239 StatisticsCalculator* stats) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200240 buffer_.remove_if([timestamp_limit, horizon_samples, stats](const Packet& p) {
241 if (timestamp_limit == p.timestamp ||
242 !IsObsoleteTimestamp(p.timestamp, timestamp_limit, horizon_samples)) {
243 return false;
244 }
245 LogPacketDiscarded(p.priority.codec_level, stats);
246 return true;
henrik.lundin63d146b2017-07-05 07:03:34 -0700247 });
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000248}
249
minyue-webrtcfae474c2017-07-05 11:17:40 +0200250void PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit,
251 StatisticsCalculator* stats) {
252 DiscardOldPackets(timestamp_limit, 0, stats);
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200253}
254
minyue-webrtcfae474c2017-07-05 11:17:40 +0200255void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type,
256 StatisticsCalculator* stats) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200257 buffer_.remove_if([payload_type, stats](const Packet& p) {
258 if (p.payload_type != payload_type) {
259 return false;
ossu61a208b2016-09-20 01:38:00 -0700260 }
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200261 LogPacketDiscarded(p.priority.codec_level, stats);
262 return true;
263 });
ossu61a208b2016-09-20 01:38:00 -0700264}
265
Peter Kastingdce40cf2015-08-24 14:52:23 -0700266size_t PacketBuffer::NumPacketsInBuffer() const {
267 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200268}
269
ossu61a208b2016-09-20 01:38:00 -0700270size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700271 size_t num_samples = 0;
272 size_t last_duration = last_decoded_length;
ossua73f6c92016-10-24 08:25:28 -0700273 for (const Packet& packet : buffer_) {
274 if (packet.frame) {
ossua70695a2016-09-22 02:06:28 -0700275 // TODO(hlundin): Verify that it's fine to count all packets and remove
276 // this check.
ossua73f6c92016-10-24 08:25:28 -0700277 if (packet.priority != Packet::Priority(0, 0)) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000278 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000279 }
ossua73f6c92016-10-24 08:25:28 -0700280 size_t duration = packet.frame->Duration();
ossu61a208b2016-09-20 01:38:00 -0700281 if (duration > 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000282 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000283 }
284 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000285 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000286 }
287 return num_samples;
288}
289
Ivo Creusenc7f09ad2018-05-22 13:21:01 +0200290bool PacketBuffer::ContainsDtxOrCngPacket(
291 const DecoderDatabase* decoder_database) const {
292 RTC_DCHECK(decoder_database);
293 for (const Packet& packet : buffer_) {
294 if ((packet.frame && packet.frame->IsDtxPacket()) ||
295 decoder_database->IsComfortNoise(packet.payload_type)) {
296 return true;
297 }
298 }
299 return false;
300}
301
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000302void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000303 *num_packets = static_cast<int>(buffer_.size());
304 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000305}
306
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000307} // namespace webrtc