blob: 2c8edf00346aa46be7fca4ad491a9491092cec5c [file] [log] [blame]
Alex Luebseeb27652017-11-20 11:13:56 -08001/*
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"
Alex Luebseeb27652017-11-20 11:13:56 -080014#include "common_audio/window_generator.h"
Alessio Bazzicad4161a32018-08-31 10:41:37 +020015#include "modules/audio_coding/codecs/opus/test/lapped_transform.h"
Alex Luebseeb27652017-11-20 11:13:56 -080016#include "modules/audio_coding/neteq/tools/audio_loop.h"
17#include "test/field_trial.h"
18#include "test/gtest.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "test/testsupport/file_utils.h"
Alex Luebseeb27652017-11-20 11:13:56 -080020
21namespace webrtc {
22namespace {
23
24constexpr size_t kNumChannels = 1u;
25constexpr int kSampleRateHz = 48000;
26constexpr size_t kMaxLoopLengthSamples = kSampleRateHz * 50; // 50 seconds.
27constexpr size_t kInputBlockSizeSamples = 10 * kSampleRateHz / 1000; // 10 ms
28constexpr size_t kOutputBlockSizeSamples = 20 * kSampleRateHz / 1000; // 20 ms
29constexpr size_t kFftSize = 1024;
30constexpr size_t kNarrowbandSize = 4000 * kFftSize / kSampleRateHz;
31constexpr float kKbdAlpha = 1.5f;
32
33class PowerRatioEstimator : public LappedTransform::Callback {
34 public:
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
42 void ProcessBlock(float* data) { transform_->ProcessChunk(&data, nullptr); }
43
44 float PowerRatio() { return high_pow_ / low_pow_; }
45
46 protected:
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
73float 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
104TEST(BandwidthAdaptationTest, BandwidthAdaptationTest) {
105 test::ScopedFieldTrials override_field_trials(
106 "WebRTC-AdjustOpusBandwidth/Enabled/");
107
Gustaf Ullbergb9fc6502018-05-21 15:50:22 +0200108 constexpr float kMaxNarrowbandRatio = 0.0035f;
Alex Luebseeb27652017-11-20 11:13:56 -0800109 constexpr float kMinWidebandRatio = 0.03f;
110
111 // Create encoder.
112 AudioEncoderOpusConfig enc_config;
Danil Chapovalovb6021232018-06-19 13:26:36 +0200113 enc_config.bitrate_bps = absl::optional<int>(7999);
Alex Luebseeb27652017-11-20 11:13:56 -0800114 enc_config.num_channels = kNumChannels;
115 constexpr int payload_type = 17;
116 auto encoder = AudioEncoderOpus::MakeAudioEncoder(enc_config, payload_type);
117
118 // Create decoder.
119 AudioDecoderOpus::Config dec_config;
120 dec_config.num_channels = kNumChannels;
121 auto decoder = AudioDecoderOpus::MakeAudioDecoder(dec_config);
122
123 // Open speech file.
124 const std::string kInputFileName =
125 webrtc::test::ResourcePath("audio_coding/speech_mono_32_48kHz", "pcm");
126 test::AudioLoop audio_loop;
127 EXPECT_EQ(kSampleRateHz, encoder->SampleRateHz());
128 ASSERT_TRUE(audio_loop.Init(kInputFileName, kMaxLoopLengthSamples,
129 kInputBlockSizeSamples));
130
131 EXPECT_LT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop),
132 kMaxNarrowbandRatio);
133
134 encoder->OnReceivedTargetAudioBitrate(9000);
135 EXPECT_LT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop),
136 kMaxNarrowbandRatio);
137
138 encoder->OnReceivedTargetAudioBitrate(9001);
139 EXPECT_GT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop),
140 kMinWidebandRatio);
141
142 encoder->OnReceivedTargetAudioBitrate(8000);
143 EXPECT_GT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop),
144 kMinWidebandRatio);
145
146 encoder->OnReceivedTargetAudioBitrate(12001);
147 EXPECT_GT(EncodedPowerRatio(encoder.get(), decoder.get(), &audio_loop),
148 kMinWidebandRatio);
149}
150
151} // namespace webrtc