diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.cc b/webrtc/modules/audio_coding/codecs/audio_decoder.cc index 8d4a2bc175..9dbecd5e0a 100644 --- a/webrtc/modules/audio_coding/codecs/audio_decoder.cc +++ b/webrtc/modules/audio_coding/codecs/audio_decoder.cc @@ -12,6 +12,8 @@ #include +#include + #include "webrtc/base/array_view.h" #include "webrtc/base/checks.h" #include "webrtc/base/sanitizer.h" @@ -19,6 +21,76 @@ namespace webrtc { +namespace { +class LegacyFrame final : public AudioDecoder::EncodedAudioFrame { + public: + LegacyFrame(AudioDecoder* decoder, + rtc::Buffer&& payload, + bool is_primary_payload) + : decoder_(decoder), + payload_(std::move(payload)), + is_primary_payload_(is_primary_payload) {} + + size_t Duration() const override { + int ret; + if (is_primary_payload_) { + ret = decoder_->PacketDuration(payload_.data(), payload_.size()); + } else { + ret = decoder_->PacketDurationRedundant(payload_.data(), payload_.size()); + } + return (ret < 0) ? 0 : static_cast(ret); + } + + rtc::Optional Decode( + rtc::ArrayView decoded) const override { + AudioDecoder::SpeechType speech_type = AudioDecoder::kSpeech; + int ret; + if (is_primary_payload_) { + ret = decoder_->Decode( + payload_.data(), payload_.size(), decoder_->SampleRateHz(), + decoded.size() * sizeof(int16_t), decoded.data(), &speech_type); + } else { + ret = decoder_->DecodeRedundant( + payload_.data(), payload_.size(), decoder_->SampleRateHz(), + decoded.size() * sizeof(int16_t), decoded.data(), &speech_type); + } + + if (ret < 0) + return rtc::Optional(); + + return rtc::Optional({static_cast(ret), speech_type}); + } + + private: + AudioDecoder* const decoder_; + const rtc::Buffer payload_; + const bool is_primary_payload_; +}; +} // namespace + +AudioDecoder::ParseResult::ParseResult() = default; +AudioDecoder::ParseResult::ParseResult(ParseResult&& b) = default; +AudioDecoder::ParseResult::ParseResult(uint32_t timestamp, + bool primary, + std::unique_ptr frame) + : timestamp(timestamp), primary(primary), frame(std::move(frame)) {} + +AudioDecoder::ParseResult::~ParseResult() = default; + +AudioDecoder::ParseResult& AudioDecoder::ParseResult::operator=( + ParseResult&& b) = default; + +std::vector AudioDecoder::ParsePayload( + rtc::Buffer&& payload, + uint32_t timestamp, + bool is_primary) { + std::vector results; + std::unique_ptr frame( + new LegacyFrame(this, std::move(payload), is_primary)); + results.emplace_back(timestamp, is_primary, std::move(frame)); + return results; +} + int AudioDecoder::Decode(const uint8_t* encoded, size_t encoded_len, int sample_rate_hz, size_t max_decoded_bytes, int16_t* decoded, SpeechType* speech_type) { diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.h b/webrtc/modules/audio_coding/codecs/audio_decoder.h index 13581bc247..9608c321db 100644 --- a/webrtc/modules/audio_coding/codecs/audio_decoder.h +++ b/webrtc/modules/audio_coding/codecs/audio_decoder.h @@ -13,7 +13,13 @@ #include // NULL +#include +#include + +#include "webrtc/base/array_view.h" +#include "webrtc/base/buffer.h" #include "webrtc/base/constructormagic.h" +#include "webrtc/base/optional.h" #include "webrtc/typedefs.h" namespace webrtc { @@ -33,6 +39,55 @@ class AudioDecoder { AudioDecoder() = default; virtual ~AudioDecoder() = default; + class EncodedAudioFrame { + public: + struct DecodeResult { + size_t num_decoded_samples; + SpeechType speech_type; + }; + + virtual ~EncodedAudioFrame() = default; + + // Returns the duration in samples-per-channel of this audio frame. + // If no duration can be ascertained, returns zero. + virtual size_t Duration() const = 0; + + // Decodes this frame of audio and writes the result in |decoded|. + // |decoded| must be large enough to store as many samples as indicated by a + // call to Duration() . On success, returns an rtc::Optional containing the + // total number of samples across all channels, as well as whether the + // decoder produced comfort noise or speech. On failure, returns an empty + // rtc::Optional. Decode may be called at most once per frame object. + virtual rtc::Optional Decode( + rtc::ArrayView decoded) const = 0; + }; + + struct ParseResult { + ParseResult(); + ParseResult(uint32_t timestamp, + bool primary, + std::unique_ptr frame); + ParseResult(ParseResult&& b); + ~ParseResult(); + + ParseResult& operator=(ParseResult&& b); + + // The timestamp of the frame is in samples per channel. + uint32_t timestamp; + bool primary; + std::unique_ptr frame; + }; + + // Let the decoder parse this payload and prepare zero or more decodable + // frames. Each frame must be between 10 ms and 120 ms long. The caller must + // ensure that the AudioDecoder object outlives any frame objects returned by + // this call. The decoder is free to swap or move the data from the |payload| + // buffer. |timestamp| is the input timestamp, in samples, corresponding to + // the start of the payload. + virtual std::vector ParsePayload(rtc::Buffer&& payload, + uint32_t timestamp, + bool is_primary); + // Decodes |encode_len| bytes from |encoded| and writes the result in // |decoded|. The maximum bytes allowed to be written into |decoded| is // |max_decoded_bytes|. Returns the total number of samples across all diff --git a/webrtc/modules/audio_coding/neteq/decision_logic.cc b/webrtc/modules/audio_coding/neteq/decision_logic.cc index 545d1d6245..1c77914bb0 100644 --- a/webrtc/modules/audio_coding/neteq/decision_logic.cc +++ b/webrtc/modules/audio_coding/neteq/decision_logic.cc @@ -108,24 +108,19 @@ Operations DecisionLogic::GetDecision(const SyncBuffer& sync_buffer, bool play_dtmf, size_t generated_noise_samples, bool* reset_decoder) { - if (prev_mode == kModeRfc3389Cng || - prev_mode == kModeCodecInternalCng || - prev_mode == kModeExpand) { - // If last mode was CNG (or Expand, since this could be covering up for - // a lost CNG packet), remember that CNG is on. This is needed if comfort - // noise is interrupted by DTMF. - if (prev_mode == kModeRfc3389Cng) { - cng_state_ = kCngRfc3389On; - } else if (prev_mode == kModeCodecInternalCng) { - cng_state_ = kCngInternalOn; - } + // If last mode was CNG (or Expand, since this could be covering up for + // a lost CNG packet), remember that CNG is on. This is needed if comfort + // noise is interrupted by DTMF. + if (prev_mode == kModeRfc3389Cng) { + cng_state_ = kCngRfc3389On; + } else if (prev_mode == kModeCodecInternalCng) { + cng_state_ = kCngInternalOn; } const size_t samples_left = sync_buffer.FutureLength() - expand.overlap_length(); const size_t cur_size_samples = - samples_left + packet_buffer_.NumSamplesInBuffer(decoder_database_, - decoder_frame_length); + samples_left + packet_buffer_.NumSamplesInBuffer(decoder_frame_length); prev_time_scale_ = prev_time_scale_ && (prev_mode == kModeAccelerateSuccess || diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc index 9c4f580906..d62d44f2b4 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc @@ -14,6 +14,7 @@ #include // memset #include +#include #include #include "webrtc/base/checks.h" @@ -282,6 +283,7 @@ int NetEqImpl::RemovePayloadType(uint8_t rtp_payload_type) { rtc::CritScope lock(&crit_sect_); int ret = decoder_database_->Remove(rtp_payload_type); if (ret == DecoderDatabase::kOK) { + packet_buffer_->DiscardPacketsWithPayloadType(rtp_payload_type); return kOK; } else if (ret == DecoderDatabase::kDecoderNotFound) { error_code_ = kDecoderNotFound; @@ -330,8 +332,7 @@ int NetEqImpl::CurrentDelayMs() const { // Sum up the samples in the packet buffer with the future length of the sync // buffer, and divide the sum by the sample rate. const size_t delay_samples = - packet_buffer_->NumSamplesInBuffer(decoder_database_.get(), - decoder_frame_length_) + + packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) + sync_buffer_->FutureLength(); // The division below will truncate. const int delay_ms = @@ -376,8 +377,7 @@ int NetEqImpl::NetworkStatistics(NetEqNetworkStatistics* stats) { rtc::CritScope lock(&crit_sect_); assert(decoder_database_.get()); const size_t total_samples_in_buffers = - packet_buffer_->NumSamplesInBuffer(decoder_database_.get(), - decoder_frame_length_) + + packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) + sync_buffer_->FutureLength(); assert(delay_manager_.get()); assert(decision_logic_.get()); @@ -662,29 +662,64 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header, receive_timestamp); } + PacketList parsed_packet_list; + while (!packet_list.empty()) { + std::unique_ptr packet(packet_list.front()); + packet_list.pop_front(); + const DecoderDatabase::DecoderInfo* info = + decoder_database_->GetDecoderInfo(packet->header.payloadType); + if (!info) { + LOG(LS_WARNING) << "SplitAudio unknown payload type"; + return kUnknownRtpPayloadType; + } + + if (info->IsComfortNoise()) { + // Carry comfort noise packets along. + parsed_packet_list.push_back(packet.release()); + } else { + std::vector results = + info->GetDecoder()->ParsePayload(std::move(packet->payload), + packet->header.timestamp, + packet->primary); + const RTPHeader& original_header = packet->header; + for (auto& result : results) { + RTC_DCHECK(result.frame); + // Reuse the packet if possible + if (!packet) { + packet.reset(new Packet); + packet->header = original_header; + } + packet->header.timestamp = result.timestamp; + // TODO(ossu): Move from primary to some sort of priority level. + packet->primary = result.primary; + packet->frame = std::move(result.frame); + parsed_packet_list.push_back(packet.release()); + } + } + } + if (nack_enabled_) { RTC_DCHECK(nack_); if (update_sample_rate_and_channels) { nack_->Reset(); } - nack_->UpdateLastReceivedPacket(packet_list.front()->header.sequenceNumber, - packet_list.front()->header.timestamp); + nack_->UpdateLastReceivedPacket( + parsed_packet_list.front()->header.sequenceNumber, + parsed_packet_list.front()->header.timestamp); } // Insert packets in buffer. const size_t buffer_length_before_insert = packet_buffer_->NumPacketsInBuffer(); ret = packet_buffer_->InsertPacketList( - &packet_list, - *decoder_database_, - ¤t_rtp_payload_type_, + &parsed_packet_list, *decoder_database_, ¤t_rtp_payload_type_, ¤t_cng_rtp_payload_type_); if (ret == PacketBuffer::kFlushed) { // Reset DSP timestamp etc. if packet buffer flushed. new_codec_ = true; update_sample_rate_and_channels = true; } else if (ret != PacketBuffer::kOK) { - PacketBuffer::DeleteAllPackets(&packet_list); + PacketBuffer::DeleteAllPackets(&parsed_packet_list); return kOtherError; } @@ -1421,36 +1456,29 @@ int NetEqImpl::DecodeLoop(PacketList* packet_list, const Operations& operation, operation == kFastAccelerate || operation == kMerge || operation == kPreemptiveExpand); packet_list->pop_front(); - const size_t payload_length = packet->payload.size(); - int decode_length; - if (!packet->primary) { - // This is a redundant payload; call the special decoder method. - decode_length = decoder->DecodeRedundant( - packet->payload.data(), packet->payload.size(), fs_hz_, - (decoded_buffer_length_ - *decoded_length) * sizeof(int16_t), - &decoded_buffer_[*decoded_length], speech_type); - } else { - decode_length = decoder->Decode( - packet->payload.data(), packet->payload.size(), fs_hz_, - (decoded_buffer_length_ - *decoded_length) * sizeof(int16_t), - &decoded_buffer_[*decoded_length], speech_type); - } - + auto opt_result = packet->frame->Decode( + rtc::ArrayView(&decoded_buffer_[*decoded_length], + decoded_buffer_length_ - *decoded_length)); delete packet; packet = NULL; - if (decode_length > 0) { - *decoded_length += decode_length; - // Update |decoder_frame_length_| with number of samples per channel. - decoder_frame_length_ = - static_cast(decode_length) / decoder->Channels(); - } else if (decode_length < 0) { + if (opt_result) { + const auto& result = *opt_result; + *speech_type = result.speech_type; + if (result.num_decoded_samples > 0) { + *decoded_length += rtc::checked_cast(result.num_decoded_samples); + // Update |decoder_frame_length_| with number of samples per channel. + decoder_frame_length_ = + result.num_decoded_samples / decoder->Channels(); + } + } else { // Error. - LOG(LS_WARNING) << "Decode " << decode_length << " " << payload_length; + // TODO(ossu): What to put here? + LOG(LS_WARNING) << "Decode error"; *decoded_length = -1; PacketBuffer::DeleteAllPackets(packet_list); break; } - if (*decoded_length > static_cast(decoded_buffer_length_)) { + if (*decoded_length > rtc::checked_cast(decoded_buffer_length_)) { // Guard against overflow. LOG(LS_WARNING) << "Decoded too much."; PacketBuffer::DeleteAllPackets(packet_list); @@ -1892,7 +1920,7 @@ int NetEqImpl::ExtractPackets(size_t required_samples, return -1; } uint32_t first_timestamp = header->timestamp; - int extracted_samples = 0; + size_t extracted_samples = 0; // Packet extraction loop. do { @@ -1908,7 +1936,7 @@ int NetEqImpl::ExtractPackets(size_t required_samples, } stats_.PacketsDiscarded(discard_count); stats_.StoreWaitingTime(packet->waiting_time->ElapsedMs()); - assert(!packet->payload.empty()); + RTC_DCHECK(!packet->empty()); packet_list->push_back(packet); // Store packet in list. if (first_packet) { @@ -1925,27 +1953,24 @@ int NetEqImpl::ExtractPackets(size_t required_samples, } // Store number of extracted samples. - int packet_duration = 0; - AudioDecoder* decoder = decoder_database_->GetDecoder( - packet->header.payloadType); - if (decoder) { - if (packet->primary) { - packet_duration = decoder->PacketDuration(packet->payload.data(), - packet->payload.size()); - } else { - packet_duration = decoder->PacketDurationRedundant( - packet->payload.data(), packet->payload.size()); - stats_.SecondaryDecodedSamples(packet_duration); + size_t packet_duration = 0; + if (packet->frame) { + packet_duration = packet->frame->Duration(); + // TODO(ossu): Is this the correct way to track samples decoded from a + // redundant packet? + if (packet_duration > 0 && !packet->primary) { + stats_.SecondaryDecodedSamples(rtc::checked_cast(packet_duration)); } } else if (!decoder_database_->IsComfortNoise(packet->header.payloadType)) { LOG(LS_WARNING) << "Unknown payload type " << static_cast(packet->header.payloadType); - assert(false); + RTC_NOTREACHED(); } - if (packet_duration <= 0) { + + if (packet_duration == 0) { // Decoder did not return a packet duration. Assume that the packet // contains the same number of samples as the previous one. - packet_duration = rtc::checked_cast(decoder_frame_length_); + packet_duration = decoder_frame_length_; } extracted_samples = packet->header.timestamp - first_timestamp + packet_duration; @@ -1964,8 +1989,7 @@ int NetEqImpl::ExtractPackets(size_t required_samples, } prev_sequence_number = header->sequenceNumber; } - } while (extracted_samples < rtc::checked_cast(required_samples) && - next_packet_available); + } while (extracted_samples < required_samples && next_packet_available); if (extracted_samples > 0) { // Delete old packets only when we are going to decode something. Otherwise, @@ -1975,7 +1999,7 @@ int NetEqImpl::ExtractPackets(size_t required_samples, packet_buffer_->DiscardAllOldPackets(timestamp_); } - return extracted_samples; + return rtc::checked_cast(extracted_samples); } void NetEqImpl::UpdatePlcComponents(int fs_hz, size_t channels) { diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc index c74342bb84..1b8ee82b25 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc @@ -791,50 +791,41 @@ TEST_F(NetEqImplTest, UnsupportedDecoder) { rtp_header.header.timestamp = 0x12345678; rtp_header.header.ssrc = 0x87654321; - class MockAudioDecoder : public AudioDecoder { - public: - // TODO(nisse): Valid overrides commented out, because the gmock - // methods don't use any override declarations, and we want to avoid - // warnings from -Winconsistent-missing-override. See - // http://crbug.com/428099. - void Reset() /* override */ {} - MOCK_CONST_METHOD2(PacketDuration, int(const uint8_t*, size_t)); - MOCK_METHOD5(DecodeInternal, int(const uint8_t*, size_t, int, int16_t*, - SpeechType*)); - int SampleRateHz() const /* override */ { return kSampleRateHz; } - size_t Channels() const /* override */ { return kChannels; } - } decoder_; + ::testing::NiceMock decoder; const uint8_t kFirstPayloadValue = 1; const uint8_t kSecondPayloadValue = 2; - EXPECT_CALL(decoder_, PacketDuration(Pointee(kFirstPayloadValue), - kPayloadLengthBytes)) - .Times(AtLeast(1)) - .WillRepeatedly(Return(kNetEqMaxFrameSize + 1)); + EXPECT_CALL(decoder, + PacketDuration(Pointee(kFirstPayloadValue), kPayloadLengthBytes)) + .Times(AtLeast(1)) + .WillRepeatedly(Return(kNetEqMaxFrameSize + 1)); - EXPECT_CALL(decoder_, - DecodeInternal(Pointee(kFirstPayloadValue), _, _, _, _)) + EXPECT_CALL(decoder, DecodeInternal(Pointee(kFirstPayloadValue), _, _, _, _)) .Times(0); - EXPECT_CALL(decoder_, DecodeInternal(Pointee(kSecondPayloadValue), - kPayloadLengthBytes, - kSampleRateHz, _, _)) + EXPECT_CALL(decoder, DecodeInternal(Pointee(kSecondPayloadValue), + kPayloadLengthBytes, kSampleRateHz, _, _)) .Times(1) - .WillOnce(DoAll(SetArrayArgument<3>(dummy_output, - dummy_output + - kPayloadLengthSamples * kChannels), - SetArgPointee<4>(AudioDecoder::kSpeech), - Return(static_cast( - kPayloadLengthSamples * kChannels)))); + .WillOnce(DoAll( + SetArrayArgument<3>(dummy_output, + dummy_output + kPayloadLengthSamples * kChannels), + SetArgPointee<4>(AudioDecoder::kSpeech), + Return(static_cast(kPayloadLengthSamples * kChannels)))); - EXPECT_CALL(decoder_, PacketDuration(Pointee(kSecondPayloadValue), - kPayloadLengthBytes)) - .Times(AtLeast(1)) - .WillRepeatedly(Return(kNetEqMaxFrameSize)); + EXPECT_CALL(decoder, + PacketDuration(Pointee(kSecondPayloadValue), kPayloadLengthBytes)) + .Times(AtLeast(1)) + .WillRepeatedly(Return(kNetEqMaxFrameSize)); + + EXPECT_CALL(decoder, SampleRateHz()) + .WillRepeatedly(Return(kSampleRateHz)); + + EXPECT_CALL(decoder, Channels()) + .WillRepeatedly(Return(kChannels)); EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder( - &decoder_, NetEqDecoder::kDecoderPCM16B, + &decoder, NetEqDecoder::kDecoderPCM16B, "dummy name", kPayloadType)); // Insert one packet. @@ -868,6 +859,10 @@ TEST_F(NetEqImplTest, UnsupportedDecoder) { EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted)); EXPECT_EQ(kExpectedOutputSize, output.samples_per_channel_ * kChannels); EXPECT_EQ(kChannels, output.num_channels_); + + // Die isn't called through NiceMock (since it's called by the + // MockAudioDecoder constructor), so it needs to be mocked explicitly. + EXPECT_CALL(decoder, Die()); } // This test inserts packets until the buffer is flushed. After that, it asks diff --git a/webrtc/modules/audio_coding/neteq/packet.h b/webrtc/modules/audio_coding/neteq/packet.h index 7119c80237..4e17a88dcd 100644 --- a/webrtc/modules/audio_coding/neteq/packet.h +++ b/webrtc/modules/audio_coding/neteq/packet.h @@ -15,6 +15,7 @@ #include #include "webrtc/base/buffer.h" +#include "webrtc/modules/audio_coding/codecs/audio_decoder.h" #include "webrtc/modules/audio_coding/neteq/tick_timer.h" #include "webrtc/modules/include/module_common_types.h" #include "webrtc/typedefs.h" @@ -28,6 +29,7 @@ struct Packet { rtc::Buffer payload; bool primary = true; // Primary, i.e., not redundant payload. std::unique_ptr waiting_time; + std::unique_ptr frame; Packet(); ~Packet(); @@ -60,6 +62,8 @@ struct Packet { bool operator>(const Packet& rhs) const { return rhs.operator<(*this); } bool operator<=(const Packet& rhs) const { return !operator>(rhs); } bool operator>=(const Packet& rhs) const { return !operator<(rhs); } + + bool empty() const { return !frame && payload.empty(); } }; // A list of packets. diff --git a/webrtc/modules/audio_coding/neteq/packet_buffer.cc b/webrtc/modules/audio_coding/neteq/packet_buffer.cc index 1c8713c487..c5b23dce06 100644 --- a/webrtc/modules/audio_coding/neteq/packet_buffer.cc +++ b/webrtc/modules/audio_coding/neteq/packet_buffer.cc @@ -68,7 +68,7 @@ bool PacketBuffer::Empty() const { } int PacketBuffer::InsertPacket(Packet* packet) { - if (!packet || packet->payload.empty()) { + if (!packet || packet->empty()) { if (packet) { delete packet; } @@ -209,7 +209,7 @@ Packet* PacketBuffer::GetNextPacket(size_t* discard_count) { Packet* packet = buffer_.front(); // Assert that the packet sanity checks in InsertPacket method works. - assert(packet && !packet->payload.empty()); + RTC_DCHECK(packet && !packet->empty()); buffer_.pop_front(); // Discard other packets with the same timestamp. These are duplicates or @@ -237,8 +237,8 @@ int PacketBuffer::DiscardNextPacket() { return kBufferEmpty; } // Assert that the packet sanity checks in InsertPacket method works. - assert(buffer_.front()); - assert(!buffer_.front()->payload.empty()); + RTC_DCHECK(buffer_.front()); + RTC_DCHECK(!buffer_.front()->empty()); DeleteFirstPacket(&buffer_); return kOK; } @@ -260,26 +260,32 @@ int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) { return DiscardOldPackets(timestamp_limit, 0); } +void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) { + for (auto it = buffer_.begin(); it != buffer_.end(); /* */) { + Packet *packet = *it; + if (packet->header.payloadType == payload_type) { + delete packet; + it = buffer_.erase(it); + } else { + ++it; + } + } +} + size_t PacketBuffer::NumPacketsInBuffer() const { return buffer_.size(); } -size_t PacketBuffer::NumSamplesInBuffer(DecoderDatabase* decoder_database, - size_t last_decoded_length) const { - PacketList::const_iterator it; +size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const { size_t num_samples = 0; size_t last_duration = last_decoded_length; - for (it = buffer_.begin(); it != buffer_.end(); ++it) { - Packet* packet = (*it); - AudioDecoder* decoder = - decoder_database->GetDecoder(packet->header.payloadType); - if (decoder) { + for (Packet* packet : buffer_) { + if (packet->frame) { if (!packet->primary) { continue; } - int duration = decoder->PacketDuration(packet->payload.data(), - packet->payload.size()); - if (duration >= 0) { + size_t duration = packet->frame->Duration(); + if (duration > 0) { last_duration = duration; // Save the most up-to-date (valid) duration. } } diff --git a/webrtc/modules/audio_coding/neteq/packet_buffer.h b/webrtc/modules/audio_coding/neteq/packet_buffer.h index be2ecebaa3..ee8c3789db 100644 --- a/webrtc/modules/audio_coding/neteq/packet_buffer.h +++ b/webrtc/modules/audio_coding/neteq/packet_buffer.h @@ -109,14 +109,16 @@ class PacketBuffer { // Discards all packets that are (strictly) older than timestamp_limit. virtual int DiscardAllOldPackets(uint32_t timestamp_limit); + // Removes all packets with a specific payload type from the buffer. + virtual void DiscardPacketsWithPayloadType(uint8_t payload_type); + // Returns the number of packets in the buffer, including duplicates and // redundant packets. virtual size_t NumPacketsInBuffer() const; // Returns the number of samples in the buffer, including samples carried in // duplicate and redundant packets. - virtual size_t NumSamplesInBuffer(DecoderDatabase* decoder_database, - size_t last_decoded_length) const; + virtual size_t NumSamplesInBuffer(size_t last_decoded_length) const; virtual void BufferStat(int* num_packets, int* max_num_packets) const;