blob: bcd0e7b4bd77701858feb453e710a4c70a1d07dc [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.org1b9df052014-05-28 07:33:39 +000015#include "webrtc/modules/audio_coding/neteq4/packet_buffer.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000016
17#include <algorithm> // find_if()
18
henrik.lundin@webrtc.org1b9df052014-05-28 07:33:39 +000019#include "webrtc/modules/audio_coding/neteq4/decoder_database.h"
20#include "webrtc/modules/audio_coding/neteq4/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));
74 buffer_.insert(rit.base(), packet); // Insert the packet at that position.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000075
76 return return_val;
77}
78
79int PacketBuffer::InsertPacketList(PacketList* packet_list,
80 const DecoderDatabase& decoder_database,
81 uint8_t* current_rtp_payload_type,
82 uint8_t* current_cng_rtp_payload_type) {
83 bool flushed = false;
84 while (!packet_list->empty()) {
85 Packet* packet = packet_list->front();
86 if (decoder_database.IsComfortNoise(packet->header.payloadType)) {
87 if (*current_cng_rtp_payload_type != 0xFF &&
88 *current_cng_rtp_payload_type != packet->header.payloadType) {
89 // New CNG payload type implies new codec type.
90 *current_rtp_payload_type = 0xFF;
91 Flush();
92 flushed = true;
93 }
94 *current_cng_rtp_payload_type = packet->header.payloadType;
95 } else if (!decoder_database.IsDtmf(packet->header.payloadType)) {
96 // This must be speech.
97 if (*current_rtp_payload_type != 0xFF &&
98 *current_rtp_payload_type != packet->header.payloadType) {
99 *current_cng_rtp_payload_type = 0xFF;
100 Flush();
101 flushed = true;
102 }
103 *current_rtp_payload_type = packet->header.payloadType;
104 }
105 int return_val = InsertPacket(packet);
106 packet_list->pop_front();
107 if (return_val == kFlushed) {
108 // The buffer flushed, but this is not an error. We can still continue.
109 flushed = true;
110 } else if (return_val != kOK) {
111 // An error occurred. Delete remaining packets in list and return.
112 DeleteAllPackets(packet_list);
113 return return_val;
114 }
115 }
116 return flushed ? kFlushed : kOK;
117}
118
119int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
120 if (Empty()) {
121 return kBufferEmpty;
122 }
123 if (!next_timestamp) {
124 return kInvalidPointer;
125 }
126 *next_timestamp = buffer_.front()->header.timestamp;
127 return kOK;
128}
129
130int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
131 uint32_t* next_timestamp) const {
132 if (Empty()) {
133 return kBufferEmpty;
134 }
135 if (!next_timestamp) {
136 return kInvalidPointer;
137 }
138 PacketList::const_iterator it;
139 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
140 if ((*it)->header.timestamp >= timestamp) {
141 // Found a packet matching the search.
142 *next_timestamp = (*it)->header.timestamp;
143 return kOK;
144 }
145 }
146 return kNotFound;
147}
148
149const RTPHeader* PacketBuffer::NextRtpHeader() const {
150 if (Empty()) {
151 return NULL;
152 }
153 return const_cast<const RTPHeader*>(&(buffer_.front()->header));
154}
155
156Packet* PacketBuffer::GetNextPacket(int* discard_count) {
157 if (Empty()) {
158 // Buffer is empty.
159 return NULL;
160 }
161
162 Packet* packet = buffer_.front();
163 // Assert that the packet sanity checks in InsertPacket method works.
164 assert(packet && packet->payload);
165 buffer_.pop_front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000166 // Discard other packets with the same timestamp. These are duplicates or
167 // redundant payloads that should not be used.
168 if (discard_count) {
169 *discard_count = 0;
170 }
171 while (!Empty() &&
172 buffer_.front()->header.timestamp == packet->header.timestamp) {
173 if (DiscardNextPacket() != kOK) {
174 assert(false); // Must be ok by design.
175 }
176 if (discard_count) {
177 ++(*discard_count);
178 }
179 }
180 return packet;
181}
182
183int PacketBuffer::DiscardNextPacket() {
184 if (Empty()) {
185 return kBufferEmpty;
186 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000187 // Assert that the packet sanity checks in InsertPacket method works.
henrik.lundin@webrtc.org12a34242014-04-28 08:36:35 +0000188 assert(buffer_.front());
189 assert(buffer_.front()->payload);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000190 DeleteFirstPacket(&buffer_);
191 return kOK;
192}
193
194int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000195 while (!Empty() &&
196 timestamp_limit != buffer_.front()->header.timestamp &&
197 static_cast<uint32_t>(timestamp_limit
198 - buffer_.front()->header.timestamp) <
199 0xFFFFFFFF / 2) {
200 if (DiscardNextPacket() != kOK) {
201 assert(false); // Must be ok by design.
202 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000203 }
204 return 0;
205}
206
207int PacketBuffer::NumSamplesInBuffer(DecoderDatabase* decoder_database,
208 int last_decoded_length) const {
209 PacketList::const_iterator it;
210 int num_samples = 0;
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000211 int last_duration = last_decoded_length;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000212 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
213 Packet* packet = (*it);
214 AudioDecoder* decoder =
215 decoder_database->GetDecoder(packet->header.payloadType);
216 if (decoder) {
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000217 int duration;
218 if (packet->sync_packet) {
219 duration = last_duration;
220 } else {
221 duration = packet->primary ?
222 decoder->PacketDuration(packet->payload, packet->payload_length) :
223 decoder->PacketDurationRedundant(packet->payload,
224 packet->payload_length);
225 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000226 if (duration >= 0) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000227 last_duration = duration; // Save the most up-to-date (valid) duration.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000228 }
229 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000230 num_samples += last_duration;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000231 }
232 return num_samples;
233}
234
235void PacketBuffer::IncrementWaitingTimes(int inc) {
236 PacketList::iterator it;
237 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
238 (*it)->waiting_time += inc;
239 }
240}
241
242bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
243 if (packet_list->empty()) {
244 return false;
245 }
246 Packet* first_packet = packet_list->front();
247 delete [] first_packet->payload;
248 delete first_packet;
249 packet_list->pop_front();
250 return true;
251}
252
253void PacketBuffer::DeleteAllPackets(PacketList* packet_list) {
254 while (DeleteFirstPacket(packet_list)) {
255 // Continue while the list is not empty.
256 }
257}
258
henrik.lundin@webrtc.org116ed1d2014-04-28 08:20:04 +0000259void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000260 *num_packets = static_cast<int>(buffer_.size());
261 *max_num_packets = static_cast<int>(max_number_of_packets_);
turaj@webrtc.org7df97062013-08-02 18:07:13 +0000262}
263
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000264} // namespace webrtc