blob: f1b898e34cf079f2590a823643ea9374fb13c94b [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
111int PacketBuffer::InsertPacketList(PacketList* packet_list,
112 const DecoderDatabase& decoder_database,
113 uint8_t* current_rtp_payload_type,
114 uint8_t* current_cng_rtp_payload_type) {
115 bool flushed = false;
116 while (!packet_list->empty()) {
117 Packet* packet = packet_list->front();
118 if (decoder_database.IsComfortNoise(packet->header.payloadType)) {
119 if (*current_cng_rtp_payload_type != 0xFF &&
120 *current_cng_rtp_payload_type != packet->header.payloadType) {
121 // New CNG payload type implies new codec type.
122 *current_rtp_payload_type = 0xFF;
123 Flush();
124 flushed = true;
125 }
126 *current_cng_rtp_payload_type = packet->header.payloadType;
127 } else if (!decoder_database.IsDtmf(packet->header.payloadType)) {
128 // This must be speech.
129 if (*current_rtp_payload_type != 0xFF &&
130 *current_rtp_payload_type != packet->header.payloadType) {
131 *current_cng_rtp_payload_type = 0xFF;
132 Flush();
133 flushed = true;
134 }
135 *current_rtp_payload_type = packet->header.payloadType;
136 }
137 int return_val = InsertPacket(packet);
138 packet_list->pop_front();
139 if (return_val == kFlushed) {
140 // The buffer flushed, but this is not an error. We can still continue.
141 flushed = true;
142 } else if (return_val != kOK) {
143 // An error occurred. Delete remaining packets in list and return.
144 DeleteAllPackets(packet_list);
145 return return_val;
146 }
147 }
148 return flushed ? kFlushed : kOK;
149}
150
151int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
152 if (Empty()) {
153 return kBufferEmpty;
154 }
155 if (!next_timestamp) {
156 return kInvalidPointer;
157 }
158 *next_timestamp = buffer_.front()->header.timestamp;
159 return kOK;
160}
161
162int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
163 uint32_t* next_timestamp) const {
164 if (Empty()) {
165 return kBufferEmpty;
166 }
167 if (!next_timestamp) {
168 return kInvalidPointer;
169 }
170 PacketList::const_iterator it;
171 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
172 if ((*it)->header.timestamp >= timestamp) {
173 // Found a packet matching the search.
174 *next_timestamp = (*it)->header.timestamp;
175 return kOK;
176 }
177 }
178 return kNotFound;
179}
180
181const RTPHeader* PacketBuffer::NextRtpHeader() const {
182 if (Empty()) {
183 return NULL;
184 }
185 return const_cast<const RTPHeader*>(&(buffer_.front()->header));
186}
187
Peter Kastingdce40cf2015-08-24 14:52:23 -0700188Packet* PacketBuffer::GetNextPacket(size_t* discard_count) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000189 if (Empty()) {
190 // Buffer is empty.
191 return NULL;
192 }
193
194 Packet* packet = buffer_.front();
195 // Assert that the packet sanity checks in InsertPacket method works.
196 assert(packet && packet->payload);
197 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000198
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000199 // Discard other packets with the same timestamp. These are duplicates or
200 // redundant payloads that should not be used.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700201 size_t discards = 0;
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000202
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000203 while (!Empty() &&
204 buffer_.front()->header.timestamp == packet->header.timestamp) {
205 if (DiscardNextPacket() != kOK) {
206 assert(false); // Must be ok by design.
207 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000208 ++discards;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000209 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000210 // The way of inserting packet should not cause any packet discarding here.
211 // TODO(minyue): remove |discard_count|.
212 assert(discards == 0);
213 if (discard_count)
214 *discard_count = discards;
215
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000216 return packet;
217}
218
219int PacketBuffer::DiscardNextPacket() {
220 if (Empty()) {
221 return kBufferEmpty;
222 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000223 // Assert that the packet sanity checks in InsertPacket method works.
henrik.lundin@webrtc.org12a34242014-04-28 08:36:35 +0000224 assert(buffer_.front());
225 assert(buffer_.front()->payload);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000226 DeleteFirstPacket(&buffer_);
227 return kOK;
228}
229
henrik.lundin@webrtc.org52b42cb2014-11-04 14:03:58 +0000230int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
231 uint32_t horizon_samples) {
232 while (!Empty() && timestamp_limit != buffer_.front()->header.timestamp &&
233 IsObsoleteTimestamp(buffer_.front()->header.timestamp,
234 timestamp_limit,
235 horizon_samples)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000236 if (DiscardNextPacket() != kOK) {
237 assert(false); // Must be ok by design.
238 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000239 }
240 return 0;
241}
242
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200243int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
244 return DiscardOldPackets(timestamp_limit, 0);
245}
246
Peter Kastingdce40cf2015-08-24 14:52:23 -0700247size_t PacketBuffer::NumPacketsInBuffer() const {
248 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200249}
250
Peter Kastingdce40cf2015-08-24 14:52:23 -0700251size_t PacketBuffer::NumSamplesInBuffer(DecoderDatabase* decoder_database,
252 size_t last_decoded_length) const {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000253 PacketList::const_iterator it;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700254 size_t num_samples = 0;
255 size_t last_duration = last_decoded_length;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000256 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
257 Packet* packet = (*it);
258 AudioDecoder* decoder =
259 decoder_database->GetDecoder(packet->header.payloadType);
Peter Kasting728d9032015-06-11 14:31:38 -0700260 if (decoder && !packet->sync_packet) {
261 if (!packet->primary) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000262 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000263 }
Peter Kasting728d9032015-06-11 14:31:38 -0700264 int duration =
pkastingb297c5a2015-07-22 15:17:22 -0700265 decoder->PacketDuration(packet->payload, packet->payload_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000266 if (duration >= 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000267 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000268 }
269 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000270 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000271 }
272 return num_samples;
273}
274
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000275bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
276 if (packet_list->empty()) {
277 return false;
278 }
279 Packet* first_packet = packet_list->front();
280 delete [] first_packet->payload;
281 delete first_packet;
282 packet_list->pop_front();
283 return true;
284}
285
286void PacketBuffer::DeleteAllPackets(PacketList* packet_list) {
287 while (DeleteFirstPacket(packet_list)) {
288 // Continue while the list is not empty.
289 }
290}
291
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000292void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000293 *num_packets = static_cast<int>(buffer_.size());
294 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000295}
296
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000297} // namespace webrtc