| Index: webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
|
| 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 1b836f36645726cac37845eaf69204f9fb8a5a5e..3e0e1865efec5a1640855dc8a168d8534f17521e 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
|
| @@ -12,92 +12,158 @@
|
|
|
| #include "webrtc/base/checks.h"
|
| #include "webrtc/common_types.h"
|
| +#include "webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_audio_network_adaptor.h"
|
| #include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h"
|
| #include "webrtc/test/gtest.h"
|
|
|
| namespace webrtc {
|
| +using ::testing::NiceMock;
|
| +using ::testing::Return;
|
|
|
| namespace {
|
| -const CodecInst kOpusSettings = {105, "opus", 48000, 960, 1, 32000};
|
| -} // namespace
|
|
|
| -class AudioEncoderOpusTest : public ::testing::Test {
|
| - protected:
|
| - void CreateCodec(int num_channels) {
|
| - codec_inst_.channels = num_channels;
|
| - encoder_.reset(new AudioEncoderOpus(codec_inst_));
|
| - auto expected_app =
|
| - num_channels == 1 ? AudioEncoderOpus::kVoip : AudioEncoderOpus::kAudio;
|
| - EXPECT_EQ(expected_app, encoder_->application());
|
| - }
|
| +const CodecInst kDefaultOpusSettings = {105, "opus", 48000, 960, 1, 32000};
|
|
|
| - CodecInst codec_inst_ = kOpusSettings;
|
| - std::unique_ptr<AudioEncoderOpus> encoder_;
|
| +AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) {
|
| + AudioEncoderOpus::Config config;
|
| + config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48);
|
| + config.num_channels = codec_inst.channels;
|
| + config.bitrate_bps = rtc::Optional<int>(codec_inst.rate);
|
| + config.payload_type = codec_inst.pltype;
|
| + config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip
|
| + : AudioEncoderOpus::kAudio;
|
| + return config;
|
| +}
|
| +
|
| +struct AudioEncoderOpusStates {
|
| + std::shared_ptr<MockAudioNetworkAdaptor*> mock_audio_network_adaptor;
|
| + std::unique_ptr<AudioEncoderOpus> encoder;
|
| };
|
|
|
| -TEST_F(AudioEncoderOpusTest, DefaultApplicationModeMono) {
|
| - CreateCodec(1);
|
| +AudioEncoderOpusStates CreateCodec(size_t num_channels) {
|
| + AudioEncoderOpusStates states;
|
| + states.mock_audio_network_adaptor =
|
| + std::make_shared<MockAudioNetworkAdaptor*>(nullptr);
|
| +
|
| + std::weak_ptr<MockAudioNetworkAdaptor*> mock_ptr(
|
| + states.mock_audio_network_adaptor);
|
| + AudioEncoderOpus::AudioNetworkAdaptorCreator creator = [mock_ptr](
|
| + const std::string&, const Clock*) {
|
| + std::unique_ptr<MockAudioNetworkAdaptor> adaptor(
|
| + new NiceMock<MockAudioNetworkAdaptor>());
|
| + EXPECT_CALL(*adaptor, Die());
|
| + if (auto sp = mock_ptr.lock()) {
|
| + *sp = adaptor.get();
|
| + } else {
|
| + RTC_NOTREACHED();
|
| + }
|
| + return adaptor;
|
| + };
|
| +
|
| + CodecInst codec_inst = kDefaultOpusSettings;
|
| + codec_inst.channels = num_channels;
|
| + auto config = CreateConfig(codec_inst);
|
| + states.encoder.reset(new AudioEncoderOpus(config, std::move(creator)));
|
| + return states;
|
| +}
|
| +
|
| +AudioNetworkAdaptor::EncoderRuntimeConfig CreateEncoderRuntimeConfig() {
|
| + constexpr int kBitrate = 40000;
|
| + constexpr int kFrameLength = 60;
|
| + constexpr bool kEnableFec = true;
|
| + constexpr bool kEnableDtx = false;
|
| + constexpr size_t kNumChannels = 1;
|
| + constexpr float kPacketLossFraction = 0.1f;
|
| + AudioNetworkAdaptor::EncoderRuntimeConfig config;
|
| + config.bitrate_bps = rtc::Optional<int>(kBitrate);
|
| + config.frame_length_ms = rtc::Optional<int>(kFrameLength);
|
| + config.enable_fec = rtc::Optional<bool>(kEnableFec);
|
| + config.enable_dtx = rtc::Optional<bool>(kEnableDtx);
|
| + config.num_channels = rtc::Optional<size_t>(kNumChannels);
|
| + config.uplink_packet_loss_fraction =
|
| + rtc::Optional<float>(kPacketLossFraction);
|
| + return config;
|
| +}
|
| +
|
| +void CheckEncoderRuntimeConfig(
|
| + const AudioEncoderOpus* encoder,
|
| + const AudioNetworkAdaptor::EncoderRuntimeConfig& config) {
|
| + EXPECT_EQ(*config.bitrate_bps, encoder->GetTargetBitrate());
|
| + EXPECT_EQ(*config.frame_length_ms, encoder->next_frame_length_ms());
|
| + EXPECT_EQ(*config.enable_fec, encoder->fec_enabled());
|
| + EXPECT_EQ(*config.enable_dtx, encoder->GetDtx());
|
| + EXPECT_EQ(*config.num_channels, encoder->num_channels_to_encode());
|
| }
|
|
|
| -TEST_F(AudioEncoderOpusTest, DefaultApplicationModeStereo) {
|
| - CreateCodec(2);
|
| +} // namespace
|
| +
|
| +TEST(AudioEncoderOpusTest, DefaultApplicationModeMono) {
|
| + auto states = CreateCodec(1);
|
| + EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application());
|
| }
|
|
|
| -TEST_F(AudioEncoderOpusTest, ChangeApplicationMode) {
|
| - CreateCodec(2);
|
| - EXPECT_TRUE(encoder_->SetApplication(AudioEncoder::Application::kSpeech));
|
| - EXPECT_EQ(AudioEncoderOpus::kVoip, encoder_->application());
|
| +TEST(AudioEncoderOpusTest, DefaultApplicationModeStereo) {
|
| + auto states = CreateCodec(2);
|
| + EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application());
|
| }
|
|
|
| -TEST_F(AudioEncoderOpusTest, ResetWontChangeApplicationMode) {
|
| - CreateCodec(2);
|
| +TEST(AudioEncoderOpusTest, ChangeApplicationMode) {
|
| + auto states = CreateCodec(2);
|
| + EXPECT_TRUE(
|
| + states.encoder->SetApplication(AudioEncoder::Application::kSpeech));
|
| + EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application());
|
| +}
|
| +
|
| +TEST(AudioEncoderOpusTest, ResetWontChangeApplicationMode) {
|
| + auto states = CreateCodec(2);
|
|
|
| // Trigger a reset.
|
| - encoder_->Reset();
|
| + states.encoder->Reset();
|
| // Verify that the mode is still kAudio.
|
| - EXPECT_EQ(AudioEncoderOpus::kAudio, encoder_->application());
|
| + EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application());
|
|
|
| // Now change to kVoip.
|
| - EXPECT_TRUE(encoder_->SetApplication(AudioEncoder::Application::kSpeech));
|
| - EXPECT_EQ(AudioEncoderOpus::kVoip, encoder_->application());
|
| + EXPECT_TRUE(
|
| + states.encoder->SetApplication(AudioEncoder::Application::kSpeech));
|
| + EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application());
|
|
|
| // Trigger a reset again.
|
| - encoder_->Reset();
|
| + states.encoder->Reset();
|
| // Verify that the mode is still kVoip.
|
| - EXPECT_EQ(AudioEncoderOpus::kVoip, encoder_->application());
|
| + EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application());
|
| }
|
|
|
| -TEST_F(AudioEncoderOpusTest, ToggleDtx) {
|
| - CreateCodec(2);
|
| +TEST(AudioEncoderOpusTest, ToggleDtx) {
|
| + auto states = CreateCodec(2);
|
| // Enable DTX
|
| - EXPECT_TRUE(encoder_->SetDtx(true));
|
| + EXPECT_TRUE(states.encoder->SetDtx(true));
|
| // Verify that the mode is still kAudio.
|
| - EXPECT_EQ(AudioEncoderOpus::kAudio, encoder_->application());
|
| + EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application());
|
| // Turn off DTX.
|
| - EXPECT_TRUE(encoder_->SetDtx(false));
|
| + EXPECT_TRUE(states.encoder->SetDtx(false));
|
| }
|
|
|
| -TEST_F(AudioEncoderOpusTest, SetBitrate) {
|
| - CreateCodec(1);
|
| - // Constants are replicated from audio_encoder_opus.cc.
|
| +TEST(AudioEncoderOpusTest, SetBitrate) {
|
| + auto states = CreateCodec(1);
|
| + // Constants are replicated from audio_states.encoderopus.cc.
|
| const int kMinBitrateBps = 500;
|
| const int kMaxBitrateBps = 512000;
|
| // Set a too low bitrate.
|
| - encoder_->SetTargetBitrate(kMinBitrateBps - 1);
|
| - EXPECT_EQ(kMinBitrateBps, encoder_->GetTargetBitrate());
|
| + states.encoder->SetTargetBitrate(kMinBitrateBps - 1);
|
| + EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate());
|
| // Set a too high bitrate.
|
| - encoder_->SetTargetBitrate(kMaxBitrateBps + 1);
|
| - EXPECT_EQ(kMaxBitrateBps, encoder_->GetTargetBitrate());
|
| + states.encoder->SetTargetBitrate(kMaxBitrateBps + 1);
|
| + EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate());
|
| // Set the minimum rate.
|
| - encoder_->SetTargetBitrate(kMinBitrateBps);
|
| - EXPECT_EQ(kMinBitrateBps, encoder_->GetTargetBitrate());
|
| + states.encoder->SetTargetBitrate(kMinBitrateBps);
|
| + EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate());
|
| // Set the maximum rate.
|
| - encoder_->SetTargetBitrate(kMaxBitrateBps);
|
| - EXPECT_EQ(kMaxBitrateBps, encoder_->GetTargetBitrate());
|
| + states.encoder->SetTargetBitrate(kMaxBitrateBps);
|
| + EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate());
|
| // Set rates from 1000 up to 32000 bps.
|
| for (int rate = 1000; rate <= 32000; rate += 1000) {
|
| - encoder_->SetTargetBitrate(rate);
|
| - EXPECT_EQ(rate, encoder_->GetTargetBitrate());
|
| + states.encoder->SetTargetBitrate(rate);
|
| + EXPECT_EQ(rate, states.encoder->GetTargetBitrate());
|
| }
|
| }
|
|
|
| @@ -128,26 +194,113 @@ void TestSetPacketLossRate(AudioEncoderOpus* encoder,
|
|
|
| } // namespace
|
|
|
| -TEST_F(AudioEncoderOpusTest, PacketLossRateOptimized) {
|
| - CreateCodec(1);
|
| +TEST(AudioEncoderOpusTest, PacketLossRateOptimized) {
|
| + auto states = CreateCodec(1);
|
| auto I = [](double a, double b) { return IntervalSteps(a, b, 10); };
|
| const double eps = 1e-15;
|
|
|
| // Note that the order of the following calls is critical.
|
|
|
| // clang-format off
|
| - TestSetPacketLossRate(encoder_.get(), I(0.00 , 0.01 - eps), 0.00);
|
| - TestSetPacketLossRate(encoder_.get(), I(0.01 + eps, 0.06 - eps), 0.01);
|
| - TestSetPacketLossRate(encoder_.get(), I(0.06 + eps, 0.11 - eps), 0.05);
|
| - TestSetPacketLossRate(encoder_.get(), I(0.11 + eps, 0.22 - eps), 0.10);
|
| - TestSetPacketLossRate(encoder_.get(), I(0.22 + eps, 1.00 ), 0.20);
|
| -
|
| - TestSetPacketLossRate(encoder_.get(), I(1.00 , 0.18 + eps), 0.20);
|
| - TestSetPacketLossRate(encoder_.get(), I(0.18 - eps, 0.09 + eps), 0.10);
|
| - TestSetPacketLossRate(encoder_.get(), I(0.09 - eps, 0.04 + eps), 0.05);
|
| - TestSetPacketLossRate(encoder_.get(), I(0.04 - eps, 0.01 + eps), 0.01);
|
| - TestSetPacketLossRate(encoder_.get(), I(0.01 - eps, 0.00 ), 0.00);
|
| + TestSetPacketLossRate(states.encoder.get(), I(0.00 , 0.01 - eps), 0.00);
|
| + TestSetPacketLossRate(states.encoder.get(), I(0.01 + eps, 0.06 - eps), 0.01);
|
| + TestSetPacketLossRate(states.encoder.get(), I(0.06 + eps, 0.11 - eps), 0.05);
|
| + TestSetPacketLossRate(states.encoder.get(), I(0.11 + eps, 0.22 - eps), 0.10);
|
| + TestSetPacketLossRate(states.encoder.get(), I(0.22 + eps, 1.00 ), 0.20);
|
| +
|
| + TestSetPacketLossRate(states.encoder.get(), I(1.00 , 0.18 + eps), 0.20);
|
| + TestSetPacketLossRate(states.encoder.get(), I(0.18 - eps, 0.09 + eps), 0.10);
|
| + TestSetPacketLossRate(states.encoder.get(), I(0.09 - eps, 0.04 + eps), 0.05);
|
| + TestSetPacketLossRate(states.encoder.get(), I(0.04 - eps, 0.01 + eps), 0.01);
|
| + TestSetPacketLossRate(states.encoder.get(), I(0.01 - eps, 0.00 ), 0.00);
|
| // clang-format on
|
| }
|
|
|
| +TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnSetUplinkBandwidth) {
|
| + auto states = CreateCodec(2);
|
| + printf("passed!\n");
|
| + states.encoder->EnableAudioNetworkAdaptor("", nullptr);
|
| +
|
| + auto config = CreateEncoderRuntimeConfig();
|
| + EXPECT_CALL(**states.mock_audio_network_adaptor, GetEncoderRuntimeConfig())
|
| + .WillOnce(Return(config));
|
| +
|
| + // Since using mock audio network adaptor, any bandwidth value is fine.
|
| + constexpr int kUplinkBandwidth = 50000;
|
| + EXPECT_CALL(**states.mock_audio_network_adaptor,
|
| + SetUplinkBandwidth(kUplinkBandwidth));
|
| + states.encoder->OnReceivedUplinkBandwidth(kUplinkBandwidth);
|
| +
|
| + CheckEncoderRuntimeConfig(states.encoder.get(), config);
|
| +}
|
| +
|
| +TEST(AudioEncoderOpusTest,
|
| + InvokeAudioNetworkAdaptorOnSetUplinkPacketLossFraction) {
|
| + auto states = CreateCodec(2);
|
| + states.encoder->EnableAudioNetworkAdaptor("", nullptr);
|
| +
|
| + auto config = CreateEncoderRuntimeConfig();
|
| + EXPECT_CALL(**states.mock_audio_network_adaptor, GetEncoderRuntimeConfig())
|
| + .WillOnce(Return(config));
|
| +
|
| + // Since using mock audio network adaptor, any packet loss fraction is fine.
|
| + constexpr float kUplinkPacketLoss = 0.1f;
|
| + EXPECT_CALL(**states.mock_audio_network_adaptor,
|
| + SetUplinkPacketLossFraction(kUplinkPacketLoss));
|
| + states.encoder->OnReceivedUplinkPacketLossFraction(kUplinkPacketLoss);
|
| +
|
| + CheckEncoderRuntimeConfig(states.encoder.get(), config);
|
| +}
|
| +
|
| +TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnSetTargetAudioBitrate) {
|
| + auto states = CreateCodec(2);
|
| + states.encoder->EnableAudioNetworkAdaptor("", nullptr);
|
| +
|
| + auto config = CreateEncoderRuntimeConfig();
|
| + EXPECT_CALL(**states.mock_audio_network_adaptor, GetEncoderRuntimeConfig())
|
| + .WillOnce(Return(config));
|
| +
|
| + // Since using mock audio network adaptor, any target audio bitrate is fine.
|
| + constexpr int kTargetAudioBitrate = 30000;
|
| + EXPECT_CALL(**states.mock_audio_network_adaptor,
|
| + SetTargetAudioBitrate(kTargetAudioBitrate));
|
| + states.encoder->OnReceivedTargetAudioBitrate(kTargetAudioBitrate);
|
| +
|
| + CheckEncoderRuntimeConfig(states.encoder.get(), config);
|
| +}
|
| +
|
| +TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnSetRtt) {
|
| + auto states = CreateCodec(2);
|
| + states.encoder->EnableAudioNetworkAdaptor("", nullptr);
|
| +
|
| + auto config = CreateEncoderRuntimeConfig();
|
| + EXPECT_CALL(**states.mock_audio_network_adaptor, GetEncoderRuntimeConfig())
|
| + .WillOnce(Return(config));
|
| +
|
| + // Since using mock audio network adaptor, any rtt is fine.
|
| + constexpr int kRtt = 30;
|
| + EXPECT_CALL(**states.mock_audio_network_adaptor, SetRtt(kRtt));
|
| + states.encoder->OnReceivedRtt(kRtt);
|
| +
|
| + CheckEncoderRuntimeConfig(states.encoder.get(), config);
|
| +}
|
| +
|
| +TEST(AudioEncoderOpusTest,
|
| + InvokeAudioNetworkAdaptorOnSetReceiverFrameLengthRange) {
|
| + auto states = CreateCodec(2);
|
| + states.encoder->EnableAudioNetworkAdaptor("", nullptr);
|
| +
|
| + auto config = CreateEncoderRuntimeConfig();
|
| + EXPECT_CALL(**states.mock_audio_network_adaptor, GetEncoderRuntimeConfig())
|
| + .WillOnce(Return(config));
|
| +
|
| + constexpr int kMinFrameLength = 10;
|
| + constexpr int kMaxFrameLength = 60;
|
| + EXPECT_CALL(**states.mock_audio_network_adaptor,
|
| + SetReceiverFrameLengthRange(kMinFrameLength, kMaxFrameLength));
|
| + states.encoder->SetReceiverFrameLengthRange(kMinFrameLength, kMaxFrameLength);
|
| +
|
| + CheckEncoderRuntimeConfig(states.encoder.get(), config);
|
| +}
|
| +
|
| } // namespace webrtc
|
|
|