blob: 431e0f122c55f4fb6fd97ab51dc6751dd65e4a28 [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.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000022
23namespace webrtc {
24
25// Predicate used when inserting packets in the buffer list.
26// Operator() returns true when |packet| goes before |new_packet|.
27class NewTimestampIsLarger {
28 public:
29 explicit NewTimestampIsLarger(const Packet* new_packet)
30 : new_packet_(new_packet) {
31 }
32 bool operator()(Packet* packet) {
33 return (*new_packet_ >= *packet);
34 }
35
36 private:
37 const Packet* new_packet_;
38};
39
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000040PacketBuffer::PacketBuffer(size_t max_number_of_packets)
41 : max_number_of_packets_(max_number_of_packets) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000042
43// Destructor. All packets in the buffer will be destroyed.
44PacketBuffer::~PacketBuffer() {
45 Flush();
46}
47
48// Flush the buffer. All packets in the buffer will be destroyed.
49void PacketBuffer::Flush() {
50 DeleteAllPackets(&buffer_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000051}
52
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020053bool PacketBuffer::Empty() const {
54 return buffer_.empty();
55}
56
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000057int PacketBuffer::InsertPacket(Packet* packet) {
58 if (!packet || !packet->payload) {
59 if (packet) {
60 delete packet;
61 }
Henrik Lundind67a2192015-08-03 12:54:37 +020062 LOG(LS_WARNING) << "InsertPacket invalid packet";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000063 return kInvalidPacket;
64 }
65
66 int return_val = kOK;
67
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000068 if (buffer_.size() >= max_number_of_packets_) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000069 // Buffer is full. Flush it.
70 Flush();
Henrik Lundind67a2192015-08-03 12:54:37 +020071 LOG(LS_WARNING) << "Packet buffer flushed";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000072 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000073 }
74
75 // Get an iterator pointing to the place in the buffer where the new packet
76 // should be inserted. The list is searched from the back, since the most
77 // likely case is that the new packet should be near the end of the list.
78 PacketList::reverse_iterator rit = std::find_if(
79 buffer_.rbegin(), buffer_.rend(),
80 NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +000081
82 // The new packet is to be inserted to the right of |rit|. If it has the same
83 // timestamp as |rit|, which has a higher priority, do not insert the new
84 // packet to list.
85 if (rit != buffer_.rend() &&
86 packet->header.timestamp == (*rit)->header.timestamp) {
87 delete [] packet->payload;
88 delete packet;
89 return return_val;
90 }
91
92 // The new packet is to be inserted to the left of |it|. If it has the same
93 // timestamp as |it|, which has a lower priority, replace |it| with the new
94 // packet.
95 PacketList::iterator it = rit.base();
96 if (it != buffer_.end() &&
97 packet->header.timestamp == (*it)->header.timestamp) {
98 delete [] (*it)->payload;
99 delete *it;
100 it = buffer_.erase(it);
101 }
102 buffer_.insert(it, packet); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000103
104 return return_val;
105}
106
107int PacketBuffer::InsertPacketList(PacketList* packet_list,
108 const DecoderDatabase& decoder_database,
109 uint8_t* current_rtp_payload_type,
110 uint8_t* current_cng_rtp_payload_type) {
111 bool flushed = false;
112 while (!packet_list->empty()) {
113 Packet* packet = packet_list->front();
114 if (decoder_database.IsComfortNoise(packet->header.payloadType)) {
115 if (*current_cng_rtp_payload_type != 0xFF &&
116 *current_cng_rtp_payload_type != packet->header.payloadType) {
117 // New CNG payload type implies new codec type.
118 *current_rtp_payload_type = 0xFF;
119 Flush();
120 flushed = true;
121 }
122 *current_cng_rtp_payload_type = packet->header.payloadType;
123 } else if (!decoder_database.IsDtmf(packet->header.payloadType)) {
124 // This must be speech.
125 if (*current_rtp_payload_type != 0xFF &&
126 *current_rtp_payload_type != packet->header.payloadType) {
127 *current_cng_rtp_payload_type = 0xFF;
128 Flush();
129 flushed = true;
130 }
131 *current_rtp_payload_type = packet->header.payloadType;
132 }
133 int return_val = InsertPacket(packet);
134 packet_list->pop_front();
135 if (return_val == kFlushed) {
136 // The buffer flushed, but this is not an error. We can still continue.
137 flushed = true;
138 } else if (return_val != kOK) {
139 // An error occurred. Delete remaining packets in list and return.
140 DeleteAllPackets(packet_list);
141 return return_val;
142 }
143 }
144 return flushed ? kFlushed : kOK;
145}
146
147int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
148 if (Empty()) {
149 return kBufferEmpty;
150 }
151 if (!next_timestamp) {
152 return kInvalidPointer;
153 }
154 *next_timestamp = buffer_.front()->header.timestamp;
155 return kOK;
156}
157
158int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
159 uint32_t* next_timestamp) const {
160 if (Empty()) {
161 return kBufferEmpty;
162 }
163 if (!next_timestamp) {
164 return kInvalidPointer;
165 }
166 PacketList::const_iterator it;
167 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
168 if ((*it)->header.timestamp >= timestamp) {
169 // Found a packet matching the search.
170 *next_timestamp = (*it)->header.timestamp;
171 return kOK;
172 }
173 }
174 return kNotFound;
175}
176
177const RTPHeader* PacketBuffer::NextRtpHeader() const {
178 if (Empty()) {
179 return NULL;
180 }
181 return const_cast<const RTPHeader*>(&(buffer_.front()->header));
182}
183
184Packet* PacketBuffer::GetNextPacket(int* discard_count) {
185 if (Empty()) {
186 // Buffer is empty.
187 return NULL;
188 }
189
190 Packet* packet = buffer_.front();
191 // Assert that the packet sanity checks in InsertPacket method works.
192 assert(packet && packet->payload);
193 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000194
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000195 // Discard other packets with the same timestamp. These are duplicates or
196 // redundant payloads that should not be used.
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000197 int discards = 0;
198
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000199 while (!Empty() &&
200 buffer_.front()->header.timestamp == packet->header.timestamp) {
201 if (DiscardNextPacket() != kOK) {
202 assert(false); // Must be ok by design.
203 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000204 ++discards;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000205 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000206 // The way of inserting packet should not cause any packet discarding here.
207 // TODO(minyue): remove |discard_count|.
208 assert(discards == 0);
209 if (discard_count)
210 *discard_count = discards;
211
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000212 return packet;
213}
214
215int PacketBuffer::DiscardNextPacket() {
216 if (Empty()) {
217 return kBufferEmpty;
218 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000219 // Assert that the packet sanity checks in InsertPacket method works.
henrik.lundin@webrtc.org12a34242014-04-28 08:36:35 +0000220 assert(buffer_.front());
221 assert(buffer_.front()->payload);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000222 DeleteFirstPacket(&buffer_);
223 return kOK;
224}
225
henrik.lundin@webrtc.org52b42cb2014-11-04 14:03:58 +0000226int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
227 uint32_t horizon_samples) {
228 while (!Empty() && timestamp_limit != buffer_.front()->header.timestamp &&
229 IsObsoleteTimestamp(buffer_.front()->header.timestamp,
230 timestamp_limit,
231 horizon_samples)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000232 if (DiscardNextPacket() != kOK) {
233 assert(false); // Must be ok by design.
234 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000235 }
236 return 0;
237}
238
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200239int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
240 return DiscardOldPackets(timestamp_limit, 0);
241}
242
243int PacketBuffer::NumPacketsInBuffer() const {
244 return static_cast<int>(buffer_.size());
245}
246
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000247int PacketBuffer::NumSamplesInBuffer(DecoderDatabase* decoder_database,
248 int last_decoded_length) const {
249 PacketList::const_iterator it;
250 int num_samples = 0;
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000251 int last_duration = last_decoded_length;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000252 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
253 Packet* packet = (*it);
254 AudioDecoder* decoder =
255 decoder_database->GetDecoder(packet->header.payloadType);
Peter Kasting728d9032015-06-11 14:31:38 -0700256 if (decoder && !packet->sync_packet) {
257 if (!packet->primary) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000258 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000259 }
Peter Kasting728d9032015-06-11 14:31:38 -0700260 int duration =
pkastingb297c5a2015-07-22 15:17:22 -0700261 decoder->PacketDuration(packet->payload, packet->payload_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000262 if (duration >= 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000263 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000264 }
265 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000266 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000267 }
268 return num_samples;
269}
270
271void PacketBuffer::IncrementWaitingTimes(int inc) {
272 PacketList::iterator it;
273 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
274 (*it)->waiting_time += inc;
275 }
276}
277
278bool 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