blob: 08b237f8463bc881f6db3b95bef62ced32a1c3db [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
kwiberg@webrtc.orge04a93b2014-12-09 10:12:53 +000019#include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000020#include "webrtc/modules/audio_coding/neteq/decoder_database.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000021
22namespace webrtc {
23
24// Predicate used when inserting packets in the buffer list.
25// Operator() returns true when |packet| goes before |new_packet|.
26class NewTimestampIsLarger {
27 public:
28 explicit NewTimestampIsLarger(const Packet* new_packet)
29 : new_packet_(new_packet) {
30 }
31 bool operator()(Packet* packet) {
32 return (*new_packet_ >= *packet);
33 }
34
35 private:
36 const Packet* new_packet_;
37};
38
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000039PacketBuffer::PacketBuffer(size_t max_number_of_packets)
40 : max_number_of_packets_(max_number_of_packets) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000041
42// Destructor. All packets in the buffer will be destroyed.
43PacketBuffer::~PacketBuffer() {
44 Flush();
45}
46
47// Flush the buffer. All packets in the buffer will be destroyed.
48void PacketBuffer::Flush() {
49 DeleteAllPackets(&buffer_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000050}
51
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020052bool PacketBuffer::Empty() const {
53 return buffer_.empty();
54}
55
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000056int PacketBuffer::InsertPacket(Packet* packet) {
57 if (!packet || !packet->payload) {
58 if (packet) {
59 delete packet;
60 }
61 return kInvalidPacket;
62 }
63
64 int return_val = kOK;
65
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000066 if (buffer_.size() >= max_number_of_packets_) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000067 // Buffer is full. Flush it.
68 Flush();
69 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000070 }
71
72 // Get an iterator pointing to the place in the buffer where the new packet
73 // should be inserted. The list is searched from the back, since the most
74 // likely case is that the new packet should be near the end of the list.
75 PacketList::reverse_iterator rit = std::find_if(
76 buffer_.rbegin(), buffer_.rend(),
77 NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +000078
79 // The new packet is to be inserted to the right of |rit|. If it has the same
80 // timestamp as |rit|, which has a higher priority, do not insert the new
81 // packet to list.
82 if (rit != buffer_.rend() &&
83 packet->header.timestamp == (*rit)->header.timestamp) {
84 delete [] packet->payload;
85 delete packet;
86 return return_val;
87 }
88
89 // The new packet is to be inserted to the left of |it|. If it has the same
90 // timestamp as |it|, which has a lower priority, replace |it| with the new
91 // packet.
92 PacketList::iterator it = rit.base();
93 if (it != buffer_.end() &&
94 packet->header.timestamp == (*it)->header.timestamp) {
95 delete [] (*it)->payload;
96 delete *it;
97 it = buffer_.erase(it);
98 }
99 buffer_.insert(it, packet); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000100
101 return return_val;
102}
103
104int PacketBuffer::InsertPacketList(PacketList* packet_list,
105 const DecoderDatabase& decoder_database,
106 uint8_t* current_rtp_payload_type,
107 uint8_t* current_cng_rtp_payload_type) {
108 bool flushed = false;
109 while (!packet_list->empty()) {
110 Packet* packet = packet_list->front();
111 if (decoder_database.IsComfortNoise(packet->header.payloadType)) {
112 if (*current_cng_rtp_payload_type != 0xFF &&
113 *current_cng_rtp_payload_type != packet->header.payloadType) {
114 // New CNG payload type implies new codec type.
115 *current_rtp_payload_type = 0xFF;
116 Flush();
117 flushed = true;
118 }
119 *current_cng_rtp_payload_type = packet->header.payloadType;
120 } else if (!decoder_database.IsDtmf(packet->header.payloadType)) {
121 // This must be speech.
122 if (*current_rtp_payload_type != 0xFF &&
123 *current_rtp_payload_type != packet->header.payloadType) {
124 *current_cng_rtp_payload_type = 0xFF;
125 Flush();
126 flushed = true;
127 }
128 *current_rtp_payload_type = packet->header.payloadType;
129 }
130 int return_val = InsertPacket(packet);
131 packet_list->pop_front();
132 if (return_val == kFlushed) {
133 // The buffer flushed, but this is not an error. We can still continue.
134 flushed = true;
135 } else if (return_val != kOK) {
136 // An error occurred. Delete remaining packets in list and return.
137 DeleteAllPackets(packet_list);
138 return return_val;
139 }
140 }
141 return flushed ? kFlushed : kOK;
142}
143
144int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
145 if (Empty()) {
146 return kBufferEmpty;
147 }
148 if (!next_timestamp) {
149 return kInvalidPointer;
150 }
151 *next_timestamp = buffer_.front()->header.timestamp;
152 return kOK;
153}
154
155int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
156 uint32_t* next_timestamp) const {
157 if (Empty()) {
158 return kBufferEmpty;
159 }
160 if (!next_timestamp) {
161 return kInvalidPointer;
162 }
163 PacketList::const_iterator it;
164 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
165 if ((*it)->header.timestamp >= timestamp) {
166 // Found a packet matching the search.
167 *next_timestamp = (*it)->header.timestamp;
168 return kOK;
169 }
170 }
171 return kNotFound;
172}
173
174const RTPHeader* PacketBuffer::NextRtpHeader() const {
175 if (Empty()) {
176 return NULL;
177 }
178 return const_cast<const RTPHeader*>(&(buffer_.front()->header));
179}
180
181Packet* PacketBuffer::GetNextPacket(int* discard_count) {
182 if (Empty()) {
183 // Buffer is empty.
184 return NULL;
185 }
186
187 Packet* packet = buffer_.front();
188 // Assert that the packet sanity checks in InsertPacket method works.
189 assert(packet && packet->payload);
190 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000191
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000192 // Discard other packets with the same timestamp. These are duplicates or
193 // redundant payloads that should not be used.
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000194 int discards = 0;
195
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000196 while (!Empty() &&
197 buffer_.front()->header.timestamp == packet->header.timestamp) {
198 if (DiscardNextPacket() != kOK) {
199 assert(false); // Must be ok by design.
200 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000201 ++discards;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000202 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000203 // The way of inserting packet should not cause any packet discarding here.
204 // TODO(minyue): remove |discard_count|.
205 assert(discards == 0);
206 if (discard_count)
207 *discard_count = discards;
208
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000209 return packet;
210}
211
212int PacketBuffer::DiscardNextPacket() {
213 if (Empty()) {
214 return kBufferEmpty;
215 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000216 // Assert that the packet sanity checks in InsertPacket method works.
henrik.lundin@webrtc.org12a34242014-04-28 08:36:35 +0000217 assert(buffer_.front());
218 assert(buffer_.front()->payload);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000219 DeleteFirstPacket(&buffer_);
220 return kOK;
221}
222
henrik.lundin@webrtc.org52b42cb2014-11-04 14:03:58 +0000223int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
224 uint32_t horizon_samples) {
225 while (!Empty() && timestamp_limit != buffer_.front()->header.timestamp &&
226 IsObsoleteTimestamp(buffer_.front()->header.timestamp,
227 timestamp_limit,
228 horizon_samples)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000229 if (DiscardNextPacket() != kOK) {
230 assert(false); // Must be ok by design.
231 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000232 }
233 return 0;
234}
235
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200236int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
237 return DiscardOldPackets(timestamp_limit, 0);
238}
239
240int PacketBuffer::NumPacketsInBuffer() const {
241 return static_cast<int>(buffer_.size());
242}
243
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000244int PacketBuffer::NumSamplesInBuffer(DecoderDatabase* decoder_database,
245 int last_decoded_length) const {
246 PacketList::const_iterator it;
247 int num_samples = 0;
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000248 int last_duration = last_decoded_length;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000249 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
250 Packet* packet = (*it);
251 AudioDecoder* decoder =
252 decoder_database->GetDecoder(packet->header.payloadType);
253 if (decoder) {
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000254 int duration;
255 if (packet->sync_packet) {
256 duration = last_duration;
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000257 } else if (packet->primary) {
258 duration =
259 decoder->PacketDuration(packet->payload, packet->payload_length);
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000260 } else {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000261 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000262 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000263 if (duration >= 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000264 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000265 }
266 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000267 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000268 }
269 return num_samples;
270}
271
272void PacketBuffer::IncrementWaitingTimes(int inc) {
273 PacketList::iterator it;
274 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
275 (*it)->waiting_time += inc;
276 }
277}
278
279bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
280 if (packet_list->empty()) {
281 return false;
282 }
283 Packet* first_packet = packet_list->front();
284 delete [] first_packet->payload;
285 delete first_packet;
286 packet_list->pop_front();
287 return true;
288}
289
290void PacketBuffer::DeleteAllPackets(PacketList* packet_list) {
291 while (DeleteFirstPacket(packet_list)) {
292 // Continue while the list is not empty.
293 }
294}
295
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000296void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000297 *num_packets = static_cast<int>(buffer_.size());
298 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000299}
300
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000301} // namespace webrtc