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}
This commit is contained in:
henrik.lundin
2016-08-24 10:58:54 -07:00
committed by Commit bot
parent f02207dde9
commit d1a10a0f77
5 changed files with 71 additions and 12 deletions

View File

@ -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<uint32_t>::ReadLittleEndian(encoded);
uint32_t samples_to_decode =
ByteReader<uint32_t>::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<size_t>(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<size_t>(samples_to_decode), decoded));
next_timestamp_from_input_ =
rtc::Optional<uint32_t>(timestamp_to_decode + samples_to_decode);
uint32_t original_payload_size_bytes =
ByteReader<uint32_t>::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<size_t>(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<uint8_t> encoded) {
RTC_CHECK_GE(encoded.size(), 8u);
RTC_CHECK_GE(encoded.size(), 12u);
ByteWriter<uint32_t>::WriteLittleEndian(&encoded[0], timestamp);
ByteWriter<uint32_t>::WriteLittleEndian(&encoded[4],
rtc::checked_cast<uint32_t>(samples));
ByteWriter<uint32_t>::WriteLittleEndian(
&encoded[8], rtc::checked_cast<uint32_t>(original_payload_size_bytes));
}
} // namespace test

View File

@ -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<uint8_t> encoded);
private:
@ -62,6 +64,8 @@ class FakeDecodeFromFile : public AudioDecoder {
rtc::Optional<uint32_t> next_timestamp_from_input_;
const int sample_rate_hz_;
const bool stereo_;
size_t last_decoded_length_ = 0;
bool cng_mode_ = false;
};
} // namespace test

View File

@ -43,8 +43,16 @@ std::unique_ptr<NetEqInput::PacketData> NetEqPacketSourceInput::PopPacket() {
}
std::unique_ptr<PacketData> packet_data(new PacketData);
packet_->ConvertHeader(&packet_data->header);
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();

View File

@ -84,11 +84,17 @@ void NetEqReplacementInput::ReplacePacket() {
rtc::Optional<RTPHeader> 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;

View File

@ -14,6 +14,7 @@
#include <memory>
#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;