AudioEncoderOpus: Add support for 16 kHz input sample rate

In addition to the 48 kHz that we've always used.

Bug: webrtc:10631
Change-Id: I5e4f6600e39a463d20d3988db098c7e38281f4a0
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/138264
Reviewed-by: Minyue Li <minyue@webrtc.org>
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28074}
This commit is contained in:
Karl Wiberg
2019-05-25 01:43:03 +02:00
committed by Commit Bot
parent 883eefc59e
commit 126f2b37ac
4 changed files with 95 additions and 79 deletions

View File

@ -33,6 +33,7 @@ constexpr int AudioEncoderOpusConfig::kMaxBitrateBps;
AudioEncoderOpusConfig::AudioEncoderOpusConfig() AudioEncoderOpusConfig::AudioEncoderOpusConfig()
: frame_size_ms(kDefaultFrameSizeMs), : frame_size_ms(kDefaultFrameSizeMs),
sample_rate_hz(48000),
num_channels(1), num_channels(1),
application(ApplicationMode::kVoip), application(ApplicationMode::kVoip),
bitrate_bps(32000), bitrate_bps(32000),
@ -55,6 +56,11 @@ AudioEncoderOpusConfig& AudioEncoderOpusConfig::operator=(
bool AudioEncoderOpusConfig::IsOk() const { bool AudioEncoderOpusConfig::IsOk() const {
if (frame_size_ms <= 0 || frame_size_ms % 10 != 0) if (frame_size_ms <= 0 || frame_size_ms % 10 != 0)
return false; return false;
if (sample_rate_hz != 16000 && sample_rate_hz != 48000) {
// Unsupported input sample rate. (libopus supports a few other rates as
// well; we can add support for them when needed.)
return false;
}
if (num_channels < 0 || num_channels >= 255) { if (num_channels < 0 || num_channels >= 255) {
return false; return false;
} }

View File

@ -36,6 +36,7 @@ struct RTC_EXPORT AudioEncoderOpusConfig {
bool IsOk() const; // Checks if the values are currently OK. bool IsOk() const; // Checks if the values are currently OK.
int frame_size_ms; int frame_size_ms;
int sample_rate_hz;
size_t num_channels; size_t num_channels;
enum class ApplicationMode { kVoip, kAudio }; enum class ApplicationMode { kVoip, kAudio };
ApplicationMode application; ApplicationMode application;

View File

@ -50,7 +50,6 @@ constexpr int kOpusBitrateNbBps = 12000;
constexpr int kOpusBitrateWbBps = 20000; constexpr int kOpusBitrateWbBps = 20000;
constexpr int kOpusBitrateFbBps = 32000; constexpr int kOpusBitrateFbBps = 32000;
constexpr int kSampleRateHz = 48000;
constexpr int kRtpTimestampRateHz = 48000; constexpr int kRtpTimestampRateHz = 48000;
constexpr int kDefaultMaxPlaybackRate = 48000; constexpr int kDefaultMaxPlaybackRate = 48000;
@ -288,7 +287,7 @@ void AudioEncoderOpusImpl::AppendSupportedEncoders(
AudioCodecInfo AudioEncoderOpusImpl::QueryAudioEncoder( AudioCodecInfo AudioEncoderOpusImpl::QueryAudioEncoder(
const AudioEncoderOpusConfig& config) { const AudioEncoderOpusConfig& config) {
RTC_DCHECK(config.IsOk()); RTC_DCHECK(config.IsOk());
AudioCodecInfo info(kRtpTimestampRateHz, config.num_channels, AudioCodecInfo info(config.sample_rate_hz, config.num_channels,
*config.bitrate_bps, *config.bitrate_bps,
AudioEncoderOpusConfig::kMinBitrateBps, AudioEncoderOpusConfig::kMinBitrateBps,
AudioEncoderOpusConfig::kMaxBitrateBps); AudioEncoderOpusConfig::kMaxBitrateBps);
@ -460,7 +459,7 @@ AudioEncoderOpusImpl::~AudioEncoderOpusImpl() {
} }
int AudioEncoderOpusImpl::SampleRateHz() const { int AudioEncoderOpusImpl::SampleRateHz() const {
return kSampleRateHz; return config_.sample_rate_hz;
} }
size_t AudioEncoderOpusImpl::NumChannels() const { size_t AudioEncoderOpusImpl::NumChannels() const {
@ -711,7 +710,8 @@ size_t AudioEncoderOpusImpl::Num10msFramesPerPacket() const {
} }
size_t AudioEncoderOpusImpl::SamplesPer10msFrame() const { size_t AudioEncoderOpusImpl::SamplesPer10msFrame() const {
return rtc::CheckedDivExact(kSampleRateHz, 100) * config_.num_channels; return rtc::CheckedDivExact(config_.sample_rate_hz, 100) *
config_.num_channels;
} }
size_t AudioEncoderOpusImpl::SufficientOutputBufferSize() const { size_t AudioEncoderOpusImpl::SufficientOutputBufferSize() const {
@ -742,7 +742,7 @@ bool AudioEncoderOpusImpl::RecreateEncoderInstance(
AudioEncoderOpusConfig::ApplicationMode::kVoip AudioEncoderOpusConfig::ApplicationMode::kVoip
? 0 ? 0
: 1, : 1,
48000)); config.sample_rate_hz));
const int bitrate = GetBitrateBps(config); const int bitrate = GetBitrateBps(config);
RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, bitrate)); RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, bitrate));
RTC_LOG(LS_INFO) << "Set Opus bitrate to " << bitrate << " bps."; RTC_LOG(LS_INFO) << "Set Opus bitrate to " << bitrate << " bps.";

View File

@ -51,7 +51,8 @@ struct AudioEncoderOpusStates {
AudioEncoderOpusConfig config; AudioEncoderOpusConfig config;
}; };
std::unique_ptr<AudioEncoderOpusStates> CreateCodec(size_t num_channels) { std::unique_ptr<AudioEncoderOpusStates> CreateCodec(int sample_rate_hz,
size_t num_channels) {
std::unique_ptr<AudioEncoderOpusStates> states = std::unique_ptr<AudioEncoderOpusStates> states =
absl::make_unique<AudioEncoderOpusStates>(); absl::make_unique<AudioEncoderOpusStates>();
states->mock_audio_network_adaptor = nullptr; states->mock_audio_network_adaptor = nullptr;
@ -70,6 +71,7 @@ std::unique_ptr<AudioEncoderOpusStates> CreateCodec(size_t num_channels) {
AudioEncoderOpusConfig config; AudioEncoderOpusConfig config;
config.frame_size_ms = rtc::CheckedDivExact(kDefaultOpusPacSize, 48); config.frame_size_ms = rtc::CheckedDivExact(kDefaultOpusPacSize, 48);
config.sample_rate_hz = sample_rate_hz;
config.num_channels = num_channels; config.num_channels = num_channels;
config.bitrate_bps = kDefaultOpusRate; config.bitrate_bps = kDefaultOpusRate;
config.application = num_channels == 1 config.application = num_channels == 1
@ -135,28 +137,36 @@ std::unique_ptr<test::AudioLoop> Create10msAudioBlocks(
} // namespace } // namespace
TEST(AudioEncoderOpusTest, DefaultApplicationModeMono) { class AudioEncoderOpusTest : public ::testing::TestWithParam<int> {
auto states = CreateCodec(1); protected:
int sample_rate_hz_{GetParam()};
};
INSTANTIATE_TEST_SUITE_P(Param,
AudioEncoderOpusTest,
::testing::Values(16000, 48000));
TEST_P(AudioEncoderOpusTest, DefaultApplicationModeMono) {
auto states = CreateCodec(sample_rate_hz_, 1);
EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip, EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip,
states->encoder->application()); states->encoder->application());
} }
TEST(AudioEncoderOpusTest, DefaultApplicationModeStereo) { TEST_P(AudioEncoderOpusTest, DefaultApplicationModeStereo) {
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kAudio, EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kAudio,
states->encoder->application()); states->encoder->application());
} }
TEST(AudioEncoderOpusTest, ChangeApplicationMode) { TEST_P(AudioEncoderOpusTest, ChangeApplicationMode) {
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
EXPECT_TRUE( EXPECT_TRUE(
states->encoder->SetApplication(AudioEncoder::Application::kSpeech)); states->encoder->SetApplication(AudioEncoder::Application::kSpeech));
EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip, EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip,
states->encoder->application()); states->encoder->application());
} }
TEST(AudioEncoderOpusTest, ResetWontChangeApplicationMode) { TEST_P(AudioEncoderOpusTest, ResetWontChangeApplicationMode) {
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
// Trigger a reset. // Trigger a reset.
states->encoder->Reset(); states->encoder->Reset();
@ -177,8 +187,8 @@ TEST(AudioEncoderOpusTest, ResetWontChangeApplicationMode) {
states->encoder->application()); states->encoder->application());
} }
TEST(AudioEncoderOpusTest, ToggleDtx) { TEST_P(AudioEncoderOpusTest, ToggleDtx) {
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
// Enable DTX // Enable DTX
EXPECT_TRUE(states->encoder->SetDtx(true)); EXPECT_TRUE(states->encoder->SetDtx(true));
EXPECT_TRUE(states->encoder->GetDtx()); EXPECT_TRUE(states->encoder->GetDtx());
@ -187,9 +197,9 @@ TEST(AudioEncoderOpusTest, ToggleDtx) {
EXPECT_FALSE(states->encoder->GetDtx()); EXPECT_FALSE(states->encoder->GetDtx());
} }
TEST(AudioEncoderOpusTest, TEST_P(AudioEncoderOpusTest,
OnReceivedUplinkBandwidthWithoutAudioNetworkAdaptor) { OnReceivedUplinkBandwidthWithoutAudioNetworkAdaptor) {
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
// Constants are replicated from audio_states->encoderopus.cc. // Constants are replicated from audio_states->encoderopus.cc.
const int kMinBitrateBps = 6000; const int kMinBitrateBps = 6000;
const int kMaxBitrateBps = 510000; const int kMaxBitrateBps = 510000;
@ -246,8 +256,8 @@ void TestSetPacketLossRate(const AudioEncoderOpusStates* states,
} // namespace } // namespace
TEST(AudioEncoderOpusTest, PacketLossRateOptimized) { TEST_P(AudioEncoderOpusTest, PacketLossRateOptimized) {
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
auto I = [](float a, float b) { return IntervalSteps(a, b, 10); }; auto I = [](float a, float b) { return IntervalSteps(a, b, 10); };
constexpr float eps = 1e-8f; constexpr float eps = 1e-8f;
@ -268,10 +278,10 @@ TEST(AudioEncoderOpusTest, PacketLossRateOptimized) {
// clang-format on // clang-format on
} }
TEST(AudioEncoderOpusTest, PacketLossRateLowerBounded) { TEST_P(AudioEncoderOpusTest, PacketLossRateLowerBounded) {
test::ScopedFieldTrials override_field_trials( test::ScopedFieldTrials override_field_trials(
"WebRTC-Audio-OpusMinPacketLossRate/Enabled-5/"); "WebRTC-Audio-OpusMinPacketLossRate/Enabled-5/");
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
auto I = [](float a, float b) { return IntervalSteps(a, b, 10); }; auto I = [](float a, float b) { return IntervalSteps(a, b, 10); };
constexpr float eps = 1e-8f; constexpr float eps = 1e-8f;
@ -290,11 +300,11 @@ TEST(AudioEncoderOpusTest, PacketLossRateLowerBounded) {
// clang-format on // clang-format on
} }
TEST(AudioEncoderOpusTest, NewPacketLossRateOptimization) { TEST_P(AudioEncoderOpusTest, NewPacketLossRateOptimization) {
{ {
test::ScopedFieldTrials override_field_trials( test::ScopedFieldTrials override_field_trials(
"WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled-5-15-0.5/"); "WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled-5-15-0.5/");
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
TestSetPacketLossRate(states.get(), {0.00f}, 0.05f); TestSetPacketLossRate(states.get(), {0.00f}, 0.05f);
TestSetPacketLossRate(states.get(), {0.12f}, 0.06f); TestSetPacketLossRate(states.get(), {0.12f}, 0.06f);
@ -304,7 +314,7 @@ TEST(AudioEncoderOpusTest, NewPacketLossRateOptimization) {
{ {
test::ScopedFieldTrials override_field_trials( test::ScopedFieldTrials override_field_trials(
"WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled/"); "WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled/");
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
TestSetPacketLossRate(states.get(), {0.00f}, 0.01f); TestSetPacketLossRate(states.get(), {0.00f}, 0.01f);
TestSetPacketLossRate(states.get(), {0.12f}, 0.12f); TestSetPacketLossRate(states.get(), {0.12f}, 0.12f);
@ -313,8 +323,8 @@ TEST(AudioEncoderOpusTest, NewPacketLossRateOptimization) {
} }
} }
TEST(AudioEncoderOpusTest, SetReceiverFrameLengthRange) { TEST_P(AudioEncoderOpusTest, SetReceiverFrameLengthRange) {
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
// Before calling to |SetReceiverFrameLengthRange|, // Before calling to |SetReceiverFrameLengthRange|,
// |supported_frame_lengths_ms| should contain only the frame length being // |supported_frame_lengths_ms| should contain only the frame length being
// used. // used.
@ -328,9 +338,9 @@ TEST(AudioEncoderOpusTest, SetReceiverFrameLengthRange) {
EXPECT_THAT(states->encoder->supported_frame_lengths_ms(), ElementsAre(20)); EXPECT_THAT(states->encoder->supported_frame_lengths_ms(), ElementsAre(20));
} }
TEST(AudioEncoderOpusTest, TEST_P(AudioEncoderOpusTest,
InvokeAudioNetworkAdaptorOnReceivedUplinkPacketLossFraction) { InvokeAudioNetworkAdaptorOnReceivedUplinkPacketLossFraction) {
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
states->encoder->EnableAudioNetworkAdaptor("", nullptr); states->encoder->EnableAudioNetworkAdaptor("", nullptr);
auto config = CreateEncoderRuntimeConfig(); auto config = CreateEncoderRuntimeConfig();
@ -346,8 +356,9 @@ TEST(AudioEncoderOpusTest,
CheckEncoderRuntimeConfig(states->encoder.get(), config); CheckEncoderRuntimeConfig(states->encoder.get(), config);
} }
TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedUplinkBandwidth) { TEST_P(AudioEncoderOpusTest,
auto states = CreateCodec(2); InvokeAudioNetworkAdaptorOnReceivedUplinkBandwidth) {
auto states = CreateCodec(sample_rate_hz_, 2);
states->encoder->EnableAudioNetworkAdaptor("", nullptr); states->encoder->EnableAudioNetworkAdaptor("", nullptr);
auto config = CreateEncoderRuntimeConfig(); auto config = CreateEncoderRuntimeConfig();
@ -368,8 +379,8 @@ TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedUplinkBandwidth) {
CheckEncoderRuntimeConfig(states->encoder.get(), config); CheckEncoderRuntimeConfig(states->encoder.get(), config);
} }
TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedRtt) { TEST_P(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedRtt) {
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
states->encoder->EnableAudioNetworkAdaptor("", nullptr); states->encoder->EnableAudioNetworkAdaptor("", nullptr);
auto config = CreateEncoderRuntimeConfig(); auto config = CreateEncoderRuntimeConfig();
@ -384,8 +395,8 @@ TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedRtt) {
CheckEncoderRuntimeConfig(states->encoder.get(), config); CheckEncoderRuntimeConfig(states->encoder.get(), config);
} }
TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedOverhead) { TEST_P(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedOverhead) {
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
states->encoder->EnableAudioNetworkAdaptor("", nullptr); states->encoder->EnableAudioNetworkAdaptor("", nullptr);
auto config = CreateEncoderRuntimeConfig(); auto config = CreateEncoderRuntimeConfig();
@ -400,9 +411,9 @@ TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedOverhead) {
CheckEncoderRuntimeConfig(states->encoder.get(), config); CheckEncoderRuntimeConfig(states->encoder.get(), config);
} }
TEST(AudioEncoderOpusTest, TEST_P(AudioEncoderOpusTest,
PacketLossFractionSmoothedOnSetUplinkPacketLossFraction) { PacketLossFractionSmoothedOnSetUplinkPacketLossFraction) {
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
// The values are carefully chosen so that if no smoothing is made, the test // The values are carefully chosen so that if no smoothing is made, the test
// will fail. // will fail.
@ -426,11 +437,11 @@ TEST(AudioEncoderOpusTest,
EXPECT_FLOAT_EQ(0.05f, states->encoder->packet_loss_rate()); EXPECT_FLOAT_EQ(0.05f, states->encoder->packet_loss_rate());
} }
TEST(AudioEncoderOpusTest, DoNotInvokeSetTargetBitrateIfOverheadUnknown) { TEST_P(AudioEncoderOpusTest, DoNotInvokeSetTargetBitrateIfOverheadUnknown) {
test::ScopedFieldTrials override_field_trials( test::ScopedFieldTrials override_field_trials(
"WebRTC-SendSideBwe-WithOverhead/Enabled/"); "WebRTC-SendSideBwe-WithOverhead/Enabled/");
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
states->encoder->OnReceivedUplinkBandwidth(kDefaultOpusRate * 2, states->encoder->OnReceivedUplinkBandwidth(kDefaultOpusRate * 2,
absl::nullopt); absl::nullopt);
@ -440,11 +451,11 @@ TEST(AudioEncoderOpusTest, DoNotInvokeSetTargetBitrateIfOverheadUnknown) {
EXPECT_EQ(kDefaultOpusRate, states->encoder->GetTargetBitrate()); EXPECT_EQ(kDefaultOpusRate, states->encoder->GetTargetBitrate());
} }
TEST(AudioEncoderOpusTest, OverheadRemovedFromTargetAudioBitrate) { TEST_P(AudioEncoderOpusTest, OverheadRemovedFromTargetAudioBitrate) {
test::ScopedFieldTrials override_field_trials( test::ScopedFieldTrials override_field_trials(
"WebRTC-SendSideBwe-WithOverhead/Enabled/"); "WebRTC-SendSideBwe-WithOverhead/Enabled/");
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
constexpr size_t kOverheadBytesPerPacket = 64; constexpr size_t kOverheadBytesPerPacket = 64;
states->encoder->OnReceivedOverhead(kOverheadBytesPerPacket); states->encoder->OnReceivedOverhead(kOverheadBytesPerPacket);
@ -458,14 +469,14 @@ TEST(AudioEncoderOpusTest, OverheadRemovedFromTargetAudioBitrate) {
states->encoder->GetTargetBitrate()); states->encoder->GetTargetBitrate());
} }
TEST(AudioEncoderOpusTest, BitrateBounded) { TEST_P(AudioEncoderOpusTest, BitrateBounded) {
test::ScopedFieldTrials override_field_trials( test::ScopedFieldTrials override_field_trials(
"WebRTC-SendSideBwe-WithOverhead/Enabled/"); "WebRTC-SendSideBwe-WithOverhead/Enabled/");
constexpr int kMinBitrateBps = 6000; constexpr int kMinBitrateBps = 6000;
constexpr int kMaxBitrateBps = 510000; constexpr int kMaxBitrateBps = 510000;
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
constexpr size_t kOverheadBytesPerPacket = 64; constexpr size_t kOverheadBytesPerPacket = 64;
states->encoder->OnReceivedOverhead(kOverheadBytesPerPacket); states->encoder->OnReceivedOverhead(kOverheadBytesPerPacket);
@ -487,39 +498,39 @@ TEST(AudioEncoderOpusTest, BitrateBounded) {
EXPECT_EQ(kMaxBitrateBps, states->encoder->GetTargetBitrate()); EXPECT_EQ(kMaxBitrateBps, states->encoder->GetTargetBitrate());
} }
TEST(AudioEncoderOpusTest, MinPacketLossRate) { TEST_P(AudioEncoderOpusTest, MinPacketLossRate) {
constexpr float kDefaultMinPacketLossRate = 0.01; constexpr float kDefaultMinPacketLossRate = 0.01;
{ {
test::ScopedFieldTrials override_field_trials( test::ScopedFieldTrials override_field_trials(
"WebRTC-Audio-OpusMinPacketLossRate/Enabled/"); "WebRTC-Audio-OpusMinPacketLossRate/Enabled/");
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
EXPECT_EQ(kDefaultMinPacketLossRate, states->encoder->packet_loss_rate()); EXPECT_EQ(kDefaultMinPacketLossRate, states->encoder->packet_loss_rate());
} }
{ {
test::ScopedFieldTrials override_field_trials( test::ScopedFieldTrials override_field_trials(
"WebRTC-Audio-OpusMinPacketLossRate/Enabled-200/"); "WebRTC-Audio-OpusMinPacketLossRate/Enabled-200/");
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
EXPECT_EQ(kDefaultMinPacketLossRate, states->encoder->packet_loss_rate()); EXPECT_EQ(kDefaultMinPacketLossRate, states->encoder->packet_loss_rate());
} }
{ {
test::ScopedFieldTrials override_field_trials( test::ScopedFieldTrials override_field_trials(
"WebRTC-Audio-OpusMinPacketLossRate/Enabled-50/"); "WebRTC-Audio-OpusMinPacketLossRate/Enabled-50/");
constexpr float kMinPacketLossRate = 0.5; constexpr float kMinPacketLossRate = 0.5;
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
EXPECT_EQ(kMinPacketLossRate, states->encoder->packet_loss_rate()); EXPECT_EQ(kMinPacketLossRate, states->encoder->packet_loss_rate());
} }
} }
TEST(AudioEncoderOpusTest, NewPacketLossRateOptimizer) { TEST_P(AudioEncoderOpusTest, NewPacketLossRateOptimizer) {
{ {
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
auto optimizer = states->encoder->new_packet_loss_optimizer(); auto optimizer = states->encoder->new_packet_loss_optimizer();
EXPECT_EQ(nullptr, optimizer); EXPECT_EQ(nullptr, optimizer);
} }
{ {
test::ScopedFieldTrials override_field_trials( test::ScopedFieldTrials override_field_trials(
"WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled/"); "WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled/");
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
auto optimizer = states->encoder->new_packet_loss_optimizer(); auto optimizer = states->encoder->new_packet_loss_optimizer();
ASSERT_NE(nullptr, optimizer); ASSERT_NE(nullptr, optimizer);
EXPECT_FLOAT_EQ(0.01, optimizer->min_packet_loss_rate()); EXPECT_FLOAT_EQ(0.01, optimizer->min_packet_loss_rate());
@ -529,7 +540,7 @@ TEST(AudioEncoderOpusTest, NewPacketLossRateOptimizer) {
{ {
test::ScopedFieldTrials override_field_trials( test::ScopedFieldTrials override_field_trials(
"WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled-2-50-0.7/"); "WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled-2-50-0.7/");
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
auto optimizer = states->encoder->new_packet_loss_optimizer(); auto optimizer = states->encoder->new_packet_loss_optimizer();
ASSERT_NE(nullptr, optimizer); ASSERT_NE(nullptr, optimizer);
EXPECT_FLOAT_EQ(0.02, optimizer->min_packet_loss_rate()); EXPECT_FLOAT_EQ(0.02, optimizer->min_packet_loss_rate());
@ -562,12 +573,11 @@ TEST(AudioEncoderOpusTest, ConfigComplexityAdaptation) {
} }
// Verifies that the bandwidth adaptation in the config works as intended. // Verifies that the bandwidth adaptation in the config works as intended.
TEST(AudioEncoderOpusTest, ConfigBandwidthAdaptation) { TEST_P(AudioEncoderOpusTest, ConfigBandwidthAdaptation) {
AudioEncoderOpusConfig config; AudioEncoderOpusConfig config;
// Sample rate of Opus. const size_t opus_rate_khz = rtc::CheckedDivExact(sample_rate_hz_, 1000);
constexpr size_t kOpusRateKhz = 48; const std::vector<int16_t> silence(
std::vector<int16_t> silence( opus_rate_khz * config.frame_size_ms * config.num_channels, 0);
kOpusRateKhz * config.frame_size_ms * config.num_channels, 0);
constexpr size_t kMaxBytes = 1000; constexpr size_t kMaxBytes = 1000;
uint8_t bitstream[kMaxBytes]; uint8_t bitstream[kMaxBytes];
@ -578,7 +588,7 @@ TEST(AudioEncoderOpusTest, ConfigBandwidthAdaptation) {
AudioEncoderOpusConfig::ApplicationMode::kVoip AudioEncoderOpusConfig::ApplicationMode::kVoip
? 0 ? 0
: 1, : 1,
48000)); sample_rate_hz_));
// Bitrate below minmum wideband. Expect narrowband. // Bitrate below minmum wideband. Expect narrowband.
config.bitrate_bps = absl::optional<int>(7999); config.bitrate_bps = absl::optional<int>(7999);
@ -620,8 +630,8 @@ TEST(AudioEncoderOpusTest, ConfigBandwidthAdaptation) {
EXPECT_EQ(0, WebRtcOpus_EncoderFree(inst)); EXPECT_EQ(0, WebRtcOpus_EncoderFree(inst));
} }
TEST(AudioEncoderOpusTest, EmptyConfigDoesNotAffectEncoderSettings) { TEST_P(AudioEncoderOpusTest, EmptyConfigDoesNotAffectEncoderSettings) {
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
states->encoder->EnableAudioNetworkAdaptor("", nullptr); states->encoder->EnableAudioNetworkAdaptor("", nullptr);
auto config = CreateEncoderRuntimeConfig(); auto config = CreateEncoderRuntimeConfig();
@ -640,11 +650,11 @@ TEST(AudioEncoderOpusTest, EmptyConfigDoesNotAffectEncoderSettings) {
CheckEncoderRuntimeConfig(states->encoder.get(), config); CheckEncoderRuntimeConfig(states->encoder.get(), config);
} }
TEST(AudioEncoderOpusTest, UpdateUplinkBandwidthInAudioNetworkAdaptor) { TEST_P(AudioEncoderOpusTest, UpdateUplinkBandwidthInAudioNetworkAdaptor) {
auto states = CreateCodec(2); auto states = CreateCodec(sample_rate_hz_, 2);
states->encoder->EnableAudioNetworkAdaptor("", nullptr); states->encoder->EnableAudioNetworkAdaptor("", nullptr);
std::array<int16_t, 480 * 2> audio; const size_t opus_rate_khz = rtc::CheckedDivExact(sample_rate_hz_, 1000);
audio.fill(0); const std::vector<int16_t> audio(opus_rate_khz * 10 * 2, 0);
rtc::Buffer encoded; rtc::Buffer encoded;
EXPECT_CALL(*states->mock_bitrate_smoother, GetAverage()) EXPECT_CALL(*states->mock_bitrate_smoother, GetAverage())
.WillOnce(Return(50000)); .WillOnce(Return(50000));
@ -670,8 +680,8 @@ TEST(AudioEncoderOpusTest, UpdateUplinkBandwidthInAudioNetworkAdaptor) {
} }
} }
TEST(AudioEncoderOpusTest, EncodeAtMinBitrate) { TEST_P(AudioEncoderOpusTest, EncodeAtMinBitrate) {
auto states = CreateCodec(1); auto states = CreateCodec(sample_rate_hz_, 1);
constexpr int kNumPacketsToEncode = 2; constexpr int kNumPacketsToEncode = 2;
auto audio_frames = auto audio_frames =
Create10msAudioBlocks(states->encoder, kNumPacketsToEncode * 20); Create10msAudioBlocks(states->encoder, kNumPacketsToEncode * 20);
@ -900,10 +910,11 @@ TEST(AudioEncoderOpusTest, SetMaxPlaybackRateFb) {
EXPECT_EQ(64000, config.bitrate_bps); EXPECT_EQ(64000, config.bitrate_bps);
} }
TEST(AudioEncoderOpusTest, OpusFlagDtxAsNonSpeech) { TEST_P(AudioEncoderOpusTest, OpusFlagDtxAsNonSpeech) {
// Create encoder with DTX enabled. // Create encoder with DTX enabled.
AudioEncoderOpusConfig config; AudioEncoderOpusConfig config;
config.dtx_enabled = true; config.dtx_enabled = true;
config.sample_rate_hz = sample_rate_hz_;
constexpr int payload_type = 17; constexpr int payload_type = 17;
const auto encoder = AudioEncoderOpus::MakeAudioEncoder(config, payload_type); const auto encoder = AudioEncoderOpus::MakeAudioEncoder(config, payload_type);
@ -911,15 +922,13 @@ TEST(AudioEncoderOpusTest, OpusFlagDtxAsNonSpeech) {
const std::string kInputFileName = const std::string kInputFileName =
webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
test::AudioLoop audio_loop; test::AudioLoop audio_loop;
// Use the file as if it were sampled at 48 kHz. // Use the file as if it were sampled at our desired input rate.
constexpr int kSampleRateHz = 48000; const size_t max_loop_length_samples =
EXPECT_EQ(kSampleRateHz, encoder->SampleRateHz()); sample_rate_hz_ * 10; // Max 10 second loop.
constexpr size_t kMaxLoopLengthSamples = const size_t input_block_size_samples =
kSampleRateHz * 10; // Max 10 second loop. 10 * sample_rate_hz_ / 1000; // 10 ms.
constexpr size_t kInputBlockSizeSamples = EXPECT_TRUE(audio_loop.Init(kInputFileName, max_loop_length_samples,
10 * kSampleRateHz / 1000; // 10 ms. input_block_size_samples));
EXPECT_TRUE(audio_loop.Init(kInputFileName, kMaxLoopLengthSamples,
kInputBlockSizeSamples));
// Encode. // Encode.
AudioEncoder::EncodedInfo info; AudioEncoder::EncodedInfo info;
@ -936,7 +945,7 @@ TEST(AudioEncoderOpusTest, OpusFlagDtxAsNonSpeech) {
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
info = info =
encoder->Encode(rtp_timestamp, audio_loop.GetNextBlock(), &encoded); encoder->Encode(rtp_timestamp, audio_loop.GetNextBlock(), &encoded);
rtp_timestamp += kInputBlockSizeSamples; rtp_timestamp += input_block_size_samples;
} }
// Bookkeeping of number of DTX frames. // Bookkeeping of number of DTX frames.