blob: 78a71c746dcdce826710474d36ca7bedb5b66d25 [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
kwiberg087bd342017-02-10 08:15:44 -080019#include "webrtc/api/audio_codecs/audio_decoder.h"
Henrik Kjellanderdca1e092017-07-01 16:42:22 +020020#include "webrtc/base/logging.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 {
henrik.lundin067d8552016-09-01 23:19:05 -070025namespace {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000026// Predicate used when inserting packets in the buffer list.
27// Operator() returns true when |packet| goes before |new_packet|.
28class NewTimestampIsLarger {
29 public:
ossua73f6c92016-10-24 08:25:28 -070030 explicit NewTimestampIsLarger(const Packet& new_packet)
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000031 : new_packet_(new_packet) {
32 }
ossua73f6c92016-10-24 08:25:28 -070033 bool operator()(const Packet& packet) {
34 return (new_packet_ >= packet);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000035 }
36
37 private:
ossua73f6c92016-10-24 08:25:28 -070038 const Packet& new_packet_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000039};
40
henrik.lundin067d8552016-09-01 23:19:05 -070041// Returns true if both payload types are known to the decoder database, and
42// have the same sample rate.
43bool EqualSampleRates(uint8_t pt1,
44 uint8_t pt2,
45 const DecoderDatabase& decoder_database) {
kjellander7c856582017-02-26 19:53:40 -080046 auto* di1 = decoder_database.GetDecoderInfo(pt1);
47 auto* di2 = decoder_database.GetDecoderInfo(pt2);
henrik.lundin067d8552016-09-01 23:19:05 -070048 return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
49}
50} // namespace
51
henrik.lundin84f8cd62016-04-26 07:45:16 -070052PacketBuffer::PacketBuffer(size_t max_number_of_packets,
53 const TickTimer* tick_timer)
54 : max_number_of_packets_(max_number_of_packets), tick_timer_(tick_timer) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000055
56// Destructor. All packets in the buffer will be destroyed.
57PacketBuffer::~PacketBuffer() {
58 Flush();
59}
60
61// Flush the buffer. All packets in the buffer will be destroyed.
62void PacketBuffer::Flush() {
ossua73f6c92016-10-24 08:25:28 -070063 buffer_.clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000064}
65
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020066bool PacketBuffer::Empty() const {
67 return buffer_.empty();
68}
69
ossua73f6c92016-10-24 08:25:28 -070070int PacketBuffer::InsertPacket(Packet&& packet) {
71 if (packet.empty()) {
Henrik Lundind67a2192015-08-03 12:54:37 +020072 LOG(LS_WARNING) << "InsertPacket invalid packet";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000073 return kInvalidPacket;
74 }
75
ossua73f6c92016-10-24 08:25:28 -070076 RTC_DCHECK_GE(packet.priority.codec_level, 0);
77 RTC_DCHECK_GE(packet.priority.red_level, 0);
ossua70695a2016-09-22 02:06:28 -070078
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000079 int return_val = kOK;
80
ossua73f6c92016-10-24 08:25:28 -070081 packet.waiting_time = tick_timer_->GetNewStopwatch();
henrik.lundin84f8cd62016-04-26 07:45:16 -070082
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +000083 if (buffer_.size() >= max_number_of_packets_) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000084 // Buffer is full. Flush it.
85 Flush();
Henrik Lundind67a2192015-08-03 12:54:37 +020086 LOG(LS_WARNING) << "Packet buffer flushed";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000087 return_val = kFlushed;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000088 }
89
90 // Get an iterator pointing to the place in the buffer where the new packet
91 // should be inserted. The list is searched from the back, since the most
92 // likely case is that the new packet should be near the end of the list.
93 PacketList::reverse_iterator rit = std::find_if(
94 buffer_.rbegin(), buffer_.rend(),
95 NewTimestampIsLarger(packet));
minyue@webrtc.orgc8039072014-10-09 10:49:54 +000096
97 // The new packet is to be inserted to the right of |rit|. If it has the same
98 // timestamp as |rit|, which has a higher priority, do not insert the new
99 // packet to list.
ossua73f6c92016-10-24 08:25:28 -0700100 if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000101 return return_val;
102 }
103
104 // The new packet is to be inserted to the left of |it|. If it has the same
105 // timestamp as |it|, which has a lower priority, replace |it| with the new
106 // packet.
107 PacketList::iterator it = rit.base();
ossua73f6c92016-10-24 08:25:28 -0700108 if (it != buffer_.end() && packet.timestamp == it->timestamp) {
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000109 it = buffer_.erase(it);
110 }
ossua73f6c92016-10-24 08:25:28 -0700111 buffer_.insert(it, std::move(packet)); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000112
113 return return_val;
114}
115
henrik.lundinda8bbf62016-08-31 03:14:11 -0700116int PacketBuffer::InsertPacketList(
117 PacketList* packet_list,
118 const DecoderDatabase& decoder_database,
119 rtc::Optional<uint8_t>* current_rtp_payload_type,
120 rtc::Optional<uint8_t>* current_cng_rtp_payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000121 bool flushed = false;
ossua73f6c92016-10-24 08:25:28 -0700122 for (auto& packet : *packet_list) {
123 if (decoder_database.IsComfortNoise(packet.payload_type)) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700124 if (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700125 **current_cng_rtp_payload_type != packet.payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000126 // New CNG payload type implies new codec type.
henrik.lundinda8bbf62016-08-31 03:14:11 -0700127 *current_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000128 Flush();
129 flushed = true;
130 }
henrik.lundinda8bbf62016-08-31 03:14:11 -0700131 *current_cng_rtp_payload_type =
ossua73f6c92016-10-24 08:25:28 -0700132 rtc::Optional<uint8_t>(packet.payload_type);
133 } else if (!decoder_database.IsDtmf(packet.payload_type)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000134 // This must be speech.
henrik.lundin067d8552016-09-01 23:19:05 -0700135 if ((*current_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700136 **current_rtp_payload_type != packet.payload_type) ||
henrik.lundin067d8552016-09-01 23:19:05 -0700137 (*current_cng_rtp_payload_type &&
ossua73f6c92016-10-24 08:25:28 -0700138 !EqualSampleRates(packet.payload_type,
henrik.lundin067d8552016-09-01 23:19:05 -0700139 **current_cng_rtp_payload_type,
140 decoder_database))) {
henrik.lundinda8bbf62016-08-31 03:14:11 -0700141 *current_cng_rtp_payload_type = rtc::Optional<uint8_t>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000142 Flush();
143 flushed = true;
144 }
ossua73f6c92016-10-24 08:25:28 -0700145 *current_rtp_payload_type = rtc::Optional<uint8_t>(packet.payload_type);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000146 }
ossua73f6c92016-10-24 08:25:28 -0700147 int return_val = InsertPacket(std::move(packet));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000148 if (return_val == kFlushed) {
149 // The buffer flushed, but this is not an error. We can still continue.
150 flushed = true;
151 } else if (return_val != kOK) {
152 // An error occurred. Delete remaining packets in list and return.
ossua73f6c92016-10-24 08:25:28 -0700153 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000154 return return_val;
155 }
156 }
ossua73f6c92016-10-24 08:25:28 -0700157 packet_list->clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000158 return flushed ? kFlushed : kOK;
159}
160
161int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
162 if (Empty()) {
163 return kBufferEmpty;
164 }
165 if (!next_timestamp) {
166 return kInvalidPointer;
167 }
ossua73f6c92016-10-24 08:25:28 -0700168 *next_timestamp = buffer_.front().timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000169 return kOK;
170}
171
172int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
173 uint32_t* next_timestamp) const {
174 if (Empty()) {
175 return kBufferEmpty;
176 }
177 if (!next_timestamp) {
178 return kInvalidPointer;
179 }
180 PacketList::const_iterator it;
181 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
ossua73f6c92016-10-24 08:25:28 -0700182 if (it->timestamp >= timestamp) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000183 // Found a packet matching the search.
ossua73f6c92016-10-24 08:25:28 -0700184 *next_timestamp = it->timestamp;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000185 return kOK;
186 }
187 }
188 return kNotFound;
189}
190
ossu7a377612016-10-18 04:06:13 -0700191const Packet* PacketBuffer::PeekNextPacket() const {
ossua73f6c92016-10-24 08:25:28 -0700192 return buffer_.empty() ? nullptr : &buffer_.front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000193}
194
ossua73f6c92016-10-24 08:25:28 -0700195rtc::Optional<Packet> PacketBuffer::GetNextPacket() {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000196 if (Empty()) {
197 // Buffer is empty.
ossua73f6c92016-10-24 08:25:28 -0700198 return rtc::Optional<Packet>();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000199 }
200
ossua73f6c92016-10-24 08:25:28 -0700201 rtc::Optional<Packet> packet(std::move(buffer_.front()));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000202 // Assert that the packet sanity checks in InsertPacket method works.
ossua73f6c92016-10-24 08:25:28 -0700203 RTC_DCHECK(!packet->empty());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000204 buffer_.pop_front();
minyue@webrtc.orgc8039072014-10-09 10:49:54 +0000205
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000206 return packet;
207}
208
209int PacketBuffer::DiscardNextPacket() {
210 if (Empty()) {
211 return kBufferEmpty;
212 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000213 // Assert that the packet sanity checks in InsertPacket method works.
ossua73f6c92016-10-24 08:25:28 -0700214 RTC_DCHECK(!buffer_.front().empty());
215 buffer_.pop_front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000216 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) {
ossua73f6c92016-10-24 08:25:28 -0700221 while (!Empty() && timestamp_limit != buffer_.front().timestamp &&
222 IsObsoleteTimestamp(buffer_.front().timestamp, timestamp_limit,
henrik.lundin@webrtc.org52b42cb2014-11-04 14:03:58 +0000223 horizon_samples)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000224 if (DiscardNextPacket() != kOK) {
225 assert(false); // Must be ok by design.
226 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000227 }
228 return 0;
229}
230
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200231int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
232 return DiscardOldPackets(timestamp_limit, 0);
233}
234
ossu61a208b2016-09-20 01:38:00 -0700235void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) {
236 for (auto it = buffer_.begin(); it != buffer_.end(); /* */) {
ossua73f6c92016-10-24 08:25:28 -0700237 const Packet& packet = *it;
238 if (packet.payload_type == payload_type) {
ossu61a208b2016-09-20 01:38:00 -0700239 it = buffer_.erase(it);
240 } else {
241 ++it;
242 }
243 }
244}
245
Peter Kastingdce40cf2015-08-24 14:52:23 -0700246size_t PacketBuffer::NumPacketsInBuffer() const {
247 return buffer_.size();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200248}
249
ossu61a208b2016-09-20 01:38:00 -0700250size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700251 size_t num_samples = 0;
252 size_t last_duration = last_decoded_length;
ossua73f6c92016-10-24 08:25:28 -0700253 for (const Packet& packet : buffer_) {
254 if (packet.frame) {
ossua70695a2016-09-22 02:06:28 -0700255 // TODO(hlundin): Verify that it's fine to count all packets and remove
256 // this check.
ossua73f6c92016-10-24 08:25:28 -0700257 if (packet.priority != Packet::Priority(0, 0)) {
minyue@webrtc.org0aa3ee62014-05-28 07:48:01 +0000258 continue;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000259 }
ossua73f6c92016-10-24 08:25:28 -0700260 size_t duration = packet.frame->Duration();
ossu61a208b2016-09-20 01:38:00 -0700261 if (duration > 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000262 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000263 }
264 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000265 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000266 }
267 return num_samples;
268}
269
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000270void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000271 *num_packets = static_cast<int>(buffer_.size());
272 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000273}
274
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000275} // namespace webrtc