blob: eba4d3e68b66d6e571e9c06e45573817af7da978 [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
17#include <algorithm> // find_if()
18
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "api/audio_codecs/audio_decoder.h"
20#include "modules/audio_coding/neteq/decoder_database.h"
21#include "modules/audio_coding/neteq/statistics_calculator.h"
22#include "modules/audio_coding/neteq/tick_timer.h"
23#include "rtc_base/logging.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000024
25namespace webrtc {
henrik.lundin067d8552016-09-01 23:19:05 -070026namespace {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000027// Predicate used when inserting packets in the buffer list.
28// Operator() returns true when |packet| goes before |new_packet|.
29class NewTimestampIsLarger {
30 public:
ossua73f6c92016-10-24 08:25:28 -070031 explicit NewTimestampIsLarger(const Packet& new_packet)
Yves Gerey665174f2018-06-19 15:03:05 +020032 : new_packet_(new_packet) {}
33 bool operator()(const Packet& packet) { return (new_packet_ >= packet); }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000034
35 private:
ossua73f6c92016-10-24 08:25:28 -070036 const Packet& new_packet_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000037};
38
henrik.lundin067d8552016-09-01 23:19:05 -070039// Returns true if both payload types are known to the decoder database, and
40// have the same sample rate.
41bool EqualSampleRates(uint8_t pt1,
42 uint8_t pt2,
43 const DecoderDatabase& decoder_database) {
kjellander7c856582017-02-26 19:53:40 -080044 auto* di1 = decoder_database.GetDecoderInfo(pt1);
45 auto* di2 = decoder_database.GetDecoderInfo(pt2);
henrik.lundin067d8552016-09-01 23:19:05 -070046 return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
47}
minyue-webrtc0c3ca752017-08-23 15:59:38 +020048
49void LogPacketDiscarded(int codec_level, StatisticsCalculator* stats) {
50 RTC_CHECK(stats);
51 if (codec_level > 0) {
52 stats->SecondaryPacketsDiscarded(1);
53 } else {
54 stats->PacketsDiscarded(1);
55 }
56}
57
henrik.lundin067d8552016-09-01 23:19:05 -070058} // namespace
59
henrik.lundin84f8cd62016-04-26 07:45:16 -070060PacketBuffer::PacketBuffer(size_t max_number_of_packets,
61 const TickTimer* tick_timer)
62 : max_number_of_packets_(max_number_of_packets), tick_timer_(tick_timer) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000063
64// Destructor. All packets in the buffer will be destroyed.
65PacketBuffer::~PacketBuffer() {
66 Flush();
67}
68
69// Flush the buffer. All packets in the buffer will be destroyed.
70void PacketBuffer::Flush() {
ossua73f6c92016-10-24 08:25:28 -070071 buffer_.clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000072}
73
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020074bool PacketBuffer::Empty() const {
75 return buffer_.empty();
76}
77
minyue-webrtc12d30842017-07-19 11:44:06 +020078int PacketBuffer::InsertPacket(Packet&& packet, StatisticsCalculator* stats) {
ossua73f6c92016-10-24 08:25:28 -070079 if (packet.empty()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010080 RTC_LOG(LS_WARNING) << "InsertPacket invalid packet";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000081 return kInvalidPacket;
82 }
83
ossua73f6c92016-10-24 08:25:28 -070084 RTC_DCHECK_GE(packet.priority.codec_level, 0);
85 RTC_DCHECK_GE(packet.priority.red_level, 0);
ossua70695a2016-09-22 02:06:28 -070086
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000087 int return_val = kOK;
88
ossua73f6c92016-10-24 08:25:28 -070089 packet.waiting_time = tick_timer_->GetNewStopwatch();
henrik.lundin84f8cd62016-04-26 07:45:16 -070090
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000091 if (buffer_.size() >= max_number_of_packets_) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000092 // Buffer is full. Flush it.
93 Flush();
Ivo Creusendc6d5532018-09-27 11:43:42 +020094 stats->FlushedPacketBuffer();
Mirko Bonadei675513b2017-11-09 11:09:25 +010095 RTC_LOG(LS_WARNING) << "Packet buffer flushed";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000096 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000097 }
98
99 // Get an iterator pointing to the place in the buffer where the new packet
100 // should be inserted. The list is searched from the back, since the most
101 // likely case is that the new packet should be near the end of the list.
102 PacketList::reverse_iterator rit = std::find_if(
Yves Gerey665174f2018-06-19 15:03:05 +0200103 buffer_.rbegin(), buffer_.rend(), NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000104
105 // The new packet is to be inserted to the right of |rit|. If it has the same
106 // timestamp as |rit|, which has a higher priority, do not insert the new
107 // packet to list.
ossua73f6c92016-10-24 08:25:28 -0700108 if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200109 LogPacketDiscarded(packet.priority.codec_level, stats);
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000110 return return_val;
111 }
112
113 // The new packet is to be inserted to the left of |it|. If it has the same
114 // timestamp as |it|, which has a lower priority, replace |it| with the new
115 // packet.
116 PacketList::iterator it = rit.base();
ossua73f6c92016-10-24 08:25:28 -0700117 if (it != buffer_.end() && packet.timestamp == it->timestamp) {
Peng Yub90e63c62018-06-07 19:20:55 +0800118 LogPacketDiscarded(it->priority.codec_level, stats);
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000119 it = buffer_.erase(it);
120 }
ossua73f6c92016-10-24 08:25:28 -0700121 buffer_.insert(it, std::move(packet)); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000122
123 return return_val;
124}
125
henrik.lundinda8bbf62016-08-31 03:14:11 -0700126int PacketBuffer::InsertPacketList(
127 PacketList* packet_list,
128 const DecoderDatabase& decoder_database,
Danil Chapovalovb6021232018-06-19 13:26:36 +0200129 absl::optional<uint8_t>* current_rtp_payload_type,
130 absl::optional<uint8_t>* current_cng_rtp_payload_type,
minyue-webrtc12d30842017-07-19 11:44:06 +0200131 StatisticsCalculator* stats) {
132 RTC_DCHECK(stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000133 bool flushed = false;
ossua73f6c92016-10-24 08:25:28 -0700134 for (auto& packet : *packet_list) {
135 if (decoder_database.IsComfortNoise(packet.payload_type)) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700136 if (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700137 **current_cng_rtp_payload_type != packet.payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000138 // New CNG payload type implies new codec type.
Danil Chapovalovb6021232018-06-19 13:26:36 +0200139 *current_rtp_payload_type = absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000140 Flush();
141 flushed = true;
142 }
Oskar Sundbom12ab00b2017-11-16 15:31:38 +0100143 *current_cng_rtp_payload_type = packet.payload_type;
ossua73f6c92016-10-24 08:25:28 -0700144 } else if (!decoder_database.IsDtmf(packet.payload_type)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000145 // This must be speech.
henrik.lundin067d8552016-09-01 23:19:05 -0700146 if ((*current_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700147 **current_rtp_payload_type != packet.payload_type) ||
henrik.lundin067d8552016-09-01 23:19:05 -0700148 (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700149 !EqualSampleRates(packet.payload_type,
henrik.lundin067d8552016-09-01 23:19:05 -0700150 **current_cng_rtp_payload_type,
151 decoder_database))) {
Danil Chapovalovb6021232018-06-19 13:26:36 +0200152 *current_cng_rtp_payload_type = absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000153 Flush();
154 flushed = true;
155 }
Oskar Sundbom12ab00b2017-11-16 15:31:38 +0100156 *current_rtp_payload_type = packet.payload_type;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000157 }
minyue-webrtc12d30842017-07-19 11:44:06 +0200158 int return_val = InsertPacket(std::move(packet), stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000159 if (return_val == kFlushed) {
160 // The buffer flushed, but this is not an error. We can still continue.
161 flushed = true;
162 } else if (return_val != kOK) {
163 // An error occurred. Delete remaining packets in list and return.
ossua73f6c92016-10-24 08:25:28 -0700164 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000165 return return_val;
166 }
167 }
ossua73f6c92016-10-24 08:25:28 -0700168 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000169 return flushed ? kFlushed : kOK;
170}
171
172int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
173 if (Empty()) {
174 return kBufferEmpty;
175 }
176 if (!next_timestamp) {
177 return kInvalidPointer;
178 }
ossua73f6c92016-10-24 08:25:28 -0700179 *next_timestamp = buffer_.front().timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000180 return kOK;
181}
182
183int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
184 uint32_t* next_timestamp) const {
185 if (Empty()) {
186 return kBufferEmpty;
187 }
188 if (!next_timestamp) {
189 return kInvalidPointer;
190 }
191 PacketList::const_iterator it;
192 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
ossua73f6c92016-10-24 08:25:28 -0700193 if (it->timestamp >= timestamp) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000194 // Found a packet matching the search.
ossua73f6c92016-10-24 08:25:28 -0700195 *next_timestamp = it->timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000196 return kOK;
197 }
198 }
199 return kNotFound;
200}
201
ossu7a377612016-10-18 04:06:13 -0700202const Packet* PacketBuffer::PeekNextPacket() const {
ossua73f6c92016-10-24 08:25:28 -0700203 return buffer_.empty() ? nullptr : &buffer_.front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000204}
205
Danil Chapovalovb6021232018-06-19 13:26:36 +0200206absl::optional<Packet> PacketBuffer::GetNextPacket() {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000207 if (Empty()) {
208 // Buffer is empty.
Danil Chapovalovb6021232018-06-19 13:26:36 +0200209 return absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000210 }
211
Danil Chapovalovb6021232018-06-19 13:26:36 +0200212 absl::optional<Packet> packet(std::move(buffer_.front()));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000213 // Assert that the packet sanity checks in InsertPacket method works.
ossua73f6c92016-10-24 08:25:28 -0700214 RTC_DCHECK(!packet->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000215 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000216
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000217 return packet;
218}
219
minyue-webrtcfae474c2017-07-05 11:17:40 +0200220int PacketBuffer::DiscardNextPacket(StatisticsCalculator* stats) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000221 if (Empty()) {
222 return kBufferEmpty;
223 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000224 // Assert that the packet sanity checks in InsertPacket method works.
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200225 const Packet& packet = buffer_.front();
226 RTC_DCHECK(!packet.empty());
227 LogPacketDiscarded(packet.priority.codec_level, stats);
ossua73f6c92016-10-24 08:25:28 -0700228 buffer_.pop_front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000229 return kOK;
230}
231
minyue-webrtcfae474c2017-07-05 11:17:40 +0200232void PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
233 uint32_t horizon_samples,
234 StatisticsCalculator* stats) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200235 buffer_.remove_if([timestamp_limit, horizon_samples, stats](const Packet& p) {
236 if (timestamp_limit == p.timestamp ||
237 !IsObsoleteTimestamp(p.timestamp, timestamp_limit, horizon_samples)) {
238 return false;
239 }
240 LogPacketDiscarded(p.priority.codec_level, stats);
241 return true;
henrik.lundin63d146b2017-07-05 07:03:34 -0700242 });
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000243}
244
minyue-webrtcfae474c2017-07-05 11:17:40 +0200245void PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit,
246 StatisticsCalculator* stats) {
247 DiscardOldPackets(timestamp_limit, 0, stats);
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200248}
249
minyue-webrtcfae474c2017-07-05 11:17:40 +0200250void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type,
251 StatisticsCalculator* stats) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200252 buffer_.remove_if([payload_type, stats](const Packet& p) {
253 if (p.payload_type != payload_type) {
254 return false;
ossu61a208b2016-09-20 01:38:00 -0700255 }
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200256 LogPacketDiscarded(p.priority.codec_level, stats);
257 return true;
258 });
ossu61a208b2016-09-20 01:38:00 -0700259}
260
Peter Kastingdce40cf2015-08-24 14:52:23 -0700261size_t PacketBuffer::NumPacketsInBuffer() const {
262 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200263}
264
ossu61a208b2016-09-20 01:38:00 -0700265size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700266 size_t num_samples = 0;
267 size_t last_duration = last_decoded_length;
ossua73f6c92016-10-24 08:25:28 -0700268 for (const Packet& packet : buffer_) {
269 if (packet.frame) {
ossua70695a2016-09-22 02:06:28 -0700270 // TODO(hlundin): Verify that it's fine to count all packets and remove
271 // this check.
ossua73f6c92016-10-24 08:25:28 -0700272 if (packet.priority != Packet::Priority(0, 0)) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000273 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000274 }
ossua73f6c92016-10-24 08:25:28 -0700275 size_t duration = packet.frame->Duration();
ossu61a208b2016-09-20 01:38:00 -0700276 if (duration > 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000277 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000278 }
279 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000280 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000281 }
282 return num_samples;
283}
284
Ivo Creusenc7f09ad2018-05-22 13:21:01 +0200285bool PacketBuffer::ContainsDtxOrCngPacket(
286 const DecoderDatabase* decoder_database) const {
287 RTC_DCHECK(decoder_database);
288 for (const Packet& packet : buffer_) {
289 if ((packet.frame && packet.frame->IsDtxPacket()) ||
290 decoder_database->IsComfortNoise(packet.payload_type)) {
291 return true;
292 }
293 }
294 return false;
295}
296
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000297void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000298 *num_packets = static_cast<int>(buffer_.size());
299 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000300}
301
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000302} // namespace webrtc