1/*
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
15#include "webrtc/modules/audio_coding/neteq/packet_buffer.h"
16
17#include <algorithm>  // find_if()
18
19#include "webrtc/modules/audio_coding/neteq/decoder_database.h"
20#include "webrtc/modules/audio_coding/neteq/interface/audio_decoder.h"
21
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
39PacketBuffer::PacketBuffer(size_t max_number_of_packets)
40    : max_number_of_packets_(max_number_of_packets) {}
41
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_);
50}
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
62  if (buffer_.size() >= max_number_of_packets_) {
63    // Buffer is full. Flush it.
64    Flush();
65    return_val = kFlushed;
66  }
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.
75
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();
166  // 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  }
187  // Assert that the packet sanity checks in InsertPacket method works.
188  assert(buffer_.front());
189  assert(buffer_.front()->payload);
190  DeleteFirstPacket(&buffer_);
191  return kOK;
192}
193
194int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit) {
195  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    }
203  }
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;
211  int last_duration = last_decoded_length;
212  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) {
217      int duration;
218      if (packet->sync_packet) {
219        duration = last_duration;
220      } else if (packet->primary) {
221        duration =
222            decoder->PacketDuration(packet->payload, packet->payload_length);
223      } else {
224        continue;
225      }
226      if (duration >= 0) {
227        last_duration = duration;  // Save the most up-to-date (valid) duration.
228      }
229    }
230    num_samples += last_duration;
231  }
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
259void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
260  *num_packets = static_cast<int>(buffer_.size());
261  *max_num_packets = static_cast<int>(max_number_of_packets_);
262}
263
264}  // namespace webrtc
265