Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | |
|
hlundin-webrtc
2015/11/13 12:18:32
2015
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 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 #include "webrtc/modules/audio_processing/audio_processing_impl.h" | |
| 11 | |
| 12 #include <math.h> | |
| 13 | |
| 14 #include <algorithm> | |
| 15 #include <vector> | |
| 16 | |
| 17 #include "testing/gtest/include/gtest/gtest.h" | |
| 18 #include "webrtc/base/array_view.h" | |
| 19 #include "webrtc/base/criticalsection.h" | |
| 20 #include "webrtc/config.h" | |
| 21 #include "webrtc/modules/audio_processing/test/test_utils.h" | |
| 22 #include "webrtc/modules/include/module_common_types.h" | |
| 23 #include "webrtc/system_wrappers/include/clock.h" | |
| 24 #include "webrtc/system_wrappers/include/event_wrapper.h" | |
| 25 #include "webrtc/system_wrappers/include/sleep.h" | |
| 26 #include "webrtc/system_wrappers/include/thread_wrapper.h" | |
| 27 #include "webrtc/test/random.h" | |
| 28 #include "webrtc/test/testsupport/perf_test.h" | |
| 29 | |
| 30 namespace webrtc { | |
| 31 | |
| 32 namespace { | |
| 33 | |
| 34 class CallSimulator; | |
| 35 | |
| 36 // Populates a float audio frame with random data. | |
|
hlundin-webrtc
2015/11/13 12:18:31
It seems to populate more than one frame. Make the
peah-webrtc
2015/11/18 10:27:26
It supports multiple channel frames, and I think i
| |
| 37 void PopulateAudioFrame(float** frame, | |
|
hlundin-webrtc
2015/11/13 12:18:31
frame is an output parameter, it should go last in
peah-webrtc
2015/11/18 10:27:27
Done.
| |
| 38 float amplitude, | |
| 39 size_t num_channels, | |
| 40 size_t samples_per_channel, | |
| 41 test::Random* rand_gen) { | |
| 42 for (size_t ch = 0; ch < num_channels; ch++) { | |
| 43 for (size_t k = 0; k < samples_per_channel; k++) { | |
| 44 // Store random 16 bit quantized float number between +-amplitude. | |
|
hlundin-webrtc
2015/11/13 12:18:32
Where does the 16-bit quantization happen? Is it i
peah-webrtc
2015/11/18 10:27:27
Sorry, that comment is completely wrong! Removed i
| |
| 45 frame[ch][k] = amplitude * (2 * rand_gen->Rand<float>() - 1); | |
| 46 } | |
| 47 } | |
| 48 } | |
| 49 | |
| 50 // Variant of echo canceller settings to use in the test. | |
| 51 enum class AecType { BasicWebRtcAecSettings, BasicWebRtcAecmSettings }; | |
| 52 | |
| 53 // Variables related to the audio data and formats. | |
| 54 struct AudioFrameData { | |
| 55 explicit AudioFrameData(int max_frame_size) { | |
|
hlundin-webrtc
2015/11/13 12:18:32
size_t
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 56 // Set up the two-dimensional arrays needed for the APM API calls. | |
| 57 input_framechannels.resize(2 * max_frame_size); | |
| 58 input_frame.resize(2); | |
| 59 input_frame[0] = &input_framechannels[0]; | |
| 60 input_frame[1] = &input_framechannels[max_frame_size]; | |
| 61 | |
| 62 output_frame_channels.resize(2 * max_frame_size); | |
| 63 output_frame.resize(2); | |
| 64 output_frame[0] = &output_frame_channels[0]; | |
| 65 output_frame[1] = &output_frame_channels[max_frame_size]; | |
| 66 } | |
| 67 | |
| 68 std::vector<float> output_frame_channels; | |
| 69 std::vector<float*> output_frame; | |
| 70 std::vector<float> input_framechannels; | |
| 71 std::vector<float*> input_frame; | |
| 72 StreamConfig input_stream_config; | |
| 73 StreamConfig output_stream_config; | |
| 74 }; | |
| 75 | |
| 76 // The configuration for the test. | |
| 77 struct SimulationConfig { | |
| 78 SimulationConfig(int sample_rate_hz, | |
| 79 AecType aec_type, | |
| 80 int min_number_of_calls, | |
| 81 bool use_realtime_simulation) | |
| 82 : sample_rate_hz(sample_rate_hz), | |
| 83 aec_type(aec_type), | |
| 84 min_number_of_calls(min_number_of_calls), | |
| 85 use_realtime_simulation(use_realtime_simulation) {} | |
| 86 int sample_rate_hz = 16000; | |
| 87 AecType aec_type = AecType::BasicWebRtcAecSettings; | |
| 88 int min_number_of_calls = 300; | |
| 89 bool use_realtime_simulation; | |
|
hlundin-webrtc
2015/11/13 12:18:32
All members but this one has default values.
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 90 }; | |
| 91 | |
| 92 // Handler for the frame counters. | |
| 93 class FrameCounters { | |
| 94 public: | |
| 95 int IncreaseRenderCounter() { | |
| 96 rtc::CritScope cs(&crit_); | |
| 97 render_count++; | |
| 98 return render_count; | |
| 99 } | |
| 100 | |
| 101 int IncreaseCaptureCounter() { | |
| 102 rtc::CritScope cs(&crit_); | |
| 103 capture_count++; | |
| 104 return capture_count; | |
| 105 } | |
| 106 | |
| 107 int GetCaptureCounter() { | |
| 108 rtc::CritScope cs(&crit_); | |
| 109 return capture_count; | |
| 110 } | |
| 111 | |
| 112 int GetRenderCounter() { | |
| 113 rtc::CritScope cs(&crit_); | |
| 114 return render_count; | |
| 115 } | |
| 116 | |
| 117 int CaptureMinusRenderCounters() { | |
| 118 rtc::CritScope cs(&crit_); | |
| 119 return capture_count - render_count; | |
| 120 } | |
| 121 | |
| 122 int RenderMinusCaptureCounters() { | |
|
hlundin-webrtc
2015/11/13 12:18:32
Do you need both "minus" methods? And if you do, y
peah-webrtc
2015/11/18 10:27:25
It is mainly for convenience and to (tiny) increas
| |
| 123 rtc::CritScope cs(&crit_); | |
| 124 return render_count - capture_count; | |
| 125 } | |
| 126 | |
| 127 bool BothCountersExceedeThreshold(int threshold) { | |
| 128 rtc::CritScope cs(&crit_); | |
| 129 return (render_count > threshold && capture_count > threshold); | |
| 130 } | |
| 131 | |
| 132 private: | |
| 133 rtc::CriticalSection crit_; | |
| 134 int render_count GUARDED_BY(crit_) = 0; | |
|
hlundin-webrtc
2015/11/13 12:18:32
Trailing underscore on both counter variables.
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 135 int capture_count GUARDED_BY(crit_) = 0; | |
| 136 }; | |
| 137 | |
| 138 // Checker for whether the capture side has been called. | |
| 139 class CaptureSideCalledChecker { | |
|
hlundin-webrtc
2015/11/13 12:18:32
Generalize the name to make it shorter. Nothing wi
peah-webrtc
2015/11/18 10:27:26
Good point! I called it LockedFlag since it is doe
| |
| 140 public: | |
| 141 bool CaptureSideCalled() { | |
|
hlundin-webrtc
2015/11/13 12:18:32
This is a simple "getter" function, albeit with a
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 142 rtc::CritScope cs(&crit_); | |
| 143 return capture_side_called_; | |
| 144 } | |
| 145 | |
| 146 void FlagCaptureSideCalled() { | |
|
hlundin-webrtc
2015/11/13 12:18:32
This is a "setter" with a lock. Name it such:
void
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 147 rtc::CritScope cs(&crit_); | |
| 148 capture_side_called_ = true; | |
| 149 } | |
| 150 | |
| 151 private: | |
| 152 rtc::CriticalSection crit_; | |
| 153 bool capture_side_called_ GUARDED_BY(crit_) = false; | |
| 154 }; | |
| 155 | |
| 156 // Parent class for the thread processors. | |
| 157 class TimedThreadApiProcessor { | |
| 158 public: | |
| 159 TimedThreadApiProcessor(int max_frame_size, | |
| 160 test::Random* rand_gen, | |
| 161 FrameCounters* shared_counters_state, | |
| 162 CaptureSideCalledChecker* capture_call_checker, | |
| 163 CallSimulator* test_framework, | |
| 164 SimulationConfig* simulation_config, | |
| 165 AudioProcessing* apm, | |
| 166 int min_number_of_calls, | |
| 167 float input_level); | |
| 168 virtual ~TimedThreadApiProcessor() {} | |
| 169 | |
| 170 bool ProcessClocked10msQuantum(); | |
| 171 std::vector<int64_t> get_api_call_durations() const { | |
| 172 return api_call_durations_; | |
| 173 } | |
| 174 int64_t GetDurationStandardDeviation() const; | |
| 175 int64_t GetDurationAverage() const; | |
| 176 | |
| 177 protected: | |
| 178 static const int kMaxCallDifference = 10; | |
| 179 | |
| 180 void PrepareFrame(); | |
| 181 void AddJitter(int max_jitter_microseconds, bool random_jitter); | |
| 182 virtual int Process() = 0; | |
| 183 virtual bool ReadyToProcess() = 0; | |
| 184 | |
| 185 test::Random* rand_gen_ = nullptr; | |
| 186 FrameCounters* frame_counters_ = nullptr; | |
| 187 CaptureSideCalledChecker* capture_call_checker_ = nullptr; | |
| 188 CallSimulator* test_ = nullptr; | |
| 189 SimulationConfig* simulation_config_ = nullptr; | |
| 190 AudioProcessing* apm_ = nullptr; | |
| 191 AudioFrameData frame_data_; | |
| 192 webrtc::Clock* clock_; | |
| 193 int num_durations_to_store_; | |
| 194 std::vector<int64_t> api_call_durations_; | |
| 195 const float input_level_; | |
| 196 }; | |
| 197 | |
| 198 // Class for handling the capture side processing. | |
| 199 class CaptureProcessor : public TimedThreadApiProcessor { | |
|
hlundin-webrtc
2015/11/13 12:18:31
Mark this class final.
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 200 public: | |
| 201 CaptureProcessor(int max_frame_size, | |
| 202 test::Random* rand_gen, | |
| 203 FrameCounters* shared_counters_state, | |
| 204 CaptureSideCalledChecker* capture_call_checker, | |
| 205 CallSimulator* test_framework, | |
| 206 SimulationConfig* simulation_config, | |
| 207 AudioProcessing* apm, | |
| 208 int min_number_of_calls, | |
| 209 float input_level); | |
| 210 | |
| 211 private: | |
| 212 // Overrides from TimedThreadApiProcessor. | |
| 213 int Process() override; | |
| 214 bool ReadyToProcess() override; | |
| 215 | |
| 216 bool first_capture_side_call_ = true; | |
| 217 }; | |
| 218 | |
| 219 // Class for handling the render side processing. | |
| 220 class RenderProcessor : public TimedThreadApiProcessor { | |
|
hlundin-webrtc
2015/11/13 12:18:31
Mark this class final.
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 221 public: | |
| 222 RenderProcessor(int max_frame_size, | |
| 223 test::Random* rand_gen, | |
| 224 FrameCounters* shared_counters_state, | |
| 225 CaptureSideCalledChecker* capture_call_checker, | |
| 226 CallSimulator* test_framework, | |
| 227 SimulationConfig* simulation_config, | |
| 228 AudioProcessing* apm, | |
| 229 int min_number_of_calls, | |
| 230 float input_level); | |
| 231 | |
| 232 private: | |
| 233 // Overrides from TimedThreadApiProcessor | |
| 234 int Process() override; | |
| 235 bool ReadyToProcess() override; | |
| 236 | |
| 237 bool first_render_side_call_ = true; | |
| 238 }; | |
| 239 | |
| 240 // Class for managing the test simulation. | |
| 241 class CallSimulator { | |
|
hlundin-webrtc
2015/11/13 12:18:32
I think this class should be made a gtest fixture
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 242 public: | |
| 243 explicit CallSimulator(SimulationConfig simulation_config); | |
| 244 EventTypeWrapper Run(int time_out_limit); | |
| 245 | |
| 246 // Tests whether all the required render and capture side calls have been | |
| 247 // done. | |
| 248 void CheckIfSimulationDone() { | |
| 249 if (frame_counters_.BothCountersExceedeThreshold( | |
| 250 simulation_config_.min_number_of_calls)) { | |
| 251 test_complete_->Set(); | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 const CaptureProcessor* GetCapture() const { return &capture_thread_state_; } | |
| 256 const RenderProcessor* GetRender() const { return &render_thread_state_; } | |
| 257 void SetUp(); | |
| 258 void TearDown(); | |
| 259 | |
| 260 private: | |
| 261 static const int kMaxFrameSize = 480; | |
| 262 static const float kCaptureInputFloatLevel; | |
| 263 static const float kRenderInputFloatLevel; | |
| 264 | |
| 265 // Thread callback for the render thread. | |
| 266 static bool RenderProcessorThreadFunc(void* context) { | |
| 267 return reinterpret_cast<CallSimulator*>(context) | |
| 268 ->render_thread_state_.ProcessClocked10msQuantum(); | |
| 269 } | |
| 270 | |
| 271 // Thread callback for the capture thread. | |
| 272 static bool CaptureProcessorThreadFunc(void* context) { | |
| 273 return reinterpret_cast<CallSimulator*>(context) | |
| 274 ->capture_thread_state_.ProcessClocked10msQuantum(); | |
| 275 } | |
| 276 | |
| 277 // Start the threads used in the test. | |
| 278 void StartThreads() { | |
| 279 ASSERT_TRUE(render_thread_->Start()); | |
| 280 render_thread_->SetPriority(kRealtimePriority); | |
| 281 ASSERT_TRUE(capture_thread_->Start()); | |
| 282 capture_thread_->SetPriority(kRealtimePriority); | |
| 283 } | |
| 284 | |
| 285 // Event handler for the test. | |
| 286 const rtc::scoped_ptr<EventWrapper> test_complete_; | |
| 287 | |
| 288 // Thread related variables. | |
| 289 rtc::scoped_ptr<ThreadWrapper> render_thread_; | |
| 290 rtc::scoped_ptr<ThreadWrapper> capture_thread_; | |
| 291 mutable test::Random rand_gen_; | |
|
hlundin-webrtc
2015/11/13 12:18:31
Why is this mutable?
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 292 | |
| 293 rtc::scoped_ptr<AudioProcessing> apm_; | |
| 294 SimulationConfig simulation_config_; | |
| 295 FrameCounters frame_counters_; | |
| 296 CaptureSideCalledChecker capture_call_checker_; | |
| 297 RenderProcessor render_thread_state_; | |
| 298 CaptureProcessor capture_thread_state_; | |
| 299 }; | |
| 300 | |
| 301 const float CallSimulator::kRenderInputFloatLevel = 0.5f; | |
| 302 const float CallSimulator::kCaptureInputFloatLevel = 0.03125f; | |
| 303 | |
| 304 CallSimulator::CallSimulator(SimulationConfig simulation_config) | |
| 305 : test_complete_(EventWrapper::Create()), | |
| 306 render_thread_(ThreadWrapper::CreateThread(RenderProcessorThreadFunc, | |
| 307 this, | |
| 308 "render")), | |
| 309 capture_thread_(ThreadWrapper::CreateThread(CaptureProcessorThreadFunc, | |
| 310 this, | |
| 311 "capture")), | |
| 312 rand_gen_(42U), | |
| 313 apm_(AudioProcessingImpl::Create()), | |
|
hlundin-webrtc
2015/11/13 12:18:31
Create() may return null in case of failure. You c
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 314 simulation_config_(simulation_config), | |
| 315 render_thread_state_(kMaxFrameSize, | |
| 316 &rand_gen_, | |
| 317 &frame_counters_, | |
| 318 &capture_call_checker_, | |
| 319 this, | |
| 320 &simulation_config_, | |
| 321 apm_.get(), | |
| 322 simulation_config_.min_number_of_calls, | |
| 323 kRenderInputFloatLevel), | |
| 324 capture_thread_state_(kMaxFrameSize, | |
| 325 &rand_gen_, | |
| 326 &frame_counters_, | |
| 327 &capture_call_checker_, | |
| 328 this, | |
| 329 &simulation_config_, | |
| 330 apm_.get(), | |
| 331 simulation_config_.min_number_of_calls, | |
| 332 kCaptureInputFloatLevel) {} | |
| 333 | |
| 334 // Run the call simulation with a timeout. | |
| 335 EventTypeWrapper CallSimulator::Run(int time_out_limit) { | |
| 336 SetUp(); | |
| 337 StartThreads(); | |
|
hlundin-webrtc
2015/11/13 12:18:31
You should make sure that none of the ASSERT_TRUEs
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 338 EventTypeWrapper result = test_complete_->Wait(time_out_limit); | |
| 339 TearDown(); | |
| 340 return result; | |
| 341 } | |
| 342 | |
| 343 // Simulator and APM setup. | |
| 344 void CallSimulator::SetUp() { | |
| 345 ASSERT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true)); | |
| 346 ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); | |
| 347 ASSERT_EQ(apm_->kNoError, | |
| 348 apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog)); | |
| 349 ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); | |
| 350 ASSERT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true)); | |
| 351 ASSERT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true)); | |
| 352 | |
| 353 Config config; | |
|
hlundin-webrtc
2015/11/13 12:18:31
Move the declaration down to within the else-claus
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 354 if (simulation_config_.aec_type == AecType::BasicWebRtcAecmSettings) { | |
| 355 ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true)); | |
| 356 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false)); | |
| 357 } else { | |
| 358 ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false)); | |
| 359 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true)); | |
| 360 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->enable_metrics(true)); | |
| 361 ASSERT_EQ(apm_->kNoError, | |
| 362 apm_->echo_cancellation()->enable_delay_logging(true)); | |
| 363 | |
| 364 config.Set<ExtendedFilter>(new ExtendedFilter(true)); | |
| 365 config.Set<DelayAgnostic>(new DelayAgnostic(true)); | |
| 366 apm_->SetExtraOptions(config); | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 void CallSimulator::TearDown() { | |
| 371 render_thread_->Stop(); | |
| 372 capture_thread_->Stop(); | |
| 373 } | |
| 374 | |
| 375 TimedThreadApiProcessor::TimedThreadApiProcessor( | |
|
hlundin-webrtc
2015/11/13 12:18:32
I think you can define all the member methods with
peah-webrtc
2015/11/18 10:27:26
Did this on all methods apart from the Process() m
| |
| 376 int max_frame_size, | |
| 377 test::Random* rand_gen, | |
| 378 FrameCounters* shared_counters_state, | |
| 379 CaptureSideCalledChecker* capture_call_checker, | |
| 380 CallSimulator* test_framework, | |
| 381 SimulationConfig* simulation_config, | |
| 382 AudioProcessing* apm, | |
| 383 int num_durations_to_store, | |
| 384 float input_level) | |
| 385 : rand_gen_(rand_gen), | |
| 386 frame_counters_(shared_counters_state), | |
| 387 capture_call_checker_(capture_call_checker), | |
| 388 test_(test_framework), | |
| 389 simulation_config_(simulation_config), | |
| 390 apm_(apm), | |
| 391 frame_data_(max_frame_size), | |
|
hlundin-webrtc
2015/11/13 12:18:31
No need to pass max_frame_size as a parameter; sim
peah-webrtc
2015/11/18 10:27:27
Done.
| |
| 392 clock_(webrtc::Clock::GetRealTimeClock()), | |
| 393 num_durations_to_store_(num_durations_to_store), | |
| 394 api_call_durations_(num_durations_to_store_), | |
| 395 input_level_(input_level) {} | |
| 396 | |
| 397 // Implements the callback functionality for the threads. | |
| 398 bool TimedThreadApiProcessor::ProcessClocked10msQuantum() { | |
| 399 PrepareFrame(); | |
| 400 | |
| 401 while (!ReadyToProcess()) { | |
| 402 AddJitter(2, true); | |
| 403 } | |
| 404 | |
| 405 const int64_t start_time = clock_->TimeInMicroseconds(); | |
| 406 Process(); | |
| 407 const int64_t end_time = clock_->TimeInMicroseconds(); | |
| 408 const int duration = static_cast<int>(end_time - start_time); | |
|
hlundin-webrtc
2015/11/13 12:18:31
duration_us, to convey the unit.
hlundin-webrtc
2015/11/13 12:18:32
use rtc::checked_cast<int> from base/safe_conversi
peah-webrtc
2015/11/18 10:27:26
Done.
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 409 const int time_left_of_10_ms_quantum = 10000 - duration; | |
| 410 | |
| 411 if (simulation_config_->use_realtime_simulation && | |
| 412 time_left_of_10_ms_quantum > 0) { | |
| 413 AddJitter(time_left_of_10_ms_quantum, false); | |
| 414 } | |
| 415 | |
| 416 test_->CheckIfSimulationDone(); | |
| 417 | |
| 418 return true; | |
| 419 } | |
| 420 | |
| 421 int64_t TimedThreadApiProcessor::GetDurationStandardDeviation() const { | |
| 422 double variance = 0; | |
| 423 const int64_t average_duration = GetDurationAverage(); | |
| 424 for (int64_t duration : api_call_durations_) { | |
| 425 int64_t tmp = duration - average_duration; | |
| 426 variance += static_cast<double>(tmp * tmp); | |
| 427 } | |
| 428 return static_cast<int64_t>(sqrt(variance / api_call_durations_.size())); | |
|
hlundin-webrtc
2015/11/13 12:18:32
rtc::checked_cast
peah-webrtc
2015/11/18 10:27:27
Done.
| |
| 429 } | |
| 430 | |
| 431 int64_t TimedThreadApiProcessor::GetDurationAverage() const { | |
| 432 int64_t average_duration = 0; | |
| 433 for (int64_t duration : api_call_durations_) { | |
| 434 average_duration += duration; | |
| 435 } | |
| 436 return average_duration / api_call_durations_.size(); | |
| 437 } | |
| 438 | |
| 439 void TimedThreadApiProcessor::PrepareFrame() { | |
| 440 // Prepare the audio input data and metadata. | |
| 441 frame_data_.input_stream_config.set_sample_rate_hz( | |
| 442 simulation_config_->sample_rate_hz); | |
| 443 frame_data_.input_stream_config.set_num_channels(1); | |
| 444 frame_data_.input_stream_config.set_has_keyboard(false); | |
| 445 PopulateAudioFrame(&frame_data_.input_frame[0], input_level_, 1, | |
| 446 (simulation_config_->sample_rate_hz * | |
| 447 AudioProcessing::kChunkSizeMs / 1000), | |
| 448 rand_gen_); | |
| 449 | |
| 450 // Prepare the float audio output data and metadata. | |
| 451 frame_data_.output_stream_config.set_sample_rate_hz( | |
| 452 simulation_config_->sample_rate_hz); | |
| 453 frame_data_.output_stream_config.set_num_channels(1); | |
| 454 frame_data_.output_stream_config.set_has_keyboard(false); | |
| 455 } | |
| 456 | |
| 457 void TimedThreadApiProcessor::AddJitter(int max_jitter_microseconds, | |
| 458 bool random_jitter) { | |
| 459 int min_method_duration; | |
| 460 if (random_jitter) { | |
| 461 min_method_duration = rand_gen_->Rand(0, max_jitter_microseconds); | |
| 462 } else { | |
| 463 min_method_duration = max_jitter_microseconds; | |
| 464 } | |
| 465 | |
| 466 const int64_t start_time = clock_->TimeInMicroseconds(); | |
|
hlundin-webrtc
2015/11/13 12:18:32
Please, comment on why you cannot just sleep.
peah-webrtc
2015/11/18 10:27:26
Very good point. As I never use this in the test a
| |
| 467 int sum = 0; | |
| 468 while ((clock_->TimeInMicroseconds() - start_time) < min_method_duration) { | |
| 469 for (int k = 0; k < 100; ++k) | |
| 470 for (int j = 1; j < 100; ++j) { | |
| 471 sum += k % j; | |
| 472 sum = sum % 79; | |
| 473 } | |
| 474 if (sum > 100) { | |
| 475 printf("Will not be print out, just present in order to ensure"); | |
| 476 printf("that sum is evaluated by the compiler\n"); | |
| 477 } | |
| 478 } | |
| 479 } | |
| 480 | |
| 481 CaptureProcessor::CaptureProcessor( | |
|
hlundin-webrtc
2015/11/13 12:18:32
There is a non-negligible overhead associated with
peah-webrtc
2015/11/18 10:27:25
Good point!!!
Will implement it like that.
Done.
| |
| 482 int max_frame_size, | |
| 483 test::Random* rand_gen, | |
| 484 FrameCounters* shared_counters_state, | |
| 485 CaptureSideCalledChecker* capture_call_checker, | |
| 486 CallSimulator* test_framework, | |
| 487 SimulationConfig* simulation_config, | |
| 488 AudioProcessing* apm, | |
| 489 int num_durations_to_store, | |
| 490 float input_level) | |
| 491 : TimedThreadApiProcessor(max_frame_size, | |
| 492 rand_gen, | |
| 493 shared_counters_state, | |
| 494 capture_call_checker, | |
| 495 test_framework, | |
| 496 simulation_config, | |
| 497 apm, | |
| 498 num_durations_to_store, | |
| 499 input_level) {} | |
| 500 | |
| 501 int CaptureProcessor::Process() { | |
| 502 // Set the stream delay | |
| 503 apm_->set_stream_delay_ms(30); | |
| 504 | |
| 505 // Call and time the specified capture side API processing method. | |
| 506 const int64_t start_time = clock_->TimeInMicroseconds(); | |
| 507 const int result = apm_->ProcessStream( | |
| 508 &frame_data_.input_frame[0], frame_data_.input_stream_config, | |
| 509 frame_data_.output_stream_config, &frame_data_.output_frame[0]); | |
| 510 const int64_t end_time = clock_->TimeInMicroseconds(); | |
| 511 | |
| 512 const int new_capture_counter = frame_counters_->IncreaseCaptureCounter(); | |
| 513 | |
| 514 if (new_capture_counter <= num_durations_to_store_) { | |
| 515 api_call_durations_[new_capture_counter - 1] = end_time - start_time; | |
|
hlundin-webrtc
2015/11/13 12:18:32
Why not just api_call_durations_.push_back(...)? Y
peah-webrtc
2015/11/18 10:27:26
Good and very valid point!
Done.
| |
| 516 } | |
| 517 | |
| 518 if (first_capture_side_call_) { | |
| 519 // Flag that the capture side has been called at least once | |
| 520 // (needed to ensure that a capture call has been done | |
| 521 // before the first render call is performed (implicitly | |
| 522 // required by the APM API). | |
| 523 capture_call_checker_->FlagCaptureSideCalled(); | |
| 524 first_capture_side_call_ = false; | |
| 525 } | |
| 526 return result; | |
| 527 } | |
| 528 | |
| 529 bool CaptureProcessor::ReadyToProcess() { | |
| 530 return (frame_counters_->CaptureMinusRenderCounters() <= kMaxCallDifference); | |
| 531 } | |
| 532 | |
| 533 RenderProcessor::RenderProcessor(int max_frame_size, | |
| 534 test::Random* rand_gen, | |
| 535 FrameCounters* shared_counters_state, | |
| 536 CaptureSideCalledChecker* capture_call_checker, | |
| 537 CallSimulator* test_framework, | |
| 538 SimulationConfig* simulation_config, | |
| 539 AudioProcessing* apm, | |
| 540 int num_durations_to_store, | |
| 541 float input_level) | |
| 542 : TimedThreadApiProcessor(max_frame_size, | |
| 543 rand_gen, | |
| 544 shared_counters_state, | |
| 545 capture_call_checker, | |
| 546 test_framework, | |
| 547 simulation_config, | |
| 548 apm, | |
| 549 num_durations_to_store, | |
| 550 input_level) {} | |
| 551 | |
| 552 int RenderProcessor::Process() { | |
| 553 // Call and time the specified render side API processing method. | |
| 554 const int64_t start_time = clock_->TimeInMicroseconds(); | |
| 555 const int result = apm_->ProcessReverseStream( | |
| 556 &frame_data_.input_frame[0], frame_data_.input_stream_config, | |
| 557 frame_data_.output_stream_config, &frame_data_.output_frame[0]); | |
| 558 const int64_t end_time = clock_->TimeInMicroseconds(); | |
| 559 | |
| 560 const int new_render_counter = frame_counters_->IncreaseRenderCounter(); | |
| 561 | |
| 562 if (new_render_counter <= num_durations_to_store_) { | |
| 563 api_call_durations_[new_render_counter - 1] = end_time - start_time; | |
| 564 } | |
| 565 | |
| 566 return result; | |
| 567 } | |
| 568 | |
| 569 bool RenderProcessor::ReadyToProcess() { | |
| 570 // Do not process until at least one capture call has been done. | |
| 571 // (implicitly required by the APM API). | |
| 572 if (first_render_side_call_ && !capture_call_checker_->CaptureSideCalled()) { | |
| 573 return false; | |
| 574 } | |
| 575 | |
| 576 // Ensure that the number of render and capture calls do not differ too much. | |
| 577 if (frame_counters_->RenderMinusCaptureCounters() > kMaxCallDifference) { | |
| 578 return false; | |
| 579 } | |
| 580 | |
| 581 first_render_side_call_ = false; | |
| 582 return true; | |
| 583 } | |
| 584 | |
| 585 // Runs the simulation and reports the results. | |
| 586 void RunSimulation(SimulationConfig simulation_config, | |
| 587 int timeout, | |
| 588 bool print_durations) { | |
| 589 // Lambda function for printing out the simulation statistics. | |
| 590 auto print_simulation_statistics = []( | |
| 591 const TimedThreadApiProcessor* processor, std::string processor_name, | |
| 592 bool print_durations) { | |
| 593 const std::string modifier = "_api_call_duration"; | |
| 594 | |
| 595 // Lambda function for creating a test printout string. | |
| 596 auto create_mean_and_variance_string = [](int64_t average, | |
| 597 int64_t standard_dev) { | |
| 598 std::string s = std::to_string(average); | |
| 599 s += ","; | |
| 600 s += std::to_string(standard_dev); | |
| 601 return s; | |
| 602 }; | |
| 603 | |
| 604 webrtc::test::PrintResult(processor_name, modifier, "avg,stdev", | |
| 605 create_mean_and_variance_string( | |
| 606 processor->GetDurationAverage(), | |
| 607 processor->GetDurationStandardDeviation()), | |
| 608 "ms", false); | |
| 609 | |
| 610 if (print_durations) { | |
| 611 std::vector<int64_t> durations = processor->get_api_call_durations(); | |
| 612 std::string value_string = ""; | |
| 613 for (int64_t duration : durations) { | |
| 614 value_string += std::to_string(duration) + ","; | |
| 615 } | |
| 616 webrtc::test::PrintResultList(processor_name, modifier, "durations", | |
| 617 value_string, "ms", false); | |
| 618 } | |
| 619 }; | |
| 620 | |
| 621 CallSimulator simulator(simulation_config); | |
| 622 | |
| 623 // Run simulation and verify that it did not time out. | |
| 624 ASSERT_EQ(EventTypeWrapper::kEventSignaled, simulator.Run(timeout)); | |
|
hlundin-webrtc
2015/11/13 12:18:32
Maybe EXPECT_EQ instead. It might still be interes
peah-webrtc
2015/11/18 10:27:27
Done.
| |
| 625 | |
| 626 print_simulation_statistics(simulator.GetRender(), "render", print_durations); | |
|
hlundin-webrtc
2015/11/13 12:18:32
To me it looks like the print_simulation_statistic
peah-webrtc
2015/11/18 10:27:26
Done.
| |
| 627 print_simulation_statistics(simulator.GetCapture(), "capture", | |
| 628 print_durations); | |
| 629 } | |
| 630 | |
| 631 const int kMaxFramesToProcess = 300; | |
| 632 const int32_t kTestTimeout = 3 * 10 * kMaxFramesToProcess; | |
| 633 const bool kUseTimedSimulation = false; | |
|
hlundin-webrtc
2015/11/13 12:18:32
I don't think it makes much sense to declare this
peah-webrtc
2015/11/18 10:27:26
Good points and I fully agree. This has been partl
| |
| 634 const bool kPrintAllDurations = false; | |
| 635 } // anonymous namespace | |
| 636 | |
| 637 TEST(AudioProcessingLockPerformanceTest, Aec8kHz) { | |
| 638 RunSimulation(SimulationConfig(8000, AecType::BasicWebRtcAecSettings, | |
| 639 kMaxFramesToProcess, kUseTimedSimulation), | |
| 640 kTestTimeout, kPrintAllDurations); | |
| 641 } | |
| 642 | |
| 643 TEST(AudioProcessingLockPerformanceTest, Aec16kHz) { | |
| 644 RunSimulation(SimulationConfig(16000, AecType::BasicWebRtcAecSettings, | |
| 645 kMaxFramesToProcess, kUseTimedSimulation), | |
| 646 kTestTimeout, kPrintAllDurations); | |
| 647 } | |
| 648 | |
| 649 TEST(AudioProcessingLockPerformanceTest, Aec32kHz) { | |
| 650 RunSimulation(SimulationConfig(32000, AecType::BasicWebRtcAecSettings, | |
| 651 kMaxFramesToProcess, kUseTimedSimulation), | |
| 652 kTestTimeout, kPrintAllDurations); | |
| 653 } | |
| 654 | |
| 655 TEST(AudioProcessingLockPerformanceTest, Aec48kHz) { | |
| 656 RunSimulation(SimulationConfig(48000, AecType::BasicWebRtcAecSettings, | |
| 657 kMaxFramesToProcess, kUseTimedSimulation), | |
| 658 kTestTimeout, kPrintAllDurations); | |
| 659 } | |
| 660 | |
| 661 TEST(AudioProcessingLockPerformanceTest, Aecm8kHz) { | |
| 662 RunSimulation(SimulationConfig(8000, AecType::BasicWebRtcAecmSettings, | |
| 663 kMaxFramesToProcess, true), | |
| 664 kTestTimeout, kPrintAllDurations); | |
| 665 } | |
| 666 | |
| 667 TEST(AudioProcessingLockPerformanceTest, Aecm16kHz) { | |
| 668 RunSimulation(SimulationConfig(16000, AecType::BasicWebRtcAecmSettings, | |
| 669 kMaxFramesToProcess, true), | |
| 670 kTestTimeout, kPrintAllDurations); | |
| 671 } | |
| 672 } // namespace webrtc | |
| OLD | NEW |