LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_coding/neteq - packet_buffer.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 136 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 21 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/base/logging.h"
      20             : #include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
      21             : #include "webrtc/modules/audio_coding/neteq/decoder_database.h"
      22             : #include "webrtc/modules/audio_coding/neteq/tick_timer.h"
      23             : 
      24             : namespace webrtc {
      25             : namespace {
      26             : // Predicate used when inserting packets in the buffer list.
      27             : // Operator() returns true when |packet| goes before |new_packet|.
      28             : class NewTimestampIsLarger {
      29             :  public:
      30           0 :   explicit NewTimestampIsLarger(const Packet& new_packet)
      31           0 :       : new_packet_(new_packet) {
      32           0 :   }
      33           0 :   bool operator()(const Packet& packet) {
      34           0 :     return (new_packet_ >= packet);
      35             :   }
      36             : 
      37             :  private:
      38             :   const Packet& new_packet_;
      39             : };
      40             : 
      41             : // Returns true if both payload types are known to the decoder database, and
      42             : // have the same sample rate.
      43           0 : bool EqualSampleRates(uint8_t pt1,
      44             :                       uint8_t pt2,
      45             :                       const DecoderDatabase& decoder_database) {
      46           0 :   auto di1 = decoder_database.GetDecoderInfo(pt1);
      47           0 :   auto di2 = decoder_database.GetDecoderInfo(pt2);
      48           0 :   return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
      49             : }
      50             : }  // namespace
      51             : 
      52           0 : PacketBuffer::PacketBuffer(size_t max_number_of_packets,
      53           0 :                            const TickTimer* tick_timer)
      54           0 :     : max_number_of_packets_(max_number_of_packets), tick_timer_(tick_timer) {}
      55             : 
      56             : // Destructor. All packets in the buffer will be destroyed.
      57           0 : PacketBuffer::~PacketBuffer() {
      58           0 :   Flush();
      59           0 : }
      60             : 
      61             : // Flush the buffer. All packets in the buffer will be destroyed.
      62           0 : void PacketBuffer::Flush() {
      63           0 :   buffer_.clear();
      64           0 : }
      65             : 
      66           0 : bool PacketBuffer::Empty() const {
      67           0 :   return buffer_.empty();
      68             : }
      69             : 
      70           0 : int PacketBuffer::InsertPacket(Packet&& packet) {
      71           0 :   if (packet.empty()) {
      72           0 :     LOG(LS_WARNING) << "InsertPacket invalid packet";
      73           0 :     return kInvalidPacket;
      74             :   }
      75             : 
      76           0 :   RTC_DCHECK_GE(packet.priority.codec_level, 0);
      77           0 :   RTC_DCHECK_GE(packet.priority.red_level, 0);
      78             : 
      79           0 :   int return_val = kOK;
      80             : 
      81           0 :   packet.waiting_time = tick_timer_->GetNewStopwatch();
      82             : 
      83           0 :   if (buffer_.size() >= max_number_of_packets_) {
      84             :     // Buffer is full. Flush it.
      85           0 :     Flush();
      86           0 :     LOG(LS_WARNING) << "Packet buffer flushed";
      87           0 :     return_val = kFlushed;
      88             :   }
      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           0 :       buffer_.rbegin(), buffer_.rend(),
      95           0 :       NewTimestampIsLarger(packet));
      96             : 
      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.
     100           0 :   if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
     101           0 :     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           0 :   PacketList::iterator it = rit.base();
     108           0 :   if (it != buffer_.end() && packet.timestamp == it->timestamp) {
     109           0 :     it = buffer_.erase(it);
     110             :   }
     111           0 :   buffer_.insert(it, std::move(packet));  // Insert the packet at that position.
     112             : 
     113           0 :   return return_val;
     114             : }
     115             : 
     116           0 : int 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) {
     121           0 :   bool flushed = false;
     122           0 :   for (auto& packet : *packet_list) {
     123           0 :     if (decoder_database.IsComfortNoise(packet.payload_type)) {
     124           0 :       if (*current_cng_rtp_payload_type &&
     125           0 :           **current_cng_rtp_payload_type != packet.payload_type) {
     126             :         // New CNG payload type implies new codec type.
     127           0 :         *current_rtp_payload_type = rtc::Optional<uint8_t>();
     128           0 :         Flush();
     129           0 :         flushed = true;
     130             :       }
     131             :       *current_cng_rtp_payload_type =
     132           0 :           rtc::Optional<uint8_t>(packet.payload_type);
     133           0 :     } else if (!decoder_database.IsDtmf(packet.payload_type)) {
     134             :       // This must be speech.
     135           0 :       if ((*current_rtp_payload_type &&
     136           0 :            **current_rtp_payload_type != packet.payload_type) ||
     137           0 :           (*current_cng_rtp_payload_type &&
     138           0 :            !EqualSampleRates(packet.payload_type,
     139           0 :                              **current_cng_rtp_payload_type,
     140           0 :                              decoder_database))) {
     141           0 :         *current_cng_rtp_payload_type = rtc::Optional<uint8_t>();
     142           0 :         Flush();
     143           0 :         flushed = true;
     144             :       }
     145           0 :       *current_rtp_payload_type = rtc::Optional<uint8_t>(packet.payload_type);
     146             :     }
     147           0 :     int return_val = InsertPacket(std::move(packet));
     148           0 :     if (return_val == kFlushed) {
     149             :       // The buffer flushed, but this is not an error. We can still continue.
     150           0 :       flushed = true;
     151           0 :     } else if (return_val != kOK) {
     152             :       // An error occurred. Delete remaining packets in list and return.
     153           0 :       packet_list->clear();
     154           0 :       return return_val;
     155             :     }
     156             :   }
     157           0 :   packet_list->clear();
     158           0 :   return flushed ? kFlushed : kOK;
     159             : }
     160             : 
     161           0 : int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
     162           0 :   if (Empty()) {
     163           0 :     return kBufferEmpty;
     164             :   }
     165           0 :   if (!next_timestamp) {
     166           0 :     return kInvalidPointer;
     167             :   }
     168           0 :   *next_timestamp = buffer_.front().timestamp;
     169           0 :   return kOK;
     170             : }
     171             : 
     172           0 : int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
     173             :                                       uint32_t* next_timestamp) const {
     174           0 :   if (Empty()) {
     175           0 :     return kBufferEmpty;
     176             :   }
     177           0 :   if (!next_timestamp) {
     178           0 :     return kInvalidPointer;
     179             :   }
     180           0 :   PacketList::const_iterator it;
     181           0 :   for (it = buffer_.begin(); it != buffer_.end(); ++it) {
     182           0 :     if (it->timestamp >= timestamp) {
     183             :       // Found a packet matching the search.
     184           0 :       *next_timestamp = it->timestamp;
     185           0 :       return kOK;
     186             :     }
     187             :   }
     188           0 :   return kNotFound;
     189             : }
     190             : 
     191           0 : const Packet* PacketBuffer::PeekNextPacket() const {
     192           0 :   return buffer_.empty() ? nullptr : &buffer_.front();
     193             : }
     194             : 
     195           0 : rtc::Optional<Packet> PacketBuffer::GetNextPacket() {
     196           0 :   if (Empty()) {
     197             :     // Buffer is empty.
     198           0 :     return rtc::Optional<Packet>();
     199             :   }
     200             : 
     201           0 :   rtc::Optional<Packet> packet(std::move(buffer_.front()));
     202             :   // Assert that the packet sanity checks in InsertPacket method works.
     203           0 :   RTC_DCHECK(!packet->empty());
     204           0 :   buffer_.pop_front();
     205             : 
     206           0 :   return packet;
     207             : }
     208             : 
     209           0 : int PacketBuffer::DiscardNextPacket() {
     210           0 :   if (Empty()) {
     211           0 :     return kBufferEmpty;
     212             :   }
     213             :   // Assert that the packet sanity checks in InsertPacket method works.
     214           0 :   RTC_DCHECK(!buffer_.front().empty());
     215           0 :   buffer_.pop_front();
     216           0 :   return kOK;
     217             : }
     218             : 
     219           0 : int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
     220             :                                     uint32_t horizon_samples) {
     221           0 :   while (!Empty() && timestamp_limit != buffer_.front().timestamp &&
     222           0 :          IsObsoleteTimestamp(buffer_.front().timestamp, timestamp_limit,
     223             :                              horizon_samples)) {
     224           0 :     if (DiscardNextPacket() != kOK) {
     225           0 :       assert(false);  // Must be ok by design.
     226             :     }
     227             :   }
     228           0 :   return 0;
     229             : }
     230             : 
     231           0 : int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
     232           0 :   return DiscardOldPackets(timestamp_limit, 0);
     233             : }
     234             : 
     235           0 : void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) {
     236           0 :   for (auto it = buffer_.begin(); it != buffer_.end(); /* */) {
     237           0 :     const Packet& packet = *it;
     238           0 :     if (packet.payload_type == payload_type) {
     239           0 :       it = buffer_.erase(it);
     240             :     } else {
     241           0 :       ++it;
     242             :     }
     243             :   }
     244           0 : }
     245             : 
     246           0 : size_t PacketBuffer::NumPacketsInBuffer() const {
     247           0 :   return buffer_.size();
     248             : }
     249             : 
     250           0 : size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
     251           0 :   size_t num_samples = 0;
     252           0 :   size_t last_duration = last_decoded_length;
     253           0 :   for (const Packet& packet : buffer_) {
     254           0 :     if (packet.frame) {
     255             :       // TODO(hlundin): Verify that it's fine to count all packets and remove
     256             :       // this check.
     257           0 :       if (packet.priority != Packet::Priority(0, 0)) {
     258           0 :         continue;
     259             :       }
     260           0 :       size_t duration = packet.frame->Duration();
     261           0 :       if (duration > 0) {
     262           0 :         last_duration = duration;  // Save the most up-to-date (valid) duration.
     263             :       }
     264             :     }
     265           0 :     num_samples += last_duration;
     266             :   }
     267           0 :   return num_samples;
     268             : }
     269             : 
     270           0 : void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
     271           0 :   *num_packets = static_cast<int>(buffer_.size());
     272           0 :   *max_num_packets = static_cast<int>(max_number_of_packets_);
     273           0 : }
     274             : 
     275             : }  // namespace webrtc

Generated by: LCOV version 1.13