diff --git a/webrtc/api/audio_codecs/opus/BUILD.gn b/webrtc/api/audio_codecs/opus/BUILD.gn new file mode 100644 index 0000000000..426403003e --- /dev/null +++ b/webrtc/api/audio_codecs/opus/BUILD.gn @@ -0,0 +1,43 @@ +# 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. + +import("../../../webrtc.gni") +if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") +} + +rtc_static_library("audio_encoder_opus_config") { + sources = [ + "audio_encoder_opus_config.cc", + "audio_encoder_opus_config.h", + ] + deps = [ + "../../../base:rtc_base_approved", + ] + defines = [] + if (rtc_opus_variable_complexity) { + defines += [ "WEBRTC_OPUS_VARIABLE_COMPLEXITY=1" ] + } else { + defines += [ "WEBRTC_OPUS_VARIABLE_COMPLEXITY=0" ] + } +} + +rtc_static_library("audio_encoder_opus") { + sources = [ + "audio_encoder_opus.cc", + "audio_encoder_opus.h", + ] + deps = [ + ":audio_encoder_opus_config", + "..:audio_codecs_api", + "../../../base:protobuf_utils", # TODO(kwiberg): Why is this needed? + "../../../base:rtc_base_approved", + "../../../modules/audio_coding:webrtc_opus", + ] +} diff --git a/webrtc/api/audio_codecs/opus/audio_encoder_opus.cc b/webrtc/api/audio_codecs/opus/audio_encoder_opus.cc new file mode 100644 index 0000000000..0969561ed1 --- /dev/null +++ b/webrtc/api/audio_codecs/opus/audio_encoder_opus.cc @@ -0,0 +1,52 @@ +/* + * 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 "webrtc/api/audio_codecs/opus/audio_encoder_opus.h" + +#include +#include + +#include "webrtc/base/ptr_util.h" +#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h" + +namespace webrtc { + +rtc::Optional AudioEncoderOpus::SdpToConfig( + const SdpAudioFormat& format) { + return AudioEncoderOpusImpl::SdpToConfig(format); +} + +void AudioEncoderOpus::AppendSupportedEncoders( + std::vector* specs) { + const SdpAudioFormat fmt = { + "opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}}; + const AudioCodecInfo info = QueryAudioEncoder(*SdpToConfig(fmt)); + specs->push_back({fmt, info}); +} + +AudioCodecInfo AudioEncoderOpus::QueryAudioEncoder( + const AudioEncoderOpusConfig& config) { + RTC_DCHECK(config.IsOk()); + AudioCodecInfo info(48000, config.num_channels, config.bitrate_bps, + AudioEncoderOpusConfig::kMinBitrateBps, + AudioEncoderOpusConfig::kMaxBitrateBps); + info.allow_comfort_noise = false; + info.supports_network_adaption = true; + return info; +} + +std::unique_ptr AudioEncoderOpus::MakeAudioEncoder( + const AudioEncoderOpusConfig& config, + int payload_type) { + RTC_DCHECK(config.IsOk()); + return rtc::MakeUnique(config, payload_type); +} + +} // namespace webrtc diff --git a/webrtc/api/audio_codecs/opus/audio_encoder_opus.h b/webrtc/api/audio_codecs/opus/audio_encoder_opus.h new file mode 100644 index 0000000000..e5bee31646 --- /dev/null +++ b/webrtc/api/audio_codecs/opus/audio_encoder_opus.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#ifndef WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_H_ +#define WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_H_ + +#include +#include + +#include "webrtc/api/audio_codecs/audio_encoder.h" +#include "webrtc/api/audio_codecs/audio_format.h" +#include "webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h" +#include "webrtc/base/optional.h" + +namespace webrtc { + +// Opus encoder API for use as a template parameter to +// CreateAudioEncoderFactory<...>(). +// +// NOTE: This struct is still under development and may change without notice. +struct AudioEncoderOpus { + static rtc::Optional SdpToConfig( + const SdpAudioFormat& audio_format); + static void AppendSupportedEncoders(std::vector* specs); + static AudioCodecInfo QueryAudioEncoder(const AudioEncoderOpusConfig& config); + static std::unique_ptr MakeAudioEncoder( + const AudioEncoderOpusConfig&, + int payload_type); +}; + +} // namespace webrtc + +#endif // WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_H_ diff --git a/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.cc b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.cc new file mode 100644 index 0000000000..d4e12e8ce8 --- /dev/null +++ b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.cc @@ -0,0 +1,67 @@ +/* + * 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 "webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h" + +namespace webrtc { + +namespace { + +#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM) +// If we are on Android, iOS and/or ARM, use a lower complexity setting by +// default, to save encoder complexity. +constexpr int kDefaultComplexity = 5; +#else +constexpr int kDefaultComplexity = 9; +#endif + +constexpr int kDefaultLowRateComplexity = + WEBRTC_OPUS_VARIABLE_COMPLEXITY ? 9 : kDefaultComplexity; + +} // namespace + +constexpr int AudioEncoderOpusConfig::kDefaultFrameSizeMs; +constexpr int AudioEncoderOpusConfig::kMinBitrateBps; +constexpr int AudioEncoderOpusConfig::kMaxBitrateBps; + +AudioEncoderOpusConfig::AudioEncoderOpusConfig() + : frame_size_ms(kDefaultFrameSizeMs), + num_channels(1), + application(ApplicationMode::kVoip), + bitrate_bps(32000), + fec_enabled(false), + cbr_enabled(false), + max_playback_rate_hz(48000), + complexity(kDefaultComplexity), + low_rate_complexity(kDefaultLowRateComplexity), + complexity_threshold_bps(12500), + complexity_threshold_window_bps(1500), + dtx_enabled(false), + uplink_bandwidth_update_interval_ms(200) {} +AudioEncoderOpusConfig::AudioEncoderOpusConfig(const AudioEncoderOpusConfig&) = + default; +AudioEncoderOpusConfig::~AudioEncoderOpusConfig() = default; +AudioEncoderOpusConfig& AudioEncoderOpusConfig::operator=( + const AudioEncoderOpusConfig&) = default; + +bool AudioEncoderOpusConfig::IsOk() const { + if (frame_size_ms <= 0 || frame_size_ms % 10 != 0) + return false; + if (num_channels != 1 && num_channels != 2) + return false; + if (bitrate_bps < kMinBitrateBps || bitrate_bps > kMaxBitrateBps) + return false; + if (complexity < 0 || complexity > 10) + return false; + if (low_rate_complexity < 0 || low_rate_complexity > 10) + return false; + return true; +} +} // namespace webrtc diff --git a/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h new file mode 100644 index 0000000000..1726c69d6e --- /dev/null +++ b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_CONFIG_H_ +#define WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_CONFIG_H_ + +#include + +#include + +namespace webrtc { + +// NOTE: This struct is still under development and may change without notice. +struct AudioEncoderOpusConfig { + static constexpr int kDefaultFrameSizeMs = 20; + + // Opus API allows a min bitrate of 500bps, but Opus documentation suggests + // bitrate should be in the range of 6000 to 510000, inclusive. + static constexpr int kMinBitrateBps = 6000; + static constexpr int kMaxBitrateBps = 510000; + + AudioEncoderOpusConfig(); + AudioEncoderOpusConfig(const AudioEncoderOpusConfig&); + ~AudioEncoderOpusConfig(); + AudioEncoderOpusConfig& operator=(const AudioEncoderOpusConfig&); + + bool IsOk() const; // Checks if the values are currently OK. + + int frame_size_ms; + size_t num_channels; + enum class ApplicationMode { kVoip, kAudio }; + ApplicationMode application; + int bitrate_bps; + bool fec_enabled; + bool cbr_enabled; + int max_playback_rate_hz; + + // |complexity| is used when the bitrate goes above + // |complexity_threshold_bps| + |complexity_threshold_window_bps|; + // |low_rate_complexity| is used when the bitrate falls below + // |complexity_threshold_bps| - |complexity_threshold_window_bps|. In the + // interval in the middle, we keep using the most recent of the two + // complexity settings. + int complexity; + int low_rate_complexity; + int complexity_threshold_bps; + int complexity_threshold_window_bps; + + bool dtx_enabled; + std::vector supported_frame_lengths_ms; + int uplink_bandwidth_update_interval_ms; +}; + +} // namespace webrtc + +#endif // WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_CONFIG_H_ diff --git a/webrtc/api/audio_codecs/test/BUILD.gn b/webrtc/api/audio_codecs/test/BUILD.gn index 08d527d2b0..3a48a33b53 100644 --- a/webrtc/api/audio_codecs/test/BUILD.gn +++ b/webrtc/api/audio_codecs/test/BUILD.gn @@ -26,6 +26,7 @@ if (rtc_include_tests) { "../../../test:test_support", "../g722:audio_decoder_g722", "../g722:audio_encoder_g722", + "../opus:audio_encoder_opus", "//testing/gmock", ] } diff --git a/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc b/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc index abca96852b..4a7e291ed4 100644 --- a/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc +++ b/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc @@ -10,6 +10,7 @@ #include "webrtc/api/audio_codecs/audio_encoder_factory_template.h" #include "webrtc/api/audio_codecs/g722/audio_encoder_g722.h" +#include "webrtc/api/audio_codecs/opus/audio_encoder_opus.h" #include "webrtc/base/ptr_util.h" #include "webrtc/test/gmock.h" #include "webrtc/test/gtest.h" @@ -133,4 +134,26 @@ TEST(AudioEncoderFactoryTemplateTest, G722) { EXPECT_EQ(16000, enc->SampleRateHz()); } +TEST(AudioEncoderFactoryTemplateTest, Opus) { + auto factory = CreateAudioEncoderFactory(); + AudioCodecInfo info = {48000, 1, 32000, 6000, 510000}; + info.allow_comfort_noise = false; + info.supports_network_adaption = true; + EXPECT_THAT( + factory->GetSupportedEncoders(), + testing::ElementsAre(AudioCodecSpec{ + {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}}, + info})); + EXPECT_EQ(rtc::Optional(), + factory->QueryAudioEncoder({"foo", 8000, 1})); + EXPECT_EQ( + rtc::Optional(info), + factory->QueryAudioEncoder( + {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}})); + EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"bar", 16000, 1})); + auto enc = factory->MakeAudioEncoder(17, {"opus", 48000, 2}); + ASSERT_NE(nullptr, enc); + EXPECT_EQ(48000, enc->SampleRateHz()); +} + } // namespace webrtc diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn index afd2720f39..c0da0e36c9 100644 --- a/webrtc/modules/audio_coding/BUILD.gn +++ b/webrtc/modules/audio_coding/BUILD.gn @@ -828,6 +828,7 @@ rtc_static_library("webrtc_opus") { ":audio_network_adaptor", "../..:webrtc_common", "../../api/audio_codecs:audio_codecs_api", + "../../api/audio_codecs/opus:audio_encoder_opus_config", "../../base:protobuf_utils", "../../base:rtc_base_approved", "../../base:rtc_numerics", @@ -839,11 +840,6 @@ rtc_static_library("webrtc_opus") { ] defines = audio_codec_defines - if (rtc_opus_variable_complexity) { - defines += [ "WEBRTC_OPUS_VARIABLE_COMPLEXITY=1" ] - } else { - defines += [ "WEBRTC_OPUS_VARIABLE_COMPLEXITY=0" ] - } if (rtc_build_opus) { public_deps += [ rtc_opus_dir ] @@ -1484,6 +1480,7 @@ if (rtc_include_tests) { ":neteq", ":neteq_tools", "../../api/audio_codecs:audio_codecs_api", + "../../api/audio_codecs/opus:audio_encoder_opus", "../../base:protobuf_utils", "../../common_audio", "../../test:test_main", diff --git a/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc b/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc index 236501a6f9..0dc89dcd94 100644 --- a/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc +++ b/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc @@ -1501,7 +1501,7 @@ TEST_F(AcmSenderBitExactnessOldApi, MAYBE_Opus_stereo_20ms) { TEST_F(AcmSenderBitExactnessNewApi, MAYBE_OpusFromFormat_stereo_20ms) { const SdpAudioFormat kOpusFormat("opus", 48000, 2, {{"stereo", "1"}}); - AudioEncoderOpus encoder(120, kOpusFormat); + AudioEncoderOpusImpl encoder(120, kOpusFormat); ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder(&encoder, 120)); Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( "855041f2490b887302bce9d544731849", @@ -1547,7 +1547,7 @@ TEST_F(AcmSenderBitExactnessOldApi, MAYBE_Opus_stereo_20ms_voip) { TEST_F(AcmSenderBitExactnessNewApi, MAYBE_OpusFromFormat_stereo_20ms_voip) { const SdpAudioFormat kOpusFormat("opus", 48000, 2, {{"stereo", "1"}}); - AudioEncoderOpus encoder(120, kOpusFormat); + AudioEncoderOpusImpl encoder(120, kOpusFormat); ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder(&encoder, 120)); // If not set, default will be kAudio in case of stereo. EXPECT_EQ(0, send_test_->acm()->SetOpusApplication(kVoip)); @@ -1664,7 +1664,7 @@ TEST_F(AcmSetBitRateOldApi, MAYBE_Opus_48khz_20ms_10kbps) { } TEST_F(AcmSetBitRateNewApi, MAYBE_OpusFromFormat_48khz_20ms_10kbps) { - AudioEncoderOpus encoder( + AudioEncoderOpusImpl encoder( 107, SdpAudioFormat("opus", 48000, 2, {{"maxaveragebitrate", "10000"}})); ASSERT_TRUE(SetUpSender()); ASSERT_TRUE(RegisterExternalSendCodec(&encoder, 107)); @@ -1693,7 +1693,7 @@ TEST_F(AcmSetBitRateOldApi, MAYBE_Opus_48khz_20ms_50kbps) { } TEST_F(AcmSetBitRateNewApi, MAYBE_OpusFromFormat_48khz_20ms_50kbps) { - AudioEncoderOpus encoder( + AudioEncoderOpusImpl encoder( 107, SdpAudioFormat("opus", 48000, 2, {{"maxaveragebitrate", "50000"}})); ASSERT_TRUE(SetUpSender()); ASSERT_TRUE(RegisterExternalSendCodec(&encoder, 107)); @@ -1721,7 +1721,7 @@ TEST_F(AcmSetBitRateOldApi, MAYBE_Opus_48khz_20ms_100kbps) { } TEST_F(AcmSetBitRateNewApi, MAYBE_OpusFromFormat_48khz_20ms_100kbps) { - AudioEncoderOpus encoder( + AudioEncoderOpusImpl encoder( 107, SdpAudioFormat("opus", 48000, 2, {{"maxaveragebitrate", "100000"}})); ASSERT_TRUE(SetUpSender()); ASSERT_TRUE(RegisterExternalSendCodec(&encoder, 107)); diff --git a/webrtc/modules/audio_coding/acm2/rent_a_codec.cc b/webrtc/modules/audio_coding/acm2/rent_a_codec.cc index 79491b83a6..bfac02d729 100644 --- a/webrtc/modules/audio_coding/acm2/rent_a_codec.cc +++ b/webrtc/modules/audio_coding/acm2/rent_a_codec.cc @@ -163,7 +163,7 @@ std::unique_ptr CreateEncoder( #endif #ifdef WEBRTC_CODEC_OPUS if (STR_CASE_CMP(speech_inst.plname, "opus") == 0) - return std::unique_ptr(new AudioEncoderOpus(speech_inst)); + return std::unique_ptr(new AudioEncoderOpusImpl(speech_inst)); #endif if (STR_CASE_CMP(speech_inst.plname, "pcmu") == 0) return std::unique_ptr(new AudioEncoderPcmU(speech_inst)); diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_internal.cc b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_internal.cc index 3f75cc8624..9c3bfbd9d2 100644 --- a/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_internal.cc +++ b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_internal.cc @@ -74,7 +74,7 @@ NamedEncoderFactory encoder_factories[] = { #endif #ifdef WEBRTC_CODEC_OPUS - NamedEncoderFactory::ForEncoder(), + NamedEncoderFactory::ForEncoder(), #endif NamedEncoderFactory::ForEncoder(), NamedEncoderFactory::ForEncoder(), diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc index be32aef152..a4ae2ca6d5 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc +++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc @@ -48,11 +48,6 @@ constexpr int kOpusBitrateNbBps = 12000; constexpr int kOpusBitrateWbBps = 20000; constexpr int kOpusBitrateFbBps = 32000; -// Opus API allows a min bitrate of 500bps, but Opus documentation suggests -// bitrate should be in the range of 6000 to 510000, inclusive. -constexpr int kOpusMinBitrateBps = 6000; -constexpr int kOpusMaxBitrateBps = 510000; - constexpr int kSampleRateHz = 48000; constexpr int kDefaultMaxPlaybackRate = 48000; @@ -133,8 +128,8 @@ int CalculateDefaultBitrate(int max_playback_rate, size_t num_channels) { return kOpusBitrateFbBps * rtc::dchecked_cast(num_channels); } }(); - RTC_DCHECK_GE(bitrate, kOpusMinBitrateBps); - RTC_DCHECK_LE(bitrate, kOpusMaxBitrateBps); + RTC_DCHECK_GE(bitrate, AudioEncoderOpusConfig::kMinBitrateBps); + RTC_DCHECK_LE(bitrate, AudioEncoderOpusConfig::kMaxBitrateBps); return bitrate; } @@ -150,7 +145,8 @@ int CalculateBitrate(int max_playback_rate_hz, const auto bitrate = rtc::StringToNumber(*bitrate_param); if (bitrate) { const int chosen_bitrate = - std::max(kOpusMinBitrateBps, std::min(*bitrate, kOpusMaxBitrateBps)); + std::max(AudioEncoderOpusConfig::kMinBitrateBps, + std::min(*bitrate, AudioEncoderOpusConfig::kMaxBitrateBps)); if (bitrate != chosen_bitrate) { LOG(LS_WARNING) << "Invalid maxaveragebitrate " << *bitrate << " clamped to " << chosen_bitrate; @@ -195,7 +191,7 @@ int GetFrameSizeMs(const SdpAudioFormat& format) { return *(std::end(kOpusSupportedFrameLengths) - 1); } - return AudioEncoderOpus::Config::kDefaultFrameSizeMs; + return AudioEncoderOpusConfig::kDefaultFrameSizeMs; } void FindSupportedFrameLengths(int min_frame_length_ms, @@ -211,9 +207,14 @@ void FindSupportedFrameLengths(int min_frame_length_ms, RTC_DCHECK(std::is_sorted(out->begin(), out->end())); } +int GetBitrateBps(const AudioEncoderOpusConfig& config) { + RTC_DCHECK(config.IsOk()); + return config.bitrate_bps; +} + } // namespace -rtc::Optional AudioEncoderOpus::QueryAudioEncoder( +rtc::Optional AudioEncoderOpusImpl::QueryAudioEncoder( const SdpAudioFormat& format) { if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0 && format.clockrate_hz == 48000 && format.num_channels == 2) { @@ -221,8 +222,9 @@ rtc::Optional AudioEncoderOpus::QueryAudioEncoder( const int bitrate = CalculateBitrate(GetMaxPlaybackRate(format), num_channels, GetFormatParameter(format, "maxaveragebitrate")); - AudioCodecInfo info(48000, num_channels, bitrate, kOpusMinBitrateBps, - kOpusMaxBitrateBps); + AudioCodecInfo info(48000, num_channels, bitrate, + AudioEncoderOpusConfig::kMinBitrateBps, + AudioEncoderOpusConfig::kMaxBitrateBps); info.allow_comfort_noise = false; info.supports_network_adaption = true; @@ -231,46 +233,44 @@ rtc::Optional AudioEncoderOpus::QueryAudioEncoder( return rtc::Optional(); } -AudioEncoderOpus::Config AudioEncoderOpus::CreateConfig( +AudioEncoderOpusConfig AudioEncoderOpusImpl::CreateConfig( const CodecInst& codec_inst) { - AudioEncoderOpus::Config config; + AudioEncoderOpusConfig config; config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); config.num_channels = codec_inst.channels; - config.bitrate_bps = rtc::Optional(codec_inst.rate); - config.payload_type = codec_inst.pltype; - config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip - : AudioEncoderOpus::kAudio; + config.bitrate_bps = codec_inst.rate; + config.application = config.num_channels == 1 + ? AudioEncoderOpusConfig::ApplicationMode::kVoip + : AudioEncoderOpusConfig::ApplicationMode::kAudio; config.supported_frame_lengths_ms.push_back(config.frame_size_ms); -#if WEBRTC_OPUS_VARIABLE_COMPLEXITY - config.low_rate_complexity = 9; -#endif return config; } -AudioEncoderOpus::Config AudioEncoderOpus::CreateConfig( - int payload_type, +rtc::Optional AudioEncoderOpusImpl::SdpToConfig( const SdpAudioFormat& format) { - AudioEncoderOpus::Config config; + if (STR_CASE_CMP(format.name.c_str(), "opus") != 0 || + format.clockrate_hz != 48000 || format.num_channels != 2) { + return rtc::Optional(); + } + AudioEncoderOpusConfig config; config.num_channels = GetChannelCount(format); config.frame_size_ms = GetFrameSizeMs(format); config.max_playback_rate_hz = GetMaxPlaybackRate(format); config.fec_enabled = (GetFormatParameter(format, "useinbandfec") == "1"); config.dtx_enabled = (GetFormatParameter(format, "usedtx") == "1"); config.cbr_enabled = (GetFormatParameter(format, "cbr") == "1"); - config.bitrate_bps = rtc::Optional( + config.bitrate_bps = CalculateBitrate(config.max_playback_rate_hz, config.num_channels, - GetFormatParameter(format, "maxaveragebitrate"))); - config.payload_type = payload_type; - config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip - : AudioEncoderOpus::kAudio; -#if WEBRTC_OPUS_VARIABLE_COMPLEXITY - config.low_rate_complexity = 9; -#endif + GetFormatParameter(format, "maxaveragebitrate")); + config.application = config.num_channels == 1 + ? AudioEncoderOpusConfig::ApplicationMode::kVoip + : AudioEncoderOpusConfig::ApplicationMode::kAudio; constexpr int kMinANAFrameLength = kANASupportedFrameLengths[0]; constexpr int kMaxANAFrameLength = kANASupportedFrameLengths[arraysize(kANASupportedFrameLengths) - 1]; + // For now, minptime and maxptime are only used with ANA. If ptime is outside // of this range, it will get adjusted once ANA takes hold. Ideally, we'd know // if ANA was to be used when setting up the config, and adjust accordingly. @@ -281,10 +281,28 @@ AudioEncoderOpus::Config AudioEncoderOpus::CreateConfig( FindSupportedFrameLengths(min_frame_length_ms, max_frame_length_ms, &config.supported_frame_lengths_ms); - return config; + RTC_DCHECK(config.IsOk()); + return rtc::Optional(config); } -class AudioEncoderOpus::PacketLossFractionSmoother { +rtc::Optional AudioEncoderOpusImpl::GetNewComplexity( + const AudioEncoderOpusConfig& config) { + RTC_DCHECK(config.IsOk()); + const int bitrate_bps = GetBitrateBps(config); + if (bitrate_bps >= config.complexity_threshold_bps - + config.complexity_threshold_window_bps && + bitrate_bps <= config.complexity_threshold_bps + + config.complexity_threshold_window_bps) { + // Within the hysteresis window; make no change. + return rtc::Optional(); + } else { + return rtc::Optional(bitrate_bps <= config.complexity_threshold_bps + ? config.low_rate_complexity + : config.complexity); + } +} + +class AudioEncoderOpusImpl::PacketLossFractionSmoother { public: explicit PacketLossFractionSmoother() : last_sample_time_ms_(rtc::TimeMillis()), @@ -311,58 +329,13 @@ class AudioEncoderOpus::PacketLossFractionSmoother { rtc::ExpFilter smoother_; }; -AudioEncoderOpus::Config::Config() { -#if WEBRTC_OPUS_VARIABLE_COMPLEXITY - low_rate_complexity = 9; -#endif -} -AudioEncoderOpus::Config::Config(const Config&) = default; -AudioEncoderOpus::Config::~Config() = default; -auto AudioEncoderOpus::Config::operator=(const Config&) -> Config& = default; - -bool AudioEncoderOpus::Config::IsOk() const { - if (frame_size_ms <= 0 || frame_size_ms % 10 != 0) - return false; - if (num_channels != 1 && num_channels != 2) - return false; - if (bitrate_bps && - (*bitrate_bps < kOpusMinBitrateBps || *bitrate_bps > kOpusMaxBitrateBps)) - return false; - if (complexity < 0 || complexity > 10) - return false; - if (low_rate_complexity < 0 || low_rate_complexity > 10) - return false; - return true; -} - -int AudioEncoderOpus::Config::GetBitrateBps() const { - RTC_DCHECK(IsOk()); - if (bitrate_bps) - return *bitrate_bps; // Explicitly set value. - else - return num_channels == 1 ? 32000 : 64000; // Default value. -} - -rtc::Optional AudioEncoderOpus::Config::GetNewComplexity() const { - RTC_DCHECK(IsOk()); - const int bitrate_bps = GetBitrateBps(); - if (bitrate_bps >= - complexity_threshold_bps - complexity_threshold_window_bps && - bitrate_bps <= - complexity_threshold_bps + complexity_threshold_window_bps) { - // Within the hysteresis window; make no change. - return rtc::Optional(); - } - return bitrate_bps <= complexity_threshold_bps - ? rtc::Optional(low_rate_complexity) - : rtc::Optional(complexity); -} - -AudioEncoderOpus::AudioEncoderOpus( - const Config& config, +AudioEncoderOpusImpl::AudioEncoderOpusImpl( + const AudioEncoderOpusConfig& config, + int payload_type, AudioNetworkAdaptorCreator&& audio_network_adaptor_creator, std::unique_ptr bitrate_smoother) - : send_side_bwe_with_overhead_(webrtc::field_trial::IsEnabled( + : payload_type_(payload_type), + send_side_bwe_with_overhead_(webrtc::field_trial::IsEnabled( "WebRTC-SendSideBwe-WithOverhead")), packet_loss_rate_(0.0), inst_(nullptr), @@ -382,42 +355,42 @@ AudioEncoderOpus::AudioEncoderOpus( RTC_CHECK(RecreateEncoderInstance(config)); } -AudioEncoderOpus::AudioEncoderOpus(const CodecInst& codec_inst) - : AudioEncoderOpus(CreateConfig(codec_inst), nullptr) {} +AudioEncoderOpusImpl::AudioEncoderOpusImpl(const CodecInst& codec_inst) + : AudioEncoderOpusImpl(CreateConfig(codec_inst), codec_inst.pltype) {} -AudioEncoderOpus::AudioEncoderOpus(int payload_type, - const SdpAudioFormat& format) - : AudioEncoderOpus(CreateConfig(payload_type, format), nullptr) {} +AudioEncoderOpusImpl::AudioEncoderOpusImpl(int payload_type, + const SdpAudioFormat& format) + : AudioEncoderOpusImpl(*SdpToConfig(format), payload_type) {} -AudioEncoderOpus::~AudioEncoderOpus() { +AudioEncoderOpusImpl::~AudioEncoderOpusImpl() { RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); } -int AudioEncoderOpus::SampleRateHz() const { +int AudioEncoderOpusImpl::SampleRateHz() const { return kSampleRateHz; } -size_t AudioEncoderOpus::NumChannels() const { +size_t AudioEncoderOpusImpl::NumChannels() const { return config_.num_channels; } -size_t AudioEncoderOpus::Num10MsFramesInNextPacket() const { +size_t AudioEncoderOpusImpl::Num10MsFramesInNextPacket() const { return Num10msFramesPerPacket(); } -size_t AudioEncoderOpus::Max10MsFramesInAPacket() const { +size_t AudioEncoderOpusImpl::Max10MsFramesInAPacket() const { return Num10msFramesPerPacket(); } -int AudioEncoderOpus::GetTargetBitrate() const { - return config_.GetBitrateBps(); +int AudioEncoderOpusImpl::GetTargetBitrate() const { + return GetBitrateBps(config_); } -void AudioEncoderOpus::Reset() { +void AudioEncoderOpusImpl::Reset() { RTC_CHECK(RecreateEncoderInstance(config_)); } -bool AudioEncoderOpus::SetFec(bool enable) { +bool AudioEncoderOpusImpl::SetFec(bool enable) { if (enable) { RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); } else { @@ -427,7 +400,7 @@ bool AudioEncoderOpus::SetFec(bool enable) { return true; } -bool AudioEncoderOpus::SetDtx(bool enable) { +bool AudioEncoderOpusImpl::SetDtx(bool enable) { if (enable) { RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); } else { @@ -437,30 +410,30 @@ bool AudioEncoderOpus::SetDtx(bool enable) { return true; } -bool AudioEncoderOpus::GetDtx() const { +bool AudioEncoderOpusImpl::GetDtx() const { return config_.dtx_enabled; } -bool AudioEncoderOpus::SetApplication(Application application) { +bool AudioEncoderOpusImpl::SetApplication(Application application) { auto conf = config_; switch (application) { case Application::kSpeech: - conf.application = AudioEncoderOpus::kVoip; + conf.application = AudioEncoderOpusConfig::ApplicationMode::kVoip; break; case Application::kAudio: - conf.application = AudioEncoderOpus::kAudio; + conf.application = AudioEncoderOpusConfig::ApplicationMode::kAudio; break; } return RecreateEncoderInstance(conf); } -void AudioEncoderOpus::SetMaxPlaybackRate(int frequency_hz) { +void AudioEncoderOpusImpl::SetMaxPlaybackRate(int frequency_hz) { auto conf = config_; conf.max_playback_rate_hz = frequency_hz; RTC_CHECK(RecreateEncoderInstance(conf)); } -bool AudioEncoderOpus::EnableAudioNetworkAdaptor( +bool AudioEncoderOpusImpl::EnableAudioNetworkAdaptor( const std::string& config_string, RtcEventLog* event_log) { audio_network_adaptor_ = @@ -468,11 +441,11 @@ bool AudioEncoderOpus::EnableAudioNetworkAdaptor( return audio_network_adaptor_.get() != nullptr; } -void AudioEncoderOpus::DisableAudioNetworkAdaptor() { +void AudioEncoderOpusImpl::DisableAudioNetworkAdaptor() { audio_network_adaptor_.reset(nullptr); } -void AudioEncoderOpus::OnReceivedUplinkPacketLossFraction( +void AudioEncoderOpusImpl::OnReceivedUplinkPacketLossFraction( float uplink_packet_loss_fraction) { if (!audio_network_adaptor_) { packet_loss_fraction_smoother_->AddSample(uplink_packet_loss_fraction); @@ -484,7 +457,7 @@ void AudioEncoderOpus::OnReceivedUplinkPacketLossFraction( ApplyAudioNetworkAdaptor(); } -void AudioEncoderOpus::OnReceivedUplinkRecoverablePacketLossFraction( +void AudioEncoderOpusImpl::OnReceivedUplinkRecoverablePacketLossFraction( float uplink_recoverable_packet_loss_fraction) { if (!audio_network_adaptor_) return; @@ -493,7 +466,7 @@ void AudioEncoderOpus::OnReceivedUplinkRecoverablePacketLossFraction( ApplyAudioNetworkAdaptor(); } -void AudioEncoderOpus::OnReceivedUplinkBandwidth( +void AudioEncoderOpusImpl::OnReceivedUplinkBandwidth( int target_audio_bitrate_bps, rtc::Optional probing_interval_ms) { if (audio_network_adaptor_) { @@ -517,28 +490,30 @@ void AudioEncoderOpus::OnReceivedUplinkBandwidth( } else if (send_side_bwe_with_overhead_) { if (!overhead_bytes_per_packet_) { LOG(LS_INFO) - << "AudioEncoderOpus: Overhead unknown, target audio bitrate " + << "AudioEncoderOpusImpl: Overhead unknown, target audio bitrate " << target_audio_bitrate_bps << " bps is ignored."; return; } const int overhead_bps = static_cast( *overhead_bytes_per_packet_ * 8 * 100 / Num10MsFramesInNextPacket()); - SetTargetBitrate(std::min( - kOpusMaxBitrateBps, - std::max(kOpusMinBitrateBps, target_audio_bitrate_bps - overhead_bps))); + SetTargetBitrate( + std::min(AudioEncoderOpusConfig::kMaxBitrateBps, + std::max(AudioEncoderOpusConfig::kMinBitrateBps, + target_audio_bitrate_bps - overhead_bps))); } else { SetTargetBitrate(target_audio_bitrate_bps); } } -void AudioEncoderOpus::OnReceivedRtt(int rtt_ms) { +void AudioEncoderOpusImpl::OnReceivedRtt(int rtt_ms) { if (!audio_network_adaptor_) return; audio_network_adaptor_->SetRtt(rtt_ms); ApplyAudioNetworkAdaptor(); } -void AudioEncoderOpus::OnReceivedOverhead(size_t overhead_bytes_per_packet) { +void AudioEncoderOpusImpl::OnReceivedOverhead( + size_t overhead_bytes_per_packet) { if (audio_network_adaptor_) { audio_network_adaptor_->SetOverhead(overhead_bytes_per_packet); ApplyAudioNetworkAdaptor(); @@ -548,8 +523,9 @@ void AudioEncoderOpus::OnReceivedOverhead(size_t overhead_bytes_per_packet) { } } -void AudioEncoderOpus::SetReceiverFrameLengthRange(int min_frame_length_ms, - int max_frame_length_ms) { +void AudioEncoderOpusImpl::SetReceiverFrameLengthRange( + int min_frame_length_ms, + int max_frame_length_ms) { // Ensure that |SetReceiverFrameLengthRange| is called before // |EnableAudioNetworkAdaptor|, otherwise we need to recreate // |audio_network_adaptor_|, which is not a needed use case. @@ -558,7 +534,7 @@ void AudioEncoderOpus::SetReceiverFrameLengthRange(int min_frame_length_ms, &config_.supported_frame_lengths_ms); } -AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeImpl( +AudioEncoder::EncodedInfo AudioEncoderOpusImpl::EncodeImpl( uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded) { @@ -597,26 +573,26 @@ AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeImpl( config_.frame_size_ms = next_frame_length_ms_; info.encoded_timestamp = first_timestamp_in_buffer_; - info.payload_type = config_.payload_type; + info.payload_type = payload_type_; info.send_even_if_empty = true; // Allows Opus to send empty packets. info.speech = (info.encoded_bytes > 0); info.encoder_type = CodecType::kOpus; return info; } -size_t AudioEncoderOpus::Num10msFramesPerPacket() const { +size_t AudioEncoderOpusImpl::Num10msFramesPerPacket() const { return static_cast(rtc::CheckedDivExact(config_.frame_size_ms, 10)); } -size_t AudioEncoderOpus::SamplesPer10msFrame() const { +size_t AudioEncoderOpusImpl::SamplesPer10msFrame() const { return rtc::CheckedDivExact(kSampleRateHz, 100) * config_.num_channels; } -size_t AudioEncoderOpus::SufficientOutputBufferSize() const { +size_t AudioEncoderOpusImpl::SufficientOutputBufferSize() const { // Calculate the number of bytes we expect the encoder to produce, // then multiply by two to give a wide margin for error. const size_t bytes_per_millisecond = - static_cast(config_.GetBitrateBps() / (1000 * 8) + 1); + static_cast(GetBitrateBps(config_) / (1000 * 8) + 1); const size_t approx_encoded_bytes = Num10msFramesPerPacket() * 10 * bytes_per_millisecond; return 2 * approx_encoded_bytes; @@ -625,7 +601,8 @@ size_t AudioEncoderOpus::SufficientOutputBufferSize() const { // If the given config is OK, recreate the Opus encoder instance with those // settings, save the config, and return true. Otherwise, do nothing and return // false. -bool AudioEncoderOpus::RecreateEncoderInstance(const Config& config) { +bool AudioEncoderOpusImpl::RecreateEncoderInstance( + const AudioEncoderOpusConfig& config) { if (!config.IsOk()) return false; config_ = config; @@ -633,9 +610,13 @@ bool AudioEncoderOpus::RecreateEncoderInstance(const Config& config) { RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); input_buffer_.clear(); input_buffer_.reserve(Num10msFramesPerPacket() * SamplesPer10msFrame()); - RTC_CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, config.num_channels, - config.application)); - RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config.GetBitrateBps())); + RTC_CHECK_EQ(0, WebRtcOpus_EncoderCreate( + &inst_, config.num_channels, + config.application == + AudioEncoderOpusConfig::ApplicationMode::kVoip + ? 0 + : 1)); + RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, GetBitrateBps(config))); if (config.fec_enabled) { RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); } else { @@ -645,7 +626,7 @@ bool AudioEncoderOpus::RecreateEncoderInstance(const Config& config) { 0, WebRtcOpus_SetMaxPlaybackRate(inst_, config.max_playback_rate_hz)); // Use the default complexity if the start bitrate is within the hysteresis // window. - complexity_ = config.GetNewComplexity().value_or(config.complexity); + complexity_ = GetNewComplexity(config).value_or(config.complexity); RTC_CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, complexity_)); if (config.dtx_enabled) { RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); @@ -665,11 +646,12 @@ bool AudioEncoderOpus::RecreateEncoderInstance(const Config& config) { return true; } -void AudioEncoderOpus::SetFrameLength(int frame_length_ms) { +void AudioEncoderOpusImpl::SetFrameLength(int frame_length_ms) { next_frame_length_ms_ = frame_length_ms; } -void AudioEncoderOpus::SetNumChannelsToEncode(size_t num_channels_to_encode) { +void AudioEncoderOpusImpl::SetNumChannelsToEncode( + size_t num_channels_to_encode) { RTC_DCHECK_GT(num_channels_to_encode, 0); RTC_DCHECK_LE(num_channels_to_encode, config_.num_channels); @@ -680,7 +662,7 @@ void AudioEncoderOpus::SetNumChannelsToEncode(size_t num_channels_to_encode) { num_channels_to_encode_ = num_channels_to_encode; } -void AudioEncoderOpus::SetProjectedPacketLossRate(float fraction) { +void AudioEncoderOpusImpl::SetProjectedPacketLossRate(float fraction) { float opt_loss_rate = OptimizePacketLossRate(fraction, packet_loss_rate_); if (packet_loss_rate_ != opt_loss_rate) { packet_loss_rate_ = opt_loss_rate; @@ -690,19 +672,20 @@ void AudioEncoderOpus::SetProjectedPacketLossRate(float fraction) { } } -void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) { - config_.bitrate_bps = rtc::Optional(rtc::SafeClamp( - bits_per_second, kOpusMinBitrateBps, kOpusMaxBitrateBps)); +void AudioEncoderOpusImpl::SetTargetBitrate(int bits_per_second) { + config_.bitrate_bps = rtc::SafeClamp( + bits_per_second, AudioEncoderOpusConfig::kMinBitrateBps, + AudioEncoderOpusConfig::kMaxBitrateBps); RTC_DCHECK(config_.IsOk()); - RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.GetBitrateBps())); - const auto new_complexity = config_.GetNewComplexity(); + RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, GetBitrateBps(config_))); + const auto new_complexity = GetNewComplexity(config_); if (new_complexity && complexity_ != *new_complexity) { complexity_ = *new_complexity; RTC_CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, complexity_)); } } -void AudioEncoderOpus::ApplyAudioNetworkAdaptor() { +void AudioEncoderOpusImpl::ApplyAudioNetworkAdaptor() { auto config = audio_network_adaptor_->GetEncoderRuntimeConfig(); RTC_DCHECK(!config.frame_length_ms || *config.frame_length_ms == 20 || *config.frame_length_ms == 60); @@ -722,20 +705,20 @@ void AudioEncoderOpus::ApplyAudioNetworkAdaptor() { } std::unique_ptr -AudioEncoderOpus::DefaultAudioNetworkAdaptorCreator( +AudioEncoderOpusImpl::DefaultAudioNetworkAdaptorCreator( const ProtoString& config_string, RtcEventLog* event_log) const { AudioNetworkAdaptorImpl::Config config; config.event_log = event_log; return std::unique_ptr(new AudioNetworkAdaptorImpl( - config, - ControllerManagerImpl::Create( - config_string, NumChannels(), supported_frame_lengths_ms(), - kOpusMinBitrateBps, num_channels_to_encode_, next_frame_length_ms_, - GetTargetBitrate(), config_.fec_enabled, GetDtx()))); + config, ControllerManagerImpl::Create( + config_string, NumChannels(), supported_frame_lengths_ms(), + AudioEncoderOpusConfig::kMinBitrateBps, + num_channels_to_encode_, next_frame_length_ms_, + GetTargetBitrate(), config_.fec_enabled, GetDtx()))); } -void AudioEncoderOpus::MaybeUpdateUplinkBandwidth() { +void AudioEncoderOpusImpl::MaybeUpdateUplinkBandwidth() { if (audio_network_adaptor_) { int64_t now_ms = rtc::TimeMillis(); if (!bitrate_smoother_last_update_time_ || diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h index a1a4d7069b..93895c21db 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h +++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h @@ -18,6 +18,7 @@ #include "webrtc/api/audio_codecs/audio_encoder.h" #include "webrtc/api/audio_codecs/audio_format.h" +#include "webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h" #include "webrtc/base/constructormagic.h" #include "webrtc/base/optional.h" #include "webrtc/base/protobuf_utils.h" @@ -31,70 +32,31 @@ class RtcEventLog; struct CodecInst; -class AudioEncoderOpus final : public AudioEncoder { +class AudioEncoderOpusImpl final : public AudioEncoder { public: - enum ApplicationMode { - kVoip = 0, - kAudio = 1, - }; + static AudioEncoderOpusConfig CreateConfig(const CodecInst& codec_inst); + static rtc::Optional SdpToConfig( + const SdpAudioFormat& format); - struct Config { - Config(); - Config(const Config&); - ~Config(); - Config& operator=(const Config&); - - bool IsOk() const; - int GetBitrateBps() const; - // Returns empty if the current bitrate falls within the hysteresis window, - // defined by complexity_threshold_bps +/- complexity_threshold_window_bps. - // Otherwise, returns the current complexity depending on whether the - // current bitrate is above or below complexity_threshold_bps. - rtc::Optional GetNewComplexity() const; - - static constexpr int kDefaultFrameSizeMs = 20; - int frame_size_ms = kDefaultFrameSizeMs; - size_t num_channels = 1; - int payload_type = 120; - ApplicationMode application = kVoip; - rtc::Optional bitrate_bps; // Unset means to use default value. - bool fec_enabled = false; - bool cbr_enabled = false; - int max_playback_rate_hz = 48000; - int complexity = kDefaultComplexity; - // This value may change in the struct's constructor. - int low_rate_complexity = kDefaultComplexity; - // low_rate_complexity is used when the bitrate is below this threshold. - int complexity_threshold_bps = 12500; - int complexity_threshold_window_bps = 1500; - bool dtx_enabled = false; - std::vector supported_frame_lengths_ms; - int uplink_bandwidth_update_interval_ms = 200; - - private: -#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM) - // If we are on Android, iOS and/or ARM, use a lower complexity setting as - // default, to save encoder complexity. - static const int kDefaultComplexity = 5; -#else - static const int kDefaultComplexity = 9; -#endif - }; - - static Config CreateConfig(int payload_type, const SdpAudioFormat& format); - static Config CreateConfig(const CodecInst& codec_inst); + // Returns empty if the current bitrate falls within the hysteresis window, + // defined by complexity_threshold_bps +/- complexity_threshold_window_bps. + // Otherwise, returns the current complexity depending on whether the current + // bitrate is above or below complexity_threshold_bps. + static rtc::Optional GetNewComplexity( + const AudioEncoderOpusConfig& config); using AudioNetworkAdaptorCreator = std::function(const std::string&, RtcEventLog*)>; - AudioEncoderOpus( - const Config& config, + AudioEncoderOpusImpl( + const AudioEncoderOpusConfig& config, + int payload_type, AudioNetworkAdaptorCreator&& audio_network_adaptor_creator = nullptr, std::unique_ptr bitrate_smoother = nullptr); - explicit AudioEncoderOpus(const CodecInst& codec_inst); - AudioEncoderOpus(int payload_type, const SdpAudioFormat& format); - ~AudioEncoderOpus() override; + explicit AudioEncoderOpusImpl(const CodecInst& codec_inst); + AudioEncoderOpusImpl(int payload_type, const SdpAudioFormat& format); + ~AudioEncoderOpusImpl() override; // Static interface for use by BuiltinAudioEncoderFactory. static constexpr const char* GetPayloadName() { return "opus"; } @@ -138,7 +100,9 @@ class AudioEncoderOpus final : public AudioEncoder { // Getters for testing. float packet_loss_rate() const { return packet_loss_rate_; } - ApplicationMode application() const { return config_.application; } + AudioEncoderOpusConfig::ApplicationMode application() const { + return config_.application; + } bool fec_enabled() const { return config_.fec_enabled; } size_t num_channels_to_encode() const { return num_channels_to_encode_; } int next_frame_length_ms() const { return next_frame_length_ms_; } @@ -154,7 +118,7 @@ class AudioEncoderOpus final : public AudioEncoder { size_t Num10msFramesPerPacket() const; size_t SamplesPer10msFrame() const; size_t SufficientOutputBufferSize() const; - bool RecreateEncoderInstance(const Config& config); + bool RecreateEncoderInstance(const AudioEncoderOpusConfig& config); void SetFrameLength(int frame_length_ms); void SetNumChannelsToEncode(size_t num_channels_to_encode); void SetProjectedPacketLossRate(float fraction); @@ -170,7 +134,8 @@ class AudioEncoderOpus final : public AudioEncoder { void MaybeUpdateUplinkBandwidth(); - Config config_; + AudioEncoderOpusConfig config_; + const int payload_type_; const bool send_side_bwe_with_overhead_; float packet_loss_rate_; std::vector input_buffer_; @@ -186,7 +151,7 @@ class AudioEncoderOpus final : public AudioEncoder { const std::unique_ptr bitrate_smoother_; rtc::Optional bitrate_smoother_last_update_time_; - RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderOpus); + RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderOpusImpl); }; } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc index 76574d6432..8137998b9c 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc +++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc @@ -33,30 +33,30 @@ namespace { const CodecInst kDefaultOpusSettings = {105, "opus", 48000, 960, 1, 32000}; constexpr int64_t kInitialTimeUs = 12345678; -AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) { - AudioEncoderOpus::Config config; +AudioEncoderOpusConfig CreateConfig(const CodecInst& codec_inst) { + AudioEncoderOpusConfig config; config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); config.num_channels = codec_inst.channels; - config.bitrate_bps = rtc::Optional(codec_inst.rate); - config.payload_type = codec_inst.pltype; - config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip - : AudioEncoderOpus::kAudio; + config.bitrate_bps = codec_inst.rate; + config.application = config.num_channels == 1 + ? AudioEncoderOpusConfig::ApplicationMode::kVoip + : AudioEncoderOpusConfig::ApplicationMode::kAudio; config.supported_frame_lengths_ms.push_back(config.frame_size_ms); return config; } -AudioEncoderOpus::Config CreateConfigWithParameters( +AudioEncoderOpusConfig CreateConfigWithParameters( const SdpAudioFormat::Parameters& params) { - SdpAudioFormat format("opus", 48000, 2, params); - return AudioEncoderOpus::CreateConfig(0, format); + const SdpAudioFormat format("opus", 48000, 2, params); + return *AudioEncoderOpusImpl::SdpToConfig(format); } struct AudioEncoderOpusStates { std::shared_ptr mock_audio_network_adaptor; MockSmoothingFilter* mock_bitrate_smoother; - std::unique_ptr encoder; + std::unique_ptr encoder; std::unique_ptr fake_clock; - AudioEncoderOpus::Config config; + AudioEncoderOpusConfig config; }; AudioEncoderOpusStates CreateCodec(size_t num_channels) { @@ -67,7 +67,7 @@ AudioEncoderOpusStates CreateCodec(size_t num_channels) { states.fake_clock->SetTimeMicros(kInitialTimeUs); std::weak_ptr mock_ptr( states.mock_audio_network_adaptor); - AudioEncoderOpus::AudioNetworkAdaptorCreator creator = + AudioEncoderOpusImpl::AudioNetworkAdaptorCreator creator = [mock_ptr](const std::string&, RtcEventLog* event_log) { std::unique_ptr adaptor( new NiceMock()); @@ -87,8 +87,9 @@ AudioEncoderOpusStates CreateCodec(size_t num_channels) { new MockSmoothingFilter()); states.mock_bitrate_smoother = bitrate_smoother.get(); - states.encoder.reset(new AudioEncoderOpus(states.config, std::move(creator), - std::move(bitrate_smoother))); + states.encoder.reset(new AudioEncoderOpusImpl( + states.config, codec_inst.pltype, std::move(creator), + std::move(bitrate_smoother))); return states; } @@ -110,7 +111,7 @@ AudioEncoderRuntimeConfig CreateEncoderRuntimeConfig() { return config; } -void CheckEncoderRuntimeConfig(const AudioEncoderOpus* encoder, +void CheckEncoderRuntimeConfig(const AudioEncoderOpusImpl* encoder, const AudioEncoderRuntimeConfig& config) { EXPECT_EQ(*config.bitrate_bps, encoder->GetTargetBitrate()); EXPECT_EQ(*config.frame_length_ms, encoder->next_frame_length_ms()); @@ -121,7 +122,7 @@ void CheckEncoderRuntimeConfig(const AudioEncoderOpus* encoder, // Create 10ms audio data blocks for a total packet size of "packet_size_ms". std::unique_ptr Create10msAudioBlocks( - const std::unique_ptr& encoder, + const std::unique_ptr& encoder, int packet_size_ms) { const std::string file_name = test::ResourcePath("audio_coding/testfile32kHz", "pcm"); @@ -142,19 +143,22 @@ std::unique_ptr Create10msAudioBlocks( TEST(AudioEncoderOpusTest, DefaultApplicationModeMono) { auto states = CreateCodec(1); - EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); + EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip, + states.encoder->application()); } TEST(AudioEncoderOpusTest, DefaultApplicationModeStereo) { auto states = CreateCodec(2); - EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application()); + EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kAudio, + states.encoder->application()); } TEST(AudioEncoderOpusTest, ChangeApplicationMode) { auto states = CreateCodec(2); EXPECT_TRUE( states.encoder->SetApplication(AudioEncoder::Application::kSpeech)); - EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); + EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip, + states.encoder->application()); } TEST(AudioEncoderOpusTest, ResetWontChangeApplicationMode) { @@ -163,17 +167,20 @@ TEST(AudioEncoderOpusTest, ResetWontChangeApplicationMode) { // Trigger a reset. states.encoder->Reset(); // Verify that the mode is still kAudio. - EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application()); + EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kAudio, + states.encoder->application()); // Now change to kVoip. EXPECT_TRUE( states.encoder->SetApplication(AudioEncoder::Application::kSpeech)); - EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); + EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip, + states.encoder->application()); // Trigger a reset again. states.encoder->Reset(); // Verify that the mode is still kVoip. - EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); + EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip, + states.encoder->application()); } TEST(AudioEncoderOpusTest, ToggleDtx) { @@ -238,7 +245,7 @@ void TestSetPacketLossRate(AudioEncoderOpusStates* states, float expected_return) { // |kSampleIntervalMs| is chosen to ease the calculation since // 0.9999 ^ 184198 = 1e-8. Which minimizes the effect of - // PacketLossFractionSmoother used in AudioEncoderOpus. + // PacketLossFractionSmoother used in AudioEncoderOpusImpl. constexpr int64_t kSampleIntervalMs = 184198; for (float loss : losses) { states->encoder->OnReceivedUplinkPacketLossFraction(loss); @@ -452,25 +459,29 @@ TEST(AudioEncoderOpusTest, BitrateBounded) { // Verifies that the complexity adaptation in the config works as intended. TEST(AudioEncoderOpusTest, ConfigComplexityAdaptation) { - AudioEncoderOpus::Config config; + AudioEncoderOpusConfig config; config.low_rate_complexity = 8; config.complexity = 6; // Bitrate within hysteresis window. Expect empty output. - config.bitrate_bps = rtc::Optional(12500); - EXPECT_EQ(rtc::Optional(), config.GetNewComplexity()); + config.bitrate_bps = 12500; + EXPECT_EQ(rtc::Optional(), + AudioEncoderOpusImpl::GetNewComplexity(config)); // Bitrate below hysteresis window. Expect higher complexity. - config.bitrate_bps = rtc::Optional(10999); - EXPECT_EQ(rtc::Optional(8), config.GetNewComplexity()); + config.bitrate_bps = 10999; + EXPECT_EQ(rtc::Optional(8), + AudioEncoderOpusImpl::GetNewComplexity(config)); // Bitrate within hysteresis window. Expect empty output. - config.bitrate_bps = rtc::Optional(12500); - EXPECT_EQ(rtc::Optional(), config.GetNewComplexity()); + config.bitrate_bps = 12500; + EXPECT_EQ(rtc::Optional(), + AudioEncoderOpusImpl::GetNewComplexity(config)); // Bitrate above hysteresis window. Expect lower complexity. - config.bitrate_bps = rtc::Optional(14001); - EXPECT_EQ(rtc::Optional(6), config.GetNewComplexity()); + config.bitrate_bps = 14001; + EXPECT_EQ(rtc::Optional(6), + AudioEncoderOpusImpl::GetNewComplexity(config)); } TEST(AudioEncoderOpusTest, EmptyConfigDoesNotAffectEncoderSettings) { @@ -552,84 +563,82 @@ TEST(AudioEncoderOpusTest, EncodeAtMinBitrate) { } TEST(AudioEncoderOpusTest, TestConfigDefaults) { - const AudioEncoderOpus::Config config = - AudioEncoderOpus::CreateConfig(0, {"opus", 48000, 2}); - - EXPECT_EQ(48000, config.max_playback_rate_hz); - EXPECT_EQ(1u, config.num_channels); - EXPECT_FALSE(config.fec_enabled); - EXPECT_FALSE(config.dtx_enabled); - EXPECT_EQ(20, config.frame_size_ms); + const auto config_opt = AudioEncoderOpusImpl::SdpToConfig({"opus", 48000, 2}); + ASSERT_TRUE(config_opt); + EXPECT_EQ(48000, config_opt->max_playback_rate_hz); + EXPECT_EQ(1u, config_opt->num_channels); + EXPECT_FALSE(config_opt->fec_enabled); + EXPECT_FALSE(config_opt->dtx_enabled); + EXPECT_EQ(20, config_opt->frame_size_ms); } TEST(AudioEncoderOpusTest, TestConfigFromParams) { - AudioEncoderOpus::Config config; + const auto config1 = CreateConfigWithParameters({{"stereo", "0"}}); + EXPECT_EQ(1U, config1.num_channels); - config = CreateConfigWithParameters({{"stereo", "0"}}); - EXPECT_EQ(1U, config.num_channels); + const auto config2 = CreateConfigWithParameters({{"stereo", "1"}}); + EXPECT_EQ(2U, config2.num_channels); - config = CreateConfigWithParameters({{"stereo", "1"}}); - EXPECT_EQ(2U, config.num_channels); + const auto config3 = CreateConfigWithParameters({{"useinbandfec", "0"}}); + EXPECT_FALSE(config3.fec_enabled); - config = CreateConfigWithParameters({{"useinbandfec", "0"}}); - EXPECT_FALSE(config.fec_enabled); + const auto config4 = CreateConfigWithParameters({{"useinbandfec", "1"}}); + EXPECT_TRUE(config4.fec_enabled); - config = CreateConfigWithParameters({{"useinbandfec", "1"}}); - EXPECT_TRUE(config.fec_enabled); + const auto config5 = CreateConfigWithParameters({{"usedtx", "0"}}); + EXPECT_FALSE(config5.dtx_enabled); - config = CreateConfigWithParameters({{"usedtx", "0"}}); - EXPECT_FALSE(config.dtx_enabled); + const auto config6 = CreateConfigWithParameters({{"usedtx", "1"}}); + EXPECT_TRUE(config6.dtx_enabled); - config = CreateConfigWithParameters({{"usedtx", "1"}}); - EXPECT_TRUE(config.dtx_enabled); + const auto config7 = CreateConfigWithParameters({{"cbr", "0"}}); + EXPECT_FALSE(config7.cbr_enabled); - config = CreateConfigWithParameters({{"cbr", "0"}}); - EXPECT_FALSE(config.cbr_enabled); + const auto config8 = CreateConfigWithParameters({{"cbr", "1"}}); + EXPECT_TRUE(config8.cbr_enabled); - config = CreateConfigWithParameters({{"cbr", "1"}}); - EXPECT_TRUE(config.cbr_enabled); + const auto config9 = + CreateConfigWithParameters({{"maxplaybackrate", "12345"}}); + EXPECT_EQ(12345, config9.max_playback_rate_hz); - config = CreateConfigWithParameters({{"maxplaybackrate", "12345"}}); - EXPECT_EQ(12345, config.max_playback_rate_hz); + const auto config10 = + CreateConfigWithParameters({{"maxaveragebitrate", "96000"}}); + EXPECT_EQ(96000, config10.bitrate_bps); - config = CreateConfigWithParameters({{"maxaveragebitrate", "96000"}}); - EXPECT_EQ(96000, config.bitrate_bps); - - config = CreateConfigWithParameters({{"maxptime", "40"}}); - for (int frame_length : config.supported_frame_lengths_ms) { + const auto config11 = CreateConfigWithParameters({{"maxptime", "40"}}); + for (int frame_length : config11.supported_frame_lengths_ms) { EXPECT_LE(frame_length, 40); } - config = CreateConfigWithParameters({{"minptime", "40"}}); - for (int frame_length : config.supported_frame_lengths_ms) { + const auto config12 = CreateConfigWithParameters({{"minptime", "40"}}); + for (int frame_length : config12.supported_frame_lengths_ms) { EXPECT_GE(frame_length, 40); } - config = CreateConfigWithParameters({{"ptime", "40"}}); - EXPECT_EQ(40, config.frame_size_ms); + const auto config13 = CreateConfigWithParameters({{"ptime", "40"}}); + EXPECT_EQ(40, config13.frame_size_ms); constexpr int kMinSupportedFrameLength = 10; constexpr int kMaxSupportedFrameLength = WEBRTC_OPUS_SUPPORT_120MS_PTIME ? 120 : 60; - config = CreateConfigWithParameters({{"ptime", "1"}}); - EXPECT_EQ(kMinSupportedFrameLength, config.frame_size_ms); + const auto config14 = CreateConfigWithParameters({{"ptime", "1"}}); + EXPECT_EQ(kMinSupportedFrameLength, config14.frame_size_ms); - config = CreateConfigWithParameters({{"ptime", "2000"}}); - EXPECT_EQ(kMaxSupportedFrameLength, config.frame_size_ms); + const auto config15 = CreateConfigWithParameters({{"ptime", "2000"}}); + EXPECT_EQ(kMaxSupportedFrameLength, config15.frame_size_ms); } TEST(AudioEncoderOpusTest, TestConfigFromInvalidParams) { const webrtc::SdpAudioFormat format("opus", 48000, 2); - const AudioEncoderOpus::Config default_config = - AudioEncoderOpus::CreateConfig(0, format); + const auto default_config = *AudioEncoderOpusImpl::SdpToConfig(format); #if WEBRTC_OPUS_SUPPORT_120MS_PTIME const std::vector default_supported_frame_lengths_ms({20, 60, 120}); #else const std::vector default_supported_frame_lengths_ms({20, 60}); #endif - AudioEncoderOpus::Config config; + AudioEncoderOpusConfig config; config = CreateConfigWithParameters({{"stereo", "invalid"}}); EXPECT_EQ(default_config.num_channels, config.num_channels); @@ -681,18 +690,18 @@ TEST(AudioEncoderOpusTest, TestConfigFromInvalidParams) { // range of 6000 and 510000 TEST(AudioEncoderOpusTest, SetSendCodecOpusMaxAverageBitrate) { // Ignore if less than 6000. - const AudioEncoderOpus::Config config1 = AudioEncoderOpus::CreateConfig( - 0, {"opus", 48000, 2, {{"maxaveragebitrate", "5999"}}}); - EXPECT_EQ(6000, config1.bitrate_bps); + const auto config1 = AudioEncoderOpusImpl::SdpToConfig( + {"opus", 48000, 2, {{"maxaveragebitrate", "5999"}}}); + EXPECT_EQ(6000, config1->bitrate_bps); // Ignore if larger than 510000. - const AudioEncoderOpus::Config config2 = AudioEncoderOpus::CreateConfig( - 0, {"opus", 48000, 2, {{"maxaveragebitrate", "510001"}}}); - EXPECT_EQ(510000, config2.bitrate_bps); + const auto config2 = AudioEncoderOpusImpl::SdpToConfig( + {"opus", 48000, 2, {{"maxaveragebitrate", "510001"}}}); + EXPECT_EQ(510000, config2->bitrate_bps); - const AudioEncoderOpus::Config config3 = AudioEncoderOpus::CreateConfig( - 0, {"opus", 48000, 2, {{"maxaveragebitrate", "200000"}}}); - EXPECT_EQ(200000, config3.bitrate_bps); + const auto config3 = AudioEncoderOpusImpl::SdpToConfig( + {"opus", 48000, 2, {{"maxaveragebitrate", "200000"}}}); + EXPECT_EQ(200000, config3->bitrate_bps); } // Test maxplaybackrate <= 8000 triggers Opus narrow band mode. diff --git a/webrtc/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc b/webrtc/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc index b19991251b..aad413acfc 100644 --- a/webrtc/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc +++ b/webrtc/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc @@ -19,9 +19,10 @@ namespace webrtc { namespace { -int64_t RunComplexityTest(const AudioEncoderOpus::Config& config) { +int64_t RunComplexityTest(const AudioEncoderOpusConfig& config) { // Create encoder. - AudioEncoderOpus encoder(config); + constexpr int payload_type = 17; + AudioEncoderOpusImpl encoder(config, payload_type); // Open speech file. const std::string kInputFileName = webrtc::test::ResourcePath("audio_coding/speech_mono_32_48kHz", "pcm"); @@ -60,14 +61,14 @@ int64_t RunComplexityTest(const AudioEncoderOpus::Config& config) { // the lower rate. TEST(AudioEncoderOpusComplexityAdaptationTest, AdaptationOn) { // Create config. - AudioEncoderOpus::Config config; + AudioEncoderOpusConfig config; // The limit -- including the hysteresis window -- at which the complexity // shuold be increased. - config.bitrate_bps = rtc::Optional(11000 - 1); + config.bitrate_bps = 11000 - 1; config.low_rate_complexity = 9; int64_t runtime_10999bps = RunComplexityTest(config); - config.bitrate_bps = rtc::Optional(15500); + config.bitrate_bps = 15500; int64_t runtime_15500bps = RunComplexityTest(config); test::PrintResult("opus_encoding_complexity_ratio", "", "adaptation_on", @@ -80,14 +81,14 @@ TEST(AudioEncoderOpusComplexityAdaptationTest, AdaptationOn) { // that the resulting ratio is less than 100% at all times. TEST(AudioEncoderOpusComplexityAdaptationTest, AdaptationOff) { // Create config. - AudioEncoderOpus::Config config; + AudioEncoderOpusConfig config; // The limit -- including the hysteresis window -- at which the complexity // shuold be increased (but not in this test since complexity adaptation is // disabled). - config.bitrate_bps = rtc::Optional(11000 - 1); + config.bitrate_bps = 11000 - 1; int64_t runtime_10999bps = RunComplexityTest(config); - config.bitrate_bps = rtc::Optional(15500); + config.bitrate_bps = 15500; int64_t runtime_15500bps = RunComplexityTest(config); test::PrintResult("opus_encoding_complexity_ratio", "", "adaptation_off", diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc index 8dcb416217..6db4317a6e 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc @@ -17,6 +17,7 @@ #include #include +#include "webrtc/api/audio_codecs/opus/audio_encoder_opus.h" #include "webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.h" #include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h" #include "webrtc/modules/audio_coding/codecs/g722/audio_decoder_g722.h" @@ -28,7 +29,6 @@ #include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h" #include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h" #include "webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h" -#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h" #include "webrtc/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h" #include "webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h" #include "webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.h" @@ -434,11 +434,10 @@ class AudioDecoderOpusTest : public AudioDecoderTest { frame_size_ = 480; data_length_ = 10 * frame_size_; decoder_ = new AudioDecoderOpus(1); - AudioEncoderOpus::Config config; + AudioEncoderOpusConfig config; config.frame_size_ms = static_cast(frame_size_) / 48; - config.payload_type = payload_type_; - config.application = AudioEncoderOpus::kVoip; - audio_encoder_.reset(new AudioEncoderOpus(config)); + config.application = AudioEncoderOpusConfig::ApplicationMode::kVoip; + audio_encoder_ = AudioEncoderOpus::MakeAudioEncoder(config, payload_type_); } }; @@ -448,12 +447,11 @@ class AudioDecoderOpusStereoTest : public AudioDecoderOpusTest { channels_ = 2; delete decoder_; decoder_ = new AudioDecoderOpus(2); - AudioEncoderOpus::Config config; + AudioEncoderOpusConfig config; config.frame_size_ms = static_cast(frame_size_) / 48; config.num_channels = 2; - config.payload_type = payload_type_; - config.application = AudioEncoderOpus::kAudio; - audio_encoder_.reset(new AudioEncoderOpus(config)); + config.application = AudioEncoderOpusConfig::ApplicationMode::kAudio; + audio_encoder_ = AudioEncoderOpus::MakeAudioEncoder(config, payload_type_); } };