Only reinitialize AudioProcessing when needed.
This takes away the burden from the user, resulting in cleaner code. Review URL: https://webrtc-codereview.appspot.com/941005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3010 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
e08adf0957
commit
8186534111
@ -100,31 +100,32 @@ AudioProcessingImpl::AudioProcessingImpl(int id)
|
||||
}
|
||||
|
||||
AudioProcessingImpl::~AudioProcessingImpl() {
|
||||
crit_->Enter();
|
||||
while (!component_list_.empty()) {
|
||||
ProcessingComponent* component = component_list_.front();
|
||||
component->Destroy();
|
||||
delete component;
|
||||
component_list_.pop_front();
|
||||
}
|
||||
{
|
||||
CriticalSectionScoped crit_scoped(crit_);
|
||||
while (!component_list_.empty()) {
|
||||
ProcessingComponent* component = component_list_.front();
|
||||
component->Destroy();
|
||||
delete component;
|
||||
component_list_.pop_front();
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
|
||||
if (debug_file_->Open()) {
|
||||
debug_file_->CloseFile();
|
||||
}
|
||||
if (debug_file_->Open()) {
|
||||
debug_file_->CloseFile();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (render_audio_) {
|
||||
delete render_audio_;
|
||||
render_audio_ = NULL;
|
||||
if (render_audio_) {
|
||||
delete render_audio_;
|
||||
render_audio_ = NULL;
|
||||
}
|
||||
|
||||
if (capture_audio_) {
|
||||
delete capture_audio_;
|
||||
capture_audio_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (capture_audio_) {
|
||||
delete capture_audio_;
|
||||
capture_audio_ = NULL;
|
||||
}
|
||||
|
||||
crit_->Leave();
|
||||
delete crit_;
|
||||
crit_ = NULL;
|
||||
}
|
||||
@ -162,7 +163,7 @@ int AudioProcessingImpl::InitializeLocked() {
|
||||
|
||||
// Initialize all components.
|
||||
std::list<ProcessingComponent*>::iterator it;
|
||||
for (it = component_list_.begin(); it != component_list_.end(); it++) {
|
||||
for (it = component_list_.begin(); it != component_list_.end(); ++it) {
|
||||
int err = (*it)->Initialize();
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
@ -183,6 +184,9 @@ int AudioProcessingImpl::InitializeLocked() {
|
||||
|
||||
int AudioProcessingImpl::set_sample_rate_hz(int rate) {
|
||||
CriticalSectionScoped crit_scoped(crit_);
|
||||
if (rate == sample_rate_hz_) {
|
||||
return kNoError;
|
||||
}
|
||||
if (rate != kSampleRate8kHz &&
|
||||
rate != kSampleRate16kHz &&
|
||||
rate != kSampleRate32kHz) {
|
||||
@ -207,6 +211,9 @@ int AudioProcessingImpl::sample_rate_hz() const {
|
||||
|
||||
int AudioProcessingImpl::set_num_reverse_channels(int channels) {
|
||||
CriticalSectionScoped crit_scoped(crit_);
|
||||
if (channels == num_reverse_channels_) {
|
||||
return kNoError;
|
||||
}
|
||||
// Only stereo supported currently.
|
||||
if (channels > 2 || channels < 1) {
|
||||
return kBadParameterError;
|
||||
@ -225,16 +232,16 @@ int AudioProcessingImpl::set_num_channels(
|
||||
int input_channels,
|
||||
int output_channels) {
|
||||
CriticalSectionScoped crit_scoped(crit_);
|
||||
if (input_channels == num_input_channels_ &&
|
||||
output_channels == num_output_channels_) {
|
||||
return kNoError;
|
||||
}
|
||||
if (output_channels > input_channels) {
|
||||
return kBadParameterError;
|
||||
}
|
||||
|
||||
// Only stereo supported currently.
|
||||
if (input_channels > 2 || input_channels < 1) {
|
||||
return kBadParameterError;
|
||||
}
|
||||
|
||||
if (output_channels > 2 || output_channels < 1) {
|
||||
if (input_channels > 2 || input_channels < 1 ||
|
||||
output_channels > 2 || output_channels < 1) {
|
||||
return kBadParameterError;
|
||||
}
|
||||
|
||||
|
||||
@ -13,8 +13,8 @@
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "module.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -124,6 +124,10 @@ class AudioProcessing : public Module {
|
||||
// should be called before beginning to process a new audio stream. However,
|
||||
// it is not necessary to call before processing the first stream after
|
||||
// creation.
|
||||
//
|
||||
// set_sample_rate_hz(), set_num_channels() and set_num_reverse_channels()
|
||||
// will trigger a full initialization if the settings are changed from their
|
||||
// existing values. Otherwise they are no-ops.
|
||||
virtual int Initialize() = 0;
|
||||
|
||||
// Sets the sample |rate| in Hz for both the primary and reverse audio
|
||||
|
||||
@ -8,12 +8,15 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef WEBRTC_ANDROID
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "audio_processing.h"
|
||||
@ -131,6 +134,22 @@ void usage() {
|
||||
printf(" --debug_file FILE Dump a debug recording.\n");
|
||||
}
|
||||
|
||||
static double MicLevel2Gain(int level) {
|
||||
return pow(10.0, ((level - 127.0) / 128.0 * 80.) / 20.);
|
||||
}
|
||||
|
||||
static void SimulateMic(int mic_level, AudioFrame* frame) {
|
||||
mic_level = std::min(std::max(mic_level, 0), 255);
|
||||
double mic_gain = MicLevel2Gain(mic_level);
|
||||
int num_samples = frame->samples_per_channel_ * frame->num_channels_;
|
||||
double v;
|
||||
for (int n = 0; n < num_samples; n++) {
|
||||
v = floor(frame->data_[n] * mic_gain + 0.5);
|
||||
v = std::max(std::min(32767., v), -32768.);
|
||||
frame->data_[n] = static_cast<int16_t>(v);
|
||||
}
|
||||
}
|
||||
|
||||
// void function for gtest.
|
||||
void void_main(int argc, char* argv[]) {
|
||||
if (argc > 1 && strcmp(argv[1], "--help") == 0) {
|
||||
@ -658,6 +677,10 @@ void void_main(int argc, char* argv[]) {
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if (apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
|
||||
SimulateMic(capture_level, &near_frame);
|
||||
}
|
||||
|
||||
if (perf_testing) {
|
||||
t0 = TickTime::Now();
|
||||
}
|
||||
@ -862,6 +885,10 @@ void void_main(int argc, char* argv[]) {
|
||||
fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
|
||||
}
|
||||
|
||||
if (apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
|
||||
SimulateMic(capture_level, &near_frame);
|
||||
}
|
||||
|
||||
if (perf_testing) {
|
||||
t0 = TickTime::Now();
|
||||
}
|
||||
|
||||
@ -8,13 +8,14 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "audio_processing.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "audio_processing.h"
|
||||
#include "event_wrapper.h"
|
||||
#include "module_common_types.h"
|
||||
#include "scoped_ptr.h"
|
||||
@ -66,6 +67,138 @@ const int kProcessSampleRates[] = {8000, 16000, 32000};
|
||||
const size_t kProcessSampleRatesSize = sizeof(kProcessSampleRates) /
|
||||
sizeof(*kProcessSampleRates);
|
||||
|
||||
// TODO(andrew): Use the MonoToStereo routine from AudioFrameOperations.
|
||||
void MixStereoToMono(const int16_t* stereo,
|
||||
int16_t* mono,
|
||||
int samples_per_channel) {
|
||||
for (int i = 0; i < samples_per_channel; i++) {
|
||||
int32_t int32 = (static_cast<int32_t>(stereo[i * 2]) +
|
||||
static_cast<int32_t>(stereo[i * 2 + 1])) >> 1;
|
||||
mono[i] = static_cast<int16_t>(int32);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyLeftToRightChannel(int16_t* stereo, int samples_per_channel) {
|
||||
for (int i = 0; i < samples_per_channel; i++) {
|
||||
stereo[i * 2 + 1] = stereo[i * 2];
|
||||
}
|
||||
}
|
||||
|
||||
void VerifyChannelsAreEqual(int16_t* stereo, int samples_per_channel) {
|
||||
for (int i = 0; i < samples_per_channel; i++) {
|
||||
EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
|
||||
}
|
||||
}
|
||||
|
||||
void SetFrameTo(AudioFrame* frame, int16_t value) {
|
||||
for (int i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
|
||||
++i) {
|
||||
frame->data_[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void SetFrameTo(AudioFrame* frame, int16_t left, int16_t right) {
|
||||
ASSERT_EQ(2, frame->num_channels_);
|
||||
for (int i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
|
||||
frame->data_[i] = left;
|
||||
frame->data_[i + 1] = right;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T AbsValue(T a) {
|
||||
return a > 0 ? a: -a;
|
||||
}
|
||||
|
||||
int16_t MaxAudioFrame(const AudioFrame& frame) {
|
||||
const int length = frame.samples_per_channel_ * frame.num_channels_;
|
||||
int16_t max_data = AbsValue(frame.data_[0]);
|
||||
for (int i = 1; i < length; i++) {
|
||||
max_data = std::max(max_data, AbsValue(frame.data_[i]));
|
||||
}
|
||||
|
||||
return max_data;
|
||||
}
|
||||
|
||||
bool FrameDataAreEqual(const AudioFrame& frame1, const AudioFrame& frame2) {
|
||||
if (frame1.samples_per_channel_ !=
|
||||
frame2.samples_per_channel_) {
|
||||
return false;
|
||||
}
|
||||
if (frame1.num_channels_ !=
|
||||
frame2.num_channels_) {
|
||||
return false;
|
||||
}
|
||||
if (memcmp(frame1.data_, frame2.data_,
|
||||
frame1.samples_per_channel_ * frame1.num_channels_ *
|
||||
sizeof(int16_t))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestStats(const AudioProcessing::Statistic& test,
|
||||
const webrtc::audioproc::Test::Statistic& reference) {
|
||||
EXPECT_EQ(reference.instant(), test.instant);
|
||||
EXPECT_EQ(reference.average(), test.average);
|
||||
EXPECT_EQ(reference.maximum(), test.maximum);
|
||||
EXPECT_EQ(reference.minimum(), test.minimum);
|
||||
}
|
||||
|
||||
void WriteStatsMessage(const AudioProcessing::Statistic& output,
|
||||
webrtc::audioproc::Test::Statistic* message) {
|
||||
message->set_instant(output.instant);
|
||||
message->set_average(output.average);
|
||||
message->set_maximum(output.maximum);
|
||||
message->set_minimum(output.minimum);
|
||||
}
|
||||
|
||||
void WriteMessageLiteToFile(const std::string filename,
|
||||
const ::google::protobuf::MessageLite& message) {
|
||||
FILE* file = fopen(filename.c_str(), "wb");
|
||||
ASSERT_TRUE(file != NULL) << "Could not open " << filename;
|
||||
int size = message.ByteSize();
|
||||
ASSERT_GT(size, 0);
|
||||
unsigned char* array = new unsigned char[size];
|
||||
ASSERT_TRUE(message.SerializeToArray(array, size));
|
||||
|
||||
ASSERT_EQ(1u, fwrite(&size, sizeof(int), 1, file));
|
||||
ASSERT_EQ(static_cast<size_t>(size),
|
||||
fwrite(array, sizeof(unsigned char), size, file));
|
||||
|
||||
delete [] array;
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void ReadMessageLiteFromFile(const std::string filename,
|
||||
::google::protobuf::MessageLite* message) {
|
||||
assert(message != NULL);
|
||||
|
||||
FILE* file = fopen(filename.c_str(), "rb");
|
||||
ASSERT_TRUE(file != NULL) << "Could not open " << filename;
|
||||
int size = 0;
|
||||
ASSERT_EQ(1u, fread(&size, sizeof(int), 1, file));
|
||||
ASSERT_GT(size, 0);
|
||||
unsigned char* array = new unsigned char[size];
|
||||
ASSERT_EQ(static_cast<size_t>(size),
|
||||
fread(array, sizeof(unsigned char), size, file));
|
||||
|
||||
ASSERT_TRUE(message->ParseFromArray(array, size));
|
||||
|
||||
delete [] array;
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
struct ThreadData {
|
||||
ThreadData(int thread_num_, AudioProcessing* ap_)
|
||||
: thread_num(thread_num_),
|
||||
error(false),
|
||||
ap(ap_) {}
|
||||
int thread_num;
|
||||
bool error;
|
||||
AudioProcessing* ap;
|
||||
};
|
||||
|
||||
class ApmTest : public ::testing::Test {
|
||||
protected:
|
||||
ApmTest();
|
||||
@ -75,7 +208,7 @@ class ApmTest : public ::testing::Test {
|
||||
static void SetUpTestCase() {
|
||||
Trace::CreateTrace();
|
||||
std::string trace_filename = webrtc::test::OutputPath() +
|
||||
"audioproc_trace.txt";
|
||||
"audioproc_trace.txt";
|
||||
ASSERT_EQ(0, Trace::SetTraceFile(trace_filename.c_str()));
|
||||
}
|
||||
|
||||
@ -94,6 +227,10 @@ class ApmTest : public ::testing::Test {
|
||||
int num_output_channels);
|
||||
void EnableAllComponents();
|
||||
bool ReadFrame(FILE* file, AudioFrame* frame);
|
||||
void ProcessWithDefaultStreamParameters(AudioFrame* frame);
|
||||
template <typename F>
|
||||
void ChangeTriggersInit(F f, AudioProcessing* ap, int initial_value,
|
||||
int changed_value);
|
||||
|
||||
const std::string output_path_;
|
||||
const std::string ref_path_;
|
||||
@ -241,28 +378,6 @@ void ApmTest::Init(int sample_rate_hz, int num_reverse_channels,
|
||||
}
|
||||
}
|
||||
|
||||
void MixStereoToMono(const int16_t* stereo,
|
||||
int16_t* mono,
|
||||
int samples_per_channel) {
|
||||
for (int i = 0; i < samples_per_channel; i++) {
|
||||
int32_t int32 = (static_cast<int32_t>(stereo[i * 2]) +
|
||||
static_cast<int32_t>(stereo[i * 2 + 1])) >> 1;
|
||||
mono[i] = static_cast<int16_t>(int32);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyLeftToRightChannel(int16_t* stereo, int samples_per_channel) {
|
||||
for (int i = 0; i < samples_per_channel; i++) {
|
||||
stereo[i * 2 + 1] = stereo[i * 2];
|
||||
}
|
||||
}
|
||||
|
||||
void VerifyChannelsAreEqual(int16_t* stereo, int samples_per_channel) {
|
||||
for (int i = 0; i < samples_per_channel; i++) {
|
||||
EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
|
||||
}
|
||||
}
|
||||
|
||||
void ApmTest::EnableAllComponents() {
|
||||
#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
|
||||
EXPECT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(16000));
|
||||
@ -321,206 +436,57 @@ bool ApmTest::ReadFrame(FILE* file, AudioFrame* frame) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetFrameTo(AudioFrame* frame, int16_t value) {
|
||||
for (int i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
|
||||
++i) {
|
||||
frame->data_[i] = value;
|
||||
}
|
||||
void ApmTest::ProcessWithDefaultStreamParameters(AudioFrame* frame) {
|
||||
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
|
||||
EXPECT_EQ(apm_->kNoError,
|
||||
apm_->echo_cancellation()->set_stream_drift_samples(0));
|
||||
EXPECT_EQ(apm_->kNoError,
|
||||
apm_->gain_control()->set_stream_analog_level(127));
|
||||
EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame));
|
||||
}
|
||||
|
||||
void SetFrameTo(AudioFrame* frame, int16_t left, int16_t right) {
|
||||
ASSERT_EQ(2, frame->num_channels_);
|
||||
for (int i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
|
||||
frame->data_[i] = left;
|
||||
frame->data_[i + 1] = right;
|
||||
}
|
||||
template <typename F>
|
||||
void ApmTest::ChangeTriggersInit(F f, AudioProcessing* ap, int initial_value,
|
||||
int changed_value) {
|
||||
EnableAllComponents();
|
||||
Init(16000, 2, 2, 2, false);
|
||||
SetFrameTo(frame_, 1000);
|
||||
AudioFrame frame_copy = *frame_;
|
||||
ProcessWithDefaultStreamParameters(frame_);
|
||||
// Verify the processing has actually changed the frame.
|
||||
EXPECT_FALSE(FrameDataAreEqual(*frame_, frame_copy));
|
||||
|
||||
// Test that a change in value triggers an init.
|
||||
f(apm_, changed_value);
|
||||
f(apm_, initial_value);
|
||||
ProcessWithDefaultStreamParameters(&frame_copy);
|
||||
EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
|
||||
|
||||
apm_->Initialize();
|
||||
SetFrameTo(frame_, 1000);
|
||||
AudioFrame initial_frame = *frame_;
|
||||
ProcessWithDefaultStreamParameters(frame_);
|
||||
ProcessWithDefaultStreamParameters(frame_);
|
||||
// Verify the processing has actually changed the frame.
|
||||
EXPECT_FALSE(FrameDataAreEqual(*frame_, initial_frame));
|
||||
|
||||
frame_copy = initial_frame;
|
||||
apm_->Initialize();
|
||||
ProcessWithDefaultStreamParameters(&frame_copy);
|
||||
// Verify an init here would result in different output.
|
||||
apm_->Initialize();
|
||||
ProcessWithDefaultStreamParameters(&frame_copy);
|
||||
EXPECT_FALSE(FrameDataAreEqual(*frame_, frame_copy));
|
||||
|
||||
frame_copy = initial_frame;
|
||||
apm_->Initialize();
|
||||
ProcessWithDefaultStreamParameters(&frame_copy);
|
||||
// Test that the same value does not trigger an init.
|
||||
f(apm_, initial_value);
|
||||
ProcessWithDefaultStreamParameters(&frame_copy);
|
||||
EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T AbsValue(T a) {
|
||||
return a > 0 ? a: -a;
|
||||
}
|
||||
|
||||
int16_t MaxAudioFrame(const AudioFrame& frame) {
|
||||
const int length = frame.samples_per_channel_ * frame.num_channels_;
|
||||
int16_t max_data = AbsValue(frame.data_[0]);
|
||||
for (int i = 1; i < length; i++) {
|
||||
max_data = std::max(max_data, AbsValue(frame.data_[i]));
|
||||
}
|
||||
|
||||
return max_data;
|
||||
}
|
||||
|
||||
bool FrameDataAreEqual(const AudioFrame& frame1, const AudioFrame& frame2) {
|
||||
if (frame1.samples_per_channel_ !=
|
||||
frame2.samples_per_channel_) {
|
||||
return false;
|
||||
}
|
||||
if (frame1.num_channels_ !=
|
||||
frame2.num_channels_) {
|
||||
return false;
|
||||
}
|
||||
if (memcmp(frame1.data_, frame2.data_,
|
||||
frame1.samples_per_channel_ * frame1.num_channels_ *
|
||||
sizeof(int16_t))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestStats(const AudioProcessing::Statistic& test,
|
||||
const webrtc::audioproc::Test::Statistic& reference) {
|
||||
EXPECT_EQ(reference.instant(), test.instant);
|
||||
EXPECT_EQ(reference.average(), test.average);
|
||||
EXPECT_EQ(reference.maximum(), test.maximum);
|
||||
EXPECT_EQ(reference.minimum(), test.minimum);
|
||||
}
|
||||
|
||||
void WriteStatsMessage(const AudioProcessing::Statistic& output,
|
||||
webrtc::audioproc::Test::Statistic* message) {
|
||||
message->set_instant(output.instant);
|
||||
message->set_average(output.average);
|
||||
message->set_maximum(output.maximum);
|
||||
message->set_minimum(output.minimum);
|
||||
}
|
||||
|
||||
void WriteMessageLiteToFile(const std::string filename,
|
||||
const ::google::protobuf::MessageLite& message) {
|
||||
FILE* file = fopen(filename.c_str(), "wb");
|
||||
ASSERT_TRUE(file != NULL) << "Could not open " << filename;
|
||||
int size = message.ByteSize();
|
||||
ASSERT_GT(size, 0);
|
||||
unsigned char* array = new unsigned char[size];
|
||||
ASSERT_TRUE(message.SerializeToArray(array, size));
|
||||
|
||||
ASSERT_EQ(1u, fwrite(&size, sizeof(int), 1, file));
|
||||
ASSERT_EQ(static_cast<size_t>(size),
|
||||
fwrite(array, sizeof(unsigned char), size, file));
|
||||
|
||||
delete [] array;
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void ReadMessageLiteFromFile(const std::string filename,
|
||||
::google::protobuf::MessageLite* message) {
|
||||
assert(message != NULL);
|
||||
|
||||
FILE* file = fopen(filename.c_str(), "rb");
|
||||
ASSERT_TRUE(file != NULL) << "Could not open " << filename;
|
||||
int size = 0;
|
||||
ASSERT_EQ(1u, fread(&size, sizeof(int), 1, file));
|
||||
ASSERT_GT(size, 0);
|
||||
unsigned char* array = new unsigned char[size];
|
||||
ASSERT_EQ(static_cast<size_t>(size),
|
||||
fread(array, sizeof(unsigned char), size, file));
|
||||
|
||||
ASSERT_TRUE(message->ParseFromArray(array, size));
|
||||
|
||||
delete [] array;
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
struct ThreadData {
|
||||
ThreadData(int thread_num_, AudioProcessing* ap_)
|
||||
: thread_num(thread_num_),
|
||||
error(false),
|
||||
ap(ap_) {}
|
||||
int thread_num;
|
||||
bool error;
|
||||
AudioProcessing* ap;
|
||||
};
|
||||
|
||||
// Don't use GTest here; non-thread-safe on Windows (as of 1.5.0).
|
||||
bool DeadlockProc(void* thread_object) {
|
||||
ThreadData* thread_data = static_cast<ThreadData*>(thread_object);
|
||||
AudioProcessing* ap = thread_data->ap;
|
||||
int err = ap->kNoError;
|
||||
|
||||
AudioFrame primary_frame;
|
||||
AudioFrame reverse_frame;
|
||||
primary_frame.samples_per_channel_ = 320;
|
||||
primary_frame.num_channels_ = 2;
|
||||
primary_frame.sample_rate_hz_ = 32000;
|
||||
reverse_frame.samples_per_channel_ = 320;
|
||||
reverse_frame.num_channels_ = 2;
|
||||
reverse_frame.sample_rate_hz_ = 32000;
|
||||
|
||||
ap->echo_cancellation()->Enable(true);
|
||||
ap->gain_control()->Enable(true);
|
||||
ap->high_pass_filter()->Enable(true);
|
||||
ap->level_estimator()->Enable(true);
|
||||
ap->noise_suppression()->Enable(true);
|
||||
ap->voice_detection()->Enable(true);
|
||||
|
||||
if (thread_data->thread_num % 2 == 0) {
|
||||
err = ap->AnalyzeReverseStream(&reverse_frame);
|
||||
if (err != ap->kNoError) {
|
||||
printf("Error in AnalyzeReverseStream(): %d\n", err);
|
||||
thread_data->error = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (thread_data->thread_num % 2 == 1) {
|
||||
ap->set_stream_delay_ms(0);
|
||||
ap->echo_cancellation()->set_stream_drift_samples(0);
|
||||
ap->gain_control()->set_stream_analog_level(0);
|
||||
err = ap->ProcessStream(&primary_frame);
|
||||
if (err == ap->kStreamParameterNotSetError) {
|
||||
printf("Expected kStreamParameterNotSetError in ProcessStream(): %d\n",
|
||||
err);
|
||||
} else if (err != ap->kNoError) {
|
||||
printf("Error in ProcessStream(): %d\n", err);
|
||||
thread_data->error = true;
|
||||
return false;
|
||||
}
|
||||
ap->gain_control()->stream_analog_level();
|
||||
}
|
||||
|
||||
EventWrapper* event = EventWrapper::Create();
|
||||
event->Wait(1);
|
||||
delete event;
|
||||
event = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*TEST_F(ApmTest, Deadlock) {
|
||||
const int num_threads = 16;
|
||||
std::vector<ThreadWrapper*> threads(num_threads);
|
||||
std::vector<ThreadData*> thread_data(num_threads);
|
||||
|
||||
ASSERT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(32000));
|
||||
ASSERT_EQ(apm_->kNoError, apm_->set_num_channels(2, 2));
|
||||
ASSERT_EQ(apm_->kNoError, apm_->set_num_reverse_channels(2));
|
||||
|
||||
for (int i = 0; i < num_threads; i++) {
|
||||
thread_data[i] = new ThreadData(i, apm_);
|
||||
threads[i] = ThreadWrapper::CreateThread(DeadlockProc,
|
||||
thread_data[i],
|
||||
kNormalPriority,
|
||||
0);
|
||||
ASSERT_TRUE(threads[i] != NULL);
|
||||
unsigned int thread_id = 0;
|
||||
threads[i]->Start(thread_id);
|
||||
}
|
||||
|
||||
EventWrapper* event = EventWrapper::Create();
|
||||
ASSERT_EQ(kEventTimeout, event->Wait(5000));
|
||||
delete event;
|
||||
event = NULL;
|
||||
|
||||
for (int i = 0; i < num_threads; i++) {
|
||||
// This will return false if the thread has deadlocked.
|
||||
ASSERT_TRUE(threads[i]->Stop());
|
||||
ASSERT_FALSE(thread_data[i]->error);
|
||||
delete threads[i];
|
||||
threads[i] = NULL;
|
||||
delete thread_data[i];
|
||||
thread_data[i] = NULL;
|
||||
}
|
||||
}*/
|
||||
|
||||
TEST_F(ApmTest, StreamParameters) {
|
||||
// No errors when the components are disabled.
|
||||
EXPECT_EQ(apm_->kNoError,
|
||||
@ -665,6 +631,29 @@ TEST_F(ApmTest, SampleRates) {
|
||||
}
|
||||
}
|
||||
|
||||
void SetSampleRate(AudioProcessing* ap, int value) {
|
||||
EXPECT_EQ(ap->kNoError, ap->set_sample_rate_hz(value));
|
||||
}
|
||||
|
||||
void SetNumReverseChannels(AudioProcessing* ap, int value) {
|
||||
EXPECT_EQ(ap->kNoError, ap->set_num_reverse_channels(value));
|
||||
}
|
||||
|
||||
void SetNumOutputChannels(AudioProcessing* ap, int value) {
|
||||
EXPECT_EQ(ap->kNoError, ap->set_num_channels(2, value));
|
||||
}
|
||||
|
||||
TEST_F(ApmTest, SampleRateChangeTriggersInit) {
|
||||
ChangeTriggersInit(SetSampleRate, apm_, 16000, 8000);
|
||||
}
|
||||
|
||||
TEST_F(ApmTest, ReverseChannelChangeTriggersInit) {
|
||||
ChangeTriggersInit(SetNumReverseChannels, apm_, 2, 1);
|
||||
}
|
||||
|
||||
TEST_F(ApmTest, ChannelChangeTriggersInit) {
|
||||
ChangeTriggersInit(SetNumOutputChannels, apm_, 2, 1);
|
||||
}
|
||||
|
||||
TEST_F(ApmTest, EchoCancellation) {
|
||||
EXPECT_EQ(apm_->kNoError,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user