Chromium Code Reviews| Index: webrtc/modules/audio_processing/audio_processing_lock_performance_unittest.cc |
| diff --git a/webrtc/modules/audio_processing/audio_processing_lock_performance_unittest.cc b/webrtc/modules/audio_processing/audio_processing_lock_performance_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a2f23535554fbc7dc0eb0e5276b53349a5bcbc77 |
| --- /dev/null |
| +++ b/webrtc/modules/audio_processing/audio_processing_lock_performance_unittest.cc |
| @@ -0,0 +1,672 @@ |
| +/* |
| + * 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.
|
| + * |
| + * Use of this source code is governed by a BSD-style license |
| + * that can be found in the LICENSE file in the root of the source |
| + * tree. An additional intellectual property rights grant can be found |
| + * in the file PATENTS. All contributing project authors may |
| + * be found in the AUTHORS file in the root of the source tree. |
| + */ |
| +#include "webrtc/modules/audio_processing/audio_processing_impl.h" |
| + |
| +#include <math.h> |
| + |
| +#include <algorithm> |
| +#include <vector> |
| + |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "webrtc/base/array_view.h" |
| +#include "webrtc/base/criticalsection.h" |
| +#include "webrtc/config.h" |
| +#include "webrtc/modules/audio_processing/test/test_utils.h" |
| +#include "webrtc/modules/include/module_common_types.h" |
| +#include "webrtc/system_wrappers/include/clock.h" |
| +#include "webrtc/system_wrappers/include/event_wrapper.h" |
| +#include "webrtc/system_wrappers/include/sleep.h" |
| +#include "webrtc/system_wrappers/include/thread_wrapper.h" |
| +#include "webrtc/test/random.h" |
| +#include "webrtc/test/testsupport/perf_test.h" |
| + |
| +namespace webrtc { |
| + |
| +namespace { |
| + |
| +class CallSimulator; |
| + |
| +// 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
|
| +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.
|
| + float amplitude, |
| + size_t num_channels, |
| + size_t samples_per_channel, |
| + test::Random* rand_gen) { |
| + for (size_t ch = 0; ch < num_channels; ch++) { |
| + for (size_t k = 0; k < samples_per_channel; k++) { |
| + // 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
|
| + frame[ch][k] = amplitude * (2 * rand_gen->Rand<float>() - 1); |
| + } |
| + } |
| +} |
| + |
| +// Variant of echo canceller settings to use in the test. |
| +enum class AecType { BasicWebRtcAecSettings, BasicWebRtcAecmSettings }; |
| + |
| +// Variables related to the audio data and formats. |
| +struct AudioFrameData { |
| + 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.
|
| + // Set up the two-dimensional arrays needed for the APM API calls. |
| + input_framechannels.resize(2 * max_frame_size); |
| + input_frame.resize(2); |
| + input_frame[0] = &input_framechannels[0]; |
| + input_frame[1] = &input_framechannels[max_frame_size]; |
| + |
| + output_frame_channels.resize(2 * max_frame_size); |
| + output_frame.resize(2); |
| + output_frame[0] = &output_frame_channels[0]; |
| + output_frame[1] = &output_frame_channels[max_frame_size]; |
| + } |
| + |
| + std::vector<float> output_frame_channels; |
| + std::vector<float*> output_frame; |
| + std::vector<float> input_framechannels; |
| + std::vector<float*> input_frame; |
| + StreamConfig input_stream_config; |
| + StreamConfig output_stream_config; |
| +}; |
| + |
| +// The configuration for the test. |
| +struct SimulationConfig { |
| + SimulationConfig(int sample_rate_hz, |
| + AecType aec_type, |
| + int min_number_of_calls, |
| + bool use_realtime_simulation) |
| + : sample_rate_hz(sample_rate_hz), |
| + aec_type(aec_type), |
| + min_number_of_calls(min_number_of_calls), |
| + use_realtime_simulation(use_realtime_simulation) {} |
| + int sample_rate_hz = 16000; |
| + AecType aec_type = AecType::BasicWebRtcAecSettings; |
| + int min_number_of_calls = 300; |
| + 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.
|
| +}; |
| + |
| +// Handler for the frame counters. |
| +class FrameCounters { |
| + public: |
| + int IncreaseRenderCounter() { |
| + rtc::CritScope cs(&crit_); |
| + render_count++; |
| + return render_count; |
| + } |
| + |
| + int IncreaseCaptureCounter() { |
| + rtc::CritScope cs(&crit_); |
| + capture_count++; |
| + return capture_count; |
| + } |
| + |
| + int GetCaptureCounter() { |
| + rtc::CritScope cs(&crit_); |
| + return capture_count; |
| + } |
| + |
| + int GetRenderCounter() { |
| + rtc::CritScope cs(&crit_); |
| + return render_count; |
| + } |
| + |
| + int CaptureMinusRenderCounters() { |
| + rtc::CritScope cs(&crit_); |
| + return capture_count - render_count; |
| + } |
| + |
| + 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
|
| + rtc::CritScope cs(&crit_); |
| + return render_count - capture_count; |
| + } |
| + |
| + bool BothCountersExceedeThreshold(int threshold) { |
| + rtc::CritScope cs(&crit_); |
| + return (render_count > threshold && capture_count > threshold); |
| + } |
| + |
| + private: |
| + rtc::CriticalSection crit_; |
| + 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.
|
| + int capture_count GUARDED_BY(crit_) = 0; |
| +}; |
| + |
| +// Checker for whether the capture side has been called. |
| +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
|
| + public: |
| + 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.
|
| + rtc::CritScope cs(&crit_); |
| + return capture_side_called_; |
| + } |
| + |
| + 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.
|
| + rtc::CritScope cs(&crit_); |
| + capture_side_called_ = true; |
| + } |
| + |
| + private: |
| + rtc::CriticalSection crit_; |
| + bool capture_side_called_ GUARDED_BY(crit_) = false; |
| +}; |
| + |
| +// Parent class for the thread processors. |
| +class TimedThreadApiProcessor { |
| + public: |
| + TimedThreadApiProcessor(int max_frame_size, |
| + test::Random* rand_gen, |
| + FrameCounters* shared_counters_state, |
| + CaptureSideCalledChecker* capture_call_checker, |
| + CallSimulator* test_framework, |
| + SimulationConfig* simulation_config, |
| + AudioProcessing* apm, |
| + int min_number_of_calls, |
| + float input_level); |
| + virtual ~TimedThreadApiProcessor() {} |
| + |
| + bool ProcessClocked10msQuantum(); |
| + std::vector<int64_t> get_api_call_durations() const { |
| + return api_call_durations_; |
| + } |
| + int64_t GetDurationStandardDeviation() const; |
| + int64_t GetDurationAverage() const; |
| + |
| + protected: |
| + static const int kMaxCallDifference = 10; |
| + |
| + void PrepareFrame(); |
| + void AddJitter(int max_jitter_microseconds, bool random_jitter); |
| + virtual int Process() = 0; |
| + virtual bool ReadyToProcess() = 0; |
| + |
| + test::Random* rand_gen_ = nullptr; |
| + FrameCounters* frame_counters_ = nullptr; |
| + CaptureSideCalledChecker* capture_call_checker_ = nullptr; |
| + CallSimulator* test_ = nullptr; |
| + SimulationConfig* simulation_config_ = nullptr; |
| + AudioProcessing* apm_ = nullptr; |
| + AudioFrameData frame_data_; |
| + webrtc::Clock* clock_; |
| + int num_durations_to_store_; |
| + std::vector<int64_t> api_call_durations_; |
| + const float input_level_; |
| +}; |
| + |
| +// Class for handling the capture side processing. |
| +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.
|
| + public: |
| + CaptureProcessor(int max_frame_size, |
| + test::Random* rand_gen, |
| + FrameCounters* shared_counters_state, |
| + CaptureSideCalledChecker* capture_call_checker, |
| + CallSimulator* test_framework, |
| + SimulationConfig* simulation_config, |
| + AudioProcessing* apm, |
| + int min_number_of_calls, |
| + float input_level); |
| + |
| + private: |
| + // Overrides from TimedThreadApiProcessor. |
| + int Process() override; |
| + bool ReadyToProcess() override; |
| + |
| + bool first_capture_side_call_ = true; |
| +}; |
| + |
| +// Class for handling the render side processing. |
| +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.
|
| + public: |
| + RenderProcessor(int max_frame_size, |
| + test::Random* rand_gen, |
| + FrameCounters* shared_counters_state, |
| + CaptureSideCalledChecker* capture_call_checker, |
| + CallSimulator* test_framework, |
| + SimulationConfig* simulation_config, |
| + AudioProcessing* apm, |
| + int min_number_of_calls, |
| + float input_level); |
| + |
| + private: |
| + // Overrides from TimedThreadApiProcessor |
| + int Process() override; |
| + bool ReadyToProcess() override; |
| + |
| + bool first_render_side_call_ = true; |
| +}; |
| + |
| +// Class for managing the test simulation. |
| +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.
|
| + public: |
| + explicit CallSimulator(SimulationConfig simulation_config); |
| + EventTypeWrapper Run(int time_out_limit); |
| + |
| + // Tests whether all the required render and capture side calls have been |
| + // done. |
| + void CheckIfSimulationDone() { |
| + if (frame_counters_.BothCountersExceedeThreshold( |
| + simulation_config_.min_number_of_calls)) { |
| + test_complete_->Set(); |
| + } |
| + } |
| + |
| + const CaptureProcessor* GetCapture() const { return &capture_thread_state_; } |
| + const RenderProcessor* GetRender() const { return &render_thread_state_; } |
| + void SetUp(); |
| + void TearDown(); |
| + |
| + private: |
| + static const int kMaxFrameSize = 480; |
| + static const float kCaptureInputFloatLevel; |
| + static const float kRenderInputFloatLevel; |
| + |
| + // Thread callback for the render thread. |
| + static bool RenderProcessorThreadFunc(void* context) { |
| + return reinterpret_cast<CallSimulator*>(context) |
| + ->render_thread_state_.ProcessClocked10msQuantum(); |
| + } |
| + |
| + // Thread callback for the capture thread. |
| + static bool CaptureProcessorThreadFunc(void* context) { |
| + return reinterpret_cast<CallSimulator*>(context) |
| + ->capture_thread_state_.ProcessClocked10msQuantum(); |
| + } |
| + |
| + // Start the threads used in the test. |
| + void StartThreads() { |
| + ASSERT_TRUE(render_thread_->Start()); |
| + render_thread_->SetPriority(kRealtimePriority); |
| + ASSERT_TRUE(capture_thread_->Start()); |
| + capture_thread_->SetPriority(kRealtimePriority); |
| + } |
| + |
| + // Event handler for the test. |
| + const rtc::scoped_ptr<EventWrapper> test_complete_; |
| + |
| + // Thread related variables. |
| + rtc::scoped_ptr<ThreadWrapper> render_thread_; |
| + rtc::scoped_ptr<ThreadWrapper> capture_thread_; |
| + 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.
|
| + |
| + rtc::scoped_ptr<AudioProcessing> apm_; |
| + SimulationConfig simulation_config_; |
| + FrameCounters frame_counters_; |
| + CaptureSideCalledChecker capture_call_checker_; |
| + RenderProcessor render_thread_state_; |
| + CaptureProcessor capture_thread_state_; |
| +}; |
| + |
| +const float CallSimulator::kRenderInputFloatLevel = 0.5f; |
| +const float CallSimulator::kCaptureInputFloatLevel = 0.03125f; |
| + |
| +CallSimulator::CallSimulator(SimulationConfig simulation_config) |
| + : test_complete_(EventWrapper::Create()), |
| + render_thread_(ThreadWrapper::CreateThread(RenderProcessorThreadFunc, |
| + this, |
| + "render")), |
| + capture_thread_(ThreadWrapper::CreateThread(CaptureProcessorThreadFunc, |
| + this, |
| + "capture")), |
| + rand_gen_(42U), |
| + 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.
|
| + simulation_config_(simulation_config), |
| + render_thread_state_(kMaxFrameSize, |
| + &rand_gen_, |
| + &frame_counters_, |
| + &capture_call_checker_, |
| + this, |
| + &simulation_config_, |
| + apm_.get(), |
| + simulation_config_.min_number_of_calls, |
| + kRenderInputFloatLevel), |
| + capture_thread_state_(kMaxFrameSize, |
| + &rand_gen_, |
| + &frame_counters_, |
| + &capture_call_checker_, |
| + this, |
| + &simulation_config_, |
| + apm_.get(), |
| + simulation_config_.min_number_of_calls, |
| + kCaptureInputFloatLevel) {} |
| + |
| +// Run the call simulation with a timeout. |
| +EventTypeWrapper CallSimulator::Run(int time_out_limit) { |
| + SetUp(); |
| + 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.
|
| + EventTypeWrapper result = test_complete_->Wait(time_out_limit); |
| + TearDown(); |
| + return result; |
| +} |
| + |
| +// Simulator and APM setup. |
| +void CallSimulator::SetUp() { |
| + ASSERT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true)); |
| + ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); |
| + ASSERT_EQ(apm_->kNoError, |
| + apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog)); |
| + ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); |
| + ASSERT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true)); |
| + ASSERT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true)); |
| + |
| + 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.
|
| + if (simulation_config_.aec_type == AecType::BasicWebRtcAecmSettings) { |
| + ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true)); |
| + ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false)); |
| + } else { |
| + ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false)); |
| + ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true)); |
| + ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->enable_metrics(true)); |
| + ASSERT_EQ(apm_->kNoError, |
| + apm_->echo_cancellation()->enable_delay_logging(true)); |
| + |
| + config.Set<ExtendedFilter>(new ExtendedFilter(true)); |
| + config.Set<DelayAgnostic>(new DelayAgnostic(true)); |
| + apm_->SetExtraOptions(config); |
| + } |
| +} |
| + |
| +void CallSimulator::TearDown() { |
| + render_thread_->Stop(); |
| + capture_thread_->Stop(); |
| +} |
| + |
| +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
|
| + int max_frame_size, |
| + test::Random* rand_gen, |
| + FrameCounters* shared_counters_state, |
| + CaptureSideCalledChecker* capture_call_checker, |
| + CallSimulator* test_framework, |
| + SimulationConfig* simulation_config, |
| + AudioProcessing* apm, |
| + int num_durations_to_store, |
| + float input_level) |
| + : rand_gen_(rand_gen), |
| + frame_counters_(shared_counters_state), |
| + capture_call_checker_(capture_call_checker), |
| + test_(test_framework), |
| + simulation_config_(simulation_config), |
| + apm_(apm), |
| + 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.
|
| + clock_(webrtc::Clock::GetRealTimeClock()), |
| + num_durations_to_store_(num_durations_to_store), |
| + api_call_durations_(num_durations_to_store_), |
| + input_level_(input_level) {} |
| + |
| +// Implements the callback functionality for the threads. |
| +bool TimedThreadApiProcessor::ProcessClocked10msQuantum() { |
| + PrepareFrame(); |
| + |
| + while (!ReadyToProcess()) { |
| + AddJitter(2, true); |
| + } |
| + |
| + const int64_t start_time = clock_->TimeInMicroseconds(); |
| + Process(); |
| + const int64_t end_time = clock_->TimeInMicroseconds(); |
| + 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.
|
| + const int time_left_of_10_ms_quantum = 10000 - duration; |
| + |
| + if (simulation_config_->use_realtime_simulation && |
| + time_left_of_10_ms_quantum > 0) { |
| + AddJitter(time_left_of_10_ms_quantum, false); |
| + } |
| + |
| + test_->CheckIfSimulationDone(); |
| + |
| + return true; |
| +} |
| + |
| +int64_t TimedThreadApiProcessor::GetDurationStandardDeviation() const { |
| + double variance = 0; |
| + const int64_t average_duration = GetDurationAverage(); |
| + for (int64_t duration : api_call_durations_) { |
| + int64_t tmp = duration - average_duration; |
| + variance += static_cast<double>(tmp * tmp); |
| + } |
| + 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.
|
| +} |
| + |
| +int64_t TimedThreadApiProcessor::GetDurationAverage() const { |
| + int64_t average_duration = 0; |
| + for (int64_t duration : api_call_durations_) { |
| + average_duration += duration; |
| + } |
| + return average_duration / api_call_durations_.size(); |
| +} |
| + |
| +void TimedThreadApiProcessor::PrepareFrame() { |
| + // Prepare the audio input data and metadata. |
| + frame_data_.input_stream_config.set_sample_rate_hz( |
| + simulation_config_->sample_rate_hz); |
| + frame_data_.input_stream_config.set_num_channels(1); |
| + frame_data_.input_stream_config.set_has_keyboard(false); |
| + PopulateAudioFrame(&frame_data_.input_frame[0], input_level_, 1, |
| + (simulation_config_->sample_rate_hz * |
| + AudioProcessing::kChunkSizeMs / 1000), |
| + rand_gen_); |
| + |
| + // Prepare the float audio output data and metadata. |
| + frame_data_.output_stream_config.set_sample_rate_hz( |
| + simulation_config_->sample_rate_hz); |
| + frame_data_.output_stream_config.set_num_channels(1); |
| + frame_data_.output_stream_config.set_has_keyboard(false); |
| +} |
| + |
| +void TimedThreadApiProcessor::AddJitter(int max_jitter_microseconds, |
| + bool random_jitter) { |
| + int min_method_duration; |
| + if (random_jitter) { |
| + min_method_duration = rand_gen_->Rand(0, max_jitter_microseconds); |
| + } else { |
| + min_method_duration = max_jitter_microseconds; |
| + } |
| + |
| + 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
|
| + int sum = 0; |
| + while ((clock_->TimeInMicroseconds() - start_time) < min_method_duration) { |
| + for (int k = 0; k < 100; ++k) |
| + for (int j = 1; j < 100; ++j) { |
| + sum += k % j; |
| + sum = sum % 79; |
| + } |
| + if (sum > 100) { |
| + printf("Will not be print out, just present in order to ensure"); |
| + printf("that sum is evaluated by the compiler\n"); |
| + } |
| + } |
| +} |
| + |
| +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.
|
| + int max_frame_size, |
| + test::Random* rand_gen, |
| + FrameCounters* shared_counters_state, |
| + CaptureSideCalledChecker* capture_call_checker, |
| + CallSimulator* test_framework, |
| + SimulationConfig* simulation_config, |
| + AudioProcessing* apm, |
| + int num_durations_to_store, |
| + float input_level) |
| + : TimedThreadApiProcessor(max_frame_size, |
| + rand_gen, |
| + shared_counters_state, |
| + capture_call_checker, |
| + test_framework, |
| + simulation_config, |
| + apm, |
| + num_durations_to_store, |
| + input_level) {} |
| + |
| +int CaptureProcessor::Process() { |
| + // Set the stream delay |
| + apm_->set_stream_delay_ms(30); |
| + |
| + // Call and time the specified capture side API processing method. |
| + const int64_t start_time = clock_->TimeInMicroseconds(); |
| + const int result = apm_->ProcessStream( |
| + &frame_data_.input_frame[0], frame_data_.input_stream_config, |
| + frame_data_.output_stream_config, &frame_data_.output_frame[0]); |
| + const int64_t end_time = clock_->TimeInMicroseconds(); |
| + |
| + const int new_capture_counter = frame_counters_->IncreaseCaptureCounter(); |
| + |
| + if (new_capture_counter <= num_durations_to_store_) { |
| + 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.
|
| + } |
| + |
| + if (first_capture_side_call_) { |
| + // Flag that the capture side has been called at least once |
| + // (needed to ensure that a capture call has been done |
| + // before the first render call is performed (implicitly |
| + // required by the APM API). |
| + capture_call_checker_->FlagCaptureSideCalled(); |
| + first_capture_side_call_ = false; |
| + } |
| + return result; |
| +} |
| + |
| +bool CaptureProcessor::ReadyToProcess() { |
| + return (frame_counters_->CaptureMinusRenderCounters() <= kMaxCallDifference); |
| +} |
| + |
| +RenderProcessor::RenderProcessor(int max_frame_size, |
| + test::Random* rand_gen, |
| + FrameCounters* shared_counters_state, |
| + CaptureSideCalledChecker* capture_call_checker, |
| + CallSimulator* test_framework, |
| + SimulationConfig* simulation_config, |
| + AudioProcessing* apm, |
| + int num_durations_to_store, |
| + float input_level) |
| + : TimedThreadApiProcessor(max_frame_size, |
| + rand_gen, |
| + shared_counters_state, |
| + capture_call_checker, |
| + test_framework, |
| + simulation_config, |
| + apm, |
| + num_durations_to_store, |
| + input_level) {} |
| + |
| +int RenderProcessor::Process() { |
| + // Call and time the specified render side API processing method. |
| + const int64_t start_time = clock_->TimeInMicroseconds(); |
| + const int result = apm_->ProcessReverseStream( |
| + &frame_data_.input_frame[0], frame_data_.input_stream_config, |
| + frame_data_.output_stream_config, &frame_data_.output_frame[0]); |
| + const int64_t end_time = clock_->TimeInMicroseconds(); |
| + |
| + const int new_render_counter = frame_counters_->IncreaseRenderCounter(); |
| + |
| + if (new_render_counter <= num_durations_to_store_) { |
| + api_call_durations_[new_render_counter - 1] = end_time - start_time; |
| + } |
| + |
| + return result; |
| +} |
| + |
| +bool RenderProcessor::ReadyToProcess() { |
| + // Do not process until at least one capture call has been done. |
| + // (implicitly required by the APM API). |
| + if (first_render_side_call_ && !capture_call_checker_->CaptureSideCalled()) { |
| + return false; |
| + } |
| + |
| + // Ensure that the number of render and capture calls do not differ too much. |
| + if (frame_counters_->RenderMinusCaptureCounters() > kMaxCallDifference) { |
| + return false; |
| + } |
| + |
| + first_render_side_call_ = false; |
| + return true; |
| +} |
| + |
| +// Runs the simulation and reports the results. |
| +void RunSimulation(SimulationConfig simulation_config, |
| + int timeout, |
| + bool print_durations) { |
| + // Lambda function for printing out the simulation statistics. |
| + auto print_simulation_statistics = []( |
| + const TimedThreadApiProcessor* processor, std::string processor_name, |
| + bool print_durations) { |
| + const std::string modifier = "_api_call_duration"; |
| + |
| + // Lambda function for creating a test printout string. |
| + auto create_mean_and_variance_string = [](int64_t average, |
| + int64_t standard_dev) { |
| + std::string s = std::to_string(average); |
| + s += ","; |
| + s += std::to_string(standard_dev); |
| + return s; |
| + }; |
| + |
| + webrtc::test::PrintResult(processor_name, modifier, "avg,stdev", |
| + create_mean_and_variance_string( |
| + processor->GetDurationAverage(), |
| + processor->GetDurationStandardDeviation()), |
| + "ms", false); |
| + |
| + if (print_durations) { |
| + std::vector<int64_t> durations = processor->get_api_call_durations(); |
| + std::string value_string = ""; |
| + for (int64_t duration : durations) { |
| + value_string += std::to_string(duration) + ","; |
| + } |
| + webrtc::test::PrintResultList(processor_name, modifier, "durations", |
| + value_string, "ms", false); |
| + } |
| + }; |
| + |
| + CallSimulator simulator(simulation_config); |
| + |
| + // Run simulation and verify that it did not time out. |
| + 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.
|
| + |
| + 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.
|
| + print_simulation_statistics(simulator.GetCapture(), "capture", |
| + print_durations); |
| +} |
| + |
| +const int kMaxFramesToProcess = 300; |
| +const int32_t kTestTimeout = 3 * 10 * kMaxFramesToProcess; |
| +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
|
| +const bool kPrintAllDurations = false; |
| +} // anonymous namespace |
| + |
| +TEST(AudioProcessingLockPerformanceTest, Aec8kHz) { |
| + RunSimulation(SimulationConfig(8000, AecType::BasicWebRtcAecSettings, |
| + kMaxFramesToProcess, kUseTimedSimulation), |
| + kTestTimeout, kPrintAllDurations); |
| +} |
| + |
| +TEST(AudioProcessingLockPerformanceTest, Aec16kHz) { |
| + RunSimulation(SimulationConfig(16000, AecType::BasicWebRtcAecSettings, |
| + kMaxFramesToProcess, kUseTimedSimulation), |
| + kTestTimeout, kPrintAllDurations); |
| +} |
| + |
| +TEST(AudioProcessingLockPerformanceTest, Aec32kHz) { |
| + RunSimulation(SimulationConfig(32000, AecType::BasicWebRtcAecSettings, |
| + kMaxFramesToProcess, kUseTimedSimulation), |
| + kTestTimeout, kPrintAllDurations); |
| +} |
| + |
| +TEST(AudioProcessingLockPerformanceTest, Aec48kHz) { |
| + RunSimulation(SimulationConfig(48000, AecType::BasicWebRtcAecSettings, |
| + kMaxFramesToProcess, kUseTimedSimulation), |
| + kTestTimeout, kPrintAllDurations); |
| +} |
| + |
| +TEST(AudioProcessingLockPerformanceTest, Aecm8kHz) { |
| + RunSimulation(SimulationConfig(8000, AecType::BasicWebRtcAecmSettings, |
| + kMaxFramesToProcess, true), |
| + kTestTimeout, kPrintAllDurations); |
| +} |
| + |
| +TEST(AudioProcessingLockPerformanceTest, Aecm16kHz) { |
| + RunSimulation(SimulationConfig(16000, AecType::BasicWebRtcAecmSettings, |
| + kMaxFramesToProcess, true), |
| + kTestTimeout, kPrintAllDurations); |
| +} |
| +} // namespace webrtc |