diff --git a/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h b/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h index 245e33430..d330eeba7 100644 --- a/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h +++ b/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h @@ -51,6 +51,7 @@ class AudioEncoderOpus final : public AudioEncoder { void SetTargetBitrate(int bits_per_second) override; void SetProjectedPacketLossRate(double fraction) override; double packet_loss_rate() const { return packet_loss_rate_; } + ApplicationMode application() const { return application_; } protected: virtual bool EncodeInternal(uint32_t rtp_timestamp, diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc index 24fdca31c..5e9930e1c 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc @@ -1715,6 +1715,11 @@ bool ACMGenericCodecWrapper::ExternalRedNeeded() { return false; } +const AudioEncoder* ACMGenericCodecWrapper::GetAudioEncoder() const { + WriteLockScoped wl(codec_wrapper_lock_); + return encoder_; +} + void ACMGenericCodecWrapper::DestructEncoderSafe() { FATAL(); } diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h index 2154ebf93..5a36a8e28 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h +++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h @@ -1111,6 +1111,9 @@ class ACMGenericCodecWrapper : public ACMGenericCodec { bool ExternalRedNeeded() override; + // This method is only for testing. + const AudioEncoder* GetAudioEncoder() const; + protected: void DestructEncoderSafe() override EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_); diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec_opus_test.cc b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec_opus_test.cc new file mode 100644 index 000000000..b7a25226a --- /dev/null +++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec_opus_test.cc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014 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 "testing/gtest/include/gtest/gtest.h" +#include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h" +#include "webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h" + +namespace webrtc { +namespace acm2 { + +#ifdef WEBRTC_CODEC_OPUS +namespace { +const CodecInst kDefaultOpusCodecInst = {105, "opus", 48000, 960, 1, 32000}; +const int kCngPt = 255; // Not using CNG in this test. +const int kRedPt = 255; // Not using RED in this test. +} // namespace + +class AcmGenericCodecOpusTest : public ::testing::Test { + protected: + AcmGenericCodecOpusTest() { + acm_codec_params_ = {kDefaultOpusCodecInst, false, false, VADNormal}; + } + + void CreateCodec() { + codec_wrapper_.reset(new ACMGenericCodecWrapper( + acm_codec_params_.codec_inst, kCngPt, kCngPt, kCngPt, kCngPt, + false /* enable RED */, kRedPt)); + ASSERT_TRUE(codec_wrapper_); + ASSERT_EQ(0, codec_wrapper_->InitEncoder(&acm_codec_params_, true)); + } + + const AudioEncoderOpus* GetAudioEncoderOpus() { + const AudioEncoderOpus* ptr = static_cast( + codec_wrapper_->GetAudioEncoder()); + EXPECT_NE(nullptr, ptr); + return ptr; + } + WebRtcACMCodecParams acm_codec_params_; + scoped_ptr codec_wrapper_; +}; + +TEST_F(AcmGenericCodecOpusTest, DefaultApplicationModeMono) { + acm_codec_params_.codec_inst.channels = 1; + CreateCodec(); + EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application()); +} + +TEST_F(AcmGenericCodecOpusTest, DefaultApplicationModeStereo) { + acm_codec_params_.codec_inst.channels = 2; + CreateCodec(); + EXPECT_EQ(AudioEncoderOpus::kAudio, GetAudioEncoderOpus()->application()); +} + +TEST_F(AcmGenericCodecOpusTest, ChangeApplicationMode) { + // Create a stereo encoder. + acm_codec_params_.codec_inst.channels = 2; + CreateCodec(); + // Verify that the mode is kAudio. + const AudioEncoderOpus* opus_ptr = GetAudioEncoderOpus(); + EXPECT_EQ(AudioEncoderOpus::kAudio, opus_ptr->application()); + + // Change mode. + EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kVoip)); + // Verify that the AudioEncoder object was changed. + EXPECT_NE(opus_ptr, GetAudioEncoderOpus()); + EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application()); +} + +TEST_F(AcmGenericCodecOpusTest, ResetWontChangeApplicationMode) { + // Create a stereo encoder. + acm_codec_params_.codec_inst.channels = 2; + CreateCodec(); + const AudioEncoderOpus* opus_ptr = GetAudioEncoderOpus(); + // Verify that the mode is kAudio. + EXPECT_EQ(AudioEncoderOpus::kAudio, opus_ptr->application()); + + // Trigger a reset. + ASSERT_EQ(0, codec_wrapper_->InitEncoder(&acm_codec_params_, false)); + // Verify that the AudioEncoder object changed. + EXPECT_NE(opus_ptr, GetAudioEncoderOpus()); + // Verify that the mode is still kAudio. + EXPECT_EQ(AudioEncoderOpus::kAudio, GetAudioEncoderOpus()->application()); + + // Now change to kVoip. + EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kVoip)); + EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application()); + + opus_ptr = GetAudioEncoderOpus(); + // Trigger a reset again. + ASSERT_EQ(0, codec_wrapper_->InitEncoder(&acm_codec_params_, false)); + // Verify that the AudioEncoder object changed. + EXPECT_NE(opus_ptr, GetAudioEncoderOpus()); + // Verify that the mode is still kVoip. + EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application()); +} +#endif // WEBRTC_CODEC_OPUS + +} // namespace acm2 +} // namespace webrtc diff --git a/webrtc/modules/audio_coding/main/acm2/acm_opus_unittest.cc b/webrtc/modules/audio_coding/main/acm2/acm_opus_unittest.cc deleted file mode 100644 index 2c4358fc8..000000000 --- a/webrtc/modules/audio_coding/main/acm2/acm_opus_unittest.cc +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2014 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/modules/audio_coding/main/acm2/acm_opus.h" - -#include "testing/gtest/include/gtest/gtest.h" -#include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h" - -namespace webrtc { - -namespace acm2 { - -namespace { - const CodecInst kOpusCodecInst = {105, "opus", 48000, 960, 1, 32000}; - // These constants correspond to those used in ACMOpus::SetPacketLossRate(). - const int kPacketLossRate20 = 20; - const int kPacketLossRate10 = 10; - const int kPacketLossRate5 = 5; - const int kPacketLossRate1 = 1; - const int kLossRate20Margin = 2; - const int kLossRate10Margin = 1; - const int kLossRate5Margin = 1; -} // namespace - -class AcmOpusTest : public ACMOpus { - public: - explicit AcmOpusTest(int16_t codec_id) : ACMOpus(codec_id, false) {} - ~AcmOpusTest() {} - int packet_loss_rate() { return packet_loss_rate_; } - OpusApplicationMode application() { return application_; } - bool encoder_initialized() { - ReadLockScoped cs(codec_wrapper_lock_); - return encoder_initialized_; - } - - void TestSetPacketLossRate(int from, int to, int expected_return); -}; - -#ifdef WEBRTC_CODEC_OPUS -void AcmOpusTest::TestSetPacketLossRate(int from, int to, int expected_return) { - for (int loss = from; loss <= to; (to >= from) ? ++loss : --loss) { - EXPECT_EQ(0, SetPacketLossRate(loss)); - EXPECT_EQ(expected_return, packet_loss_rate()); - } -} - -TEST(AcmOpusTest, PacketLossRateOptimized) { - AcmOpusTest opus(ACMCodecDB::kOpus); - WebRtcACMCodecParams params; - memcpy(&(params.codec_inst), &kOpusCodecInst, sizeof(CodecInst)); - EXPECT_EQ(0, opus.InitEncoder(¶ms, true)); - EXPECT_EQ(0, opus.SetFEC(true)); - - // Note that the order of the following calls is critical. - opus.TestSetPacketLossRate(0, 0, 0); - opus.TestSetPacketLossRate(kPacketLossRate1, - kPacketLossRate5 + kLossRate5Margin - 1, - kPacketLossRate1); - opus.TestSetPacketLossRate(kPacketLossRate5 + kLossRate5Margin, - kPacketLossRate10 + kLossRate10Margin - 1, - kPacketLossRate5); - opus.TestSetPacketLossRate(kPacketLossRate10 + kLossRate10Margin, - kPacketLossRate20 + kLossRate20Margin - 1, - kPacketLossRate10); - opus.TestSetPacketLossRate(kPacketLossRate20 + kLossRate20Margin, - 100, - kPacketLossRate20); - opus.TestSetPacketLossRate(kPacketLossRate20 + kLossRate20Margin, - kPacketLossRate20 - kLossRate20Margin, - kPacketLossRate20); - opus.TestSetPacketLossRate(kPacketLossRate20 - kLossRate20Margin - 1, - kPacketLossRate10 - kLossRate10Margin, - kPacketLossRate10); - opus.TestSetPacketLossRate(kPacketLossRate10 - kLossRate10Margin - 1, - kPacketLossRate5 - kLossRate5Margin, - kPacketLossRate5); - opus.TestSetPacketLossRate(kPacketLossRate5 - kLossRate5Margin - 1, - kPacketLossRate1, - kPacketLossRate1); - opus.TestSetPacketLossRate(0, 0, 0); -} - -TEST(AcmOpusTest, DefaultApplicationMode) { - AcmOpusTest opus(ACMCodecDB::kOpus); - WebRtcACMCodecParams params; - memcpy(&(params.codec_inst), &kOpusCodecInst, sizeof(CodecInst)); - - params.codec_inst.channels = 2; - // Codec is not initialized, and hence without force initialization (2nd - // argument being false), an initialization will take place. - EXPECT_FALSE(opus.encoder_initialized()); - EXPECT_EQ(0, opus.InitEncoder(¶ms, false)); - EXPECT_EQ(kAudio, opus.application()); - - params.codec_inst.channels = 1; - EXPECT_EQ(0, opus.InitEncoder(¶ms, true)); - EXPECT_EQ(kVoip, opus.application()); -} - -TEST(AcmOpusTest, ChangeApplicationMode) { - AcmOpusTest opus(ACMCodecDB::kOpus); - WebRtcACMCodecParams params; - memcpy(&(params.codec_inst), &kOpusCodecInst, sizeof(CodecInst)); - - params.codec_inst.channels = 2; - // Codec is not initialized, and hence without force initialization (2nd - // argument being false), an initialization will take place. - EXPECT_EQ(0, opus.InitEncoder(¶ms, false)); - EXPECT_EQ(kAudio, opus.application()); - - opus.SetOpusApplication(kVoip); - EXPECT_EQ(kVoip, opus.application()); -} - -TEST(AcmOpusTest, ResetWontChangeApplicationMode) { - AcmOpusTest opus(ACMCodecDB::kOpus); - WebRtcACMCodecParams params; - memcpy(&(params.codec_inst), &kOpusCodecInst, sizeof(CodecInst)); - - params.codec_inst.channels = 2; - // Codec is not initialized, and hence without force initialization (2nd - // argument being false), an initialization will take place. - EXPECT_EQ(0, opus.InitEncoder(¶ms, false)); - EXPECT_EQ(kAudio, opus.application()); - - opus.ResetEncoder(); - EXPECT_EQ(kAudio, opus.application()); -} - -#else -void AcmOpusTest:TestSetPacketLossRate(int /* from */, int /* to */, - int /* expected_return */) { - return; -} -#endif // WEBRTC_CODEC_OPUS - -} // namespace acm2 - -} // namespace webrtc diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index c1c8dabb2..d9f071e99 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -91,7 +91,7 @@ ], 'sources': [ 'audio_coding/codecs/cng/audio_encoder_cng_unittest.cc', - 'audio_coding/main/acm2/acm_opus_unittest.cc', + 'audio_coding/main/acm2/acm_generic_codec_opus_test.cc', 'audio_coding/main/acm2/acm_receiver_unittest.cc', 'audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc', 'audio_coding/main/acm2/audio_coding_module_unittest.cc',