diff options
Diffstat (limited to 'webrtc/modules/audio_processing/audio_processing_performance_unittest.cc')
-rw-r--r-- | webrtc/modules/audio_processing/audio_processing_performance_unittest.cc | 724 |
1 files changed, 724 insertions, 0 deletions
diff --git a/webrtc/modules/audio_processing/audio_processing_performance_unittest.cc b/webrtc/modules/audio_processing/audio_processing_performance_unittest.cc new file mode 100644 index 0000000000..0c8c060ea3 --- /dev/null +++ b/webrtc/modules/audio_processing/audio_processing_performance_unittest.cc @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * 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/base/platform_thread.h" +#include "webrtc/base/random.h" +#include "webrtc/base/safe_conversions.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/test/testsupport/perf_test.h" + +namespace webrtc { + +namespace { + +static const bool kPrintAllDurations = false; + +class CallSimulator; + +// Type of the render thread APM API call to use in the test. +enum class ProcessorType { kRender, kCapture }; + +// Variant of APM processing settings to use in the test. +enum class SettingsType { + kDefaultApmDesktop, + kDefaultApmMobile, + kDefaultApmDesktopAndBeamformer, + kDefaultApmDesktopAndIntelligibilityEnhancer, + kAllSubmodulesTurnedOff, + kDefaultDesktopApmWithoutDelayAgnostic, + kDefaultDesktopApmWithoutExtendedFilter +}; + +// Variables related to the audio data and formats. +struct AudioFrameData { + explicit AudioFrameData(size_t max_frame_size) { + // 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, SettingsType simulation_settings) + : sample_rate_hz(sample_rate_hz), + simulation_settings(simulation_settings) {} + + static std::vector<SimulationConfig> GenerateSimulationConfigs() { + std::vector<SimulationConfig> simulation_configs; +#ifndef WEBRTC_ANDROID + const SettingsType desktop_settings[] = { + SettingsType::kDefaultApmDesktop, SettingsType::kAllSubmodulesTurnedOff, + SettingsType::kDefaultDesktopApmWithoutDelayAgnostic, + SettingsType::kDefaultDesktopApmWithoutExtendedFilter}; + + const int desktop_sample_rates[] = {8000, 16000, 32000, 48000}; + + for (auto sample_rate : desktop_sample_rates) { + for (auto settings : desktop_settings) { + simulation_configs.push_back(SimulationConfig(sample_rate, settings)); + } + } + + const SettingsType intelligibility_enhancer_settings[] = { + SettingsType::kDefaultApmDesktopAndIntelligibilityEnhancer}; + + const int intelligibility_enhancer_sample_rates[] = {8000, 16000, 32000, + 48000}; + + for (auto sample_rate : intelligibility_enhancer_sample_rates) { + for (auto settings : intelligibility_enhancer_settings) { + simulation_configs.push_back(SimulationConfig(sample_rate, settings)); + } + } + + const SettingsType beamformer_settings[] = { + SettingsType::kDefaultApmDesktopAndBeamformer}; + + const int beamformer_sample_rates[] = {8000, 16000, 32000, 48000}; + + for (auto sample_rate : beamformer_sample_rates) { + for (auto settings : beamformer_settings) { + simulation_configs.push_back(SimulationConfig(sample_rate, settings)); + } + } +#endif + + const SettingsType mobile_settings[] = {SettingsType::kDefaultApmMobile}; + + const int mobile_sample_rates[] = {8000, 16000}; + + for (auto sample_rate : mobile_sample_rates) { + for (auto settings : mobile_settings) { + simulation_configs.push_back(SimulationConfig(sample_rate, settings)); + } + } + + return simulation_configs; + } + + std::string SettingsDescription() const { + std::string description; + switch (simulation_settings) { + case SettingsType::kDefaultApmMobile: + description = "DefaultApmMobile"; + break; + case SettingsType::kDefaultApmDesktop: + description = "DefaultApmDesktop"; + break; + case SettingsType::kDefaultApmDesktopAndBeamformer: + description = "DefaultApmDesktopAndBeamformer"; + break; + case SettingsType::kDefaultApmDesktopAndIntelligibilityEnhancer: + description = "DefaultApmDesktopAndIntelligibilityEnhancer"; + break; + case SettingsType::kAllSubmodulesTurnedOff: + description = "AllSubmodulesOff"; + break; + case SettingsType::kDefaultDesktopApmWithoutDelayAgnostic: + description = "DefaultDesktopApmWithoutDelayAgnostic"; + break; + case SettingsType::kDefaultDesktopApmWithoutExtendedFilter: + description = "DefaultDesktopApmWithoutExtendedFilter"; + break; + } + return description; + } + + int sample_rate_hz = 16000; + SettingsType simulation_settings = SettingsType::kDefaultApmDesktop; +}; + +// Handler for the frame counters. +class FrameCounters { + public: + void IncreaseRenderCounter() { + rtc::CritScope cs(&crit_); + render_count_++; + } + + void IncreaseCaptureCounter() { + rtc::CritScope cs(&crit_); + capture_count_++; + } + + int GetCaptureCounter() const { + rtc::CritScope cs(&crit_); + return capture_count_; + } + + int GetRenderCounter() const { + rtc::CritScope cs(&crit_); + return render_count_; + } + + int CaptureMinusRenderCounters() const { + rtc::CritScope cs(&crit_); + return capture_count_ - render_count_; + } + + int RenderMinusCaptureCounters() const { + return -CaptureMinusRenderCounters(); + } + + bool BothCountersExceedeThreshold(int threshold) const { + rtc::CritScope cs(&crit_); + return (render_count_ > threshold && capture_count_ > threshold); + } + + private: + mutable rtc::CriticalSection crit_; + int render_count_ GUARDED_BY(crit_) = 0; + int capture_count_ GUARDED_BY(crit_) = 0; +}; + +// Class that protects a flag using a lock. +class LockedFlag { + public: + bool get_flag() const { + rtc::CritScope cs(&crit_); + return flag_; + } + + void set_flag() { + rtc::CritScope cs(&crit_); + flag_ = true; + } + + private: + mutable rtc::CriticalSection crit_; + bool flag_ GUARDED_BY(crit_) = false; +}; + +// Parent class for the thread processors. +class TimedThreadApiProcessor { + public: + TimedThreadApiProcessor(ProcessorType processor_type, + Random* rand_gen, + FrameCounters* shared_counters_state, + LockedFlag* capture_call_checker, + CallSimulator* test_framework, + const SimulationConfig* simulation_config, + AudioProcessing* apm, + int num_durations_to_store, + float input_level, + int num_channels) + : 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_(kMaxFrameSize), + clock_(webrtc::Clock::GetRealTimeClock()), + num_durations_to_store_(num_durations_to_store), + input_level_(input_level), + processor_type_(processor_type), + num_channels_(num_channels) { + api_call_durations_.reserve(num_durations_to_store_); + } + + // Implements the callback functionality for the threads. + bool Process(); + + // Method for printing out the simulation statistics. + void print_processor_statistics(std::string processor_name) const { + const std::string modifier = "_api_call_duration"; + + // Lambda function for creating a test printout string. + auto create_mean_and_std_string = [](int64_t average, + int64_t standard_dev) { + std::string s = std::to_string(average); + s += ", "; + s += std::to_string(standard_dev); + return s; + }; + + const std::string sample_rate_name = + "_" + std::to_string(simulation_config_->sample_rate_hz) + "Hz"; + + webrtc::test::PrintResultMeanAndError( + "apm_timing", sample_rate_name, processor_name, + create_mean_and_std_string(GetDurationAverage(), + GetDurationStandardDeviation()), + "us", false); + + if (kPrintAllDurations) { + std::string value_string = ""; + for (int64_t duration : api_call_durations_) { + value_string += std::to_string(duration) + ","; + } + webrtc::test::PrintResultList("apm_call_durations", sample_rate_name, + processor_name, value_string, "us", false); + } + } + + void AddDuration(int64_t duration) { + if (api_call_durations_.size() < num_durations_to_store_) { + api_call_durations_.push_back(duration); + } + } + + private: + static const int kMaxCallDifference = 10; + static const int kMaxFrameSize = 480; + static const int kNumInitializationFrames = 5; + + int64_t GetDurationStandardDeviation() const { + double variance = 0; + const int64_t average_duration = GetDurationAverage(); + for (size_t k = kNumInitializationFrames; k < api_call_durations_.size(); + k++) { + int64_t tmp = api_call_durations_[k] - average_duration; + variance += static_cast<double>(tmp * tmp); + } + const int denominator = rtc::checked_cast<int>(api_call_durations_.size()) - + kNumInitializationFrames; + return (denominator > 0 + ? rtc::checked_cast<int64_t>(sqrt(variance / denominator)) + : -1); + } + + int64_t GetDurationAverage() const { + int64_t average_duration = 0; + for (size_t k = kNumInitializationFrames; k < api_call_durations_.size(); + k++) { + average_duration += api_call_durations_[k]; + } + const int denominator = rtc::checked_cast<int>(api_call_durations_.size()) - + kNumInitializationFrames; + return (denominator > 0 ? average_duration / denominator : -1); + } + + int ProcessCapture() { + // 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(); + + frame_counters_->IncreaseCaptureCounter(); + + AddDuration(end_time - start_time); + + if (first_process_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_->set_flag(); + first_process_call_ = false; + } + return result; + } + + bool ReadyToProcessCapture() { + return (frame_counters_->CaptureMinusRenderCounters() <= + kMaxCallDifference); + } + + int ProcessRender() { + // 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(); + frame_counters_->IncreaseRenderCounter(); + + AddDuration(end_time - start_time); + + return result; + } + + bool ReadyToProcessRender() { + // Do not process until at least one capture call has been done. + // (implicitly required by the APM API). + if (first_process_call_ && !capture_call_checker_->get_flag()) { + return false; + } + + // Ensure that the number of render and capture calls do not differ too + // much. + if (frame_counters_->RenderMinusCaptureCounters() > kMaxCallDifference) { + return false; + } + + first_process_call_ = false; + return true; + } + + void PrepareFrame() { + // Lambda function for populating a float multichannel audio frame + // with random data. + auto populate_audio_frame = [](float amplitude, size_t num_channels, + size_t samples_per_channel, Random* rand_gen, + float** frame) { + for (size_t ch = 0; ch < num_channels; ch++) { + for (size_t k = 0; k < samples_per_channel; k++) { + // Store random float number with a value between +-amplitude. + frame[ch][k] = amplitude * (2 * rand_gen->Rand<float>() - 1); + } + } + }; + + // 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(num_channels_); + frame_data_.input_stream_config.set_has_keyboard(false); + populate_audio_frame(input_level_, num_channels_, + (simulation_config_->sample_rate_hz * + AudioProcessing::kChunkSizeMs / 1000), + rand_gen_, &frame_data_.input_frame[0]); + + // 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); + } + + bool ReadyToProcess() { + switch (processor_type_) { + case ProcessorType::kRender: + return ReadyToProcessRender(); + break; + case ProcessorType::kCapture: + return ReadyToProcessCapture(); + break; + } + + // Should not be reached, but the return statement is needed for the code to + // build successfully on Android. + RTC_NOTREACHED(); + return false; + } + + Random* rand_gen_ = nullptr; + FrameCounters* frame_counters_ = nullptr; + LockedFlag* capture_call_checker_ = nullptr; + CallSimulator* test_ = nullptr; + const SimulationConfig* const simulation_config_ = nullptr; + AudioProcessing* apm_ = nullptr; + AudioFrameData frame_data_; + webrtc::Clock* clock_; + const size_t num_durations_to_store_; + std::vector<int64_t> api_call_durations_; + const float input_level_; + bool first_process_call_ = true; + const ProcessorType processor_type_; + const int num_channels_ = 1; +}; + +// Class for managing the test simulation. +class CallSimulator : public ::testing::TestWithParam<SimulationConfig> { + public: + CallSimulator() + : test_complete_(EventWrapper::Create()), + render_thread_( + new rtc::PlatformThread(RenderProcessorThreadFunc, this, "render")), + capture_thread_(new rtc::PlatformThread(CaptureProcessorThreadFunc, + this, + "capture")), + rand_gen_(42U), + simulation_config_(static_cast<SimulationConfig>(GetParam())) {} + + // Run the call simulation with a timeout. + EventTypeWrapper Run() { + StartThreads(); + + EventTypeWrapper result = test_complete_->Wait(kTestTimeout); + + StopThreads(); + + render_thread_state_->print_processor_statistics( + simulation_config_.SettingsDescription() + "_render"); + capture_thread_state_->print_processor_statistics( + simulation_config_.SettingsDescription() + "_capture"); + + return result; + } + + // Tests whether all the required render and capture side calls have been + // done. + bool MaybeEndTest() { + if (frame_counters_.BothCountersExceedeThreshold(kMinNumFramesToProcess)) { + test_complete_->Set(); + return true; + } + return false; + } + + private: + static const float kCaptureInputFloatLevel; + static const float kRenderInputFloatLevel; + static const int kMinNumFramesToProcess = 150; + static const int32_t kTestTimeout = 3 * 10 * kMinNumFramesToProcess; + + // ::testing::TestWithParam<> implementation. + void TearDown() override { StopThreads(); } + + // Stop all running threads. + void StopThreads() { + render_thread_->Stop(); + capture_thread_->Stop(); + } + + // Simulator and APM setup. + void SetUp() override { + // Lambda function for setting the default APM runtime settings for desktop. + auto set_default_desktop_apm_runtime_settings = [](AudioProcessing* apm) { + 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::kAdaptiveDigital)); + 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)); + 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)); + }; + + // Lambda function for setting the default APM runtime settings for mobile. + auto set_default_mobile_apm_runtime_settings = [](AudioProcessing* apm) { + 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::kAdaptiveDigital)); + 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)); + ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true)); + ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(false)); + }; + + // Lambda function for turning off all of the APM runtime settings + // submodules. + auto turn_off_default_apm_runtime_settings = [](AudioProcessing* apm) { + ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false)); + ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(false)); + ASSERT_EQ(apm->kNoError, + apm->gain_control()->set_mode(GainControl::kAdaptiveDigital)); + ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(false)); + ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(false)); + ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(false)); + ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(false)); + ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(false)); + ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->enable_metrics(false)); + ASSERT_EQ(apm->kNoError, + apm->echo_cancellation()->enable_delay_logging(false)); + }; + + // Lambda function for adding default desktop APM settings to a config. + auto add_default_desktop_config = [](Config* config) { + config->Set<ExtendedFilter>(new ExtendedFilter(true)); + config->Set<DelayAgnostic>(new DelayAgnostic(true)); + }; + + // Lambda function for adding beamformer settings to a config. + auto add_beamformer_config = [](Config* config) { + const size_t num_mics = 2; + const std::vector<Point> array_geometry = + ParseArrayGeometry("0 0 0 0.05 0 0", num_mics); + RTC_CHECK_EQ(array_geometry.size(), num_mics); + + config->Set<Beamforming>( + new Beamforming(true, array_geometry, + SphericalPointf(DegreesToRadians(90), 0.f, 1.f))); + }; + + int num_capture_channels = 1; + switch (simulation_config_.simulation_settings) { + case SettingsType::kDefaultApmMobile: { + apm_.reset(AudioProcessingImpl::Create()); + ASSERT_TRUE(!!apm_); + set_default_mobile_apm_runtime_settings(apm_.get()); + break; + } + case SettingsType::kDefaultApmDesktop: { + Config config; + add_default_desktop_config(&config); + apm_.reset(AudioProcessingImpl::Create(config)); + ASSERT_TRUE(!!apm_); + set_default_desktop_apm_runtime_settings(apm_.get()); + apm_->SetExtraOptions(config); + break; + } + case SettingsType::kDefaultApmDesktopAndBeamformer: { + Config config; + add_beamformer_config(&config); + add_default_desktop_config(&config); + apm_.reset(AudioProcessingImpl::Create(config)); + ASSERT_TRUE(!!apm_); + set_default_desktop_apm_runtime_settings(apm_.get()); + apm_->SetExtraOptions(config); + num_capture_channels = 2; + break; + } + case SettingsType::kDefaultApmDesktopAndIntelligibilityEnhancer: { + Config config; + config.Set<Intelligibility>(new Intelligibility(true)); + add_default_desktop_config(&config); + apm_.reset(AudioProcessingImpl::Create(config)); + ASSERT_TRUE(!!apm_); + set_default_desktop_apm_runtime_settings(apm_.get()); + apm_->SetExtraOptions(config); + break; + } + case SettingsType::kAllSubmodulesTurnedOff: { + apm_.reset(AudioProcessingImpl::Create()); + ASSERT_TRUE(!!apm_); + turn_off_default_apm_runtime_settings(apm_.get()); + break; + } + case SettingsType::kDefaultDesktopApmWithoutDelayAgnostic: { + Config config; + config.Set<ExtendedFilter>(new ExtendedFilter(true)); + config.Set<DelayAgnostic>(new DelayAgnostic(false)); + apm_.reset(AudioProcessingImpl::Create(config)); + ASSERT_TRUE(!!apm_); + set_default_desktop_apm_runtime_settings(apm_.get()); + apm_->SetExtraOptions(config); + break; + } + case SettingsType::kDefaultDesktopApmWithoutExtendedFilter: { + Config config; + config.Set<ExtendedFilter>(new ExtendedFilter(false)); + config.Set<DelayAgnostic>(new DelayAgnostic(true)); + apm_.reset(AudioProcessingImpl::Create(config)); + ASSERT_TRUE(!!apm_); + set_default_desktop_apm_runtime_settings(apm_.get()); + apm_->SetExtraOptions(config); + break; + } + } + + render_thread_state_.reset(new TimedThreadApiProcessor( + ProcessorType::kRender, &rand_gen_, &frame_counters_, + &capture_call_checker_, this, &simulation_config_, apm_.get(), + kMinNumFramesToProcess, kRenderInputFloatLevel, 1)); + capture_thread_state_.reset(new TimedThreadApiProcessor( + ProcessorType::kCapture, &rand_gen_, &frame_counters_, + &capture_call_checker_, this, &simulation_config_, apm_.get(), + kMinNumFramesToProcess, kCaptureInputFloatLevel, num_capture_channels)); + } + + // Thread callback for the render thread. + static bool RenderProcessorThreadFunc(void* context) { + return reinterpret_cast<CallSimulator*>(context) + ->render_thread_state_->Process(); + } + + // Thread callback for the capture thread. + static bool CaptureProcessorThreadFunc(void* context) { + return reinterpret_cast<CallSimulator*>(context) + ->capture_thread_state_->Process(); + } + + // Start the threads used in the test. + void StartThreads() { + ASSERT_NO_FATAL_FAILURE(render_thread_->Start()); + render_thread_->SetPriority(rtc::kRealtimePriority); + ASSERT_NO_FATAL_FAILURE(capture_thread_->Start()); + capture_thread_->SetPriority(rtc::kRealtimePriority); + } + + // Event handler for the test. + const rtc::scoped_ptr<EventWrapper> test_complete_; + + // Thread related variables. + rtc::scoped_ptr<rtc::PlatformThread> render_thread_; + rtc::scoped_ptr<rtc::PlatformThread> capture_thread_; + Random rand_gen_; + + rtc::scoped_ptr<AudioProcessing> apm_; + const SimulationConfig simulation_config_; + FrameCounters frame_counters_; + LockedFlag capture_call_checker_; + rtc::scoped_ptr<TimedThreadApiProcessor> render_thread_state_; + rtc::scoped_ptr<TimedThreadApiProcessor> capture_thread_state_; +}; + +// Implements the callback functionality for the threads. +bool TimedThreadApiProcessor::Process() { + PrepareFrame(); + + // Wait in a spinlock manner until it is ok to start processing. + // Note that SleepMs is not applicable since it only allows sleeping + // on a millisecond basis which is too long. + while (!ReadyToProcess()) { + } + + int result = AudioProcessing::kNoError; + switch (processor_type_) { + case ProcessorType::kRender: + result = ProcessRender(); + break; + case ProcessorType::kCapture: + result = ProcessCapture(); + break; + } + + EXPECT_EQ(result, AudioProcessing::kNoError); + + return !test_->MaybeEndTest(); +} + +const float CallSimulator::kRenderInputFloatLevel = 0.5f; +const float CallSimulator::kCaptureInputFloatLevel = 0.03125f; +} // anonymous namespace + +TEST_P(CallSimulator, ApiCallDurationTest) { + // Run test and verify that it did not time out. + EXPECT_EQ(kEventSignaled, Run()); +} + +INSTANTIATE_TEST_CASE_P( + AudioProcessingPerformanceTest, + CallSimulator, + ::testing::ValuesIn(SimulationConfig::GenerateSimulationConfigs())); + +} // namespace webrtc |