blob: 1e71525dc06dabb475a585b5e54637e0729fa855 [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
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000015#include "webrtc/modules/audio_coding/neteq/packet_buffer.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000016
17#include <algorithm> // find_if()
18
kwiberg087bd342017-02-10 08:15:44 -080019#include "webrtc/api/audio_codecs/audio_decoder.h"
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000020#include "webrtc/modules/audio_coding/neteq/decoder_database.h"
minyue-webrtcfae474c2017-07-05 11:17:40 +020021#include "webrtc/modules/audio_coding/neteq/statistics_calculator.h"
henrik.lundin84f8cd62016-04-26 07:45:16 -070022#include "webrtc/modules/audio_coding/neteq/tick_timer.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020023#include "webrtc/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)
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000032 : new_packet_(new_packet) {
33 }
ossua73f6c92016-10-24 08:25:28 -070034 bool operator()(const Packet& packet) {
35 return (new_packet_ >= packet);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000036 }
37
38 private:
ossua73f6c92016-10-24 08:25:28 -070039 const Packet& new_packet_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000040};
41
henrik.lundin067d8552016-09-01 23:19:05 -070042// Returns true if both payload types are known to the decoder database, and
43// have the same sample rate.
44bool EqualSampleRates(uint8_t pt1,
45 uint8_t pt2,
46 const DecoderDatabase& decoder_database) {
kjellander7c856582017-02-26 19:53:40 -080047 auto* di1 = decoder_database.GetDecoderInfo(pt1);
48 auto* di2 = decoder_database.GetDecoderInfo(pt2);
henrik.lundin067d8552016-09-01 23:19:05 -070049 return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
50}
51} // namespace
52
henrik.lundin84f8cd62016-04-26 07:45:16 -070053PacketBuffer::PacketBuffer(size_t max_number_of_packets,
54 const TickTimer* tick_timer)
55 : max_number_of_packets_(max_number_of_packets), tick_timer_(tick_timer) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000056
57// Destructor. All packets in the buffer will be destroyed.
58PacketBuffer::~PacketBuffer() {
59 Flush();
60}
61
62// Flush the buffer. All packets in the buffer will be destroyed.
63void PacketBuffer::Flush() {
ossua73f6c92016-10-24 08:25:28 -070064 buffer_.clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000065}
66
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020067bool PacketBuffer::Empty() const {
68 return buffer_.empty();
69}
70
minyue-webrtc12d30842017-07-19 11:44:06 +020071int PacketBuffer::InsertPacket(Packet&& packet, StatisticsCalculator* stats) {
ossua73f6c92016-10-24 08:25:28 -070072 if (packet.empty()) {
Henrik Lundind67a2192015-08-03 12:54:37 +020073 LOG(LS_WARNING) << "InsertPacket invalid packet";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000074 return kInvalidPacket;
75 }
76
ossua73f6c92016-10-24 08:25:28 -070077 RTC_DCHECK_GE(packet.priority.codec_level, 0);
78 RTC_DCHECK_GE(packet.priority.red_level, 0);
ossua70695a2016-09-22 02:06:28 -070079
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000080 int return_val = kOK;
81
ossua73f6c92016-10-24 08:25:28 -070082 packet.waiting_time = tick_timer_->GetNewStopwatch();
henrik.lundin84f8cd62016-04-26 07:45:16 -070083
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000084 if (buffer_.size() >= max_number_of_packets_) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000085 // Buffer is full. Flush it.
86 Flush();
Henrik Lundind67a2192015-08-03 12:54:37 +020087 LOG(LS_WARNING) << "Packet buffer flushed";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000088 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000089 }
90
91 // Get an iterator pointing to the place in the buffer where the new packet
92 // should be inserted. The list is searched from the back, since the most
93 // likely case is that the new packet should be near the end of the list.
94 PacketList::reverse_iterator rit = std::find_if(
95 buffer_.rbegin(), buffer_.rend(),
96 NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +000097
98 // The new packet is to be inserted to the right of |rit|. If it has the same
99 // timestamp as |rit|, which has a higher priority, do not insert the new
100 // packet to list.
ossua73f6c92016-10-24 08:25:28 -0700101 if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
minyue-webrtc12d30842017-07-19 11:44:06 +0200102 RTC_CHECK(stats);
103 stats->PacketsDiscarded(1);
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000104 return return_val;
105 }
106
107 // The new packet is to be inserted to the left of |it|. If it has the same
108 // timestamp as |it|, which has a lower priority, replace |it| with the new
109 // packet.
110 PacketList::iterator it = rit.base();
ossua73f6c92016-10-24 08:25:28 -0700111 if (it != buffer_.end() && packet.timestamp == it->timestamp) {
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000112 it = buffer_.erase(it);
minyue-webrtc12d30842017-07-19 11:44:06 +0200113 RTC_CHECK(stats);
114 stats->PacketsDiscarded(1);
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000115 }
ossua73f6c92016-10-24 08:25:28 -0700116 buffer_.insert(it, std::move(packet)); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000117
118 return return_val;
119}
120
henrik.lundinda8bbf62016-08-31 03:14:11 -0700121int PacketBuffer::InsertPacketList(
122 PacketList* packet_list,
123 const DecoderDatabase& decoder_database,
124 rtc::Optional<uint8_t>* current_rtp_payload_type,
minyue-webrtc12d30842017-07-19 11:44:06 +0200125 rtc::Optional<uint8_t>* current_cng_rtp_payload_type,
126 StatisticsCalculator* stats) {
127 RTC_DCHECK(stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000128 bool flushed = false;
ossua73f6c92016-10-24 08:25:28 -0700129 for (auto& packet : *packet_list) {
130 if (decoder_database.IsComfortNoise(packet.payload_type)) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700131 if (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700132 **current_cng_rtp_payload_type != packet.payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000133 // New CNG payload type implies new codec type.
henrik.lundinda8bbf62016-08-31 03:14:11 -0700134 *current_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000135 Flush();
136 flushed = true;
137 }
henrik.lundinda8bbf62016-08-31 03:14:11 -0700138 *current_cng_rtp_payload_type =
ossua73f6c92016-10-24 08:25:28 -0700139 rtc::Optional<uint8_t>(packet.payload_type);
140 } else if (!decoder_database.IsDtmf(packet.payload_type)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000141 // This must be speech.
henrik.lundin067d8552016-09-01 23:19:05 -0700142 if ((*current_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700143 **current_rtp_payload_type != packet.payload_type) ||
henrik.lundin067d8552016-09-01 23:19:05 -0700144 (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700145 !EqualSampleRates(packet.payload_type,
henrik.lundin067d8552016-09-01 23:19:05 -0700146 **current_cng_rtp_payload_type,
147 decoder_database))) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700148 *current_cng_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000149 Flush();
150 flushed = true;
151 }
ossua73f6c92016-10-24 08:25:28 -0700152 *current_rtp_payload_type = rtc::Optional<uint8_t>(packet.payload_type);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000153 }
minyue-webrtc12d30842017-07-19 11:44:06 +0200154 int return_val = InsertPacket(std::move(packet), stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000155 if (return_val == kFlushed) {
156 // The buffer flushed, but this is not an error. We can still continue.
157 flushed = true;
158 } else if (return_val != kOK) {
159 // An error occurred. Delete remaining packets in list and return.
ossua73f6c92016-10-24 08:25:28 -0700160 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000161 return return_val;
162 }
163 }
ossua73f6c92016-10-24 08:25:28 -0700164 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000165 return flushed ? kFlushed : kOK;
166}
167
168int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
169 if (Empty()) {
170 return kBufferEmpty;
171 }
172 if (!next_timestamp) {
173 return kInvalidPointer;
174 }
ossua73f6c92016-10-24 08:25:28 -0700175 *next_timestamp = buffer_.front().timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000176 return kOK;
177}
178
179int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
180 uint32_t* next_timestamp) const {
181 if (Empty()) {
182 return kBufferEmpty;
183 }
184 if (!next_timestamp) {
185 return kInvalidPointer;
186 }
187 PacketList::const_iterator it;
188 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
ossua73f6c92016-10-24 08:25:28 -0700189 if (it->timestamp >= timestamp) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000190 // Found a packet matching the search.
ossua73f6c92016-10-24 08:25:28 -0700191 *next_timestamp = it->timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000192 return kOK;
193 }
194 }
195 return kNotFound;
196}
197
ossu7a377612016-10-18 04:06:13 -0700198const Packet* PacketBuffer::PeekNextPacket() const {
ossua73f6c92016-10-24 08:25:28 -0700199 return buffer_.empty() ? nullptr : &buffer_.front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000200}
201
ossua73f6c92016-10-24 08:25:28 -0700202rtc::Optional<Packet> PacketBuffer::GetNextPacket() {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000203 if (Empty()) {
204 // Buffer is empty.
ossua73f6c92016-10-24 08:25:28 -0700205 return rtc::Optional<Packet>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000206 }
207
ossua73f6c92016-10-24 08:25:28 -0700208 rtc::Optional<Packet> packet(std::move(buffer_.front()));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000209 // Assert that the packet sanity checks in InsertPacket method works.
ossua73f6c92016-10-24 08:25:28 -0700210 RTC_DCHECK(!packet->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000211 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000212
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000213 return packet;
214}
215
minyue-webrtcfae474c2017-07-05 11:17:40 +0200216int PacketBuffer::DiscardNextPacket(StatisticsCalculator* stats) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000217 if (Empty()) {
218 return kBufferEmpty;
219 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000220 // Assert that the packet sanity checks in InsertPacket method works.
ossua73f6c92016-10-24 08:25:28 -0700221 RTC_DCHECK(!buffer_.front().empty());
222 buffer_.pop_front();
minyue-webrtc12d30842017-07-19 11:44:06 +0200223 RTC_CHECK(stats);
minyue-webrtcfae474c2017-07-05 11:17:40 +0200224 stats->PacketsDiscarded(1);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000225 return kOK;
226}
227
minyue-webrtcfae474c2017-07-05 11:17:40 +0200228void PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
229 uint32_t horizon_samples,
230 StatisticsCalculator* stats) {
henrik.lundin63d146b2017-07-05 07:03:34 -0700231 const size_t old_size = buffer_.size();
232 buffer_.remove_if([timestamp_limit, horizon_samples](const Packet& p) {
233 return timestamp_limit != p.timestamp &&
234 IsObsoleteTimestamp(p.timestamp, timestamp_limit, horizon_samples);
235 });
236 if (old_size > buffer_.size()) {
minyue-webrtc12d30842017-07-19 11:44:06 +0200237 RTC_CHECK(stats);
henrik.lundin63d146b2017-07-05 07:03:34 -0700238 stats->PacketsDiscarded(old_size - buffer_.size());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000239 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000240}
241
minyue-webrtcfae474c2017-07-05 11:17:40 +0200242void PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit,
243 StatisticsCalculator* stats) {
244 DiscardOldPackets(timestamp_limit, 0, stats);
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200245}
246
minyue-webrtcfae474c2017-07-05 11:17:40 +0200247void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type,
248 StatisticsCalculator* stats) {
249 int packets_discarded = 0;
ossu61a208b2016-09-20 01:38:00 -0700250 for (auto it = buffer_.begin(); it != buffer_.end(); /* */) {
ossua73f6c92016-10-24 08:25:28 -0700251 const Packet& packet = *it;
252 if (packet.payload_type == payload_type) {
ossu61a208b2016-09-20 01:38:00 -0700253 it = buffer_.erase(it);
minyue-webrtcfae474c2017-07-05 11:17:40 +0200254 ++packets_discarded;
ossu61a208b2016-09-20 01:38:00 -0700255 } else {
256 ++it;
257 }
258 }
minyue-webrtc12d30842017-07-19 11:44:06 +0200259 if (packets_discarded > 0) {
260 RTC_CHECK(stats);
minyue-webrtcfae474c2017-07-05 11:17:40 +0200261 stats->PacketsDiscarded(packets_discarded);
minyue-webrtc12d30842017-07-19 11:44:06 +0200262 }
ossu61a208b2016-09-20 01:38:00 -0700263}
264
Peter Kastingdce40cf2015-08-24 14:52:23 -0700265size_t PacketBuffer::NumPacketsInBuffer() const {
266 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200267}
268
ossu61a208b2016-09-20 01:38:00 -0700269size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700270 size_t num_samples = 0;
271 size_t last_duration = last_decoded_length;
ossua73f6c92016-10-24 08:25:28 -0700272 for (const Packet& packet : buffer_) {
273 if (packet.frame) {
ossua70695a2016-09-22 02:06:28 -0700274 // TODO(hlundin): Verify that it's fine to count all packets and remove
275 // this check.
ossua73f6c92016-10-24 08:25:28 -0700276 if (packet.priority != Packet::Priority(0, 0)) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000277 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000278 }
ossua73f6c92016-10-24 08:25:28 -0700279 size_t duration = packet.frame->Duration();
ossu61a208b2016-09-20 01:38:00 -0700280 if (duration > 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000281 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000282 }
283 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000284 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000285 }
286 return num_samples;
287}
288
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000289void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000290 *num_packets = static_cast<int>(buffer_.size());
291 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000292}
293
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000294} // namespace webrtc