blob: 61cc9575d8f2fb7a55edf47ecd9d41a0db092d51 [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 {
25
26// 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.lundin84f8cd62016-04-26 07:45:16 -070041PacketBuffer::PacketBuffer(size_t max_number_of_packets,
42 const TickTimer* tick_timer)
43 : max_number_of_packets_(max_number_of_packets), tick_timer_(tick_timer) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000044
45// Destructor. All packets in the buffer will be destroyed.
46PacketBuffer::~PacketBuffer() {
47 Flush();
48}
49
50// Flush the buffer. All packets in the buffer will be destroyed.
51void PacketBuffer::Flush() {
52 DeleteAllPackets(&buffer_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000053}
54
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020055bool PacketBuffer::Empty() const {
56 return buffer_.empty();
57}
58
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000059int PacketBuffer::InsertPacket(Packet* packet) {
60 if (!packet || !packet->payload) {
61 if (packet) {
62 delete packet;
63 }
Henrik Lundind67a2192015-08-03 12:54:37 +020064 LOG(LS_WARNING) << "InsertPacket invalid packet";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000065 return kInvalidPacket;
66 }
67
68 int return_val = kOK;
69
henrik.lundin84f8cd62016-04-26 07:45:16 -070070 packet->waiting_time = tick_timer_->GetNewStopwatch();
71
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000072 if (buffer_.size() >= max_number_of_packets_) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000073 // Buffer is full. Flush it.
74 Flush();
Henrik Lundind67a2192015-08-03 12:54:37 +020075 LOG(LS_WARNING) << "Packet buffer flushed";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000076 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000077 }
78
79 // Get an iterator pointing to the place in the buffer where the new packet
80 // should be inserted. The list is searched from the back, since the most
81 // likely case is that the new packet should be near the end of the list.
82 PacketList::reverse_iterator rit = std::find_if(
83 buffer_.rbegin(), buffer_.rend(),
84 NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +000085
86 // The new packet is to be inserted to the right of |rit|. If it has the same
87 // timestamp as |rit|, which has a higher priority, do not insert the new
88 // packet to list.
89 if (rit != buffer_.rend() &&
90 packet->header.timestamp == (*rit)->header.timestamp) {
91 delete [] packet->payload;
92 delete packet;
93 return return_val;
94 }
95
96 // The new packet is to be inserted to the left of |it|. If it has the same
97 // timestamp as |it|, which has a lower priority, replace |it| with the new
98 // packet.
99 PacketList::iterator it = rit.base();
100 if (it != buffer_.end() &&
101 packet->header.timestamp == (*it)->header.timestamp) {
102 delete [] (*it)->payload;
103 delete *it;
104 it = buffer_.erase(it);
105 }
106 buffer_.insert(it, packet); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000107
108 return return_val;
109}
110
henrik.lundinda8bbf62016-08-31 03:14:11 -0700111int PacketBuffer::InsertPacketList(
112 PacketList* packet_list,
113 const DecoderDatabase& decoder_database,
114 rtc::Optional<uint8_t>* current_rtp_payload_type,
115 rtc::Optional<uint8_t>* current_cng_rtp_payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000116 bool flushed = false;
117 while (!packet_list->empty()) {
118 Packet* packet = packet_list->front();
119 if (decoder_database.IsComfortNoise(packet->header.payloadType)) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700120 if (*current_cng_rtp_payload_type &&
121 **current_cng_rtp_payload_type != packet->header.payloadType) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000122 // New CNG payload type implies new codec type.
henrik.lundinda8bbf62016-08-31 03:14:11 -0700123 *current_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000124 Flush();
125 flushed = true;
126 }
henrik.lundinda8bbf62016-08-31 03:14:11 -0700127 *current_cng_rtp_payload_type =
128 rtc::Optional<uint8_t>(packet->header.payloadType);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000129 } else if (!decoder_database.IsDtmf(packet->header.payloadType)) {
130 // This must be speech.
henrik.lundinda8bbf62016-08-31 03:14:11 -0700131 if (*current_rtp_payload_type &&
132 **current_rtp_payload_type != packet->header.payloadType) {
133 *current_cng_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_rtp_payload_type =
138 rtc::Optional<uint8_t>(packet->header.payloadType);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000139 }
140 int return_val = InsertPacket(packet);
141 packet_list->pop_front();
142 if (return_val == kFlushed) {
143 // The buffer flushed, but this is not an error. We can still continue.
144 flushed = true;
145 } else if (return_val != kOK) {
146 // An error occurred. Delete remaining packets in list and return.
147 DeleteAllPackets(packet_list);
148 return return_val;
149 }
150 }
151 return flushed ? kFlushed : kOK;
152}
153
154int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
155 if (Empty()) {
156 return kBufferEmpty;
157 }
158 if (!next_timestamp) {
159 return kInvalidPointer;
160 }
161 *next_timestamp = buffer_.front()->header.timestamp;
162 return kOK;
163}
164
165int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
166 uint32_t* next_timestamp) const {
167 if (Empty()) {
168 return kBufferEmpty;
169 }
170 if (!next_timestamp) {
171 return kInvalidPointer;
172 }
173 PacketList::const_iterator it;
174 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
175 if ((*it)->header.timestamp >= timestamp) {
176 // Found a packet matching the search.
177 *next_timestamp = (*it)->header.timestamp;
178 return kOK;
179 }
180 }
181 return kNotFound;
182}
183
184const RTPHeader* PacketBuffer::NextRtpHeader() const {
185 if (Empty()) {
186 return NULL;
187 }
188 return const_cast<const RTPHeader*>(&(buffer_.front()->header));
189}
190
Peter Kastingdce40cf2015-08-24 14:52:23 -0700191Packet* PacketBuffer::GetNextPacket(size_t* discard_count) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000192 if (Empty()) {
193 // Buffer is empty.
194 return NULL;
195 }
196
197 Packet* packet = buffer_.front();
198 // Assert that the packet sanity checks in InsertPacket method works.
199 assert(packet && packet->payload);
200 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000201
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000202 // Discard other packets with the same timestamp. These are duplicates or
203 // redundant payloads that should not be used.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700204 size_t discards = 0;
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000205
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000206 while (!Empty() &&
207 buffer_.front()->header.timestamp == packet->header.timestamp) {
208 if (DiscardNextPacket() != kOK) {
209 assert(false); // Must be ok by design.
210 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000211 ++discards;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000212 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000213 // The way of inserting packet should not cause any packet discarding here.
214 // TODO(minyue): remove |discard_count|.
215 assert(discards == 0);
216 if (discard_count)
217 *discard_count = discards;
218
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000219 return packet;
220}
221
222int PacketBuffer::DiscardNextPacket() {
223 if (Empty()) {
224 return kBufferEmpty;
225 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000226 // Assert that the packet sanity checks in InsertPacket method works.
henrik.lundin@webrtc.org12a34242014-04-28 08:36:35 +0000227 assert(buffer_.front());
228 assert(buffer_.front()->payload);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000229 DeleteFirstPacket(&buffer_);
230 return kOK;
231}
232
henrik.lundin@webrtc.org52b42cb2014-11-04 14:03:58 +0000233int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
234 uint32_t horizon_samples) {
235 while (!Empty() && timestamp_limit != buffer_.front()->header.timestamp &&
236 IsObsoleteTimestamp(buffer_.front()->header.timestamp,
237 timestamp_limit,
238 horizon_samples)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000239 if (DiscardNextPacket() != kOK) {
240 assert(false); // Must be ok by design.
241 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000242 }
243 return 0;
244}
245
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200246int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
247 return DiscardOldPackets(timestamp_limit, 0);
248}
249
Peter Kastingdce40cf2015-08-24 14:52:23 -0700250size_t PacketBuffer::NumPacketsInBuffer() const {
251 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200252}
253
Peter Kastingdce40cf2015-08-24 14:52:23 -0700254size_t PacketBuffer::NumSamplesInBuffer(DecoderDatabase* decoder_database,
255 size_t last_decoded_length) const {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000256 PacketList::const_iterator it;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700257 size_t num_samples = 0;
258 size_t last_duration = last_decoded_length;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000259 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
260 Packet* packet = (*it);
261 AudioDecoder* decoder =
262 decoder_database->GetDecoder(packet->header.payloadType);
Peter Kasting728d9032015-06-11 14:31:38 -0700263 if (decoder && !packet->sync_packet) {
264 if (!packet->primary) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000265 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000266 }
Peter Kasting728d9032015-06-11 14:31:38 -0700267 int duration =
pkastingb297c5a2015-07-22 15:17:22 -0700268 decoder->PacketDuration(packet->payload, packet->payload_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000269 if (duration >= 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000270 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000271 }
272 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000273 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000274 }
275 return num_samples;
276}
277
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000278bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
279 if (packet_list->empty()) {
280 return false;
281 }
282 Packet* first_packet = packet_list->front();
283 delete [] first_packet->payload;
284 delete first_packet;
285 packet_list->pop_front();
286 return true;
287}
288
289void PacketBuffer::DeleteAllPackets(PacketList* packet_list) {
290 while (DeleteFirstPacket(packet_list)) {
291 // Continue while the list is not empty.
292 }
293}
294
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000295void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000296 *num_packets = static_cast<int>(buffer_.size());
297 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000298}
299
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000300} // namespace webrtc