blob: c5b23dce068c3df75b816579b2964500fd828b7d [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
79 int return_val = kOK;
80
henrik.lundin84f8cd62016-04-26 07:45:16 -070081 packet->waiting_time = tick_timer_->GetNewStopwatch();
82
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000083 if (buffer_.size() >= max_number_of_packets_) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000084 // Buffer is full. Flush it.
85 Flush();
Henrik Lundind67a2192015-08-03 12:54:37 +020086 LOG(LS_WARNING) << "Packet buffer flushed";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000087 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000088 }
89
90 // Get an iterator pointing to the place in the buffer where the new packet
91 // should be inserted. The list is searched from the back, since the most
92 // likely case is that the new packet should be near the end of the list.
93 PacketList::reverse_iterator rit = std::find_if(
94 buffer_.rbegin(), buffer_.rend(),
95 NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +000096
97 // The new packet is to be inserted to the right of |rit|. If it has the same
98 // timestamp as |rit|, which has a higher priority, do not insert the new
99 // packet to list.
100 if (rit != buffer_.rend() &&
101 packet->header.timestamp == (*rit)->header.timestamp) {
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000102 delete packet;
103 return return_val;
104 }
105
106 // The new packet is to be inserted to the left of |it|. If it has the same
107 // timestamp as |it|, which has a lower priority, replace |it| with the new
108 // packet.
109 PacketList::iterator it = rit.base();
110 if (it != buffer_.end() &&
111 packet->header.timestamp == (*it)->header.timestamp) {
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000112 delete *it;
113 it = buffer_.erase(it);
114 }
115 buffer_.insert(it, packet); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000116
117 return return_val;
118}
119
henrik.lundinda8bbf62016-08-31 03:14:11 -0700120int PacketBuffer::InsertPacketList(
121 PacketList* packet_list,
122 const DecoderDatabase& decoder_database,
123 rtc::Optional<uint8_t>* current_rtp_payload_type,
124 rtc::Optional<uint8_t>* current_cng_rtp_payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000125 bool flushed = false;
126 while (!packet_list->empty()) {
127 Packet* packet = packet_list->front();
128 if (decoder_database.IsComfortNoise(packet->header.payloadType)) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700129 if (*current_cng_rtp_payload_type &&
130 **current_cng_rtp_payload_type != packet->header.payloadType) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000131 // New CNG payload type implies new codec type.
henrik.lundinda8bbf62016-08-31 03:14:11 -0700132 *current_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000133 Flush();
134 flushed = true;
135 }
henrik.lundinda8bbf62016-08-31 03:14:11 -0700136 *current_cng_rtp_payload_type =
137 rtc::Optional<uint8_t>(packet->header.payloadType);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000138 } else if (!decoder_database.IsDtmf(packet->header.payloadType)) {
139 // This must be speech.
henrik.lundin067d8552016-09-01 23:19:05 -0700140 if ((*current_rtp_payload_type &&
141 **current_rtp_payload_type != packet->header.payloadType) ||
142 (*current_cng_rtp_payload_type &&
143 !EqualSampleRates(packet->header.payloadType,
144 **current_cng_rtp_payload_type,
145 decoder_database))) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700146 *current_cng_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000147 Flush();
148 flushed = true;
149 }
henrik.lundinda8bbf62016-08-31 03:14:11 -0700150 *current_rtp_payload_type =
151 rtc::Optional<uint8_t>(packet->header.payloadType);
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 }
174 *next_timestamp = buffer_.front()->header.timestamp;
175 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) {
188 if ((*it)->header.timestamp >= timestamp) {
189 // Found a packet matching the search.
190 *next_timestamp = (*it)->header.timestamp;
191 return kOK;
192 }
193 }
194 return kNotFound;
195}
196
197const RTPHeader* PacketBuffer::NextRtpHeader() const {
198 if (Empty()) {
199 return NULL;
200 }
201 return const_cast<const RTPHeader*>(&(buffer_.front()->header));
202}
203
Peter Kastingdce40cf2015-08-24 14:52:23 -0700204Packet* PacketBuffer::GetNextPacket(size_t* discard_count) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000205 if (Empty()) {
206 // Buffer is empty.
207 return NULL;
208 }
209
210 Packet* packet = buffer_.front();
211 // Assert that the packet sanity checks in InsertPacket method works.
ossu61a208b2016-09-20 01:38:00 -0700212 RTC_DCHECK(packet && !packet->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000213 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000214
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000215 // Discard other packets with the same timestamp. These are duplicates or
216 // redundant payloads that should not be used.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700217 size_t discards = 0;
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000218
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000219 while (!Empty() &&
220 buffer_.front()->header.timestamp == packet->header.timestamp) {
221 if (DiscardNextPacket() != kOK) {
222 assert(false); // Must be ok by design.
223 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000224 ++discards;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000225 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000226 // The way of inserting packet should not cause any packet discarding here.
227 // TODO(minyue): remove |discard_count|.
228 assert(discards == 0);
229 if (discard_count)
230 *discard_count = discards;
231
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000232 return packet;
233}
234
235int PacketBuffer::DiscardNextPacket() {
236 if (Empty()) {
237 return kBufferEmpty;
238 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000239 // Assert that the packet sanity checks in InsertPacket method works.
ossu61a208b2016-09-20 01:38:00 -0700240 RTC_DCHECK(buffer_.front());
241 RTC_DCHECK(!buffer_.front()->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000242 DeleteFirstPacket(&buffer_);
243 return kOK;
244}
245
henrik.lundin@webrtc.org52b42cb2014-11-04 14:03:58 +0000246int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
247 uint32_t horizon_samples) {
248 while (!Empty() && timestamp_limit != buffer_.front()->header.timestamp &&
249 IsObsoleteTimestamp(buffer_.front()->header.timestamp,
250 timestamp_limit,
251 horizon_samples)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000252 if (DiscardNextPacket() != kOK) {
253 assert(false); // Must be ok by design.
254 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000255 }
256 return 0;
257}
258
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200259int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
260 return DiscardOldPackets(timestamp_limit, 0);
261}
262
ossu61a208b2016-09-20 01:38:00 -0700263void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) {
264 for (auto it = buffer_.begin(); it != buffer_.end(); /* */) {
265 Packet *packet = *it;
266 if (packet->header.payloadType == payload_type) {
267 delete packet;
268 it = buffer_.erase(it);
269 } else {
270 ++it;
271 }
272 }
273}
274
Peter Kastingdce40cf2015-08-24 14:52:23 -0700275size_t PacketBuffer::NumPacketsInBuffer() const {
276 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200277}
278
ossu61a208b2016-09-20 01:38:00 -0700279size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700280 size_t num_samples = 0;
281 size_t last_duration = last_decoded_length;
ossu61a208b2016-09-20 01:38:00 -0700282 for (Packet* packet : buffer_) {
283 if (packet->frame) {
Peter Kasting728d9032015-06-11 14:31:38 -0700284 if (!packet->primary) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000285 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000286 }
ossu61a208b2016-09-20 01:38:00 -0700287 size_t duration = packet->frame->Duration();
288 if (duration > 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000289 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000290 }
291 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000292 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000293 }
294 return num_samples;
295}
296
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000297bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
298 if (packet_list->empty()) {
299 return false;
300 }
301 Packet* first_packet = packet_list->front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000302 delete first_packet;
303 packet_list->pop_front();
304 return true;
305}
306
307void PacketBuffer::DeleteAllPackets(PacketList* packet_list) {
308 while (DeleteFirstPacket(packet_list)) {
309 // Continue while the list is not empty.
310 }
311}
312
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000313void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000314 *num_packets = static_cast<int>(buffer_.size());
315 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000316}
317
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000318} // namespace webrtc