opus_bandwidth_unittest.cc (6329B)
1 /* 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <complex> 12 #include <cstddef> 13 #include <cstdint> 14 #include <cstdlib> 15 #include <memory> 16 #include <optional> 17 #include <string> 18 #include <vector> 19 20 #include "api/audio_codecs/audio_decoder.h" 21 #include "api/audio_codecs/audio_encoder.h" 22 #include "api/audio_codecs/opus/audio_decoder_opus.h" 23 #include "api/audio_codecs/opus/audio_encoder_opus.h" 24 #include "api/audio_codecs/opus/audio_encoder_opus_config.h" 25 #include "api/environment/environment.h" 26 #include "api/environment/environment_factory.h" 27 #include "api/field_trials.h" 28 #include "common_audio/include/audio_util.h" 29 #include "common_audio/window_generator.h" 30 #include "modules/audio_coding/codecs/opus/test/lapped_transform.h" 31 #include "modules/audio_coding/neteq/tools/audio_loop.h" 32 #include "rtc_base/buffer.h" 33 #include "test/create_test_field_trials.h" 34 #include "test/gtest.h" 35 #include "test/testsupport/file_utils.h" 36 37 namespace webrtc { 38 namespace { 39 40 constexpr size_t kNumChannels = 1u; 41 constexpr int kSampleRateHz = 48000; 42 constexpr size_t kMaxLoopLengthSamples = kSampleRateHz * 50; // 50 seconds. 43 constexpr size_t kInputBlockSizeSamples = 10 * kSampleRateHz / 1000; // 10 ms 44 constexpr size_t kOutputBlockSizeSamples = 20 * kSampleRateHz / 1000; // 20 ms 45 constexpr size_t kFftSize = 1024; 46 constexpr size_t kNarrowbandSize = 4000 * kFftSize / kSampleRateHz; 47 constexpr float kKbdAlpha = 1.5f; 48 49 class PowerRatioEstimator : public LappedTransform::Callback { 50 public: 51 PowerRatioEstimator() : low_pow_(0.f), high_pow_(0.f) { 52 WindowGenerator::KaiserBesselDerived(kKbdAlpha, kFftSize, window_); 53 transform_.reset(new LappedTransform(kNumChannels, 0u, 54 kInputBlockSizeSamples, window_, 55 kFftSize, kFftSize / 2, this)); 56 } 57 58 void ProcessBlock(float* data) { transform_->ProcessChunk(&data, nullptr); } 59 60 float PowerRatio() { return high_pow_ / low_pow_; } 61 62 protected: 63 void ProcessAudioBlock(const std::complex<float>* const* input, 64 size_t num_input_channels, 65 size_t /* num_freq_bins */, 66 size_t /* num_output_channels */, 67 std::complex<float>* const* /* output */) override { 68 float low_pow = 0.f; 69 float high_pow = 0.f; 70 for (size_t i = 0u; i < num_input_channels; ++i) { 71 for (size_t j = 0u; j < kNarrowbandSize; ++j) { 72 float low_mag = std::abs(input[i][j]); 73 low_pow += low_mag * low_mag; 74 float high_mag = std::abs(input[i][j + kNarrowbandSize]); 75 high_pow += high_mag * high_mag; 76 } 77 } 78 low_pow_ += low_pow / (num_input_channels * kFftSize); 79 high_pow_ += high_pow / (num_input_channels * kFftSize); 80 } 81 82 private: 83 std::unique_ptr<LappedTransform> transform_; 84 float window_[kFftSize]; 85 float low_pow_; 86 float high_pow_; 87 }; 88 89 float EncodedPowerRatio(AudioEncoder* encoder, 90 AudioDecoder* decoder, 91 test::AudioLoop* audio_loop) { 92 // Encode and decode. 93 uint32_t rtp_timestamp = 0u; 94 constexpr size_t kBufferSize = 500; 95 Buffer encoded(kBufferSize); 96 std::vector<int16_t> decoded(kOutputBlockSizeSamples); 97 std::vector<float> decoded_float(kOutputBlockSizeSamples); 98 AudioDecoder::SpeechType speech_type = AudioDecoder::kSpeech; 99 PowerRatioEstimator power_ratio_estimator; 100 for (size_t i = 0; i < 1000; ++i) { 101 encoded.Clear(); 102 AudioEncoder::EncodedInfo encoder_info = 103 encoder->Encode(rtp_timestamp, audio_loop->GetNextBlock(), &encoded); 104 rtp_timestamp += kInputBlockSizeSamples; 105 if (!encoded.empty()) { 106 int decoder_info = decoder->Decode( 107 encoded.data(), encoded.size(), kSampleRateHz, 108 decoded.size() * sizeof(decoded[0]), decoded.data(), &speech_type); 109 if (decoder_info > 0) { 110 S16ToFloat(decoded.data(), decoded.size(), decoded_float.data()); 111 power_ratio_estimator.ProcessBlock(decoded_float.data()); 112 } 113 } 114 } 115 return power_ratio_estimator.PowerRatio(); 116 } 117 118 } // namespace 119 120 // TODO(ivoc): Remove this test, WebRTC-AdjustOpusBandwidth is obsolete. 121 TEST(BandwidthAdaptationTest, BandwidthAdaptationTest) { 122 const Environment env = CreateEnvironment(std::make_unique<FieldTrials>( 123 CreateTestFieldTrials("WebRTC-AdjustOpusBandwidth/Enabled/"))); 124 125 constexpr float kMaxNarrowbandRatio = 0.0035f; 126 constexpr float kMinWidebandRatio = 0.01f; 127 128 // Create encoder. 129 AudioEncoderOpusConfig enc_config; 130 enc_config.bitrate_bps = std::optional<int>(7999); 131 enc_config.num_channels = kNumChannels; 132 auto encoder = 133 AudioEncoderOpus::MakeAudioEncoder(env, enc_config, {.payload_type = 17}); 134 135 // Create decoder. 136 AudioDecoderOpus::Config dec_config; 137 dec_config.num_channels = kNumChannels; 138 auto decoder = AudioDecoderOpus::MakeAudioDecoder(env, dec_config); 139 140 // Open speech file. 141 const std::string kInputFileName = 142 test::ResourcePath("audio_coding/speech_mono_32_48kHz", "pcm"); 143 test::AudioLoop audio_loop; 144 EXPECT_EQ(kSampleRateHz, encoder->SampleRateHz()); 145 ASSERT_TRUE(audio_loop.Init(kInputFileName, kMaxLoopLengthSamples, 146 kInputBlockSizeSamples)); 147 148 EXPECT_LT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop), 149 kMaxNarrowbandRatio); 150 151 encoder->OnReceivedTargetAudioBitrate(9000); 152 EXPECT_LT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop), 153 kMaxNarrowbandRatio); 154 155 encoder->OnReceivedTargetAudioBitrate(9001); 156 EXPECT_GT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop), 157 kMinWidebandRatio); 158 159 encoder->OnReceivedTargetAudioBitrate(8000); 160 EXPECT_GT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop), 161 kMinWidebandRatio); 162 163 encoder->OnReceivedTargetAudioBitrate(12001); 164 EXPECT_GT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop), 165 kMinWidebandRatio); 166 } 167 168 } // namespace webrtc