OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2016 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 <numeric> |
| 12 #include <vector> |
| 13 |
| 14 #include "testing/gtest/include/gtest/gtest.h" |
| 15 #include "webrtc/base/array_view.h" |
| 16 #include "webrtc/base/random.h" |
| 17 #include "webrtc/modules/audio_processing/audio_buffer.h" |
| 18 #include "webrtc/modules/audio_processing/include/audio_processing.h" |
| 19 #include "webrtc/modules/audio_processing/level_controller/level_controller.h" |
| 20 #include "webrtc/modules/audio_processing/test/audio_buffer_tools.h" |
| 21 #include "webrtc/modules/audio_processing/test/bitexactness_tools.h" |
| 22 #include "webrtc/system_wrappers/include/clock.h" |
| 23 #include "webrtc/test/testsupport/perf_test.h" |
| 24 |
| 25 namespace webrtc { |
| 26 namespace { |
| 27 |
| 28 const size_t kNumFramesToProcess = 100; |
| 29 |
| 30 struct SimulatorBuffers { |
| 31 SimulatorBuffers(int render_input_sample_rate_hz, |
| 32 int capture_input_sample_rate_hz, |
| 33 int render_output_sample_rate_hz, |
| 34 int capture_output_sample_rate_hz, |
| 35 size_t num_render_input_channels, |
| 36 size_t num_capture_input_channels, |
| 37 size_t num_render_output_channels, |
| 38 size_t num_capture_output_channels) { |
| 39 Random rand_gen(42); |
| 40 CreateConfigAndBuffer(render_input_sample_rate_hz, |
| 41 num_render_input_channels, &rand_gen, |
| 42 &render_input_buffer, &render_input_config, |
| 43 &render_input, &render_input_samples); |
| 44 |
| 45 CreateConfigAndBuffer(render_output_sample_rate_hz, |
| 46 num_render_output_channels, &rand_gen, |
| 47 &render_output_buffer, &render_output_config, |
| 48 &render_output, &render_output_samples); |
| 49 |
| 50 CreateConfigAndBuffer(capture_input_sample_rate_hz, |
| 51 num_capture_input_channels, &rand_gen, |
| 52 &capture_input_buffer, &capture_input_config, |
| 53 &capture_input, &capture_input_samples); |
| 54 |
| 55 CreateConfigAndBuffer(capture_output_sample_rate_hz, |
| 56 num_capture_output_channels, &rand_gen, |
| 57 &capture_output_buffer, &capture_output_config, |
| 58 &capture_output, &capture_output_samples); |
| 59 |
| 60 UpdateInputBuffers(); |
| 61 } |
| 62 |
| 63 void CreateConfigAndBuffer(int sample_rate_hz, |
| 64 size_t num_channels, |
| 65 Random* rand_gen, |
| 66 std::unique_ptr<AudioBuffer>* buffer, |
| 67 StreamConfig* config, |
| 68 std::vector<float*>* buffer_data, |
| 69 std::vector<float>* buffer_data_samples) { |
| 70 int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100); |
| 71 *config = StreamConfig(sample_rate_hz, num_channels, false); |
| 72 buffer->reset(new AudioBuffer(config->num_frames(), config->num_channels(), |
| 73 config->num_frames(), config->num_channels(), |
| 74 config->num_frames())); |
| 75 |
| 76 buffer_data_samples->resize(samples_per_channel * num_channels); |
| 77 for (auto& v : *buffer_data_samples) { |
| 78 v = rand_gen->Rand<float>(); |
| 79 } |
| 80 |
| 81 buffer_data->resize(num_channels); |
| 82 for (size_t ch = 0; ch < num_channels; ++ch) { |
| 83 (*buffer_data)[ch] = &(*buffer_data_samples)[ch * samples_per_channel]; |
| 84 } |
| 85 } |
| 86 |
| 87 void UpdateInputBuffers() { |
| 88 test::CopyVectorToAudioBuffer(capture_input_config, capture_input_samples, |
| 89 capture_input_buffer.get()); |
| 90 test::CopyVectorToAudioBuffer(render_input_config, render_input_samples, |
| 91 render_input_buffer.get()); |
| 92 } |
| 93 |
| 94 std::unique_ptr<AudioBuffer> render_input_buffer; |
| 95 std::unique_ptr<AudioBuffer> capture_input_buffer; |
| 96 std::unique_ptr<AudioBuffer> render_output_buffer; |
| 97 std::unique_ptr<AudioBuffer> capture_output_buffer; |
| 98 StreamConfig render_input_config; |
| 99 StreamConfig capture_input_config; |
| 100 StreamConfig render_output_config; |
| 101 StreamConfig capture_output_config; |
| 102 std::vector<float*> render_input; |
| 103 std::vector<float> render_input_samples; |
| 104 std::vector<float*> capture_input; |
| 105 std::vector<float> capture_input_samples; |
| 106 std::vector<float*> render_output; |
| 107 std::vector<float> render_output_samples; |
| 108 std::vector<float*> capture_output; |
| 109 std::vector<float> capture_output_samples; |
| 110 }; |
| 111 |
| 112 class SubmodulePerformanceTimer { |
| 113 public: |
| 114 SubmodulePerformanceTimer() : clock_(webrtc::Clock::GetRealTimeClock()) { |
| 115 timestamps_us_.reserve(kNumFramesToProcess); |
| 116 } |
| 117 |
| 118 void StartTimer() { |
| 119 start_timestamp_us_ = rtc::Optional<int64_t>(clock_->TimeInMicroseconds()); |
| 120 } |
| 121 void StopTimer() { |
| 122 RTC_DCHECK(start_timestamp_us_); |
| 123 timestamps_us_.push_back(clock_->TimeInMicroseconds() - |
| 124 *start_timestamp_us_); |
| 125 } |
| 126 |
| 127 double GetDurationAverage() const { |
| 128 RTC_DCHECK(!timestamps_us_.empty()); |
| 129 return static_cast<double>(std::accumulate(timestamps_us_.begin(), |
| 130 timestamps_us_.end(), 0)) / |
| 131 timestamps_us_.size(); |
| 132 } |
| 133 |
| 134 double GetDurationStandardDeviation() const { |
| 135 RTC_DCHECK(!timestamps_us_.empty()); |
| 136 double average_duration = GetDurationAverage(); |
| 137 |
| 138 int64_t variance = |
| 139 std::accumulate(timestamps_us_.begin(), timestamps_us_.end(), 0, |
| 140 [average_duration](const int64_t& a, const int64_t& b) { |
| 141 return a + (b - average_duration); |
| 142 }); |
| 143 |
| 144 return sqrt(variance / timestamps_us_.size()); |
| 145 } |
| 146 |
| 147 private: |
| 148 webrtc::Clock* clock_; |
| 149 rtc::Optional<int64_t> start_timestamp_us_; |
| 150 std::vector<int64_t> timestamps_us_; |
| 151 }; |
| 152 |
| 153 std::string FormPerformanceMeasureString( |
| 154 const SubmodulePerformanceTimer& timer) { |
| 155 std::string s = std::to_string(timer.GetDurationAverage()); |
| 156 s += ", "; |
| 157 s += std::to_string(timer.GetDurationStandardDeviation()); |
| 158 return s; |
| 159 } |
| 160 |
| 161 void RunStandaloneSubmodule(int sample_rate_hz, size_t num_channels) { |
| 162 SimulatorBuffers buffers(sample_rate_hz, sample_rate_hz, sample_rate_hz, |
| 163 sample_rate_hz, num_channels, num_channels, |
| 164 num_channels, num_channels); |
| 165 SubmodulePerformanceTimer timer; |
| 166 |
| 167 LevelController level_controller; |
| 168 level_controller.Initialize(sample_rate_hz); |
| 169 |
| 170 for (size_t frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) { |
| 171 buffers.UpdateInputBuffers(); |
| 172 |
| 173 timer.StartTimer(); |
| 174 level_controller.Process(buffers.capture_input_buffer.get()); |
| 175 timer.StopTimer(); |
| 176 } |
| 177 webrtc::test::PrintResultMeanAndError( |
| 178 "level_controller_call_durations", |
| 179 "_" + std::to_string(sample_rate_hz) + "Hz_" + |
| 180 std::to_string(num_channels) + "_channels", |
| 181 "StandaloneLevelControl", FormPerformanceMeasureString(timer), "us", |
| 182 false); |
| 183 } |
| 184 |
| 185 void RunTogetherWithApm(std::string test_description, |
| 186 int render_input_sample_rate_hz, |
| 187 int render_output_sample_rate_hz, |
| 188 int capture_input_sample_rate_hz, |
| 189 int capture_output_sample_rate_hz, |
| 190 size_t num_channels, |
| 191 bool use_mobile_aec, |
| 192 bool include_default_apm_processing) { |
| 193 SimulatorBuffers buffers( |
| 194 render_input_sample_rate_hz, capture_input_sample_rate_hz, |
| 195 render_output_sample_rate_hz, capture_output_sample_rate_hz, num_channels, |
| 196 num_channels, num_channels, num_channels); |
| 197 SubmodulePerformanceTimer render_timer; |
| 198 SubmodulePerformanceTimer capture_timer; |
| 199 SubmodulePerformanceTimer total_timer; |
| 200 |
| 201 Config config; |
| 202 if (include_default_apm_processing) { |
| 203 config.Set<DelayAgnostic>(new DelayAgnostic(true)); |
| 204 config.Set<ExtendedFilter>(new ExtendedFilter(true)); |
| 205 } |
| 206 config.Set<LevelControl>(new LevelControl(true)); |
| 207 |
| 208 std::unique_ptr<AudioProcessing> apm; |
| 209 apm.reset(AudioProcessing::Create(config)); |
| 210 ASSERT_TRUE(apm.get()); |
| 211 |
| 212 ASSERT_EQ(AudioProcessing::kNoError, |
| 213 apm->gain_control()->Enable(include_default_apm_processing)); |
| 214 if (use_mobile_aec) { |
| 215 ASSERT_EQ(AudioProcessing::kNoError, |
| 216 apm->echo_cancellation()->Enable(false)); |
| 217 ASSERT_EQ(AudioProcessing::kNoError, apm->echo_control_mobile()->Enable( |
| 218 include_default_apm_processing)); |
| 219 } else { |
| 220 ASSERT_EQ(AudioProcessing::kNoError, |
| 221 apm->echo_cancellation()->Enable(include_default_apm_processing)); |
| 222 ASSERT_EQ(AudioProcessing::kNoError, |
| 223 apm->echo_control_mobile()->Enable(false)); |
| 224 } |
| 225 ASSERT_EQ(AudioProcessing::kNoError, |
| 226 apm->high_pass_filter()->Enable(include_default_apm_processing)); |
| 227 ASSERT_EQ(AudioProcessing::kNoError, |
| 228 apm->noise_suppression()->Enable(include_default_apm_processing)); |
| 229 ASSERT_EQ(AudioProcessing::kNoError, |
| 230 apm->voice_detection()->Enable(include_default_apm_processing)); |
| 231 ASSERT_EQ(AudioProcessing::kNoError, |
| 232 apm->level_estimator()->Enable(include_default_apm_processing)); |
| 233 |
| 234 StreamConfig render_input_config(render_input_sample_rate_hz, num_channels, |
| 235 false); |
| 236 StreamConfig render_output_config(render_output_sample_rate_hz, num_channels, |
| 237 false); |
| 238 StreamConfig capture_input_config(capture_input_sample_rate_hz, num_channels, |
| 239 false); |
| 240 StreamConfig capture_output_config(capture_output_sample_rate_hz, |
| 241 num_channels, false); |
| 242 |
| 243 for (size_t frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) { |
| 244 buffers.UpdateInputBuffers(); |
| 245 |
| 246 total_timer.StartTimer(); |
| 247 render_timer.StartTimer(); |
| 248 ASSERT_EQ(AudioProcessing::kNoError, |
| 249 apm->ProcessReverseStream( |
| 250 &buffers.render_input[0], render_input_config, |
| 251 render_output_config, &buffers.render_output[0])); |
| 252 |
| 253 render_timer.StopTimer(); |
| 254 |
| 255 capture_timer.StartTimer(); |
| 256 ASSERT_EQ(AudioProcessing::kNoError, apm->set_stream_delay_ms(0)); |
| 257 ASSERT_EQ( |
| 258 AudioProcessing::kNoError, |
| 259 apm->ProcessStream(&buffers.capture_input[0], capture_input_config, |
| 260 capture_output_config, &buffers.capture_output[0])); |
| 261 |
| 262 capture_timer.StopTimer(); |
| 263 total_timer.StopTimer(); |
| 264 } |
| 265 |
| 266 webrtc::test::PrintResultMeanAndError( |
| 267 "level_controller_call_durations", |
| 268 "_" + std::to_string(render_input_sample_rate_hz) + "_" + |
| 269 std::to_string(render_output_sample_rate_hz) + "_" + |
| 270 std::to_string(capture_input_sample_rate_hz) + "_" + |
| 271 std::to_string(capture_output_sample_rate_hz) + "Hz_" + |
| 272 std::to_string(num_channels) + "_channels" + "_render", |
| 273 test_description, FormPerformanceMeasureString(render_timer), "us", |
| 274 false); |
| 275 webrtc::test::PrintResultMeanAndError( |
| 276 "level_controller_call_durations", |
| 277 "_" + std::to_string(render_input_sample_rate_hz) + "_" + |
| 278 std::to_string(render_output_sample_rate_hz) + "_" + |
| 279 std::to_string(capture_input_sample_rate_hz) + "_" + |
| 280 std::to_string(capture_output_sample_rate_hz) + "Hz_" + |
| 281 std::to_string(num_channels) + "_channels" + "_capture", |
| 282 test_description, FormPerformanceMeasureString(capture_timer), "us", |
| 283 false); |
| 284 webrtc::test::PrintResultMeanAndError( |
| 285 "level_controller_call_durations", |
| 286 "_" + std::to_string(render_input_sample_rate_hz) + "_" + |
| 287 std::to_string(render_output_sample_rate_hz) + "_" + |
| 288 std::to_string(capture_input_sample_rate_hz) + "_" + |
| 289 std::to_string(capture_output_sample_rate_hz) + "Hz_" + |
| 290 std::to_string(num_channels) + "_channels" + "_total", |
| 291 test_description, FormPerformanceMeasureString(total_timer), "us", false); |
| 292 } |
| 293 |
| 294 } // namespace |
| 295 |
| 296 TEST(LevelControllerPerformanceTest, StandaloneProcessing) { |
| 297 int sample_rates_to_test[] = { |
| 298 AudioProcessing::kSampleRate8kHz, AudioProcessing::kSampleRate16kHz, |
| 299 AudioProcessing::kSampleRate32kHz, AudioProcessing::kSampleRate48kHz}; |
| 300 for (auto sample_rate : sample_rates_to_test) { |
| 301 for (size_t num_channels = 1; num_channels <= 2; ++num_channels) { |
| 302 RunStandaloneSubmodule(sample_rate, num_channels); |
| 303 } |
| 304 } |
| 305 } |
| 306 |
| 307 TEST(LevelControllerPerformanceTest, ProcessingViaApm) { |
| 308 int sample_rates_to_test[] = {AudioProcessing::kSampleRate8kHz, |
| 309 AudioProcessing::kSampleRate16kHz, |
| 310 AudioProcessing::kSampleRate32kHz, |
| 311 AudioProcessing::kSampleRate48kHz, 44100}; |
| 312 for (auto capture_input_sample_rate_hz : sample_rates_to_test) { |
| 313 for (auto capture_output_sample_rate_hz : sample_rates_to_test) { |
| 314 for (size_t num_channels = 1; num_channels <= 2; ++num_channels) { |
| 315 RunTogetherWithApm("SimpleLevelControlViaApm", 48000, 48000, |
| 316 capture_input_sample_rate_hz, |
| 317 capture_output_sample_rate_hz, num_channels, false, |
| 318 false); |
| 319 } |
| 320 } |
| 321 } |
| 322 } |
| 323 |
| 324 TEST(LevelControllerPerformanceTest, InteractionWithDefaultApm) { |
| 325 int sample_rates_to_test[] = {AudioProcessing::kSampleRate8kHz, |
| 326 AudioProcessing::kSampleRate16kHz, |
| 327 AudioProcessing::kSampleRate32kHz, |
| 328 AudioProcessing::kSampleRate48kHz, 44100}; |
| 329 for (auto capture_input_sample_rate_hz : sample_rates_to_test) { |
| 330 for (auto capture_output_sample_rate_hz : sample_rates_to_test) { |
| 331 for (size_t num_channels = 1; num_channels <= 2; ++num_channels) { |
| 332 RunTogetherWithApm("LevelControlAndDefaultDesktopApm", 48000, 48000, |
| 333 capture_input_sample_rate_hz, |
| 334 capture_output_sample_rate_hz, num_channels, false, |
| 335 true); |
| 336 RunTogetherWithApm("LevelControlAndDefaultMobileApm", 48000, 48000, |
| 337 capture_input_sample_rate_hz, |
| 338 capture_output_sample_rate_hz, num_channels, true, |
| 339 true); |
| 340 } |
| 341 } |
| 342 } |
| 343 } |
| 344 |
| 345 } // namespace webrtc |
OLD | NEW |