* 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 <algorithm>
#include <memory>
#include <vector>
#include "api/array_view.h"
#include "modules/audio_processing/audio_processing_impl.h"
#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
#include "modules/audio_processing/test/test_utils.h"
#include "rtc_base/event.h"
#include "rtc_base/platform_thread.h"
#include "rtc_base/random.h"
#include "rtc_base/synchronization/mutex.h"
#include "system_wrappers/include/sleep.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
constexpr int kMaxFrameSize = 480;
constexpr TimeDelta kTestTimeOutLimit = TimeDelta::Minutes(10);
class AudioProcessingImplLockTest;
enum class RenderApiImpl {
ProcessReverseStreamImplInteger,
ProcessReverseStreamImplFloat,
AnalyzeReverseStreamImplFloat,
};
enum class CaptureApiImpl { ProcessStreamImplInteger, ProcessStreamImplFloat };
enum class RuntimeParameterSettingScheme {
SparseStreamMetadataChangeScheme,
ExtremeStreamMetadataChangeScheme,
FixedMonoStreamMetadataScheme,
FixedStereoStreamMetadataScheme
};
enum class AecType {
BasicWebRtcAecSettings,
AecTurnedOff,
BasicWebRtcAecSettingsWithExtentedFilter,
BasicWebRtcAecSettingsWithDelayAgnosticAec,
BasicWebRtcAecSettingsWithAecMobile
};
class RandomGenerator {
public:
RandomGenerator() : rand_gen_(42U) {}
int RandInt(int min, int max) {
MutexLock lock(&mutex_);
return rand_gen_.Rand(min, max);
}
int RandInt(int max) {
MutexLock lock(&mutex_);
return rand_gen_.Rand(max);
}
float RandFloat() {
MutexLock lock(&mutex_);
return rand_gen_.Rand<float>();
}
private:
Mutex mutex_;
Random rand_gen_ RTC_GUARDED_BY(mutex_);
};
struct AudioFrameData {
explicit AudioFrameData(int max_frame_size) {
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];
frame.resize(2 * max_frame_size);
}
std::vector<int16_t> frame;
std::vector<float*> output_frame;
std::vector<float> output_frame_channels;
std::vector<float*> input_frame;
std::vector<float> input_framechannels;
int input_sample_rate_hz = 16000;
int input_number_of_channels = 1;
int output_sample_rate_hz = 16000;
int output_number_of_channels = 1;
};
struct TestConfig {
static std::vector<TestConfig> GenerateBriefTestConfigs() {
std::vector<TestConfig> test_configs;
AecType aec_types[] = {AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec,
AecType::BasicWebRtcAecSettingsWithAecMobile};
for (auto aec_type : aec_types) {
TestConfig test_config;
test_config.aec_type = aec_type;
test_config.min_number_of_calls = 300;
test_config.runtime_parameter_setting_scheme =
RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme;
test_config.initial_sample_rate_hz = 16000;
test_config.render_api_function =
RenderApiImpl::ProcessReverseStreamImplInteger;
test_config.capture_api_function =
CaptureApiImpl::ProcessStreamImplInteger;
test_configs.push_back(test_config);
test_config.render_api_function =
RenderApiImpl::ProcessReverseStreamImplFloat;
test_config.capture_api_function = CaptureApiImpl::ProcessStreamImplFloat;
test_configs.push_back(test_config);
}
return test_configs;
}
static std::vector<TestConfig> GenerateExtensiveTestConfigs() {
auto add_processing_apis = [](TestConfig test_config) {
struct AllowedApiCallCombinations {
RenderApiImpl render_api;
CaptureApiImpl capture_api;
};
const AllowedApiCallCombinations api_calls[] = {
{RenderApiImpl::ProcessReverseStreamImplInteger,
CaptureApiImpl::ProcessStreamImplInteger},
{RenderApiImpl::ProcessReverseStreamImplFloat,
CaptureApiImpl::ProcessStreamImplFloat},
{RenderApiImpl::AnalyzeReverseStreamImplFloat,
CaptureApiImpl::ProcessStreamImplFloat},
{RenderApiImpl::ProcessReverseStreamImplInteger,
CaptureApiImpl::ProcessStreamImplFloat},
{RenderApiImpl::ProcessReverseStreamImplFloat,
CaptureApiImpl::ProcessStreamImplInteger}};
std::vector<TestConfig> out;
for (auto api_call : api_calls) {
test_config.render_api_function = api_call.render_api;
test_config.capture_api_function = api_call.capture_api;
out.push_back(test_config);
}
return out;
};
auto add_aec_settings = [](const std::vector<TestConfig>& in) {
std::vector<TestConfig> out;
AecType aec_types[] = {
AecType::BasicWebRtcAecSettings, AecType::AecTurnedOff,
AecType::BasicWebRtcAecSettingsWithExtentedFilter,
AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec,
AecType::BasicWebRtcAecSettingsWithAecMobile};
for (auto test_config : in) {
for (auto type : aec_types) {
test_config.aec_type = type;
out.push_back(test_config);
}
}
return out;
};
auto add_settings_scheme = [](const std::vector<TestConfig>& in) {
std::vector<TestConfig> out;
RuntimeParameterSettingScheme schemes[] = {
RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme,
RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme,
RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme,
RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme};
for (auto test_config : in) {
for (auto scheme : schemes) {
test_config.runtime_parameter_setting_scheme = scheme;
out.push_back(test_config);
}
}
return out;
};
auto add_sample_rates = [](const std::vector<TestConfig>& in) {
const int sample_rates[] = {8000, 16000, 32000, 48000};
std::vector<TestConfig> out;
for (auto test_config : in) {
auto available_rates =
(test_config.aec_type ==
AecType::BasicWebRtcAecSettingsWithAecMobile
? rtc::ArrayView<const int>(sample_rates, 2)
: rtc::ArrayView<const int>(sample_rates));
for (auto rate : available_rates) {
test_config.initial_sample_rate_hz = rate;
out.push_back(test_config);
}
}
return out;
};
TestConfig test_config;
test_config.min_number_of_calls = 10000;
return add_sample_rates(add_settings_scheme(
add_aec_settings(add_processing_apis(test_config))));
}
RenderApiImpl render_api_function =
RenderApiImpl::ProcessReverseStreamImplFloat;
CaptureApiImpl capture_api_function = CaptureApiImpl::ProcessStreamImplFloat;
RuntimeParameterSettingScheme runtime_parameter_setting_scheme =
RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme;
int initial_sample_rate_hz = 16000;
AecType aec_type = AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec;
int min_number_of_calls = 300;
};
class FrameCounters {
public:
void IncreaseRenderCounter() {
MutexLock lock(&mutex_);
render_count++;
}
void IncreaseCaptureCounter() {
MutexLock lock(&mutex_);
capture_count++;
}
int GetCaptureCounter() const {
MutexLock lock(&mutex_);
return capture_count;
}
int GetRenderCounter() const {
MutexLock lock(&mutex_);
return render_count;
}
int CaptureMinusRenderCounters() const {
MutexLock lock(&mutex_);
return capture_count - render_count;
}
int RenderMinusCaptureCounters() const {
return -CaptureMinusRenderCounters();
}
bool BothCountersExceedeThreshold(int threshold) {
MutexLock lock(&mutex_);
return (render_count > threshold && capture_count > threshold);
}
private:
mutable Mutex mutex_;
int render_count RTC_GUARDED_BY(mutex_) = 0;
int capture_count RTC_GUARDED_BY(mutex_) = 0;
};
class CaptureProcessor {
public:
CaptureProcessor(int max_frame_size,
RandomGenerator* rand_gen,
rtc::Event* render_call_event,
rtc::Event* capture_call_event,
FrameCounters* shared_counters_state,
const TestConfig* test_config,
AudioProcessing* apm);
void Process();
private:
static constexpr int kMaxCallDifference = 10;
static constexpr float kCaptureInputFloatLevel = 0.03125f;
static constexpr int kCaptureInputFixLevel = 1024;
void PrepareFrame();
void CallApmCaptureSide();
void ApplyRuntimeSettingScheme();
RandomGenerator* const rand_gen_ = nullptr;
rtc::Event* const render_call_event_ = nullptr;
rtc::Event* const capture_call_event_ = nullptr;
FrameCounters* const frame_counters_ = nullptr;
const TestConfig* const test_config_ = nullptr;
AudioProcessing* const apm_ = nullptr;
AudioFrameData frame_data_;
};
class StatsProcessor {
public:
StatsProcessor(RandomGenerator* rand_gen,
const TestConfig* test_config,
AudioProcessing* apm);
void Process();
private:
RandomGenerator* rand_gen_ = nullptr;
const TestConfig* const test_config_ = nullptr;
AudioProcessing* apm_ = nullptr;
};
class RenderProcessor {
public:
RenderProcessor(int max_frame_size,
RandomGenerator* rand_gen,
rtc::Event* render_call_event,
rtc::Event* capture_call_event,
FrameCounters* shared_counters_state,
const TestConfig* test_config,
AudioProcessing* apm);
void Process();
private:
static constexpr int kMaxCallDifference = 10;
static constexpr int kRenderInputFixLevel = 16384;
static constexpr float kRenderInputFloatLevel = 0.5f;
void PrepareFrame();
void CallApmRenderSide();
void ApplyRuntimeSettingScheme();
RandomGenerator* const rand_gen_ = nullptr;
rtc::Event* const render_call_event_ = nullptr;
rtc::Event* const capture_call_event_ = nullptr;
FrameCounters* const frame_counters_ = nullptr;
const TestConfig* const test_config_ = nullptr;
AudioProcessing* const apm_ = nullptr;
AudioFrameData frame_data_;
bool first_render_call_ = true;
};
class AudioProcessingImplLockTest
: public ::testing::TestWithParam<TestConfig> {
public:
AudioProcessingImplLockTest();
bool RunTest();
bool MaybeEndTest();
private:
void SetUp() override;
void TearDown() override;
bool TestDone() {
return frame_counters_.BothCountersExceedeThreshold(
test_config_.min_number_of_calls);
}
void StartThreads() {
const auto attributes =
rtc::ThreadAttributes().SetPriority(rtc::ThreadPriority::kRealtime);
render_thread_ = rtc::PlatformThread::SpawnJoinable(
[this] {
while (!MaybeEndTest())
render_thread_state_.Process();
},
"render", attributes);
capture_thread_ = rtc::PlatformThread::SpawnJoinable(
[this] {
while (!MaybeEndTest()) {
capture_thread_state_.Process();
}
},
"capture", attributes);
stats_thread_ = rtc::PlatformThread::SpawnJoinable(
[this] {
while (!MaybeEndTest())
stats_thread_state_.Process();
},
"stats", attributes);
}
rtc::Event test_complete_;
rtc::Event render_call_event_;
rtc::Event capture_call_event_;
mutable RandomGenerator rand_gen_;
const TestConfig test_config_;
rtc::scoped_refptr<AudioProcessing> apm_;
FrameCounters frame_counters_;
RenderProcessor render_thread_state_;
CaptureProcessor capture_thread_state_;
StatsProcessor stats_thread_state_;
rtc::PlatformThread render_thread_;
rtc::PlatformThread capture_thread_;
rtc::PlatformThread stats_thread_;
};
void SleepRandomMs(int max_sleep, RandomGenerator* rand_gen) {
int sleeptime = rand_gen->RandInt(0, max_sleep);
SleepMs(sleeptime);
}
void PopulateAudioFrame(float** frame,
float amplitude,
size_t num_channels,
size_t samples_per_channel,
RandomGenerator* rand_gen) {
for (size_t ch = 0; ch < num_channels; ch++) {
for (size_t k = 0; k < samples_per_channel; k++) {
frame[ch][k] = amplitude * (2 * rand_gen->RandFloat() - 1);
}
}
}
void PopulateAudioFrame(float amplitude,
size_t num_channels,
size_t samples_per_channel,
rtc::ArrayView<int16_t> frame,
RandomGenerator* rand_gen) {
ASSERT_GT(amplitude, 0);
ASSERT_LE(amplitude, 32767);
for (size_t ch = 0; ch < num_channels; ch++) {
for (size_t k = 0; k < samples_per_channel; k++) {
frame[k * ch] = rand_gen->RandInt(2 * amplitude + 1) - amplitude - 1;
}
}
}
AudioProcessing::Config GetApmTestConfig(AecType aec_type) {
AudioProcessing::Config apm_config;
apm_config.echo_canceller.enabled = aec_type != AecType::AecTurnedOff;
apm_config.echo_canceller.mobile_mode =
aec_type == AecType::BasicWebRtcAecSettingsWithAecMobile;
apm_config.gain_controller1.enabled = true;
apm_config.gain_controller1.mode =
AudioProcessing::Config::GainController1::kAdaptiveDigital;
apm_config.noise_suppression.enabled = true;
return apm_config;
}
AudioProcessingImplLockTest::AudioProcessingImplLockTest()
: test_config_(GetParam()),
apm_(AudioProcessingBuilderForTesting()
.SetConfig(GetApmTestConfig(test_config_.aec_type))
.Create()),
render_thread_state_(kMaxFrameSize,
&rand_gen_,
&render_call_event_,
&capture_call_event_,
&frame_counters_,
&test_config_,
apm_.get()),
capture_thread_state_(kMaxFrameSize,
&rand_gen_,
&render_call_event_,
&capture_call_event_,
&frame_counters_,
&test_config_,
apm_.get()),
stats_thread_state_(&rand_gen_, &test_config_, apm_.get()) {}
bool AudioProcessingImplLockTest::RunTest() {
StartThreads();
return test_complete_.Wait(kTestTimeOutLimit);
}
bool AudioProcessingImplLockTest::MaybeEndTest() {
if (HasFatalFailure() || TestDone()) {
test_complete_.Set();
return true;
}
return false;
}
void AudioProcessingImplLockTest::SetUp() {}
void AudioProcessingImplLockTest::TearDown() {
render_call_event_.Set();
capture_call_event_.Set();
}
StatsProcessor::StatsProcessor(RandomGenerator* rand_gen,
const TestConfig* test_config,
AudioProcessing* apm)
: rand_gen_(rand_gen), test_config_(test_config), apm_(apm) {}
void StatsProcessor::Process() {
SleepRandomMs(100, rand_gen_);
AudioProcessing::Config apm_config = apm_->GetConfig();
if (test_config_->aec_type != AecType::AecTurnedOff) {
EXPECT_TRUE(apm_config.echo_canceller.enabled);
EXPECT_EQ(apm_config.echo_canceller.mobile_mode,
(test_config_->aec_type ==
AecType::BasicWebRtcAecSettingsWithAecMobile));
} else {
EXPECT_FALSE(apm_config.echo_canceller.enabled);
}
EXPECT_TRUE(apm_config.gain_controller1.enabled);
EXPECT_TRUE(apm_config.noise_suppression.enabled);
apm_->GetStatistics();
}
CaptureProcessor::CaptureProcessor(int max_frame_size,
RandomGenerator* rand_gen,
rtc::Event* render_call_event,
rtc::Event* capture_call_event,
FrameCounters* shared_counters_state,
const TestConfig* test_config,
AudioProcessing* apm)
: rand_gen_(rand_gen),
render_call_event_(render_call_event),
capture_call_event_(capture_call_event),
frame_counters_(shared_counters_state),
test_config_(test_config),
apm_(apm),
frame_data_(max_frame_size) {}
void CaptureProcessor::Process() {
SleepRandomMs(3, rand_gen_);
if (frame_counters_->CaptureMinusRenderCounters() > kMaxCallDifference) {
render_call_event_->Wait(rtc::Event::kForever);
}
ApplyRuntimeSettingScheme();
CallApmCaptureSide();
frame_counters_->IncreaseCaptureCounter();
capture_call_event_->Set();
}
void CaptureProcessor::PrepareFrame() {
if (test_config_->capture_api_function ==
CaptureApiImpl::ProcessStreamImplInteger) {
frame_data_.input_sample_rate_hz = test_config_->initial_sample_rate_hz;
frame_data_.output_sample_rate_hz = test_config_->initial_sample_rate_hz;
}
StreamConfig input_stream_config(frame_data_.input_sample_rate_hz,
frame_data_.input_number_of_channels);
PopulateAudioFrame(kCaptureInputFixLevel, input_stream_config.num_channels(),
input_stream_config.num_frames(), frame_data_.frame,
rand_gen_);
PopulateAudioFrame(&frame_data_.input_frame[0], kCaptureInputFloatLevel,
input_stream_config.num_channels(),
input_stream_config.num_frames(), rand_gen_);
}
void CaptureProcessor::CallApmCaptureSide() {
PrepareFrame();
apm_->set_stream_delay_ms(30);
apm_->set_stream_analog_level(80);
StreamConfig input_stream_config(frame_data_.input_sample_rate_hz,
frame_data_.input_number_of_channels);
StreamConfig output_stream_config(frame_data_.output_sample_rate_hz,
frame_data_.output_number_of_channels);
int result = AudioProcessing::kNoError;
switch (test_config_->capture_api_function) {
case CaptureApiImpl::ProcessStreamImplInteger:
result =
apm_->ProcessStream(frame_data_.frame.data(), input_stream_config,
output_stream_config, frame_data_.frame.data());
break;
case CaptureApiImpl::ProcessStreamImplFloat:
result = apm_->ProcessStream(&frame_data_.input_frame[0],
input_stream_config, output_stream_config,
&frame_data_.output_frame[0]);
break;
default:
FAIL();
}
apm_->recommended_stream_analog_level();
ASSERT_EQ(AudioProcessing::kNoError, result);
}
void CaptureProcessor::ApplyRuntimeSettingScheme() {
const int capture_count_local = frame_counters_->GetCaptureCounter();
switch (test_config_->runtime_parameter_setting_scheme) {
case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
if (capture_count_local == 0)
frame_data_.input_sample_rate_hz = 16000;
else if (capture_count_local % 11 == 0)
frame_data_.input_sample_rate_hz = 32000;
else if (capture_count_local % 73 == 0)
frame_data_.input_sample_rate_hz = 48000;
else if (capture_count_local % 89 == 0)
frame_data_.input_sample_rate_hz = 16000;
else if (capture_count_local % 97 == 0)
frame_data_.input_sample_rate_hz = 8000;
if (capture_count_local == 0)
frame_data_.input_number_of_channels = 1;
else if (capture_count_local % 4 == 0)
frame_data_.input_number_of_channels =
(frame_data_.input_number_of_channels == 1 ? 2 : 1);
if (capture_count_local == 0)
frame_data_.output_sample_rate_hz = 16000;
else if (capture_count_local % 5 == 0)
frame_data_.output_sample_rate_hz = 32000;
else if (capture_count_local % 47 == 0)
frame_data_.output_sample_rate_hz = 48000;
else if (capture_count_local % 53 == 0)
frame_data_.output_sample_rate_hz = 16000;
else if (capture_count_local % 71 == 0)
frame_data_.output_sample_rate_hz = 8000;
if (capture_count_local == 0)
frame_data_.output_number_of_channels = 1;
else if (capture_count_local % 8 == 0)
frame_data_.output_number_of_channels =
(frame_data_.output_number_of_channels == 1 ? 2 : 1);
break;
case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
if (capture_count_local % 2 == 0) {
frame_data_.input_number_of_channels = 1;
frame_data_.input_sample_rate_hz = 16000;
frame_data_.output_number_of_channels = 1;
frame_data_.output_sample_rate_hz = 16000;
} else {
frame_data_.input_number_of_channels =
(frame_data_.input_number_of_channels == 1 ? 2 : 1);
if (frame_data_.input_sample_rate_hz == 8000)
frame_data_.input_sample_rate_hz = 16000;
else if (frame_data_.input_sample_rate_hz == 16000)
frame_data_.input_sample_rate_hz = 32000;
else if (frame_data_.input_sample_rate_hz == 32000)
frame_data_.input_sample_rate_hz = 48000;
else if (frame_data_.input_sample_rate_hz == 48000)
frame_data_.input_sample_rate_hz = 8000;
frame_data_.output_number_of_channels =
(frame_data_.output_number_of_channels == 1 ? 2 : 1);
if (frame_data_.output_sample_rate_hz == 8000)
frame_data_.output_sample_rate_hz = 16000;
else if (frame_data_.output_sample_rate_hz == 16000)
frame_data_.output_sample_rate_hz = 32000;
else if (frame_data_.output_sample_rate_hz == 32000)
frame_data_.output_sample_rate_hz = 48000;
else if (frame_data_.output_sample_rate_hz == 48000)
frame_data_.output_sample_rate_hz = 8000;
}
break;
case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
if (capture_count_local == 0) {
frame_data_.input_sample_rate_hz = 16000;
frame_data_.input_number_of_channels = 1;
frame_data_.output_sample_rate_hz = 16000;
frame_data_.output_number_of_channels = 1;
}
break;
case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
if (capture_count_local == 0) {
frame_data_.input_sample_rate_hz = 16000;
frame_data_.input_number_of_channels = 2;
frame_data_.output_sample_rate_hz = 16000;
frame_data_.output_number_of_channels = 2;
}
break;
default:
FAIL();
}
switch (test_config_->runtime_parameter_setting_scheme) {
case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
break;
case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
if (capture_count_local % 2 == 0) {
ASSERT_EQ(AudioProcessing::Error::kNoError,
apm_->set_stream_delay_ms(30));
apm_->set_stream_key_pressed(true);
} else {
ASSERT_EQ(AudioProcessing::Error::kNoError,
apm_->set_stream_delay_ms(50));
apm_->set_stream_key_pressed(false);
}
break;
default:
FAIL();
}
frame_data_.output_number_of_channels =
std::min(frame_data_.output_number_of_channels,
frame_data_.input_number_of_channels);
}
RenderProcessor::RenderProcessor(int max_frame_size,
RandomGenerator* rand_gen,
rtc::Event* render_call_event,
rtc::Event* capture_call_event,
FrameCounters* shared_counters_state,
const TestConfig* test_config,
AudioProcessing* apm)
: rand_gen_(rand_gen),
render_call_event_(render_call_event),
capture_call_event_(capture_call_event),
frame_counters_(shared_counters_state),
test_config_(test_config),
apm_(apm),
frame_data_(max_frame_size) {}
void RenderProcessor::Process() {
if (first_render_call_) {
capture_call_event_->Wait(rtc::Event::kForever);
first_render_call_ = false;
}
SleepRandomMs(3, rand_gen_);
if (frame_counters_->RenderMinusCaptureCounters() > kMaxCallDifference) {
capture_call_event_->Wait(rtc::Event::kForever);
}
ApplyRuntimeSettingScheme();
CallApmRenderSide();
frame_counters_->IncreaseRenderCounter();
render_call_event_->Set();
}
void RenderProcessor::PrepareFrame() {
if ((test_config_->render_api_function ==
RenderApiImpl::ProcessReverseStreamImplInteger) ||
(test_config_->aec_type !=
AecType::BasicWebRtcAecSettingsWithAecMobile)) {
frame_data_.input_sample_rate_hz = test_config_->initial_sample_rate_hz;
frame_data_.output_sample_rate_hz = test_config_->initial_sample_rate_hz;
}
StreamConfig input_stream_config(frame_data_.input_sample_rate_hz,
frame_data_.input_number_of_channels);
PopulateAudioFrame(kRenderInputFixLevel, input_stream_config.num_channels(),
input_stream_config.num_frames(), frame_data_.frame,
rand_gen_);
PopulateAudioFrame(&frame_data_.input_frame[0], kRenderInputFloatLevel,
input_stream_config.num_channels(),
input_stream_config.num_frames(), rand_gen_);
}
void RenderProcessor::CallApmRenderSide() {
PrepareFrame();
StreamConfig input_stream_config(frame_data_.input_sample_rate_hz,
frame_data_.input_number_of_channels);
StreamConfig output_stream_config(frame_data_.output_sample_rate_hz,
frame_data_.output_number_of_channels);
int result = AudioProcessing::kNoError;
switch (test_config_->render_api_function) {
case RenderApiImpl::ProcessReverseStreamImplInteger:
result = apm_->ProcessReverseStream(
frame_data_.frame.data(), input_stream_config, output_stream_config,
frame_data_.frame.data());
break;
case RenderApiImpl::ProcessReverseStreamImplFloat:
result = apm_->ProcessReverseStream(
&frame_data_.input_frame[0], input_stream_config,
output_stream_config, &frame_data_.output_frame[0]);
break;
case RenderApiImpl::AnalyzeReverseStreamImplFloat:
result = apm_->AnalyzeReverseStream(&frame_data_.input_frame[0],
input_stream_config);
break;
default:
FAIL();
}
ASSERT_EQ(AudioProcessing::kNoError, result);
}
void RenderProcessor::ApplyRuntimeSettingScheme() {
const int render_count_local = frame_counters_->GetRenderCounter();
switch (test_config_->runtime_parameter_setting_scheme) {
case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
if (render_count_local == 0)
frame_data_.input_sample_rate_hz = 16000;
else if (render_count_local % 47 == 0)
frame_data_.input_sample_rate_hz = 32000;
else if (render_count_local % 71 == 0)
frame_data_.input_sample_rate_hz = 48000;
else if (render_count_local % 79 == 0)
frame_data_.input_sample_rate_hz = 16000;
else if (render_count_local % 83 == 0)
frame_data_.input_sample_rate_hz = 8000;
if (render_count_local == 0)
frame_data_.input_number_of_channels = 1;
else if (render_count_local % 4 == 0)
frame_data_.input_number_of_channels =
(frame_data_.input_number_of_channels == 1 ? 2 : 1);
if (render_count_local == 0)
frame_data_.output_sample_rate_hz = 16000;
else if (render_count_local % 17 == 0)
frame_data_.output_sample_rate_hz = 32000;
else if (render_count_local % 19 == 0)
frame_data_.output_sample_rate_hz = 48000;
else if (render_count_local % 29 == 0)
frame_data_.output_sample_rate_hz = 16000;
else if (render_count_local % 61 == 0)
frame_data_.output_sample_rate_hz = 8000;
if (render_count_local == 0)
frame_data_.output_number_of_channels = 1;
else if (render_count_local % 8 == 0)
frame_data_.output_number_of_channels =
(frame_data_.output_number_of_channels == 1 ? 2 : 1);
break;
case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
if (render_count_local == 0) {
frame_data_.input_number_of_channels = 1;
frame_data_.input_sample_rate_hz = 16000;
frame_data_.output_number_of_channels = 1;
frame_data_.output_sample_rate_hz = 16000;
} else {
frame_data_.input_number_of_channels =
(frame_data_.input_number_of_channels == 1 ? 2 : 1);
if (frame_data_.input_sample_rate_hz == 8000)
frame_data_.input_sample_rate_hz = 16000;
else if (frame_data_.input_sample_rate_hz == 16000)
frame_data_.input_sample_rate_hz = 32000;
else if (frame_data_.input_sample_rate_hz == 32000)
frame_data_.input_sample_rate_hz = 48000;
else if (frame_data_.input_sample_rate_hz == 48000)
frame_data_.input_sample_rate_hz = 8000;
frame_data_.output_number_of_channels =
(frame_data_.output_number_of_channels == 1 ? 2 : 1);
if (frame_data_.output_sample_rate_hz == 8000)
frame_data_.output_sample_rate_hz = 16000;
else if (frame_data_.output_sample_rate_hz == 16000)
frame_data_.output_sample_rate_hz = 32000;
else if (frame_data_.output_sample_rate_hz == 32000)
frame_data_.output_sample_rate_hz = 48000;
else if (frame_data_.output_sample_rate_hz == 48000)
frame_data_.output_sample_rate_hz = 8000;
}
break;
case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
if (render_count_local == 0) {
frame_data_.input_sample_rate_hz = 16000;
frame_data_.input_number_of_channels = 1;
frame_data_.output_sample_rate_hz = 16000;
frame_data_.output_number_of_channels = 1;
}
break;
case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
if (render_count_local == 0) {
frame_data_.input_sample_rate_hz = 16000;
frame_data_.input_number_of_channels = 2;
frame_data_.output_sample_rate_hz = 16000;
frame_data_.output_number_of_channels = 2;
}
break;
default:
FAIL();
}
frame_data_.output_number_of_channels =
std::min(frame_data_.output_number_of_channels,
frame_data_.input_number_of_channels);
}
}
TEST_P(AudioProcessingImplLockTest, LockTest) {
ASSERT_TRUE(RunTest());
}
INSTANTIATE_TEST_SUITE_P(
DISABLED_AudioProcessingImplLockExtensive,
AudioProcessingImplLockTest,
::testing::ValuesIn(TestConfig::GenerateExtensiveTestConfigs()));
INSTANTIATE_TEST_SUITE_P(
AudioProcessingImplLockBrief,
AudioProcessingImplLockTest,
::testing::ValuesIn(TestConfig::GenerateBriefTestConfigs()));
}