blob: c04534eaa66d7b0ec473321fa5812af1fd669c5b [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();
Mirko Bonadei675513b2017-11-09 11:09:25 +010094 RTC_LOG(LS_WARNING) << "Packet buffer flushed";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000095 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000096 }
97
98 // Get an iterator pointing to the place in the buffer where the new packet
99 // should be inserted. The list is searched from the back, since the most
100 // likely case is that the new packet should be near the end of the list.
101 PacketList::reverse_iterator rit = std::find_if(
Yves Gerey665174f2018-06-19 15:03:05 +0200102 buffer_.rbegin(), buffer_.rend(), NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000103
104 // The new packet is to be inserted to the right of |rit|. If it has the same
105 // timestamp as |rit|, which has a higher priority, do not insert the new
106 // packet to list.
ossua73f6c92016-10-24 08:25:28 -0700107 if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200108 LogPacketDiscarded(packet.priority.codec_level, stats);
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000109 return return_val;
110 }
111
112 // The new packet is to be inserted to the left of |it|. If it has the same
113 // timestamp as |it|, which has a lower priority, replace |it| with the new
114 // packet.
115 PacketList::iterator it = rit.base();
ossua73f6c92016-10-24 08:25:28 -0700116 if (it != buffer_.end() && packet.timestamp == it->timestamp) {
Peng Yub90e63c62018-06-07 19:20:55 +0800117 LogPacketDiscarded(it->priority.codec_level, stats);
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000118 it = buffer_.erase(it);
119 }
ossua73f6c92016-10-24 08:25:28 -0700120 buffer_.insert(it, std::move(packet)); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000121
122 return return_val;
123}
124
henrik.lundinda8bbf62016-08-31 03:14:11 -0700125int PacketBuffer::InsertPacketList(
126 PacketList* packet_list,
127 const DecoderDatabase& decoder_database,
Danil Chapovalovb6021232018-06-19 13:26:36 +0200128 absl::optional<uint8_t>* current_rtp_payload_type,
129 absl::optional<uint8_t>* current_cng_rtp_payload_type,
minyue-webrtc12d30842017-07-19 11:44:06 +0200130 StatisticsCalculator* stats) {
131 RTC_DCHECK(stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000132 bool flushed = false;
ossua73f6c92016-10-24 08:25:28 -0700133 for (auto& packet : *packet_list) {
134 if (decoder_database.IsComfortNoise(packet.payload_type)) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700135 if (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700136 **current_cng_rtp_payload_type != packet.payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000137 // New CNG payload type implies new codec type.
Danil Chapovalovb6021232018-06-19 13:26:36 +0200138 *current_rtp_payload_type = absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000139 Flush();
140 flushed = true;
141 }
Oskar Sundbom12ab00b2017-11-16 15:31:38 +0100142 *current_cng_rtp_payload_type = packet.payload_type;
ossua73f6c92016-10-24 08:25:28 -0700143 } else if (!decoder_database.IsDtmf(packet.payload_type)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000144 // This must be speech.
henrik.lundin067d8552016-09-01 23:19:05 -0700145 if ((*current_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700146 **current_rtp_payload_type != packet.payload_type) ||
henrik.lundin067d8552016-09-01 23:19:05 -0700147 (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700148 !EqualSampleRates(packet.payload_type,
henrik.lundin067d8552016-09-01 23:19:05 -0700149 **current_cng_rtp_payload_type,
150 decoder_database))) {
Danil Chapovalovb6021232018-06-19 13:26:36 +0200151 *current_cng_rtp_payload_type = absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000152 Flush();
153 flushed = true;
154 }
Oskar Sundbom12ab00b2017-11-16 15:31:38 +0100155 *current_rtp_payload_type = packet.payload_type;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000156 }
minyue-webrtc12d30842017-07-19 11:44:06 +0200157 int return_val = InsertPacket(std::move(packet), stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000158 if (return_val == kFlushed) {
159 // The buffer flushed, but this is not an error. We can still continue.
160 flushed = true;
161 } else if (return_val != kOK) {
162 // An error occurred. Delete remaining packets in list and return.
ossua73f6c92016-10-24 08:25:28 -0700163 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000164 return return_val;
165 }
166 }
ossua73f6c92016-10-24 08:25:28 -0700167 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000168 return flushed ? kFlushed : kOK;
169}
170
171int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
172 if (Empty()) {
173 return kBufferEmpty;
174 }
175 if (!next_timestamp) {
176 return kInvalidPointer;
177 }
ossua73f6c92016-10-24 08:25:28 -0700178 *next_timestamp = buffer_.front().timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000179 return kOK;
180}
181
182int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
183 uint32_t* next_timestamp) const {
184 if (Empty()) {
185 return kBufferEmpty;
186 }
187 if (!next_timestamp) {
188 return kInvalidPointer;
189 }
190 PacketList::const_iterator it;
191 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
ossua73f6c92016-10-24 08:25:28 -0700192 if (it->timestamp >= timestamp) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000193 // Found a packet matching the search.
ossua73f6c92016-10-24 08:25:28 -0700194 *next_timestamp = it->timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000195 return kOK;
196 }
197 }
198 return kNotFound;
199}
200
ossu7a377612016-10-18 04:06:13 -0700201const Packet* PacketBuffer::PeekNextPacket() const {
ossua73f6c92016-10-24 08:25:28 -0700202 return buffer_.empty() ? nullptr : &buffer_.front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000203}
204
Danil Chapovalovb6021232018-06-19 13:26:36 +0200205absl::optional<Packet> PacketBuffer::GetNextPacket() {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000206 if (Empty()) {
207 // Buffer is empty.
Danil Chapovalovb6021232018-06-19 13:26:36 +0200208 return absl::nullopt;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000209 }
210
Danil Chapovalovb6021232018-06-19 13:26:36 +0200211 absl::optional<Packet> packet(std::move(buffer_.front()));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000212 // Assert that the packet sanity checks in InsertPacket method works.
ossua73f6c92016-10-24 08:25:28 -0700213 RTC_DCHECK(!packet->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000214 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000215
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000216 return packet;
217}
218
minyue-webrtcfae474c2017-07-05 11:17:40 +0200219int PacketBuffer::DiscardNextPacket(StatisticsCalculator* stats) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000220 if (Empty()) {
221 return kBufferEmpty;
222 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000223 // Assert that the packet sanity checks in InsertPacket method works.
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200224 const Packet& packet = buffer_.front();
225 RTC_DCHECK(!packet.empty());
226 LogPacketDiscarded(packet.priority.codec_level, stats);
ossua73f6c92016-10-24 08:25:28 -0700227 buffer_.pop_front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000228 return kOK;
229}
230
minyue-webrtcfae474c2017-07-05 11:17:40 +0200231void PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
232 uint32_t horizon_samples,
233 StatisticsCalculator* stats) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200234 buffer_.remove_if([timestamp_limit, horizon_samples, stats](const Packet& p) {
235 if (timestamp_limit == p.timestamp ||
236 !IsObsoleteTimestamp(p.timestamp, timestamp_limit, horizon_samples)) {
237 return false;
238 }
239 LogPacketDiscarded(p.priority.codec_level, stats);
240 return true;
henrik.lundin63d146b2017-07-05 07:03:34 -0700241 });
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000242}
243
minyue-webrtcfae474c2017-07-05 11:17:40 +0200244void PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit,
245 StatisticsCalculator* stats) {
246 DiscardOldPackets(timestamp_limit, 0, stats);
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200247}
248
minyue-webrtcfae474c2017-07-05 11:17:40 +0200249void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type,
250 StatisticsCalculator* stats) {
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200251 buffer_.remove_if([payload_type, stats](const Packet& p) {
252 if (p.payload_type != payload_type) {
253 return false;
ossu61a208b2016-09-20 01:38:00 -0700254 }
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200255 LogPacketDiscarded(p.priority.codec_level, stats);
256 return true;
257 });
ossu61a208b2016-09-20 01:38:00 -0700258}
259
Peter Kastingdce40cf2015-08-24 14:52:23 -0700260size_t PacketBuffer::NumPacketsInBuffer() const {
261 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200262}
263
ossu61a208b2016-09-20 01:38:00 -0700264size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700265 size_t num_samples = 0;
266 size_t last_duration = last_decoded_length;
ossua73f6c92016-10-24 08:25:28 -0700267 for (const Packet& packet : buffer_) {
268 if (packet.frame) {
ossua70695a2016-09-22 02:06:28 -0700269 // TODO(hlundin): Verify that it's fine to count all packets and remove
270 // this check.
ossua73f6c92016-10-24 08:25:28 -0700271 if (packet.priority != Packet::Priority(0, 0)) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000272 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000273 }
ossua73f6c92016-10-24 08:25:28 -0700274 size_t duration = packet.frame->Duration();
ossu61a208b2016-09-20 01:38:00 -0700275 if (duration > 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000276 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000277 }
278 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000279 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000280 }
281 return num_samples;
282}
283
Ivo Creusenc7f09ad2018-05-22 13:21:01 +0200284bool PacketBuffer::ContainsDtxOrCngPacket(
285 const DecoderDatabase* decoder_database) const {
286 RTC_DCHECK(decoder_database);
287 for (const Packet& packet : buffer_) {
288 if ((packet.frame && packet.frame->IsDtxPacket()) ||
289 decoder_database->IsComfortNoise(packet.payload_type)) {
290 return true;
291 }
292 }
293 return false;
294}
295
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000296void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000297 *num_packets = static_cast<int>(buffer_.size());
298 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000299}
300
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000301} // namespace webrtc