2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
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.
15 #include "webrtc/modules/audio_coding/neteq/packet_buffer.h"
17 #include <algorithm> // find_if()
19 #include "webrtc/modules/audio_coding/neteq/decoder_database.h"
20 #include "webrtc/modules/audio_coding/neteq/interface/audio_decoder.h"
24 // Predicate used when inserting packets in the buffer list.
25 // Operator() returns true when |packet| goes before |new_packet|.
26 class NewTimestampIsLarger {
28 explicit NewTimestampIsLarger(const Packet* new_packet)
29 : new_packet_(new_packet) {
31 bool operator()(Packet* packet) {
32 return (*new_packet_ >= *packet);
36 const Packet* new_packet_;
39 PacketBuffer::PacketBuffer(size_t max_number_of_packets)
40 : max_number_of_packets_(max_number_of_packets) {}
42 // Destructor. All packets in the buffer will be destroyed.
43 PacketBuffer::~PacketBuffer() {
47 // Flush the buffer. All packets in the buffer will be destroyed.
48 void PacketBuffer::Flush() {
49 DeleteAllPackets(&buffer_);
52 int PacketBuffer::InsertPacket(Packet* packet) {
53 if (!packet || !packet->payload) {
57 return kInvalidPacket;
62 if (buffer_.size() >= max_number_of_packets_) {
63 // Buffer is full. Flush it.
65 return_val = kFlushed;
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));
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
78 if (rit != buffer_.rend() &&
79 packet->header.timestamp == (*rit)->header.timestamp) {
80 delete [] packet->payload;
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
88 PacketList::iterator it = rit.base();
89 if (it != buffer_.end() &&
90 packet->header.timestamp == (*it)->header.timestamp) {
91 delete [] (*it)->payload;
93 it = buffer_.erase(it);
95 buffer_.insert(it, packet); // Insert the packet at that position.
100 int 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;
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;
124 *current_rtp_payload_type = packet->header.payloadType;
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.
131 } else if (return_val != kOK) {
132 // An error occurred. Delete remaining packets in list and return.
133 DeleteAllPackets(packet_list);
137 return flushed ? kFlushed : kOK;
140 int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
144 if (!next_timestamp) {
145 return kInvalidPointer;
147 *next_timestamp = buffer_.front()->header.timestamp;
151 int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
152 uint32_t* next_timestamp) const {
156 if (!next_timestamp) {
157 return kInvalidPointer;
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;
170 const RTPHeader* PacketBuffer::NextRtpHeader() const {
174 return const_cast<const RTPHeader*>(&(buffer_.front()->header));
177 Packet* PacketBuffer::GetNextPacket(int* discard_count) {
183 Packet* packet = buffer_.front();
184 // Assert that the packet sanity checks in InsertPacket method works.
185 assert(packet && packet->payload);
188 // Discard other packets with the same timestamp. These are duplicates or
189 // redundant payloads that should not be used.
193 buffer_.front()->header.timestamp == packet->header.timestamp) {
194 if (DiscardNextPacket() != kOK) {
195 assert(false); // Must be ok by design.
199 // The way of inserting packet should not cause any packet discarding here.
200 // TODO(minyue): remove |discard_count|.
201 assert(discards == 0);
203 *discard_count = discards;
208 int PacketBuffer::DiscardNextPacket() {
212 // Assert that the packet sanity checks in InsertPacket method works.
213 assert(buffer_.front());
214 assert(buffer_.front()->payload);
215 DeleteFirstPacket(&buffer_);
219 int 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,
225 if (DiscardNextPacket() != kOK) {
226 assert(false); // Must be ok by design.
232 int PacketBuffer::NumSamplesInBuffer(DecoderDatabase* decoder_database,
233 int last_decoded_length) const {
234 PacketList::const_iterator it;
236 int last_duration = last_decoded_length;
237 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
238 Packet* packet = (*it);
239 AudioDecoder* decoder =
240 decoder_database->GetDecoder(packet->header.payloadType);
243 if (packet->sync_packet) {
244 duration = last_duration;
245 } else if (packet->primary) {
247 decoder->PacketDuration(packet->payload, packet->payload_length);
252 last_duration = duration; // Save the most up-to-date (valid) duration.
255 num_samples += last_duration;
260 void PacketBuffer::IncrementWaitingTimes(int inc) {
261 PacketList::iterator it;
262 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
263 (*it)->waiting_time += inc;
267 bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
268 if (packet_list->empty()) {
271 Packet* first_packet = packet_list->front();
272 delete [] first_packet->payload;
274 packet_list->pop_front();
278 void PacketBuffer::DeleteAllPackets(PacketList* packet_list) {
279 while (DeleteFirstPacket(packet_list)) {
280 // Continue while the list is not empty.
284 void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
285 *num_packets = static_cast<int>(buffer_.size());
286 *max_num_packets = static_cast<int>(max_number_of_packets_);
289 } // namespace webrtc