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 "api/audio_codecs/opus/audio_decoder_opus.h"
12 #include "api/audio_codecs/opus/audio_encoder_opus.h"
13 #include "common_audio/include/audio_util.h"
14 #include "common_audio/window_generator.h"
15 #include "modules/audio_coding/codecs/opus/test/lapped_transform.h"
16 #include "modules/audio_coding/neteq/tools/audio_loop.h"
17 #include "test/field_trial.h"
18 #include "test/gtest.h"
19 #include "test/testsupport/file_utils.h"
20 
21 namespace webrtc {
22 namespace {
23 
24 constexpr size_t kNumChannels = 1u;
25 constexpr int kSampleRateHz = 48000;
26 constexpr size_t kMaxLoopLengthSamples = kSampleRateHz * 50;  // 50 seconds.
27 constexpr size_t kInputBlockSizeSamples = 10 * kSampleRateHz / 1000;   // 10 ms
28 constexpr size_t kOutputBlockSizeSamples = 20 * kSampleRateHz / 1000;  // 20 ms
29 constexpr size_t kFftSize = 1024;
30 constexpr size_t kNarrowbandSize = 4000 * kFftSize / kSampleRateHz;
31 constexpr float kKbdAlpha = 1.5f;
32 
33 class PowerRatioEstimator : public LappedTransform::Callback {
34  public:
PowerRatioEstimator()35   PowerRatioEstimator() : low_pow_(0.f), high_pow_(0.f) {
36     WindowGenerator::KaiserBesselDerived(kKbdAlpha, kFftSize, window_);
37     transform_.reset(new LappedTransform(kNumChannels, 0u,
38                                          kInputBlockSizeSamples, window_,
39                                          kFftSize, kFftSize / 2, this));
40   }
41 
ProcessBlock(float * data)42   void ProcessBlock(float* data) { transform_->ProcessChunk(&data, nullptr); }
43 
PowerRatio()44   float PowerRatio() { return high_pow_ / low_pow_; }
45 
46  protected:
ProcessAudioBlock(const std::complex<float> * const * input,size_t num_input_channels,size_t num_freq_bins,size_t num_output_channels,std::complex<float> * const * output)47   void ProcessAudioBlock(const std::complex<float>* const* input,
48                          size_t num_input_channels,
49                          size_t num_freq_bins,
50                          size_t num_output_channels,
51                          std::complex<float>* const* output) override {
52     float low_pow = 0.f;
53     float high_pow = 0.f;
54     for (size_t i = 0u; i < num_input_channels; ++i) {
55       for (size_t j = 0u; j < kNarrowbandSize; ++j) {
56         float low_mag = std::abs(input[i][j]);
57         low_pow += low_mag * low_mag;
58         float high_mag = std::abs(input[i][j + kNarrowbandSize]);
59         high_pow += high_mag * high_mag;
60       }
61     }
62     low_pow_ += low_pow / (num_input_channels * kFftSize);
63     high_pow_ += high_pow / (num_input_channels * kFftSize);
64   }
65 
66  private:
67   std::unique_ptr<LappedTransform> transform_;
68   float window_[kFftSize];
69   float low_pow_;
70   float high_pow_;
71 };
72 
EncodedPowerRatio(AudioEncoder * encoder,AudioDecoder * decoder,test::AudioLoop * audio_loop)73 float EncodedPowerRatio(AudioEncoder* encoder,
74                         AudioDecoder* decoder,
75                         test::AudioLoop* audio_loop) {
76   // Encode and decode.
77   uint32_t rtp_timestamp = 0u;
78   constexpr size_t kBufferSize = 500;
79   rtc::Buffer encoded(kBufferSize);
80   std::vector<int16_t> decoded(kOutputBlockSizeSamples);
81   std::vector<float> decoded_float(kOutputBlockSizeSamples);
82   AudioDecoder::SpeechType speech_type = AudioDecoder::kSpeech;
83   PowerRatioEstimator power_ratio_estimator;
84   for (size_t i = 0; i < 1000; ++i) {
85     encoded.Clear();
86     AudioEncoder::EncodedInfo encoder_info =
87         encoder->Encode(rtp_timestamp, audio_loop->GetNextBlock(), &encoded);
88     rtp_timestamp += kInputBlockSizeSamples;
89     if (encoded.size() > 0) {
90       int decoder_info = decoder->Decode(
91           encoded.data(), encoded.size(), kSampleRateHz,
92           decoded.size() * sizeof(decoded[0]), decoded.data(), &speech_type);
93       if (decoder_info > 0) {
94         S16ToFloat(decoded.data(), decoded.size(), decoded_float.data());
95         power_ratio_estimator.ProcessBlock(decoded_float.data());
96       }
97     }
98   }
99   return power_ratio_estimator.PowerRatio();
100 }
101 
102 }  // namespace
103 
104 // TODO(ivoc): Remove this test, WebRTC-AdjustOpusBandwidth is obsolete.
TEST(BandwidthAdaptationTest,BandwidthAdaptationTest)105 TEST(BandwidthAdaptationTest, BandwidthAdaptationTest) {
106   test::ScopedFieldTrials override_field_trials(
107       "WebRTC-AdjustOpusBandwidth/Enabled/");
108 
109   constexpr float kMaxNarrowbandRatio = 0.0035f;
110   constexpr float kMinWidebandRatio = 0.01f;
111 
112   // Create encoder.
113   AudioEncoderOpusConfig enc_config;
114   enc_config.bitrate_bps = absl::optional<int>(7999);
115   enc_config.num_channels = kNumChannels;
116   constexpr int payload_type = 17;
117   auto encoder = AudioEncoderOpus::MakeAudioEncoder(enc_config, payload_type);
118 
119   // Create decoder.
120   AudioDecoderOpus::Config dec_config;
121   dec_config.num_channels = kNumChannels;
122   auto decoder = AudioDecoderOpus::MakeAudioDecoder(dec_config);
123 
124   // Open speech file.
125   const std::string kInputFileName =
126       webrtc::test::ResourcePath("audio_coding/speech_mono_32_48kHz", "pcm");
127   test::AudioLoop audio_loop;
128   EXPECT_EQ(kSampleRateHz, encoder->SampleRateHz());
129   ASSERT_TRUE(audio_loop.Init(kInputFileName, kMaxLoopLengthSamples,
130                               kInputBlockSizeSamples));
131 
132   EXPECT_LT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop),
133             kMaxNarrowbandRatio);
134 
135   encoder->OnReceivedTargetAudioBitrate(9000);
136   EXPECT_LT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop),
137             kMaxNarrowbandRatio);
138 
139   encoder->OnReceivedTargetAudioBitrate(9001);
140   EXPECT_GT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop),
141             kMinWidebandRatio);
142 
143   encoder->OnReceivedTargetAudioBitrate(8000);
144   EXPECT_GT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop),
145             kMinWidebandRatio);
146 
147   encoder->OnReceivedTargetAudioBitrate(12001);
148   EXPECT_GT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop),
149             kMinWidebandRatio);
150 }
151 
152 }  // namespace webrtc
153