blob: eeb1d272b990d987ea3cf541024990024d5dce0c [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.
103 if (rit != buffer_.rend() &&
104 packet->header.timestamp == (*rit)->header.timestamp) {
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000105 delete packet;
106 return return_val;
107 }
108
109 // The new packet is to be inserted to the left of |it|. If it has the same
110 // timestamp as |it|, which has a lower priority, replace |it| with the new
111 // packet.
112 PacketList::iterator it = rit.base();
113 if (it != buffer_.end() &&
114 packet->header.timestamp == (*it)->header.timestamp) {
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000115 delete *it;
116 it = buffer_.erase(it);
117 }
118 buffer_.insert(it, packet); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000119
120 return return_val;
121}
122
henrik.lundinda8bbf62016-08-31 03:14:11 -0700123int PacketBuffer::InsertPacketList(
124 PacketList* packet_list,
125 const DecoderDatabase& decoder_database,
126 rtc::Optional<uint8_t>* current_rtp_payload_type,
127 rtc::Optional<uint8_t>* current_cng_rtp_payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000128 bool flushed = false;
129 while (!packet_list->empty()) {
130 Packet* packet = packet_list->front();
131 if (decoder_database.IsComfortNoise(packet->header.payloadType)) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700132 if (*current_cng_rtp_payload_type &&
133 **current_cng_rtp_payload_type != packet->header.payloadType) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000134 // New CNG payload type implies new codec type.
henrik.lundinda8bbf62016-08-31 03:14:11 -0700135 *current_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000136 Flush();
137 flushed = true;
138 }
henrik.lundinda8bbf62016-08-31 03:14:11 -0700139 *current_cng_rtp_payload_type =
140 rtc::Optional<uint8_t>(packet->header.payloadType);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000141 } else if (!decoder_database.IsDtmf(packet->header.payloadType)) {
142 // This must be speech.
henrik.lundin067d8552016-09-01 23:19:05 -0700143 if ((*current_rtp_payload_type &&
144 **current_rtp_payload_type != packet->header.payloadType) ||
145 (*current_cng_rtp_payload_type &&
146 !EqualSampleRates(packet->header.payloadType,
147 **current_cng_rtp_payload_type,
148 decoder_database))) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700149 *current_cng_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000150 Flush();
151 flushed = true;
152 }
henrik.lundinda8bbf62016-08-31 03:14:11 -0700153 *current_rtp_payload_type =
154 rtc::Optional<uint8_t>(packet->header.payloadType);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000155 }
156 int return_val = InsertPacket(packet);
157 packet_list->pop_front();
158 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.
163 DeleteAllPackets(packet_list);
164 return return_val;
165 }
166 }
167 return flushed ? kFlushed : kOK;
168}
169
170int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
171 if (Empty()) {
172 return kBufferEmpty;
173 }
174 if (!next_timestamp) {
175 return kInvalidPointer;
176 }
177 *next_timestamp = buffer_.front()->header.timestamp;
178 return kOK;
179}
180
181int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
182 uint32_t* next_timestamp) const {
183 if (Empty()) {
184 return kBufferEmpty;
185 }
186 if (!next_timestamp) {
187 return kInvalidPointer;
188 }
189 PacketList::const_iterator it;
190 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
191 if ((*it)->header.timestamp >= timestamp) {
192 // Found a packet matching the search.
193 *next_timestamp = (*it)->header.timestamp;
194 return kOK;
195 }
196 }
197 return kNotFound;
198}
199
200const RTPHeader* PacketBuffer::NextRtpHeader() const {
201 if (Empty()) {
202 return NULL;
203 }
204 return const_cast<const RTPHeader*>(&(buffer_.front()->header));
205}
206
Peter Kastingdce40cf2015-08-24 14:52:23 -0700207Packet* PacketBuffer::GetNextPacket(size_t* discard_count) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000208 if (Empty()) {
209 // Buffer is empty.
210 return NULL;
211 }
212
213 Packet* packet = buffer_.front();
214 // Assert that the packet sanity checks in InsertPacket method works.
ossu61a208b2016-09-20 01:38:00 -0700215 RTC_DCHECK(packet && !packet->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000216 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000217
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000218 // Discard other packets with the same timestamp. These are duplicates or
219 // redundant payloads that should not be used.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700220 size_t discards = 0;
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000221
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000222 while (!Empty() &&
223 buffer_.front()->header.timestamp == packet->header.timestamp) {
224 if (DiscardNextPacket() != kOK) {
225 assert(false); // Must be ok by design.
226 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000227 ++discards;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000228 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000229 // The way of inserting packet should not cause any packet discarding here.
230 // TODO(minyue): remove |discard_count|.
231 assert(discards == 0);
232 if (discard_count)
233 *discard_count = discards;
234
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000235 return packet;
236}
237
238int PacketBuffer::DiscardNextPacket() {
239 if (Empty()) {
240 return kBufferEmpty;
241 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000242 // Assert that the packet sanity checks in InsertPacket method works.
ossu61a208b2016-09-20 01:38:00 -0700243 RTC_DCHECK(buffer_.front());
244 RTC_DCHECK(!buffer_.front()->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000245 DeleteFirstPacket(&buffer_);
246 return kOK;
247}
248
henrik.lundin@webrtc.org52b42cb2014-11-04 14:03:58 +0000249int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
250 uint32_t horizon_samples) {
251 while (!Empty() && timestamp_limit != buffer_.front()->header.timestamp &&
252 IsObsoleteTimestamp(buffer_.front()->header.timestamp,
253 timestamp_limit,
254 horizon_samples)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000255 if (DiscardNextPacket() != kOK) {
256 assert(false); // Must be ok by design.
257 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000258 }
259 return 0;
260}
261
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200262int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
263 return DiscardOldPackets(timestamp_limit, 0);
264}
265
ossu61a208b2016-09-20 01:38:00 -0700266void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) {
267 for (auto it = buffer_.begin(); it != buffer_.end(); /* */) {
ossua70695a2016-09-22 02:06:28 -0700268 Packet* packet = *it;
ossu61a208b2016-09-20 01:38:00 -0700269 if (packet->header.payloadType == payload_type) {
270 delete packet;
271 it = buffer_.erase(it);
272 } else {
273 ++it;
274 }
275 }
276}
277
Peter Kastingdce40cf2015-08-24 14:52:23 -0700278size_t PacketBuffer::NumPacketsInBuffer() const {
279 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200280}
281
ossu61a208b2016-09-20 01:38:00 -0700282size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700283 size_t num_samples = 0;
284 size_t last_duration = last_decoded_length;
ossu61a208b2016-09-20 01:38:00 -0700285 for (Packet* packet : buffer_) {
286 if (packet->frame) {
ossua70695a2016-09-22 02:06:28 -0700287 // TODO(hlundin): Verify that it's fine to count all packets and remove
288 // this check.
289 if (packet->priority != Packet::Priority(0, 0)) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000290 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000291 }
ossu61a208b2016-09-20 01:38:00 -0700292 size_t duration = packet->frame->Duration();
293 if (duration > 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000294 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000295 }
296 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000297 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000298 }
299 return num_samples;
300}
301
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000302bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
303 if (packet_list->empty()) {
304 return false;
305 }
306 Packet* first_packet = packet_list->front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000307 delete first_packet;
308 packet_list->pop_front();
309 return true;
310}
311
312void PacketBuffer::DeleteAllPackets(PacketList* packet_list) {
313 while (DeleteFirstPacket(packet_list)) {
314 // Continue while the list is not empty.
315 }
316}
317
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000318void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000319 *num_packets = static_cast<int>(buffer_.size());
320 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000321}
322
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000323} // namespace webrtc