blob: ac83861c87e09edfdabab61793f611578d8b4545 [file] [log] [blame]
/*
* Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <array>
#include <limits>
#include <vector>
#include "api/array_view.h"
#include "api/audio_codecs/isac/audio_decoder_isac_fix.h"
#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 "test/gtest.h"
namespace webrtc {
namespace {
constexpr int kPayloadType = 42;
constexpr int kBitrateBps = 20000;
enum class IsacImpl { kFixed, kFloat };
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));
}
return v;
}
class IsacApiTest
: public testing::TestWithParam<std::tuple<int, int, IsacImpl, IsacImpl>> {
protected:
IsacApiTest() : input_frame_(GetRandomSamplesVector(GetInputFrameLength())) {}
rtc::ArrayView<const int16_t> GetInputFrame() { return input_frame_; }
int GetSampleRateHz() const { return std::get<0>(GetParam()); }
int GetEncoderFrameLenght() const {
return GetEncoderFrameLenghtMs() * GetSampleRateHz() / 1000;
}
std::unique_ptr<AudioEncoder> CreateEncoder() const {
switch (GetEncoderIsacImpl()) {
case IsacImpl::kFixed: {
AudioEncoderIsacFix::Config config;
config.frame_size_ms = GetEncoderFrameLenghtMs();
RTC_CHECK_EQ(16000, GetSampleRateHz());
return AudioEncoderIsacFix::MakeAudioEncoder(config, kPayloadType);
}
case IsacImpl::kFloat: {
AudioEncoderIsacFloat::Config config;
config.bit_rate = kBitrateBps;
config.frame_size_ms = GetEncoderFrameLenghtMs();
config.sample_rate_hz = GetSampleRateHz();
return AudioEncoderIsacFloat::MakeAudioEncoder(config, kPayloadType);
}
}
}
std::unique_ptr<AudioDecoder> CreateDecoder() const {
switch (GetDecoderIsacImpl()) {
case IsacImpl::kFixed: {
webrtc::AudioDecoderIsacFix::Config config;
RTC_CHECK_EQ(16000, GetSampleRateHz());
return webrtc::AudioDecoderIsacFix::MakeAudioDecoder(config);
}
case IsacImpl::kFloat: {
webrtc::AudioDecoderIsacFloat::Config config;
config.sample_rate_hz = GetSampleRateHz();
return webrtc::AudioDecoderIsacFloat::MakeAudioDecoder(config);
}
}
}
private:
const std::vector<int16_t> input_frame_;
int GetInputFrameLength() const {
return rtc::CheckedDivExact(std::get<0>(GetParam()), 100); // 10 ms.
}
int GetEncoderFrameLenghtMs() const {
int frame_size_ms = std::get<1>(GetParam());
RTC_CHECK(frame_size_ms == 30 || frame_size_ms == 60);
return frame_size_ms;
}
IsacImpl GetEncoderIsacImpl() const { return std::get<2>(GetParam()); }
IsacImpl GetDecoderIsacImpl() const { return std::get<3>(GetParam()); }
};
// Checks that the number of encoded and decoded samples match.
TEST_P(IsacApiTest, EncodeDecode) {
auto encoder = CreateEncoder();
auto decoder = CreateDecoder();
const int encoder_frame_length = GetEncoderFrameLenght();
std::vector<int16_t> out(encoder_frame_length);
size_t num_encoded_samples = 0;
size_t num_decoded_samples = 0;
constexpr int kNumFrames = 12;
for (int i = 0; i < kNumFrames; ++i) {
rtc::Buffer encoded;
auto in = GetInputFrame();
encoder->Encode(/*rtp_timestamp=*/0, in, &encoded);
num_encoded_samples += in.size();
if (encoded.empty()) {
continue;
}
// Decode.
const std::vector<AudioDecoder::ParseResult> parse_result =
decoder->ParsePayload(std::move(encoded), /*timestamp=*/0);
EXPECT_EQ(parse_result.size(), size_t{1});
auto decode_result = parse_result[0].frame->Decode(out);
EXPECT_TRUE(decode_result.has_value());
EXPECT_EQ(out.size(), decode_result->num_decoded_samples);
num_decoded_samples += decode_result->num_decoded_samples;
}
EXPECT_EQ(num_encoded_samples, num_decoded_samples);
}
// Creates tests for different encoder frame lengths and different
// encoder/decoder implementations.
INSTANTIATE_TEST_SUITE_P(
AllTest,
IsacApiTest,
::testing::ValuesIn([] {
std::vector<std::tuple<int, int, IsacImpl, IsacImpl>> cases;
for (int frame_length_ms : {30, 60}) {
for (IsacImpl enc : {IsacImpl::kFloat, IsacImpl::kFixed}) {
for (IsacImpl dec : {IsacImpl::kFloat, IsacImpl::kFixed}) {
cases.push_back({16000, frame_length_ms, enc, dec});
}
}
}
cases.push_back({32000, 30, IsacImpl::kFloat, IsacImpl::kFloat});
return cases;
}()));
} // namespace
} // namespace webrtc