blob: 816713d874648e5a29f372f549171677497ef7f2 [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.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000019#include "webrtc/modules/audio_coding/neteq/decoder_database.h"
kwiberg@webrtc.org3800e132014-12-03 16:28:17 +000020#include "webrtc/modules/audio_coding/neteq/interface/audio_decoder.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
52int PacketBuffer::InsertPacket(Packet* packet) {
53 if (!packet || !packet->payload) {
54 if (packet) {
55 delete packet;
56 }
57 return kInvalidPacket;
58 }
59
60 int return_val = kOK;
61
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000062 if (buffer_.size() >= max_number_of_packets_) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000063 // Buffer is full. Flush it.
64 Flush();
65 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000066 }
67
68 // Get an iterator pointing to the place in the buffer where the new packet
69 // should be inserted. The list is searched from the back, since the most
70 // likely case is that the new packet should be near the end of the list.
71 PacketList::reverse_iterator rit = std::find_if(
72 buffer_.rbegin(), buffer_.rend(),
73 NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +000074
75 // The new packet is to be inserted to the right of |rit|. If it has the same
76 // timestamp as |rit|, which has a higher priority, do not insert the new
77 // packet to list.
78 if (rit != buffer_.rend() &&
79 packet->header.timestamp == (*rit)->header.timestamp) {
80 delete [] packet->payload;
81 delete packet;
82 return return_val;
83 }
84
85 // The new packet is to be inserted to the left of |it|. If it has the same
86 // timestamp as |it|, which has a lower priority, replace |it| with the new
87 // packet.
88 PacketList::iterator it = rit.base();
89 if (it != buffer_.end() &&
90 packet->header.timestamp == (*it)->header.timestamp) {
91 delete [] (*it)->payload;
92 delete *it;
93 it = buffer_.erase(it);
94 }
95 buffer_.insert(it, packet); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000096
97 return return_val;
98}
99
100int PacketBuffer::InsertPacketList(PacketList* packet_list,
101 const DecoderDatabase& decoder_database,
102 uint8_t* current_rtp_payload_type,
103 uint8_t* current_cng_rtp_payload_type) {
104 bool flushed = false;
105 while (!packet_list->empty()) {
106 Packet* packet = packet_list->front();
107 if (decoder_database.IsComfortNoise(packet->header.payloadType)) {
108 if (*current_cng_rtp_payload_type != 0xFF &&
109 *current_cng_rtp_payload_type != packet->header.payloadType) {
110 // New CNG payload type implies new codec type.
111 *current_rtp_payload_type = 0xFF;
112 Flush();
113 flushed = true;
114 }
115 *current_cng_rtp_payload_type = packet->header.payloadType;
116 } else if (!decoder_database.IsDtmf(packet->header.payloadType)) {
117 // This must be speech.
118 if (*current_rtp_payload_type != 0xFF &&
119 *current_rtp_payload_type != packet->header.payloadType) {
120 *current_cng_rtp_payload_type = 0xFF;
121 Flush();
122 flushed = true;
123 }
124 *current_rtp_payload_type = packet->header.payloadType;
125 }
126 int return_val = InsertPacket(packet);
127 packet_list->pop_front();
128 if (return_val == kFlushed) {
129 // The buffer flushed, but this is not an error. We can still continue.
130 flushed = true;
131 } else if (return_val != kOK) {
132 // An error occurred. Delete remaining packets in list and return.
133 DeleteAllPackets(packet_list);
134 return return_val;
135 }
136 }
137 return flushed ? kFlushed : kOK;
138}
139
140int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
141 if (Empty()) {
142 return kBufferEmpty;
143 }
144 if (!next_timestamp) {
145 return kInvalidPointer;
146 }
147 *next_timestamp = buffer_.front()->header.timestamp;
148 return kOK;
149}
150
151int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
152 uint32_t* next_timestamp) const {
153 if (Empty()) {
154 return kBufferEmpty;
155 }
156 if (!next_timestamp) {
157 return kInvalidPointer;
158 }
159 PacketList::const_iterator it;
160 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
161 if ((*it)->header.timestamp >= timestamp) {
162 // Found a packet matching the search.
163 *next_timestamp = (*it)->header.timestamp;
164 return kOK;
165 }
166 }
167 return kNotFound;
168}
169
170const RTPHeader* PacketBuffer::NextRtpHeader() const {
171 if (Empty()) {
172 return NULL;
173 }
174 return const_cast<const RTPHeader*>(&(buffer_.front()->header));
175}
176
177Packet* PacketBuffer::GetNextPacket(int* discard_count) {
178 if (Empty()) {
179 // Buffer is empty.
180 return NULL;
181 }
182
183 Packet* packet = buffer_.front();
184 // Assert that the packet sanity checks in InsertPacket method works.
185 assert(packet && packet->payload);
186 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000187
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000188 // Discard other packets with the same timestamp. These are duplicates or
189 // redundant payloads that should not be used.
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000190 int discards = 0;
191
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000192 while (!Empty() &&
193 buffer_.front()->header.timestamp == packet->header.timestamp) {
194 if (DiscardNextPacket() != kOK) {
195 assert(false); // Must be ok by design.
196 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000197 ++discards;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000198 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000199 // The way of inserting packet should not cause any packet discarding here.
200 // TODO(minyue): remove |discard_count|.
201 assert(discards == 0);
202 if (discard_count)
203 *discard_count = discards;
204
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000205 return packet;
206}
207
208int PacketBuffer::DiscardNextPacket() {
209 if (Empty()) {
210 return kBufferEmpty;
211 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000212 // Assert that the packet sanity checks in InsertPacket method works.
henrik.lundin@webrtc.org12a34242014-04-28 08:36:35 +0000213 assert(buffer_.front());
214 assert(buffer_.front()->payload);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000215 DeleteFirstPacket(&buffer_);
216 return kOK;
217}
218
henrik.lundin@webrtc.org52b42cb2014-11-04 14:03:58 +0000219int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
220 uint32_t horizon_samples) {
221 while (!Empty() && timestamp_limit != buffer_.front()->header.timestamp &&
222 IsObsoleteTimestamp(buffer_.front()->header.timestamp,
223 timestamp_limit,
224 horizon_samples)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000225 if (DiscardNextPacket() != kOK) {
226 assert(false); // Must be ok by design.
227 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000228 }
229 return 0;
230}
231
232int PacketBuffer::NumSamplesInBuffer(DecoderDatabase* decoder_database,
233 int last_decoded_length) const {
234 PacketList::const_iterator it;
235 int num_samples = 0;
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000236 int last_duration = last_decoded_length;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000237 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
238 Packet* packet = (*it);
239 AudioDecoder* decoder =
240 decoder_database->GetDecoder(packet->header.payloadType);
241 if (decoder) {
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000242 int duration;
243 if (packet->sync_packet) {
244 duration = last_duration;
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000245 } else if (packet->primary) {
246 duration =
247 decoder->PacketDuration(packet->payload, packet->payload_length);
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000248 } else {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000249 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000250 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000251 if (duration >= 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000252 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000253 }
254 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000255 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000256 }
257 return num_samples;
258}
259
260void PacketBuffer::IncrementWaitingTimes(int inc) {
261 PacketList::iterator it;
262 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
263 (*it)->waiting_time += inc;
264 }
265}
266
267bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
268 if (packet_list->empty()) {
269 return false;
270 }
271 Packet* first_packet = packet_list->front();
272 delete [] first_packet->payload;
273 delete first_packet;
274 packet_list->pop_front();
275 return true;
276}
277
278void PacketBuffer::DeleteAllPackets(PacketList* packet_list) {
279 while (DeleteFirstPacket(packet_list)) {
280 // Continue while the list is not empty.
281 }
282}
283
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000284void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000285 *num_packets = static_cast<int>(buffer_.size());
286 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000287}
288
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000289} // namespace webrtc