blob: ee1439809b599688a7560ba1497bd513a3c986ec [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
Henrik Lundind67a2192015-08-03 12:54:37 +020019#include "webrtc/base/logging.h"
kwiberg@webrtc.orge04a93b2014-12-09 10:12:53 +000020#include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000021#include "webrtc/modules/audio_coding/neteq/decoder_database.h"
henrik.lundin84f8cd62016-04-26 07:45:16 -070022#include "webrtc/modules/audio_coding/neteq/tick_timer.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000023
24namespace webrtc {
henrik.lundin067d8552016-09-01 23:19:05 -070025namespace {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000026// Predicate used when inserting packets in the buffer list.
27// Operator() returns true when |packet| goes before |new_packet|.
28class NewTimestampIsLarger {
29 public:
30 explicit NewTimestampIsLarger(const Packet* new_packet)
31 : new_packet_(new_packet) {
32 }
33 bool operator()(Packet* packet) {
34 return (*new_packet_ >= *packet);
35 }
36
37 private:
38 const Packet* new_packet_;
39};
40
henrik.lundin067d8552016-09-01 23:19:05 -070041// Returns true if both payload types are known to the decoder database, and
42// have the same sample rate.
43bool EqualSampleRates(uint8_t pt1,
44 uint8_t pt2,
45 const DecoderDatabase& decoder_database) {
46 auto di1 = decoder_database.GetDecoderInfo(pt1);
47 auto di2 = decoder_database.GetDecoderInfo(pt2);
48 return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
49}
50} // namespace
51
henrik.lundin84f8cd62016-04-26 07:45:16 -070052PacketBuffer::PacketBuffer(size_t max_number_of_packets,
53 const TickTimer* tick_timer)
54 : max_number_of_packets_(max_number_of_packets), tick_timer_(tick_timer) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000055
56// Destructor. All packets in the buffer will be destroyed.
57PacketBuffer::~PacketBuffer() {
58 Flush();
59}
60
61// Flush the buffer. All packets in the buffer will be destroyed.
62void PacketBuffer::Flush() {
63 DeleteAllPackets(&buffer_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000064}
65
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020066bool PacketBuffer::Empty() const {
67 return buffer_.empty();
68}
69
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000070int PacketBuffer::InsertPacket(Packet* packet) {
ossu61a208b2016-09-20 01:38:00 -070071 if (!packet || packet->empty()) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000072 if (packet) {
73 delete packet;
74 }
Henrik Lundind67a2192015-08-03 12:54:37 +020075 LOG(LS_WARNING) << "InsertPacket invalid packet";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000076 return kInvalidPacket;
77 }
78
ossua70695a2016-09-22 02:06:28 -070079 RTC_DCHECK_GE(packet->priority.codec_level, 0);
80 RTC_DCHECK_GE(packet->priority.red_level, 0);
81
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000082 int return_val = kOK;
83
henrik.lundin84f8cd62016-04-26 07:45:16 -070084 packet->waiting_time = tick_timer_->GetNewStopwatch();
85
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000086 if (buffer_.size() >= max_number_of_packets_) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000087 // Buffer is full. Flush it.
88 Flush();
Henrik Lundind67a2192015-08-03 12:54:37 +020089 LOG(LS_WARNING) << "Packet buffer flushed";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000090 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000091 }
92
93 // Get an iterator pointing to the place in the buffer where the new packet
94 // should be inserted. The list is searched from the back, since the most
95 // likely case is that the new packet should be near the end of the list.
96 PacketList::reverse_iterator rit = std::find_if(
97 buffer_.rbegin(), buffer_.rend(),
98 NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +000099
100 // The new packet is to be inserted to the right of |rit|. If it has the same
101 // timestamp as |rit|, which has a higher priority, do not insert the new
102 // packet to list.
ossu7a377612016-10-18 04:06:13 -0700103 if (rit != buffer_.rend() && packet->timestamp == (*rit)->timestamp) {
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000104 delete packet;
105 return return_val;
106 }
107
108 // The new packet is to be inserted to the left of |it|. If it has the same
109 // timestamp as |it|, which has a lower priority, replace |it| with the new
110 // packet.
111 PacketList::iterator it = rit.base();
ossu7a377612016-10-18 04:06:13 -0700112 if (it != buffer_.end() && packet->timestamp == (*it)->timestamp) {
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000113 delete *it;
114 it = buffer_.erase(it);
115 }
116 buffer_.insert(it, 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,
125 rtc::Optional<uint8_t>* current_cng_rtp_payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000126 bool flushed = false;
127 while (!packet_list->empty()) {
128 Packet* packet = packet_list->front();
ossu7a377612016-10-18 04:06:13 -0700129 if (decoder_database.IsComfortNoise(packet->payload_type)) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700130 if (*current_cng_rtp_payload_type &&
ossu7a377612016-10-18 04:06:13 -0700131 **current_cng_rtp_payload_type != packet->payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000132 // New CNG payload type implies new codec type.
henrik.lundinda8bbf62016-08-31 03:14:11 -0700133 *current_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000134 Flush();
135 flushed = true;
136 }
henrik.lundinda8bbf62016-08-31 03:14:11 -0700137 *current_cng_rtp_payload_type =
ossu7a377612016-10-18 04:06:13 -0700138 rtc::Optional<uint8_t>(packet->payload_type);
139 } else if (!decoder_database.IsDtmf(packet->payload_type)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000140 // This must be speech.
henrik.lundin067d8552016-09-01 23:19:05 -0700141 if ((*current_rtp_payload_type &&
ossu7a377612016-10-18 04:06:13 -0700142 **current_rtp_payload_type != packet->payload_type) ||
henrik.lundin067d8552016-09-01 23:19:05 -0700143 (*current_cng_rtp_payload_type &&
ossu7a377612016-10-18 04:06:13 -0700144 !EqualSampleRates(packet->payload_type,
henrik.lundin067d8552016-09-01 23:19:05 -0700145 **current_cng_rtp_payload_type,
146 decoder_database))) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700147 *current_cng_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000148 Flush();
149 flushed = true;
150 }
ossu7a377612016-10-18 04:06:13 -0700151 *current_rtp_payload_type = rtc::Optional<uint8_t>(packet->payload_type);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000152 }
153 int return_val = InsertPacket(packet);
154 packet_list->pop_front();
155 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.
160 DeleteAllPackets(packet_list);
161 return return_val;
162 }
163 }
164 return flushed ? kFlushed : kOK;
165}
166
167int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
168 if (Empty()) {
169 return kBufferEmpty;
170 }
171 if (!next_timestamp) {
172 return kInvalidPointer;
173 }
ossu7a377612016-10-18 04:06:13 -0700174 *next_timestamp = buffer_.front()->timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000175 return kOK;
176}
177
178int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
179 uint32_t* next_timestamp) const {
180 if (Empty()) {
181 return kBufferEmpty;
182 }
183 if (!next_timestamp) {
184 return kInvalidPointer;
185 }
186 PacketList::const_iterator it;
187 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
ossu7a377612016-10-18 04:06:13 -0700188 if ((*it)->timestamp >= timestamp) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000189 // Found a packet matching the search.
ossu7a377612016-10-18 04:06:13 -0700190 *next_timestamp = (*it)->timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000191 return kOK;
192 }
193 }
194 return kNotFound;
195}
196
ossu7a377612016-10-18 04:06:13 -0700197const Packet* PacketBuffer::PeekNextPacket() const {
198 return buffer_.empty() ? nullptr : buffer_.front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000199}
200
Peter Kastingdce40cf2015-08-24 14:52:23 -0700201Packet* PacketBuffer::GetNextPacket(size_t* discard_count) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000202 if (Empty()) {
203 // Buffer is empty.
204 return NULL;
205 }
206
207 Packet* packet = buffer_.front();
208 // Assert that the packet sanity checks in InsertPacket method works.
ossu61a208b2016-09-20 01:38:00 -0700209 RTC_DCHECK(packet && !packet->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000210 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000211
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000212 // Discard other packets with the same timestamp. These are duplicates or
213 // redundant payloads that should not be used.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700214 size_t discards = 0;
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000215
ossu7a377612016-10-18 04:06:13 -0700216 while (!Empty() && buffer_.front()->timestamp == packet->timestamp) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000217 if (DiscardNextPacket() != kOK) {
218 assert(false); // Must be ok by design.
219 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000220 ++discards;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000221 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000222 // The way of inserting packet should not cause any packet discarding here.
223 // TODO(minyue): remove |discard_count|.
224 assert(discards == 0);
225 if (discard_count)
226 *discard_count = discards;
227
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000228 return packet;
229}
230
231int PacketBuffer::DiscardNextPacket() {
232 if (Empty()) {
233 return kBufferEmpty;
234 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000235 // Assert that the packet sanity checks in InsertPacket method works.
ossu61a208b2016-09-20 01:38:00 -0700236 RTC_DCHECK(buffer_.front());
237 RTC_DCHECK(!buffer_.front()->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000238 DeleteFirstPacket(&buffer_);
239 return kOK;
240}
241
henrik.lundin@webrtc.org52b42cb2014-11-04 14:03:58 +0000242int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
243 uint32_t horizon_samples) {
ossu7a377612016-10-18 04:06:13 -0700244 while (!Empty() && timestamp_limit != buffer_.front()->timestamp &&
245 IsObsoleteTimestamp(buffer_.front()->timestamp, timestamp_limit,
henrik.lundin@webrtc.org52b42cb2014-11-04 14:03:58 +0000246 horizon_samples)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000247 if (DiscardNextPacket() != kOK) {
248 assert(false); // Must be ok by design.
249 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000250 }
251 return 0;
252}
253
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200254int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
255 return DiscardOldPackets(timestamp_limit, 0);
256}
257
ossu61a208b2016-09-20 01:38:00 -0700258void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) {
259 for (auto it = buffer_.begin(); it != buffer_.end(); /* */) {
ossua70695a2016-09-22 02:06:28 -0700260 Packet* packet = *it;
ossu7a377612016-10-18 04:06:13 -0700261 if (packet->payload_type == payload_type) {
ossu61a208b2016-09-20 01:38:00 -0700262 delete packet;
263 it = buffer_.erase(it);
264 } else {
265 ++it;
266 }
267 }
268}
269
Peter Kastingdce40cf2015-08-24 14:52:23 -0700270size_t PacketBuffer::NumPacketsInBuffer() const {
271 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200272}
273
ossu61a208b2016-09-20 01:38:00 -0700274size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700275 size_t num_samples = 0;
276 size_t last_duration = last_decoded_length;
ossu61a208b2016-09-20 01:38:00 -0700277 for (Packet* packet : buffer_) {
278 if (packet->frame) {
ossua70695a2016-09-22 02:06:28 -0700279 // TODO(hlundin): Verify that it's fine to count all packets and remove
280 // this check.
281 if (packet->priority != Packet::Priority(0, 0)) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000282 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000283 }
ossu61a208b2016-09-20 01:38:00 -0700284 size_t duration = packet->frame->Duration();
285 if (duration > 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000286 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000287 }
288 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000289 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000290 }
291 return num_samples;
292}
293
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000294bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
295 if (packet_list->empty()) {
296 return false;
297 }
298 Packet* first_packet = packet_list->front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000299 delete first_packet;
300 packet_list->pop_front();
301 return true;
302}
303
304void PacketBuffer::DeleteAllPackets(PacketList* packet_list) {
305 while (DeleteFirstPacket(packet_list)) {
306 // Continue while the list is not empty.
307 }
308}
309
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000310void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000311 *num_packets = static_cast<int>(buffer_.size());
312 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000313}
314
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000315} // namespace webrtc