From d1a10a0f7795213210f9a9f5720167f97bade8c9 Mon Sep 17 00:00:00 2001 From: "henrik.lundin" Date: Wed, 24 Aug 2016 10:58:54 -0700 Subject: [PATCH] Make FakeDecodeFromFile handle codec-internal CNG This implementation interprets payloads of size 1 as codec-internal SID frames, marking the start of a CNG period. Changes were made to other parts of the test payload chain, since it had to make use of the virtual payload size in the case of header-only RTP files. BUG=webrtc:2692 Review-Url: https://codereview.webrtc.org/2275903002 Cr-Commit-Position: refs/heads/master@{#13901} --- .../neteq/tools/fake_decode_from_file.cc | 49 +++++++++++++++++-- .../neteq/tools/fake_decode_from_file.h | 10 ++-- .../neteq/tools/neteq_packet_source_input.cc | 12 ++++- .../neteq/tools/neteq_replacement_input.cc | 10 +++- .../audio_coding/neteq/tools/packet.cc | 2 + 5 files changed, 71 insertions(+), 12 deletions(-) diff --git a/webrtc/modules/audio_coding/neteq/tools/fake_decode_from_file.cc b/webrtc/modules/audio_coding/neteq/tools/fake_decode_from_file.cc index 9ca5fb810b..29beed5644 100644 --- a/webrtc/modules/audio_coding/neteq/tools/fake_decode_from_file.cc +++ b/webrtc/modules/audio_coding/neteq/tools/fake_decode_from_file.cc @@ -19,14 +19,37 @@ namespace test { int FakeDecodeFromFile::DecodeInternal(const uint8_t* encoded, size_t encoded_len, - int /*sample_rate_hz*/, + int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) { - RTC_CHECK_GE(encoded_len, 8u); + if (encoded_len == 0) { + // Decoder is asked to produce codec-internal comfort noise. + RTC_DCHECK(!encoded); // NetEq always sends nullptr in this case. + RTC_DCHECK(cng_mode_); + RTC_DCHECK_GT(last_decoded_length_, 0u); + std::fill_n(decoded, last_decoded_length_, 0); + *speech_type = kComfortNoise; + return last_decoded_length_; + } + + RTC_CHECK_GE(encoded_len, 12u); uint32_t timestamp_to_decode = ByteReader::ReadLittleEndian(encoded); uint32_t samples_to_decode = ByteReader::ReadLittleEndian(&encoded[4]); + if (samples_to_decode == 0) { + // Number of samples in packet is unknown. + if (last_decoded_length_ > 0) { + // Use length of last decoded packet, but since this is the total for all + // channels, we have to divide by 2 in the stereo case. + samples_to_decode = rtc::CheckedDivExact( + last_decoded_length_, static_cast(stereo_ ? 2uL : 1uL)); + } else { + // This is the first packet to decode, and we do not know the length of + // it. Set it to 10 ms. + samples_to_decode = rtc::CheckedDivExact(sample_rate_hz, 100); + } + } if (next_timestamp_from_input_ && timestamp_to_decode != *next_timestamp_from_input_) { @@ -36,10 +59,23 @@ int FakeDecodeFromFile::DecodeInternal(const uint8_t* encoded, RTC_CHECK(input_->Seek(jump)); } - RTC_CHECK(input_->Read(static_cast(samples_to_decode), decoded)); next_timestamp_from_input_ = rtc::Optional(timestamp_to_decode + samples_to_decode); + uint32_t original_payload_size_bytes = + ByteReader::ReadLittleEndian(&encoded[8]); + if (original_payload_size_bytes == 1) { + // This is a comfort noise payload. + RTC_DCHECK_GT(last_decoded_length_, 0u); + std::fill_n(decoded, last_decoded_length_, 0); + *speech_type = kComfortNoise; + cng_mode_ = true; + return last_decoded_length_; + } + + cng_mode_ = false; + RTC_CHECK(input_->Read(static_cast(samples_to_decode), decoded)); + if (stereo_) { InputAudioFile::DuplicateInterleaved(decoded, samples_to_decode, 2, decoded); @@ -47,16 +83,19 @@ int FakeDecodeFromFile::DecodeInternal(const uint8_t* encoded, } *speech_type = kSpeech; - return samples_to_decode; + return last_decoded_length_ = samples_to_decode; } void FakeDecodeFromFile::PrepareEncoded(uint32_t timestamp, size_t samples, + size_t original_payload_size_bytes, rtc::ArrayView encoded) { - RTC_CHECK_GE(encoded.size(), 8u); + RTC_CHECK_GE(encoded.size(), 12u); ByteWriter::WriteLittleEndian(&encoded[0], timestamp); ByteWriter::WriteLittleEndian(&encoded[4], rtc::checked_cast(samples)); + ByteWriter::WriteLittleEndian( + &encoded[8], rtc::checked_cast(original_payload_size_bytes)); } } // namespace test diff --git a/webrtc/modules/audio_coding/neteq/tools/fake_decode_from_file.h b/webrtc/modules/audio_coding/neteq/tools/fake_decode_from_file.h index 2c51998261..69f9c82d38 100644 --- a/webrtc/modules/audio_coding/neteq/tools/fake_decode_from_file.h +++ b/webrtc/modules/audio_coding/neteq/tools/fake_decode_from_file.h @@ -50,11 +50,13 @@ class FakeDecodeFromFile : public AudioDecoder { int16_t* decoded, SpeechType* speech_type) override; - // Helper method. Writes |timestamp| and |samples| to |encoded| in a format - // that the FakeDecpdeFromFile decoder will understand. |encoded| must be at - // least 8 bytes long. + // Helper method. Writes |timestamp|, |samples| and + // |original_payload_size_bytes| to |encoded| in a format that the + // FakeDecodeFromFile decoder will understand. |encoded| must be at least 12 + // bytes long. static void PrepareEncoded(uint32_t timestamp, size_t samples, + size_t original_payload_size_bytes, rtc::ArrayView encoded); private: @@ -62,6 +64,8 @@ class FakeDecodeFromFile : public AudioDecoder { rtc::Optional next_timestamp_from_input_; const int sample_rate_hz_; const bool stereo_; + size_t last_decoded_length_ = 0; + bool cng_mode_ = false; }; } // namespace test diff --git a/webrtc/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc b/webrtc/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc index 5c7c1edd5f..9af20898fd 100644 --- a/webrtc/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc +++ b/webrtc/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc @@ -43,8 +43,16 @@ std::unique_ptr NetEqPacketSourceInput::PopPacket() { } std::unique_ptr packet_data(new PacketData); packet_->ConvertHeader(&packet_data->header); - packet_data->payload.SetData(packet_->payload(), - packet_->payload_length_bytes()); + if (packet_->payload_length_bytes() == 0 && + packet_->virtual_payload_length_bytes() > 0) { + // This is a header-only "dummy" packet. Set the payload to all zeros, with + // length according to the virtual length. + packet_data->payload.SetSize(packet_->virtual_payload_length_bytes()); + std::fill_n(packet_data->payload.data(), packet_data->payload.size(), 0); + } else { + packet_data->payload.SetData(packet_->payload(), + packet_->payload_length_bytes()); + } packet_data->time_ms = packet_->time_ms(); LoadNextPacket(); diff --git a/webrtc/modules/audio_coding/neteq/tools/neteq_replacement_input.cc b/webrtc/modules/audio_coding/neteq/tools/neteq_replacement_input.cc index 2a940fedc4..d5bd97d459 100644 --- a/webrtc/modules/audio_coding/neteq/tools/neteq_replacement_input.cc +++ b/webrtc/modules/audio_coding/neteq/tools/neteq_replacement_input.cc @@ -84,11 +84,17 @@ void NetEqReplacementInput::ReplacePacket() { rtc::Optional next_hdr = source_->NextHeader(); RTC_DCHECK(next_hdr); - uint8_t payload[8]; + uint8_t payload[12]; uint32_t input_frame_size_timestamps = next_hdr->timestamp - packet_->header.header.timestamp; + if (next_hdr->sequenceNumber != packet_->header.header.sequenceNumber + 1) { + // Gap in packet sequence. Cannot estimate payload length based on timestamp + // difference. + input_frame_size_timestamps = 0; + } FakeDecodeFromFile::PrepareEncoded(packet_->header.header.timestamp, - input_frame_size_timestamps, payload); + input_frame_size_timestamps, + packet_->payload.size(), payload); packet_->payload.SetData(payload); packet_->header.header.payloadType = replacement_payload_type_; return; diff --git a/webrtc/modules/audio_coding/neteq/tools/packet.cc b/webrtc/modules/audio_coding/neteq/tools/packet.cc index 46fd0cbc8c..a31d080146 100644 --- a/webrtc/modules/audio_coding/neteq/tools/packet.cc +++ b/webrtc/modules/audio_coding/neteq/tools/packet.cc @@ -14,6 +14,7 @@ #include +#include "webrtc/base/checks.h" #include "webrtc/modules/include/module_common_types.h" #include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" @@ -142,6 +143,7 @@ bool Packet::ParseHeader(const RtpHeaderParser& parser) { payload_ = &payload_memory_[header_.headerLength]; assert(packet_length_bytes_ >= header_.headerLength); payload_length_bytes_ = packet_length_bytes_ - header_.headerLength; + RTC_CHECK_GE(virtual_packet_length_bytes_, packet_length_bytes_); assert(virtual_packet_length_bytes_ >= header_.headerLength); virtual_payload_length_bytes_ = virtual_packet_length_bytes_ - header_.headerLength;