blob: 0e512b64d1277a43c91a03f3e230b5e08265ab2a [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) {
ossudc431ce2016-08-31 08:51:13 -070060 if (!packet || packet->payload.empty()) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000061 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) {
minyue@webrtc.orgc8039072014-10-09 10:49:54 +000091 delete packet;
92 return return_val;
93 }
94
95 // The new packet is to be inserted to the left of |it|. If it has the same
96 // timestamp as |it|, which has a lower priority, replace |it| with the new
97 // packet.
98 PacketList::iterator it = rit.base();
99 if (it != buffer_.end() &&
100 packet->header.timestamp == (*it)->header.timestamp) {
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000101 delete *it;
102 it = buffer_.erase(it);
103 }
104 buffer_.insert(it, packet); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000105
106 return return_val;
107}
108
henrik.lundinda8bbf62016-08-31 03:14:11 -0700109int PacketBuffer::InsertPacketList(
110 PacketList* packet_list,
111 const DecoderDatabase& decoder_database,
112 rtc::Optional<uint8_t>* current_rtp_payload_type,
113 rtc::Optional<uint8_t>* current_cng_rtp_payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000114 bool flushed = false;
115 while (!packet_list->empty()) {
116 Packet* packet = packet_list->front();
117 if (decoder_database.IsComfortNoise(packet->header.payloadType)) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700118 if (*current_cng_rtp_payload_type &&
119 **current_cng_rtp_payload_type != packet->header.payloadType) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000120 // New CNG payload type implies new codec type.
henrik.lundinda8bbf62016-08-31 03:14:11 -0700121 *current_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000122 Flush();
123 flushed = true;
124 }
henrik.lundinda8bbf62016-08-31 03:14:11 -0700125 *current_cng_rtp_payload_type =
126 rtc::Optional<uint8_t>(packet->header.payloadType);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000127 } else if (!decoder_database.IsDtmf(packet->header.payloadType)) {
128 // This must be speech.
henrik.lundinda8bbf62016-08-31 03:14:11 -0700129 if (*current_rtp_payload_type &&
130 **current_rtp_payload_type != packet->header.payloadType) {
131 *current_cng_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000132 Flush();
133 flushed = true;
134 }
henrik.lundinda8bbf62016-08-31 03:14:11 -0700135 *current_rtp_payload_type =
136 rtc::Optional<uint8_t>(packet->header.payloadType);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000137 }
138 int return_val = InsertPacket(packet);
139 packet_list->pop_front();
140 if (return_val == kFlushed) {
141 // The buffer flushed, but this is not an error. We can still continue.
142 flushed = true;
143 } else if (return_val != kOK) {
144 // An error occurred. Delete remaining packets in list and return.
145 DeleteAllPackets(packet_list);
146 return return_val;
147 }
148 }
149 return flushed ? kFlushed : kOK;
150}
151
152int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
153 if (Empty()) {
154 return kBufferEmpty;
155 }
156 if (!next_timestamp) {
157 return kInvalidPointer;
158 }
159 *next_timestamp = buffer_.front()->header.timestamp;
160 return kOK;
161}
162
163int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
164 uint32_t* next_timestamp) const {
165 if (Empty()) {
166 return kBufferEmpty;
167 }
168 if (!next_timestamp) {
169 return kInvalidPointer;
170 }
171 PacketList::const_iterator it;
172 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
173 if ((*it)->header.timestamp >= timestamp) {
174 // Found a packet matching the search.
175 *next_timestamp = (*it)->header.timestamp;
176 return kOK;
177 }
178 }
179 return kNotFound;
180}
181
182const RTPHeader* PacketBuffer::NextRtpHeader() const {
183 if (Empty()) {
184 return NULL;
185 }
186 return const_cast<const RTPHeader*>(&(buffer_.front()->header));
187}
188
Peter Kastingdce40cf2015-08-24 14:52:23 -0700189Packet* PacketBuffer::GetNextPacket(size_t* discard_count) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000190 if (Empty()) {
191 // Buffer is empty.
192 return NULL;
193 }
194
195 Packet* packet = buffer_.front();
196 // Assert that the packet sanity checks in InsertPacket method works.
ossudc431ce2016-08-31 08:51:13 -0700197 assert(packet && !packet->payload.empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000198 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000199
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000200 // Discard other packets with the same timestamp. These are duplicates or
201 // redundant payloads that should not be used.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700202 size_t discards = 0;
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000203
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000204 while (!Empty() &&
205 buffer_.front()->header.timestamp == packet->header.timestamp) {
206 if (DiscardNextPacket() != kOK) {
207 assert(false); // Must be ok by design.
208 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000209 ++discards;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000210 }
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000211 // The way of inserting packet should not cause any packet discarding here.
212 // TODO(minyue): remove |discard_count|.
213 assert(discards == 0);
214 if (discard_count)
215 *discard_count = discards;
216
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000217 return packet;
218}
219
220int PacketBuffer::DiscardNextPacket() {
221 if (Empty()) {
222 return kBufferEmpty;
223 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000224 // Assert that the packet sanity checks in InsertPacket method works.
henrik.lundin@webrtc.org12a34242014-04-28 08:36:35 +0000225 assert(buffer_.front());
ossudc431ce2016-08-31 08:51:13 -0700226 assert(!buffer_.front()->payload.empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000227 DeleteFirstPacket(&buffer_);
228 return kOK;
229}
230
henrik.lundin@webrtc.org52b42cb2014-11-04 14:03:58 +0000231int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
232 uint32_t horizon_samples) {
233 while (!Empty() && timestamp_limit != buffer_.front()->header.timestamp &&
234 IsObsoleteTimestamp(buffer_.front()->header.timestamp,
235 timestamp_limit,
236 horizon_samples)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000237 if (DiscardNextPacket() != kOK) {
238 assert(false); // Must be ok by design.
239 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000240 }
241 return 0;
242}
243
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200244int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
245 return DiscardOldPackets(timestamp_limit, 0);
246}
247
Peter Kastingdce40cf2015-08-24 14:52:23 -0700248size_t PacketBuffer::NumPacketsInBuffer() const {
249 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200250}
251
Peter Kastingdce40cf2015-08-24 14:52:23 -0700252size_t PacketBuffer::NumSamplesInBuffer(DecoderDatabase* decoder_database,
253 size_t last_decoded_length) const {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000254 PacketList::const_iterator it;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700255 size_t num_samples = 0;
256 size_t last_duration = last_decoded_length;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000257 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
258 Packet* packet = (*it);
259 AudioDecoder* decoder =
260 decoder_database->GetDecoder(packet->header.payloadType);
Peter Kasting728d9032015-06-11 14:31:38 -0700261 if (decoder && !packet->sync_packet) {
262 if (!packet->primary) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000263 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000264 }
ossudc431ce2016-08-31 08:51:13 -0700265 int duration = decoder->PacketDuration(packet->payload.data(),
266 packet->payload.size());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000267 if (duration >= 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000268 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000269 }
270 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000271 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000272 }
273 return num_samples;
274}
275
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000276bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
277 if (packet_list->empty()) {
278 return false;
279 }
280 Packet* first_packet = packet_list->front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000281 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