iSAC API wrapper unit test fix

Use speech content instead of white noise and enable target vs measured
bitrate tests.

Bug: webrtc:11360
Change-Id: If8c8e73f943eda14efeb22ba406c7a1bed7d32b4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168660
Commit-Queue: Alessio Bazzica <alessiob@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30630}
This commit is contained in:
Alessio Bazzica 2020-02-27 13:46:51 +01:00 committed by Commit Bot
parent 4a6f81829b
commit a7382f7879
6 changed files with 53 additions and 39 deletions

View file

@ -57,6 +57,7 @@ rtc_source_set("module_fec_api") {
if (rtc_include_tests) {
modules_tests_resources = [
"../resources/audio_coding/testfile16kHz.pcm",
"../resources/audio_coding/testfile32kHz.pcm",
"../resources/audio_coding/teststereo32kHz.pcm",
"../resources/foreman_cif.yuv",
@ -111,6 +112,7 @@ if (rtc_include_tests) {
"../resources/audio_coding/speech_4_channels_48k_one_second.wav",
"../resources/audio_coding/speech_mono_16kHz.pcm",
"../resources/audio_coding/speech_mono_32_48kHz.pcm",
"../resources/audio_coding/testfile16kHz.pcm",
"../resources/audio_coding/testfile32kHz.pcm",
"../resources/audio_coding/testfile_fake_stereo_32kHz.pcm",
"../resources/audio_coding/teststereo32kHz.pcm",

View file

@ -28,7 +28,6 @@ class AudioEncoderIsacT final : public AudioEncoder {
// - 32000 Hz, 30 ms, 10000-56000 bps (if T has super-wideband support)
struct Config {
bool IsOk() const;
int payload_type = 103;
int sample_rate_hz = 16000;
int frame_size_ms = 30;

View file

@ -126,7 +126,7 @@ void AudioEncoderIsacT<T>::RecreateEncoderInstance(const Config& config) {
if (isac_state_)
RTC_CHECK_EQ(0, T::Free(isac_state_));
RTC_CHECK_EQ(0, T::Create(&isac_state_));
RTC_CHECK_EQ(0, T::EncoderInit(isac_state_, 1));
RTC_CHECK_EQ(0, T::EncoderInit(isac_state_, /*coding_mode=*/1));
RTC_CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz));
const int bit_rate = config.bit_rate == 0 ? kDefaultBitRate : config.bit_rate;
RTC_CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms));

View file

@ -9,7 +9,7 @@
*/
#include <array>
#include <limits>
#include <memory>
#include <vector>
#include "absl/strings/string_view.h"
@ -18,9 +18,11 @@
#include "api/audio_codecs/isac/audio_decoder_isac_float.h"
#include "api/audio_codecs/isac/audio_encoder_isac_fix.h"
#include "api/audio_codecs/isac/audio_encoder_isac_float.h"
#include "rtc_base/random.h"
#include "modules/audio_coding/test/PCMFile.h"
#include "rtc_base/checks.h"
#include "rtc_base/strings/string_builder.h"
#include "test/gtest.h"
#include "test/testsupport/file_utils.h"
namespace webrtc {
namespace {
@ -38,15 +40,31 @@ absl::string_view IsacImplToString(IsacImpl impl) {
}
}
std::vector<int16_t> GetRandomSamplesVector(size_t size) {
constexpr int32_t kMin = std::numeric_limits<int16_t>::min();
constexpr int32_t kMax = std::numeric_limits<int16_t>::max();
std::vector<int16_t> v(size);
Random gen(/*seed=*/42);
for (auto& x : v) {
x = static_cast<int16_t>(gen.Rand(kMin, kMax));
std::unique_ptr<PCMFile> GetPcmTestFileReader(int sample_rate_hz) {
std::string filename;
switch (sample_rate_hz) {
case 16000:
filename = test::ResourcePath("audio_coding/testfile16kHz", "pcm");
break;
case 32000:
filename = test::ResourcePath("audio_coding/testfile32kHz", "pcm");
break;
default:
RTC_NOTREACHED() << "No test file available for " << sample_rate_hz
<< " Hz.";
}
return v;
auto pcm_file = std::make_unique<PCMFile>();
pcm_file->ReadStereo(false);
pcm_file->Open(filename, sample_rate_hz, "rb", /*auto_rewind=*/true);
pcm_file->FastForward(/*num_10ms_blocks=*/100); // Skip initial silence.
RTC_CHECK(!pcm_file->EndOfFile());
return pcm_file;
}
// Returns a view to the interleaved samples of an AudioFrame object.
rtc::ArrayView<const int16_t> AudioFrameToView(const AudioFrame& audio_frame) {
return {audio_frame.data(),
audio_frame.samples_per_channel() * audio_frame.num_channels()};
}
std::unique_ptr<AudioEncoder> CreateEncoder(IsacImpl impl,
@ -119,6 +137,7 @@ TEST_P(EncoderTest, TestConfig) {
// checks that the number of produces bytes in the first case is less than that
// of the second case.
TEST_P(EncoderTest, TestDifferentBitrates) {
auto pcm_file = GetPcmTestFileReader(GetSampleRateHz());
constexpr int kLowBps = 20000;
constexpr int kHighBps = 25000;
auto encoder_low = CreateEncoder(GetIsacImpl(), GetSampleRateHz(),
@ -127,39 +146,39 @@ TEST_P(EncoderTest, TestDifferentBitrates) {
GetFrameSizeMs(), kHighBps);
int num_bytes_low = 0;
int num_bytes_high = 0;
const auto in = GetRandomSamplesVector(
/*size=*/rtc::CheckedDivExact(GetSampleRateHz(), 100));
constexpr int kNumFrames = 12;
for (int i = 0; i < kNumFrames; ++i) {
AudioFrame in;
pcm_file->Read10MsData(in);
rtc::Buffer low, high;
encoder_low->Encode(/*rtp_timestamp=*/0, in, &low);
encoder_high->Encode(/*rtp_timestamp=*/0, in, &high);
encoder_low->Encode(/*rtp_timestamp=*/0, AudioFrameToView(in), &low);
encoder_high->Encode(/*rtp_timestamp=*/0, AudioFrameToView(in), &high);
num_bytes_low += low.size();
num_bytes_high += high.size();
}
EXPECT_LT(num_bytes_low, num_bytes_high);
}
// Checks that the target and the measured bitrates are within tolerance.
// TODO(webrtc:11360): Add CBR flag to the config and re-enable test with CBR.
TEST_P(EncoderTest, DISABLED_TestBitrateNearTarget) {
const auto in = GetRandomSamplesVector(
/*size=*/rtc::CheckedDivExact(GetSampleRateHz(), 100)); // 10 ms.
// Checks that, given a target bitrate, the encoder does not overshoot too much.
TEST_P(EncoderTest, DoNotOvershootTargetBitrate) {
for (int bitrate_bps : {10000, 15000, 20000, 26000, 32000}) {
SCOPED_TRACE(bitrate_bps);
auto pcm_file = GetPcmTestFileReader(GetSampleRateHz());
auto e = CreateEncoder(GetIsacImpl(), GetSampleRateHz(), GetFrameSizeMs(),
bitrate_bps);
int num_bytes = 0;
constexpr int kNumFrames = 60;
constexpr int kNumFrames = 200; // 2 seconds.
for (int i = 0; i < kNumFrames; ++i) {
AudioFrame in;
pcm_file->Read10MsData(in);
rtc::Buffer encoded;
e->Encode(/*rtp_timestamp=*/0, in, &encoded);
e->Encode(/*rtp_timestamp=*/0, AudioFrameToView(in), &encoded);
num_bytes += encoded.size();
}
// Inverse of the duration of |kNumFrames| 10 ms frames (unit: seconds^-1).
constexpr float kAudioDurationInv = 100.f / kNumFrames;
const int measured_bitrate_bps = 8 * num_bytes * kAudioDurationInv;
EXPECT_NEAR(bitrate_bps, measured_bitrate_bps, 1000); // Max 1 kbps.
EXPECT_LT(measured_bitrate_bps, bitrate_bps + 2000); // Max 2 kbps extra.
}
}
@ -227,27 +246,19 @@ struct EncoderDecoderPairTestParams {
class EncoderDecoderPairTest
: public testing::TestWithParam<EncoderDecoderPairTestParams> {
protected:
EncoderDecoderPairTest()
: input_frame_(GetRandomSamplesVector(GetInputFrameSize())) {}
rtc::ArrayView<const int16_t> GetInputFrame() { return input_frame_; }
EncoderDecoderPairTest() = default;
int GetSampleRateHz() const { return GetParam().sample_rate_hz; }
int GetEncoderFrameSizeMs() const { return GetParam().frame_size_ms; }
IsacImpl GetEncoderIsacImpl() const { return GetParam().encoder_impl; }
IsacImpl GetDecoderIsacImpl() const { return GetParam().decoder_impl; }
int GetEncoderFrameSize() const {
return GetEncoderFrameSizeMs() * GetSampleRateHz() / 1000;
}
private:
const std::vector<int16_t> input_frame_;
int GetInputFrameSize() const {
return rtc::CheckedDivExact(GetParam().sample_rate_hz, 100); // 10 ms.
}
};
// Checks that the number of encoded and decoded samples match.
TEST_P(EncoderDecoderPairTest, EncodeDecode) {
auto pcm_file = GetPcmTestFileReader(GetSampleRateHz());
auto encoder = CreateEncoder(GetEncoderIsacImpl(), GetSampleRateHz(),
GetEncoderFrameSizeMs(), /*bitrate_bps=*/20000);
auto decoder = CreateDecoder(GetDecoderIsacImpl(), GetSampleRateHz());
@ -257,10 +268,11 @@ TEST_P(EncoderDecoderPairTest, EncodeDecode) {
size_t num_decoded_samples = 0;
constexpr int kNumFrames = 12;
for (int i = 0; i < kNumFrames; ++i) {
AudioFrame in;
pcm_file->Read10MsData(in);
rtc::Buffer encoded;
auto in = GetInputFrame();
encoder->Encode(/*rtp_timestamp=*/0, in, &encoded);
num_encoded_samples += in.size();
encoder->Encode(/*rtp_timestamp=*/0, AudioFrameToView(in), &encoded);
num_encoded_samples += in.samples_per_channel();
if (encoded.empty()) {
continue;
}

View file

@ -304,7 +304,7 @@ typedef struct {
int16_t maxRateInBytes;
/*---
If set to 1 iSAC will not addapt the frame-size, if used in
If set to 1 iSAC will not adapt the frame-size, if used in
channel-adaptive mode. The initial value will be used for all rates.
---*/
int16_t enforceFrameSize;
@ -312,7 +312,7 @@ typedef struct {
/*-----
This records the BWE index the encoder injected into the bit-stream.
It will be used in RCU. The same BWE index of main payload will be in
the redundant payload. We can not retrive it from BWE because it is
the redundant payload. We can not retrieve it from BWE because it is
a recursive procedure (WebRtcIsac_GetDownlinkBwJitIndexImpl) and has to be
called only once per each encode.
-----*/

View file

@ -0,0 +1 @@
0d2702e5c350c2a4ad3a641c4d96271e8aa12e6c