blob: 26ae1eda8a0b525db0d91b9cac1a67c37c9bf062 [file] [log] [blame]
/*
* Copyright (c) 2017 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 "api/audio_codecs/builtin_audio_encoder_factory.h"
#include <limits>
#include <memory>
#include <vector>
#include "rtc_base/numerics/safe_conversions.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
class AudioEncoderFactoryTest
: public ::testing::TestWithParam<rtc::scoped_refptr<AudioEncoderFactory>> {
};
TEST_P(AudioEncoderFactoryTest, SupportsAtLeastOneFormat) {
auto factory = GetParam();
auto supported_encoders = factory->GetSupportedEncoders();
EXPECT_FALSE(supported_encoders.empty());
}
TEST_P(AudioEncoderFactoryTest, CanQueryAllSupportedFormats) {
auto factory = GetParam();
auto supported_encoders = factory->GetSupportedEncoders();
for (const auto& spec : supported_encoders) {
auto info = factory->QueryAudioEncoder(spec.format);
EXPECT_TRUE(info);
}
}
TEST_P(AudioEncoderFactoryTest, CanConstructAllSupportedEncoders) {
auto factory = GetParam();
auto supported_encoders = factory->GetSupportedEncoders();
for (const auto& spec : supported_encoders) {
auto info = factory->QueryAudioEncoder(spec.format);
auto encoder = factory->MakeAudioEncoder(127, spec.format, absl::nullopt);
EXPECT_TRUE(encoder);
EXPECT_EQ(encoder->SampleRateHz(), info->sample_rate_hz);
EXPECT_EQ(encoder->NumChannels(), info->num_channels);
EXPECT_EQ(encoder->RtpTimestampRateHz(), spec.format.clockrate_hz);
}
}
TEST_P(AudioEncoderFactoryTest, CanRunAllSupportedEncoders) {
constexpr int kTestPayloadType = 127;
auto factory = GetParam();
auto supported_encoders = factory->GetSupportedEncoders();
for (const auto& spec : supported_encoders) {
auto encoder =
factory->MakeAudioEncoder(kTestPayloadType, spec.format, absl::nullopt);
EXPECT_TRUE(encoder);
encoder->Reset();
const int num_samples = rtc::checked_cast<int>(
encoder->SampleRateHz() * encoder->NumChannels() / 100);
rtc::Buffer out;
rtc::BufferT<int16_t> audio;
audio.SetData(num_samples, [](rtc::ArrayView<int16_t> audio) {
for (size_t i = 0; i != audio.size(); ++i) {
// Just put some numbers in there, ensure they're within range.
audio[i] =
static_cast<int16_t>(i & std::numeric_limits<int16_t>::max());
}
return audio.size();
});
// This is here to stop the test going forever with a broken encoder.
constexpr int kMaxEncodeCalls = 100;
int blocks = 0;
for (; blocks < kMaxEncodeCalls; ++blocks) {
AudioEncoder::EncodedInfo info = encoder->Encode(
blocks * encoder->RtpTimestampRateHz() / 100, audio, &out);
EXPECT_EQ(info.encoded_bytes, out.size());
if (info.encoded_bytes > 0) {
EXPECT_EQ(0u, info.encoded_timestamp);
EXPECT_EQ(kTestPayloadType, info.payload_type);
break;
}
}
ASSERT_LT(blocks, kMaxEncodeCalls);
const unsigned int next_timestamp =
blocks * encoder->RtpTimestampRateHz() / 100;
out.Clear();
for (; blocks < kMaxEncodeCalls; ++blocks) {
AudioEncoder::EncodedInfo info = encoder->Encode(
blocks * encoder->RtpTimestampRateHz() / 100, audio, &out);
EXPECT_EQ(info.encoded_bytes, out.size());
if (info.encoded_bytes > 0) {
EXPECT_EQ(next_timestamp, info.encoded_timestamp);
EXPECT_EQ(kTestPayloadType, info.payload_type);
break;
}
}
ASSERT_LT(blocks, kMaxEncodeCalls);
}
}
INSTANTIATE_TEST_SUITE_P(BuiltinAudioEncoderFactoryTest,
AudioEncoderFactoryTest,
::testing::Values(CreateBuiltinAudioEncoderFactory()));
TEST(BuiltinAudioEncoderFactoryTest, SupportsTheExpectedFormats) {
using ::testing::ElementsAreArray;
// Check that we claim to support the formats we expect from build flags, and
// we've ordered them correctly.
auto factory = CreateBuiltinAudioEncoderFactory();
auto specs = factory->GetSupportedEncoders();
const std::vector<SdpAudioFormat> supported_formats = [&specs] {
std::vector<SdpAudioFormat> formats;
formats.reserve(specs.size());
for (const auto& spec : specs) {
formats.push_back(spec.format);
}
return formats;
}();
const std::vector<SdpAudioFormat> expected_formats = {
#ifdef WEBRTC_CODEC_OPUS
{"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}},
#endif
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
{"isac", 16000, 1},
#endif
#ifdef WEBRTC_CODEC_ISAC
{"isac", 32000, 1},
#endif
{"G722", 8000, 1},
#ifdef WEBRTC_CODEC_ILBC
{"ilbc", 8000, 1},
#endif
{"pcmu", 8000, 1},
{"pcma", 8000, 1}
};
ASSERT_THAT(supported_formats, ElementsAreArray(expected_formats));
}
// Tests that using more channels than the maximum does not work.
TEST(BuiltinAudioEncoderFactoryTest, MaxNrOfChannels) {
rtc::scoped_refptr<AudioEncoderFactory> aef =
CreateBuiltinAudioEncoderFactory();
std::vector<std::string> codecs = {
#ifdef WEBRTC_CODEC_OPUS
"opus",
#endif
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
"isac",
#endif
#ifdef WEBRTC_CODEC_ILBC
"ilbc",
#endif
"pcmu",
"pcma",
"l16",
"G722",
"G711",
};
for (auto codec : codecs) {
EXPECT_FALSE(aef->MakeAudioEncoder(
/*payload_type=*/111,
/*format=*/
SdpAudioFormat(codec, 32000, AudioEncoder::kMaxNumberOfChannels + 1),
/*codec_pair_id=*/absl::nullopt));
}
}
} // namespace webrtc