git-svn-id: http://webrtc.googlecode.com/svn/trunk@4 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
77
modules/audio_processing/main/source/apm.gyp
Normal file
77
modules/audio_processing/main/source/apm.gyp
Normal file
@@ -0,0 +1,77 @@
|
||||
# Copyright (c) 2011 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.
|
||||
|
||||
{
|
||||
'includes': [
|
||||
'../../../../common_settings.gypi', # Common settings
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'audio_processing',
|
||||
'type': '<(library)',
|
||||
'conditions': [
|
||||
['prefer_fixed_point==1', {
|
||||
'dependencies': ['../../ns/main/source/ns.gyp:ns_fix'],
|
||||
'defines': ['WEBRTC_NS_FIXED'],
|
||||
}, { # else: prefer_fixed_point==0
|
||||
'dependencies': ['../../ns/main/source/ns.gyp:ns'],
|
||||
'defines': ['WEBRTC_NS_FLOAT'],
|
||||
}],
|
||||
],
|
||||
'dependencies': [
|
||||
'../../../../system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||
'../../aec/main/source/aec.gyp:aec',
|
||||
'../../aecm/main/source/aecm.gyp:aecm',
|
||||
'../../agc/main/source/agc.gyp:agc',
|
||||
'../../../../common_audio/signal_processing_library/main/source/spl.gyp:spl',
|
||||
'../../../../common_audio/vad/main/source/vad.gyp:vad',
|
||||
],
|
||||
'include_dirs': [
|
||||
'../interface',
|
||||
'../../../interface',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'../interface',
|
||||
'../../../interface',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'../interface/audio_processing.h',
|
||||
'audio_buffer.cc',
|
||||
'audio_buffer.h',
|
||||
'audio_processing_impl.cc',
|
||||
'audio_processing_impl.h',
|
||||
'echo_cancellation_impl.cc',
|
||||
'echo_cancellation_impl.h',
|
||||
'echo_control_mobile_impl.cc',
|
||||
'echo_control_mobile_impl.h',
|
||||
'gain_control_impl.cc',
|
||||
'gain_control_impl.h',
|
||||
'high_pass_filter_impl.cc',
|
||||
'high_pass_filter_impl.h',
|
||||
'level_estimator_impl.cc',
|
||||
'level_estimator_impl.h',
|
||||
'noise_suppression_impl.cc',
|
||||
'noise_suppression_impl.h',
|
||||
'splitting_filter.cc',
|
||||
'splitting_filter.h',
|
||||
'processing_component.cc',
|
||||
'processing_component.h',
|
||||
'voice_detection_impl.cc',
|
||||
'voice_detection_impl.h',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:2
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=2 shiftwidth=2:
|
||||
278
modules/audio_processing/main/source/audio_buffer.cc
Normal file
278
modules/audio_processing/main/source/audio_buffer.cc
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "audio_buffer.h"
|
||||
|
||||
#include "module_common_types.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
enum {
|
||||
kSamplesPer8kHzChannel = 80,
|
||||
kSamplesPer16kHzChannel = 160,
|
||||
kSamplesPer32kHzChannel = 320
|
||||
};
|
||||
|
||||
void StereoToMono(const WebRtc_Word16* left, const WebRtc_Word16* right,
|
||||
WebRtc_Word16* out, int samples_per_channel) {
|
||||
WebRtc_Word32 data_int32 = 0;
|
||||
for (int i = 0; i < samples_per_channel; i++) {
|
||||
data_int32 = (left[i] + right[i]) >> 1;
|
||||
if (data_int32 > 32767) {
|
||||
data_int32 = 32767;
|
||||
} else if (data_int32 < -32768) {
|
||||
data_int32 = -32768;
|
||||
}
|
||||
|
||||
out[i] = static_cast<WebRtc_Word16>(data_int32);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
struct AudioChannel {
|
||||
AudioChannel() {
|
||||
memset(data, 0, sizeof(data));
|
||||
}
|
||||
|
||||
WebRtc_Word16 data[kSamplesPer32kHzChannel];
|
||||
};
|
||||
|
||||
struct SplitAudioChannel {
|
||||
SplitAudioChannel() {
|
||||
memset(low_pass_data, 0, sizeof(low_pass_data));
|
||||
memset(high_pass_data, 0, sizeof(high_pass_data));
|
||||
memset(analysis_filter_state1, 0, sizeof(analysis_filter_state1));
|
||||
memset(analysis_filter_state2, 0, sizeof(analysis_filter_state2));
|
||||
memset(synthesis_filter_state1, 0, sizeof(synthesis_filter_state1));
|
||||
memset(synthesis_filter_state2, 0, sizeof(synthesis_filter_state2));
|
||||
}
|
||||
|
||||
WebRtc_Word16 low_pass_data[kSamplesPer16kHzChannel];
|
||||
WebRtc_Word16 high_pass_data[kSamplesPer16kHzChannel];
|
||||
|
||||
WebRtc_Word32 analysis_filter_state1[6];
|
||||
WebRtc_Word32 analysis_filter_state2[6];
|
||||
WebRtc_Word32 synthesis_filter_state1[6];
|
||||
WebRtc_Word32 synthesis_filter_state2[6];
|
||||
};
|
||||
|
||||
// TODO(am): check range of input parameters?
|
||||
AudioBuffer::AudioBuffer(WebRtc_Word32 max_num_channels,
|
||||
WebRtc_Word32 samples_per_channel)
|
||||
: max_num_channels_(max_num_channels),
|
||||
num_channels_(0),
|
||||
num_mixed_channels_(0),
|
||||
num_mixed_low_pass_channels_(0),
|
||||
samples_per_channel_(samples_per_channel),
|
||||
samples_per_split_channel_(samples_per_channel),
|
||||
reference_copied_(false),
|
||||
data_(NULL),
|
||||
channels_(NULL),
|
||||
split_channels_(NULL),
|
||||
mixed_low_pass_channels_(NULL),
|
||||
low_pass_reference_channels_(NULL) {
|
||||
if (max_num_channels_ > 1) {
|
||||
channels_ = new AudioChannel[max_num_channels_];
|
||||
mixed_low_pass_channels_ = new AudioChannel[max_num_channels_];
|
||||
}
|
||||
low_pass_reference_channels_ = new AudioChannel[max_num_channels_];
|
||||
|
||||
if (samples_per_channel_ == kSamplesPer32kHzChannel) {
|
||||
split_channels_ = new SplitAudioChannel[max_num_channels_];
|
||||
samples_per_split_channel_ = kSamplesPer16kHzChannel;
|
||||
}
|
||||
}
|
||||
|
||||
AudioBuffer::~AudioBuffer() {
|
||||
if (channels_ != NULL) {
|
||||
delete [] channels_;
|
||||
}
|
||||
|
||||
if (mixed_low_pass_channels_ != NULL) {
|
||||
delete [] mixed_low_pass_channels_;
|
||||
}
|
||||
|
||||
if (low_pass_reference_channels_ != NULL) {
|
||||
delete [] low_pass_reference_channels_;
|
||||
}
|
||||
|
||||
if (split_channels_ != NULL) {
|
||||
delete [] split_channels_;
|
||||
}
|
||||
}
|
||||
|
||||
WebRtc_Word16* AudioBuffer::data(WebRtc_Word32 channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
if (data_ != NULL) {
|
||||
return data_;
|
||||
}
|
||||
|
||||
return channels_[channel].data;
|
||||
}
|
||||
|
||||
WebRtc_Word16* AudioBuffer::low_pass_split_data(WebRtc_Word32 channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
if (split_channels_ == NULL) {
|
||||
return data(channel);
|
||||
}
|
||||
|
||||
return split_channels_[channel].low_pass_data;
|
||||
}
|
||||
|
||||
WebRtc_Word16* AudioBuffer::high_pass_split_data(WebRtc_Word32 channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
if (split_channels_ == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return split_channels_[channel].high_pass_data;
|
||||
}
|
||||
|
||||
WebRtc_Word16* AudioBuffer::mixed_low_pass_data(WebRtc_Word32 channel) const {
|
||||
assert(channel >= 0 && channel < num_mixed_low_pass_channels_);
|
||||
|
||||
return mixed_low_pass_channels_[channel].data;
|
||||
}
|
||||
|
||||
WebRtc_Word16* AudioBuffer::low_pass_reference(WebRtc_Word32 channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
if (!reference_copied_) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return low_pass_reference_channels_[channel].data;
|
||||
}
|
||||
|
||||
WebRtc_Word32* AudioBuffer::analysis_filter_state1(WebRtc_Word32 channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
return split_channels_[channel].analysis_filter_state1;
|
||||
}
|
||||
|
||||
WebRtc_Word32* AudioBuffer::analysis_filter_state2(WebRtc_Word32 channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
return split_channels_[channel].analysis_filter_state2;
|
||||
}
|
||||
|
||||
WebRtc_Word32* AudioBuffer::synthesis_filter_state1(WebRtc_Word32 channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
return split_channels_[channel].synthesis_filter_state1;
|
||||
}
|
||||
|
||||
WebRtc_Word32* AudioBuffer::synthesis_filter_state2(WebRtc_Word32 channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
return split_channels_[channel].synthesis_filter_state2;
|
||||
}
|
||||
|
||||
WebRtc_Word32 AudioBuffer::num_channels() const {
|
||||
return num_channels_;
|
||||
}
|
||||
|
||||
WebRtc_Word32 AudioBuffer::samples_per_channel() const {
|
||||
return samples_per_channel_;
|
||||
}
|
||||
|
||||
WebRtc_Word32 AudioBuffer::samples_per_split_channel() const {
|
||||
return samples_per_split_channel_;
|
||||
}
|
||||
|
||||
// TODO(ajm): Do deinterleaving and mixing in one step?
|
||||
void AudioBuffer::DeinterleaveFrom(AudioFrame* audioFrame) {
|
||||
assert(audioFrame->_audioChannel <= max_num_channels_);
|
||||
assert(audioFrame->_payloadDataLengthInSamples == samples_per_channel_);
|
||||
|
||||
num_channels_ = audioFrame->_audioChannel;
|
||||
num_mixed_channels_ = 0;
|
||||
num_mixed_low_pass_channels_ = 0;
|
||||
reference_copied_ = false;
|
||||
|
||||
if (num_channels_ == 1) {
|
||||
// We can get away with a pointer assignment in this case.
|
||||
data_ = audioFrame->_payloadData;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_channels_; i++) {
|
||||
WebRtc_Word16* deinterleaved = channels_[i].data;
|
||||
WebRtc_Word16* interleaved = audioFrame->_payloadData;
|
||||
WebRtc_Word32 interleaved_idx = i;
|
||||
for (int j = 0; j < samples_per_channel_; j++) {
|
||||
deinterleaved[j] = interleaved[interleaved_idx];
|
||||
interleaved_idx += num_channels_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBuffer::InterleaveTo(AudioFrame* audioFrame) const {
|
||||
assert(audioFrame->_audioChannel == num_channels_);
|
||||
assert(audioFrame->_payloadDataLengthInSamples == samples_per_channel_);
|
||||
|
||||
if (num_channels_ == 1) {
|
||||
if (num_mixed_channels_ == 1) {
|
||||
memcpy(audioFrame->_payloadData,
|
||||
channels_[0].data,
|
||||
sizeof(WebRtc_Word16) * samples_per_channel_);
|
||||
} else {
|
||||
// These should point to the same buffer in this case.
|
||||
assert(data_ == audioFrame->_payloadData);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_channels_; i++) {
|
||||
WebRtc_Word16* deinterleaved = channels_[i].data;
|
||||
WebRtc_Word16* interleaved = audioFrame->_payloadData;
|
||||
WebRtc_Word32 interleaved_idx = i;
|
||||
for (int j = 0; j < samples_per_channel_; j++) {
|
||||
interleaved[interleaved_idx] = deinterleaved[j];
|
||||
interleaved_idx += num_channels_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(ajm): would be good to support the no-mix case with pointer assignment.
|
||||
// TODO(ajm): handle mixing to multiple channels?
|
||||
void AudioBuffer::Mix(WebRtc_Word32 num_mixed_channels) {
|
||||
// We currently only support the stereo to mono case.
|
||||
assert(num_channels_ == 2);
|
||||
assert(num_mixed_channels == 1);
|
||||
|
||||
StereoToMono(channels_[0].data,
|
||||
channels_[1].data,
|
||||
channels_[0].data,
|
||||
samples_per_channel_);
|
||||
|
||||
num_channels_ = num_mixed_channels;
|
||||
num_mixed_channels_ = num_mixed_channels;
|
||||
}
|
||||
|
||||
void AudioBuffer::CopyAndMixLowPass(WebRtc_Word32 num_mixed_channels) {
|
||||
// We currently only support the stereo to mono case.
|
||||
assert(num_channels_ == 2);
|
||||
assert(num_mixed_channels == 1);
|
||||
|
||||
StereoToMono(low_pass_split_data(0),
|
||||
low_pass_split_data(1),
|
||||
mixed_low_pass_channels_[0].data,
|
||||
samples_per_split_channel_);
|
||||
|
||||
num_mixed_low_pass_channels_ = num_mixed_channels;
|
||||
}
|
||||
|
||||
void AudioBuffer::CopyLowPassToReference() {
|
||||
reference_copied_ = true;
|
||||
for (int i = 0; i < num_channels_; i++) {
|
||||
memcpy(low_pass_reference_channels_[i].data,
|
||||
low_pass_split_data(i),
|
||||
sizeof(WebRtc_Word16) * samples_per_split_channel_);
|
||||
}
|
||||
}
|
||||
} // namespace webrtc
|
||||
68
modules/audio_processing/main/source/audio_buffer.h
Normal file
68
modules/audio_processing/main/source/audio_buffer.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_BUFFER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_BUFFER_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
struct AudioChannel;
|
||||
struct SplitAudioChannel;
|
||||
class AudioFrame;
|
||||
|
||||
class AudioBuffer {
|
||||
public:
|
||||
AudioBuffer(WebRtc_Word32 max_num_channels, WebRtc_Word32 samples_per_channel);
|
||||
virtual ~AudioBuffer();
|
||||
|
||||
WebRtc_Word32 num_channels() const;
|
||||
WebRtc_Word32 samples_per_channel() const;
|
||||
WebRtc_Word32 samples_per_split_channel() const;
|
||||
|
||||
WebRtc_Word16* data(WebRtc_Word32 channel) const;
|
||||
WebRtc_Word16* low_pass_split_data(WebRtc_Word32 channel) const;
|
||||
WebRtc_Word16* high_pass_split_data(WebRtc_Word32 channel) const;
|
||||
WebRtc_Word16* mixed_low_pass_data(WebRtc_Word32 channel) const;
|
||||
WebRtc_Word16* low_pass_reference(WebRtc_Word32 channel) const;
|
||||
|
||||
WebRtc_Word32* analysis_filter_state1(WebRtc_Word32 channel) const;
|
||||
WebRtc_Word32* analysis_filter_state2(WebRtc_Word32 channel) const;
|
||||
WebRtc_Word32* synthesis_filter_state1(WebRtc_Word32 channel) const;
|
||||
WebRtc_Word32* synthesis_filter_state2(WebRtc_Word32 channel) const;
|
||||
|
||||
void DeinterleaveFrom(AudioFrame* audioFrame);
|
||||
void InterleaveTo(AudioFrame* audioFrame) const;
|
||||
void Mix(WebRtc_Word32 num_mixed_channels);
|
||||
void CopyAndMixLowPass(WebRtc_Word32 num_mixed_channels);
|
||||
void CopyLowPassToReference();
|
||||
|
||||
private:
|
||||
const WebRtc_Word32 max_num_channels_;
|
||||
WebRtc_Word32 num_channels_;
|
||||
WebRtc_Word32 num_mixed_channels_;
|
||||
WebRtc_Word32 num_mixed_low_pass_channels_;
|
||||
const WebRtc_Word32 samples_per_channel_;
|
||||
WebRtc_Word32 samples_per_split_channel_;
|
||||
bool reference_copied_;
|
||||
|
||||
WebRtc_Word16* data_;
|
||||
// TODO(ajm): Prefer to make these vectors if permitted...
|
||||
AudioChannel* channels_;
|
||||
SplitAudioChannel* split_channels_;
|
||||
// TODO(ajm): improve this, we don't need the full 32 kHz space here.
|
||||
AudioChannel* mixed_low_pass_channels_;
|
||||
AudioChannel* low_pass_reference_channels_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_BUFFER_H_
|
||||
636
modules/audio_processing/main/source/audio_processing_impl.cc
Normal file
636
modules/audio_processing/main/source/audio_processing_impl.cc
Normal file
@@ -0,0 +1,636 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "audio_processing_impl.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "module_common_types.h"
|
||||
|
||||
#include "critical_section_wrapper.h"
|
||||
#include "file_wrapper.h"
|
||||
|
||||
#include "audio_buffer.h"
|
||||
#include "echo_cancellation_impl.h"
|
||||
#include "echo_control_mobile_impl.h"
|
||||
#include "high_pass_filter_impl.h"
|
||||
#include "gain_control_impl.h"
|
||||
#include "level_estimator_impl.h"
|
||||
#include "noise_suppression_impl.h"
|
||||
#include "processing_component.h"
|
||||
#include "splitting_filter.h"
|
||||
#include "voice_detection_impl.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
enum Events {
|
||||
kInitializeEvent,
|
||||
kRenderEvent,
|
||||
kCaptureEvent
|
||||
};
|
||||
|
||||
const char kMagicNumber[] = "#!vqetrace1.2";
|
||||
} // namespace
|
||||
|
||||
AudioProcessing* AudioProcessing::Create(int id) {
|
||||
/*WEBRTC_TRACE(webrtc::kTraceModuleCall,
|
||||
webrtc::kTraceVqe,
|
||||
id,
|
||||
"AudioProcessing::Create()");*/
|
||||
|
||||
AudioProcessingImpl* apm = new AudioProcessingImpl(id);
|
||||
if (apm->Initialize() != kNoError) {
|
||||
delete apm;
|
||||
apm = NULL;
|
||||
}
|
||||
|
||||
return apm;
|
||||
}
|
||||
|
||||
void AudioProcessing::Destroy(AudioProcessing* apm) {
|
||||
delete static_cast<AudioProcessingImpl*>(apm);
|
||||
}
|
||||
|
||||
AudioProcessingImpl::AudioProcessingImpl(int id)
|
||||
: id_(id),
|
||||
echo_cancellation_(NULL),
|
||||
echo_control_mobile_(NULL),
|
||||
gain_control_(NULL),
|
||||
high_pass_filter_(NULL),
|
||||
level_estimator_(NULL),
|
||||
noise_suppression_(NULL),
|
||||
voice_detection_(NULL),
|
||||
debug_file_(FileWrapper::Create()),
|
||||
crit_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||
render_audio_(NULL),
|
||||
capture_audio_(NULL),
|
||||
sample_rate_hz_(kSampleRate16kHz),
|
||||
split_sample_rate_hz_(kSampleRate16kHz),
|
||||
samples_per_channel_(sample_rate_hz_ / 100),
|
||||
stream_delay_ms_(0),
|
||||
was_stream_delay_set_(false),
|
||||
num_render_input_channels_(1),
|
||||
num_capture_input_channels_(1),
|
||||
num_capture_output_channels_(1) {
|
||||
|
||||
echo_cancellation_ = new EchoCancellationImpl(this);
|
||||
component_list_.push_back(echo_cancellation_);
|
||||
|
||||
echo_control_mobile_ = new EchoControlMobileImpl(this);
|
||||
component_list_.push_back(echo_control_mobile_);
|
||||
|
||||
gain_control_ = new GainControlImpl(this);
|
||||
component_list_.push_back(gain_control_);
|
||||
|
||||
high_pass_filter_ = new HighPassFilterImpl(this);
|
||||
component_list_.push_back(high_pass_filter_);
|
||||
|
||||
level_estimator_ = new LevelEstimatorImpl(this);
|
||||
component_list_.push_back(level_estimator_);
|
||||
|
||||
noise_suppression_ = new NoiseSuppressionImpl(this);
|
||||
component_list_.push_back(noise_suppression_);
|
||||
|
||||
voice_detection_ = new VoiceDetectionImpl(this);
|
||||
component_list_.push_back(voice_detection_);
|
||||
}
|
||||
|
||||
AudioProcessingImpl::~AudioProcessingImpl() {
|
||||
while (!component_list_.empty()) {
|
||||
ProcessingComponent* component = component_list_.front();
|
||||
component->Destroy();
|
||||
delete component;
|
||||
component_list_.pop_front();
|
||||
}
|
||||
|
||||
if (debug_file_->Open()) {
|
||||
debug_file_->CloseFile();
|
||||
}
|
||||
delete debug_file_;
|
||||
debug_file_ = NULL;
|
||||
|
||||
delete crit_;
|
||||
crit_ = NULL;
|
||||
|
||||
if (render_audio_ != NULL) {
|
||||
delete render_audio_;
|
||||
render_audio_ = NULL;
|
||||
}
|
||||
|
||||
if (capture_audio_ != NULL) {
|
||||
delete capture_audio_;
|
||||
capture_audio_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CriticalSectionWrapper* AudioProcessingImpl::crit() const {
|
||||
return crit_;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::split_sample_rate_hz() const {
|
||||
return split_sample_rate_hz_;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::Initialize() {
|
||||
CriticalSectionScoped crit_scoped(*crit_);
|
||||
return InitializeLocked();
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::InitializeLocked() {
|
||||
if (render_audio_ != NULL) {
|
||||
delete render_audio_;
|
||||
render_audio_ = NULL;
|
||||
}
|
||||
|
||||
if (capture_audio_ != NULL) {
|
||||
delete capture_audio_;
|
||||
capture_audio_ = NULL;
|
||||
}
|
||||
|
||||
render_audio_ = new AudioBuffer(num_render_input_channels_,
|
||||
samples_per_channel_);
|
||||
capture_audio_ = new AudioBuffer(num_capture_input_channels_,
|
||||
samples_per_channel_);
|
||||
|
||||
was_stream_delay_set_ = false;
|
||||
|
||||
// Initialize all components.
|
||||
std::list<ProcessingComponent*>::iterator it;
|
||||
for (it = component_list_.begin(); it != component_list_.end(); it++) {
|
||||
int err = (*it)->Initialize();
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::set_sample_rate_hz(int rate) {
|
||||
CriticalSectionScoped crit_scoped(*crit_);
|
||||
if (rate != kSampleRate8kHz &&
|
||||
rate != kSampleRate16kHz &&
|
||||
rate != kSampleRate32kHz) {
|
||||
return kBadParameterError;
|
||||
}
|
||||
|
||||
sample_rate_hz_ = rate;
|
||||
samples_per_channel_ = rate / 100;
|
||||
|
||||
if (sample_rate_hz_ == kSampleRate32kHz) {
|
||||
split_sample_rate_hz_ = kSampleRate16kHz;
|
||||
} else {
|
||||
split_sample_rate_hz_ = sample_rate_hz_;
|
||||
}
|
||||
|
||||
return InitializeLocked();
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::sample_rate_hz() const {
|
||||
return sample_rate_hz_;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::set_num_reverse_channels(int channels) {
|
||||
CriticalSectionScoped crit_scoped(*crit_);
|
||||
// Only stereo supported currently.
|
||||
if (channels > 2 || channels < 1) {
|
||||
return kBadParameterError;
|
||||
}
|
||||
|
||||
num_render_input_channels_ = channels;
|
||||
|
||||
return InitializeLocked();
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::num_reverse_channels() const {
|
||||
return num_render_input_channels_;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::set_num_channels(
|
||||
int input_channels,
|
||||
int output_channels) {
|
||||
CriticalSectionScoped crit_scoped(*crit_);
|
||||
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) {
|
||||
return kBadParameterError;
|
||||
}
|
||||
|
||||
num_capture_input_channels_ = input_channels;
|
||||
num_capture_output_channels_ = output_channels;
|
||||
|
||||
return InitializeLocked();
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::num_input_channels() const {
|
||||
return num_capture_input_channels_;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::num_output_channels() const {
|
||||
return num_capture_output_channels_;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
|
||||
CriticalSectionScoped crit_scoped(*crit_);
|
||||
int err = kNoError;
|
||||
|
||||
if (frame == NULL) {
|
||||
return kNullPointerError;
|
||||
}
|
||||
|
||||
if (frame->_frequencyInHz !=
|
||||
static_cast<WebRtc_UWord32>(sample_rate_hz_)) {
|
||||
return kBadSampleRateError;
|
||||
}
|
||||
|
||||
if (frame->_audioChannel != num_capture_input_channels_) {
|
||||
return kBadNumberChannelsError;
|
||||
}
|
||||
|
||||
if (frame->_payloadDataLengthInSamples != samples_per_channel_) {
|
||||
return kBadDataLengthError;
|
||||
}
|
||||
|
||||
if (debug_file_->Open()) {
|
||||
WebRtc_UWord8 event = kCaptureEvent;
|
||||
if (!debug_file_->Write(&event, sizeof(event))) {
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
if (!debug_file_->Write(&frame->_frequencyInHz,
|
||||
sizeof(frame->_frequencyInHz))) {
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
if (!debug_file_->Write(&frame->_audioChannel,
|
||||
sizeof(frame->_audioChannel))) {
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
if (!debug_file_->Write(&frame->_payloadDataLengthInSamples,
|
||||
sizeof(frame->_payloadDataLengthInSamples))) {
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
if (!debug_file_->Write(frame->_payloadData,
|
||||
sizeof(WebRtc_Word16) * frame->_payloadDataLengthInSamples *
|
||||
frame->_audioChannel)) {
|
||||
return kFileError;
|
||||
}
|
||||
}
|
||||
|
||||
capture_audio_->DeinterleaveFrom(frame);
|
||||
|
||||
// TODO(ajm): experiment with mixing and AEC placement.
|
||||
if (num_capture_output_channels_ < num_capture_input_channels_) {
|
||||
capture_audio_->Mix(num_capture_output_channels_);
|
||||
|
||||
frame->_audioChannel = num_capture_output_channels_;
|
||||
}
|
||||
|
||||
if (sample_rate_hz_ == kSampleRate32kHz) {
|
||||
for (int i = 0; i < num_capture_input_channels_; i++) {
|
||||
// Split into a low and high band.
|
||||
SplittingFilterAnalysis(capture_audio_->data(i),
|
||||
capture_audio_->low_pass_split_data(i),
|
||||
capture_audio_->high_pass_split_data(i),
|
||||
capture_audio_->analysis_filter_state1(i),
|
||||
capture_audio_->analysis_filter_state2(i));
|
||||
}
|
||||
}
|
||||
|
||||
err = high_pass_filter_->ProcessCaptureAudio(capture_audio_);
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gain_control_->AnalyzeCaptureAudio(capture_audio_);
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = echo_cancellation_->ProcessCaptureAudio(capture_audio_);
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (echo_control_mobile_->is_enabled() &&
|
||||
noise_suppression_->is_enabled()) {
|
||||
capture_audio_->CopyLowPassToReference();
|
||||
}
|
||||
|
||||
err = noise_suppression_->ProcessCaptureAudio(capture_audio_);
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = echo_control_mobile_->ProcessCaptureAudio(capture_audio_);
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = voice_detection_->ProcessCaptureAudio(capture_audio_);
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gain_control_->ProcessCaptureAudio(capture_audio_);
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
//err = level_estimator_->ProcessCaptureAudio(capture_audio_);
|
||||
//if (err != kNoError) {
|
||||
// return err;
|
||||
//}
|
||||
|
||||
if (sample_rate_hz_ == kSampleRate32kHz) {
|
||||
for (int i = 0; i < num_capture_output_channels_; i++) {
|
||||
// Recombine low and high bands.
|
||||
SplittingFilterSynthesis(capture_audio_->low_pass_split_data(i),
|
||||
capture_audio_->high_pass_split_data(i),
|
||||
capture_audio_->data(i),
|
||||
capture_audio_->synthesis_filter_state1(i),
|
||||
capture_audio_->synthesis_filter_state2(i));
|
||||
}
|
||||
}
|
||||
|
||||
capture_audio_->InterleaveTo(frame);
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) {
|
||||
CriticalSectionScoped crit_scoped(*crit_);
|
||||
int err = kNoError;
|
||||
|
||||
if (frame == NULL) {
|
||||
return kNullPointerError;
|
||||
}
|
||||
|
||||
if (frame->_frequencyInHz !=
|
||||
static_cast<WebRtc_UWord32>(sample_rate_hz_)) {
|
||||
return kBadSampleRateError;
|
||||
}
|
||||
|
||||
if (frame->_audioChannel != num_render_input_channels_) {
|
||||
return kBadNumberChannelsError;
|
||||
}
|
||||
|
||||
if (frame->_payloadDataLengthInSamples != samples_per_channel_) {
|
||||
return kBadDataLengthError;
|
||||
}
|
||||
|
||||
if (debug_file_->Open()) {
|
||||
WebRtc_UWord8 event = kRenderEvent;
|
||||
if (!debug_file_->Write(&event, sizeof(event))) {
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
if (!debug_file_->Write(&frame->_frequencyInHz,
|
||||
sizeof(frame->_frequencyInHz))) {
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
if (!debug_file_->Write(&frame->_audioChannel,
|
||||
sizeof(frame->_audioChannel))) {
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
if (!debug_file_->Write(&frame->_payloadDataLengthInSamples,
|
||||
sizeof(frame->_payloadDataLengthInSamples))) {
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
if (!debug_file_->Write(frame->_payloadData,
|
||||
sizeof(WebRtc_Word16) * frame->_payloadDataLengthInSamples *
|
||||
frame->_audioChannel)) {
|
||||
return kFileError;
|
||||
}
|
||||
}
|
||||
|
||||
render_audio_->DeinterleaveFrom(frame);
|
||||
|
||||
// TODO(ajm): turn the splitting filter into a component?
|
||||
if (sample_rate_hz_ == kSampleRate32kHz) {
|
||||
for (int i = 0; i < num_render_input_channels_; i++) {
|
||||
// Split into low and high band.
|
||||
SplittingFilterAnalysis(render_audio_->data(i),
|
||||
render_audio_->low_pass_split_data(i),
|
||||
render_audio_->high_pass_split_data(i),
|
||||
render_audio_->analysis_filter_state1(i),
|
||||
render_audio_->analysis_filter_state2(i));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(ajm): warnings possible from components?
|
||||
err = echo_cancellation_->ProcessRenderAudio(render_audio_);
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = echo_control_mobile_->ProcessRenderAudio(render_audio_);
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gain_control_->ProcessRenderAudio(render_audio_);
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
//err = level_estimator_->AnalyzeReverseStream(render_audio_);
|
||||
//if (err != kNoError) {
|
||||
// return err;
|
||||
//}
|
||||
|
||||
was_stream_delay_set_ = false;
|
||||
return err; // TODO(ajm): this is for returning warnings; necessary?
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::set_stream_delay_ms(int delay) {
|
||||
was_stream_delay_set_ = true;
|
||||
if (delay < 0) {
|
||||
return kBadParameterError;
|
||||
}
|
||||
|
||||
// TODO(ajm): the max is rather arbitrarily chosen; investigate.
|
||||
if (delay > 500) {
|
||||
stream_delay_ms_ = 500;
|
||||
return kBadStreamParameterWarning;
|
||||
}
|
||||
|
||||
stream_delay_ms_ = delay;
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::stream_delay_ms() const {
|
||||
return stream_delay_ms_;
|
||||
}
|
||||
|
||||
bool AudioProcessingImpl::was_stream_delay_set() const {
|
||||
return was_stream_delay_set_;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::StartDebugRecording(
|
||||
const char filename[AudioProcessing::kMaxFilenameSize]) {
|
||||
CriticalSectionScoped crit_scoped(*crit_);
|
||||
assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize);
|
||||
|
||||
if (filename == NULL) {
|
||||
return kNullPointerError;
|
||||
}
|
||||
|
||||
// Stop any ongoing recording.
|
||||
if (debug_file_->Open()) {
|
||||
if (debug_file_->CloseFile() == -1) {
|
||||
return kFileError;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_file_->OpenFile(filename, false) == -1) {
|
||||
debug_file_->CloseFile();
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
if (debug_file_->WriteText("%s\n", kMagicNumber) == -1) {
|
||||
debug_file_->CloseFile();
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
// TODO(ajm): should we do this? If so, we need the number of channels etc.
|
||||
// Record the default sample rate.
|
||||
WebRtc_UWord8 event = kInitializeEvent;
|
||||
if (!debug_file_->Write(&event, sizeof(event))) {
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
if (!debug_file_->Write(&sample_rate_hz_, sizeof(sample_rate_hz_))) {
|
||||
return kFileError;
|
||||
}
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::StopDebugRecording() {
|
||||
CriticalSectionScoped crit_scoped(*crit_);
|
||||
// We just return if recording hasn't started.
|
||||
if (debug_file_->Open()) {
|
||||
if (debug_file_->CloseFile() == -1) {
|
||||
return kFileError;
|
||||
}
|
||||
}
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
EchoCancellation* AudioProcessingImpl::echo_cancellation() const {
|
||||
return echo_cancellation_;
|
||||
}
|
||||
|
||||
EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const {
|
||||
return echo_control_mobile_;
|
||||
}
|
||||
|
||||
GainControl* AudioProcessingImpl::gain_control() const {
|
||||
return gain_control_;
|
||||
}
|
||||
|
||||
HighPassFilter* AudioProcessingImpl::high_pass_filter() const {
|
||||
return high_pass_filter_;
|
||||
}
|
||||
|
||||
LevelEstimator* AudioProcessingImpl::level_estimator() const {
|
||||
return level_estimator_;
|
||||
}
|
||||
|
||||
NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
|
||||
return noise_suppression_;
|
||||
}
|
||||
|
||||
VoiceDetection* AudioProcessingImpl::voice_detection() const {
|
||||
return voice_detection_;
|
||||
}
|
||||
|
||||
WebRtc_Word32 AudioProcessingImpl::Version(WebRtc_Word8* version,
|
||||
WebRtc_UWord32& bytes_remaining, WebRtc_UWord32& position) const {
|
||||
if (version == NULL) {
|
||||
/*WEBRTC_TRACE(webrtc::kTraceError,
|
||||
webrtc::kTraceVqe,
|
||||
-1,
|
||||
"Null version pointer");*/
|
||||
return kNullPointerError;
|
||||
}
|
||||
memset(&version[position], 0, bytes_remaining);
|
||||
|
||||
WebRtc_Word8 my_version[] = "AudioProcessing 1.0.0";
|
||||
// Includes null termination.
|
||||
WebRtc_UWord32 length = static_cast<WebRtc_UWord32>(strlen(my_version));
|
||||
if (bytes_remaining < length) {
|
||||
/*WEBRTC_TRACE(webrtc::kTraceError,
|
||||
webrtc::kTraceVqe,
|
||||
-1,
|
||||
"Buffer of insufficient length");*/
|
||||
return kBadParameterError;
|
||||
}
|
||||
memcpy(&version[position], my_version, length);
|
||||
bytes_remaining -= length;
|
||||
position += length;
|
||||
|
||||
std::list<ProcessingComponent*>::const_iterator it;
|
||||
for (it = component_list_.begin(); it != component_list_.end(); it++) {
|
||||
char component_version[256];
|
||||
strcpy(component_version, "\n");
|
||||
int err = (*it)->get_version(&component_version[1],
|
||||
sizeof(component_version) - 1);
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
if (strncmp(&component_version[1], "\0", 1) == 0) {
|
||||
// Assume empty if first byte is NULL.
|
||||
continue;
|
||||
}
|
||||
|
||||
length = static_cast<WebRtc_UWord32>(strlen(component_version));
|
||||
if (bytes_remaining < length) {
|
||||
/*WEBRTC_TRACE(webrtc::kTraceError,
|
||||
webrtc::kTraceVqe,
|
||||
-1,
|
||||
"Buffer of insufficient length");*/
|
||||
return kBadParameterError;
|
||||
}
|
||||
memcpy(&version[position], component_version, length);
|
||||
bytes_remaining -= length;
|
||||
position += length;
|
||||
}
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
WebRtc_Word32 AudioProcessingImpl::ChangeUniqueId(const WebRtc_Word32 id) {
|
||||
CriticalSectionScoped crit_scoped(*crit_);
|
||||
/*WEBRTC_TRACE(webrtc::kTraceModuleCall,
|
||||
webrtc::kTraceVqe,
|
||||
id_,
|
||||
"ChangeUniqueId(new id = %d)",
|
||||
id);*/
|
||||
id_ = id;
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
} // namespace webrtc
|
||||
109
modules/audio_processing/main/source/audio_processing_impl.h
Normal file
109
modules/audio_processing/main/source/audio_processing_impl.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_PROCESSING_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_PROCESSING_IMPL_H_
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "audio_processing.h"
|
||||
|
||||
namespace webrtc {
|
||||
class CriticalSectionWrapper;
|
||||
class FileWrapper;
|
||||
|
||||
class AudioBuffer;
|
||||
class EchoCancellationImpl;
|
||||
class EchoControlMobileImpl;
|
||||
class GainControlImpl;
|
||||
class HighPassFilterImpl;
|
||||
class LevelEstimatorImpl;
|
||||
class NoiseSuppressionImpl;
|
||||
class ProcessingComponent;
|
||||
class VoiceDetectionImpl;
|
||||
|
||||
class AudioProcessingImpl : public AudioProcessing {
|
||||
public:
|
||||
enum {
|
||||
kSampleRate8kHz = 8000,
|
||||
kSampleRate16kHz = 16000,
|
||||
kSampleRate32kHz = 32000
|
||||
};
|
||||
|
||||
explicit AudioProcessingImpl(int id);
|
||||
virtual ~AudioProcessingImpl();
|
||||
|
||||
CriticalSectionWrapper* crit() const;
|
||||
|
||||
int split_sample_rate_hz() const;
|
||||
bool was_stream_delay_set() const;
|
||||
|
||||
// AudioProcessing methods.
|
||||
virtual int Initialize();
|
||||
virtual int InitializeLocked();
|
||||
virtual int set_sample_rate_hz(int rate);
|
||||
virtual int sample_rate_hz() const;
|
||||
virtual int set_num_channels(int input_channels, int output_channels);
|
||||
virtual int num_input_channels() const;
|
||||
virtual int num_output_channels() const;
|
||||
virtual int set_num_reverse_channels(int channels);
|
||||
virtual int num_reverse_channels() const;
|
||||
virtual int ProcessStream(AudioFrame* frame);
|
||||
virtual int AnalyzeReverseStream(AudioFrame* frame);
|
||||
virtual int set_stream_delay_ms(int delay);
|
||||
virtual int stream_delay_ms() const;
|
||||
virtual int StartDebugRecording(const char filename[kMaxFilenameSize]);
|
||||
virtual int StopDebugRecording();
|
||||
virtual EchoCancellation* echo_cancellation() const;
|
||||
virtual EchoControlMobile* echo_control_mobile() const;
|
||||
virtual GainControl* gain_control() const;
|
||||
virtual HighPassFilter* high_pass_filter() const;
|
||||
virtual LevelEstimator* level_estimator() const;
|
||||
virtual NoiseSuppression* noise_suppression() const;
|
||||
virtual VoiceDetection* voice_detection() const;
|
||||
|
||||
// Module methods.
|
||||
virtual WebRtc_Word32 Version(WebRtc_Word8* version,
|
||||
WebRtc_UWord32& remainingBufferInBytes,
|
||||
WebRtc_UWord32& position) const;
|
||||
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
|
||||
|
||||
private:
|
||||
int id_;
|
||||
|
||||
EchoCancellationImpl* echo_cancellation_;
|
||||
EchoControlMobileImpl* echo_control_mobile_;
|
||||
GainControlImpl* gain_control_;
|
||||
HighPassFilterImpl* high_pass_filter_;
|
||||
LevelEstimatorImpl* level_estimator_;
|
||||
NoiseSuppressionImpl* noise_suppression_;
|
||||
VoiceDetectionImpl* voice_detection_;
|
||||
|
||||
std::list<ProcessingComponent*> component_list_;
|
||||
|
||||
FileWrapper* debug_file_;
|
||||
CriticalSectionWrapper* crit_;
|
||||
|
||||
AudioBuffer* render_audio_;
|
||||
AudioBuffer* capture_audio_;
|
||||
|
||||
int sample_rate_hz_;
|
||||
int split_sample_rate_hz_;
|
||||
int samples_per_channel_;
|
||||
int stream_delay_ms_;
|
||||
bool was_stream_delay_set_;
|
||||
|
||||
int num_render_input_channels_;
|
||||
int num_capture_input_channels_;
|
||||
int num_capture_output_channels_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_PROCESSING_IMPL_H_
|
||||
393
modules/audio_processing/main/source/echo_cancellation_impl.cc
Normal file
393
modules/audio_processing/main/source/echo_cancellation_impl.cc
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "echo_cancellation_impl.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <string.h>
|
||||
|
||||
#include "critical_section_wrapper.h"
|
||||
#include "echo_cancellation.h"
|
||||
|
||||
#include "audio_processing_impl.h"
|
||||
#include "audio_buffer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
typedef void Handle;
|
||||
|
||||
namespace {
|
||||
int MapError(int err) {
|
||||
switch (err) {
|
||||
case AEC_UNSUPPORTED_FUNCTION_ERROR:
|
||||
return AudioProcessing::kUnsupportedFunctionError;
|
||||
break;
|
||||
case AEC_BAD_PARAMETER_ERROR:
|
||||
return AudioProcessing::kBadParameterError;
|
||||
break;
|
||||
case AEC_BAD_PARAMETER_WARNING:
|
||||
return AudioProcessing::kBadStreamParameterWarning;
|
||||
break;
|
||||
default:
|
||||
// AEC_UNSPECIFIED_ERROR
|
||||
// AEC_UNINITIALIZED_ERROR
|
||||
// AEC_NULL_POINTER_ERROR
|
||||
return AudioProcessing::kUnspecifiedError;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
EchoCancellationImpl::EchoCancellationImpl(const AudioProcessingImpl* apm)
|
||||
: ProcessingComponent(apm),
|
||||
apm_(apm),
|
||||
drift_compensation_enabled_(false),
|
||||
metrics_enabled_(false),
|
||||
suppression_level_(kModerateSuppression),
|
||||
device_sample_rate_hz_(48000),
|
||||
stream_drift_samples_(0),
|
||||
was_stream_drift_set_(false),
|
||||
stream_has_echo_(false) {}
|
||||
|
||||
EchoCancellationImpl::~EchoCancellationImpl() {}
|
||||
|
||||
int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) {
|
||||
if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
assert(audio->samples_per_split_channel() <= 160);
|
||||
assert(audio->num_channels() == apm_->num_reverse_channels());
|
||||
|
||||
int err = apm_->kNoError;
|
||||
|
||||
// The ordering convention must be followed to pass to the correct AEC.
|
||||
size_t handle_index = 0;
|
||||
for (int i = 0; i < apm_->num_output_channels(); i++) {
|
||||
for (int j = 0; j < audio->num_channels(); j++) {
|
||||
Handle* my_handle = static_cast<Handle*>(handle(handle_index));
|
||||
err = WebRtcAec_BufferFarend(
|
||||
my_handle,
|
||||
audio->low_pass_split_data(j),
|
||||
static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
return GetHandleError(my_handle); // TODO(ajm): warning possible?
|
||||
}
|
||||
|
||||
handle_index++;
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) {
|
||||
if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
if (!apm_->was_stream_delay_set()) {
|
||||
return apm_->kStreamParameterNotSetError;
|
||||
}
|
||||
|
||||
if (drift_compensation_enabled_ && !was_stream_drift_set_) {
|
||||
return apm_->kStreamParameterNotSetError;
|
||||
}
|
||||
|
||||
assert(audio->samples_per_split_channel() <= 160);
|
||||
assert(audio->num_channels() == apm_->num_output_channels());
|
||||
|
||||
int err = apm_->kNoError;
|
||||
|
||||
// The ordering convention must be followed to pass to the correct AEC.
|
||||
size_t handle_index = 0;
|
||||
stream_has_echo_ = false;
|
||||
for (int i = 0; i < audio->num_channels(); i++) {
|
||||
for (int j = 0; j < apm_->num_reverse_channels(); j++) {
|
||||
Handle* my_handle = handle(handle_index);
|
||||
err = WebRtcAec_Process(
|
||||
my_handle,
|
||||
audio->low_pass_split_data(i),
|
||||
audio->high_pass_split_data(i),
|
||||
audio->low_pass_split_data(i),
|
||||
audio->high_pass_split_data(i),
|
||||
static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
|
||||
apm_->stream_delay_ms(),
|
||||
stream_drift_samples_);
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
err = GetHandleError(my_handle);
|
||||
// TODO(ajm): Figure out how to return warnings properly.
|
||||
if (err != apm_->kBadStreamParameterWarning) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
WebRtc_Word16 status = 0;
|
||||
err = WebRtcAec_get_echo_status(my_handle, &status);
|
||||
if (err != apm_->kNoError) {
|
||||
return GetHandleError(my_handle);
|
||||
}
|
||||
|
||||
if (status == 1) {
|
||||
stream_has_echo_ = true;
|
||||
}
|
||||
|
||||
handle_index++;
|
||||
}
|
||||
}
|
||||
|
||||
was_stream_drift_set_ = false;
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::Enable(bool enable) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
// Ensure AEC and AECM are not both enabled.
|
||||
if (enable && apm_->echo_control_mobile()->is_enabled()) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
return EnableComponent(enable);
|
||||
}
|
||||
|
||||
bool EchoCancellationImpl::is_enabled() const {
|
||||
return is_component_enabled();
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
if (level != kLowSuppression &&
|
||||
level != kModerateSuppression &&
|
||||
level != kHighSuppression) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
suppression_level_ = level;
|
||||
return Configure();
|
||||
}
|
||||
|
||||
EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level()
|
||||
const {
|
||||
return suppression_level_;
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::enable_drift_compensation(bool enable) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
drift_compensation_enabled_ = enable;
|
||||
return Configure();
|
||||
}
|
||||
|
||||
bool EchoCancellationImpl::is_drift_compensation_enabled() const {
|
||||
return drift_compensation_enabled_;
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::set_device_sample_rate_hz(int rate) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
if (rate < 8000 || rate > 96000) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
device_sample_rate_hz_ = rate;
|
||||
return Initialize();
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::device_sample_rate_hz() const {
|
||||
return device_sample_rate_hz_;
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::set_stream_drift_samples(int drift) {
|
||||
was_stream_drift_set_ = true;
|
||||
stream_drift_samples_ = drift;
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::stream_drift_samples() const {
|
||||
return stream_drift_samples_;
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::enable_metrics(bool enable) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
metrics_enabled_ = enable;
|
||||
return Configure();
|
||||
}
|
||||
|
||||
bool EchoCancellationImpl::are_metrics_enabled() const {
|
||||
return metrics_enabled_;
|
||||
}
|
||||
|
||||
// TODO(ajm): we currently just use the metrics from the first AEC. Think more
|
||||
// aboue the best way to extend this to multi-channel.
|
||||
int EchoCancellationImpl::GetMetrics(Metrics* metrics) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
if (metrics == NULL) {
|
||||
return apm_->kNullPointerError;
|
||||
}
|
||||
|
||||
if (!is_component_enabled() || !metrics_enabled_) {
|
||||
return apm_->kNotEnabledError;
|
||||
}
|
||||
|
||||
AecMetrics my_metrics;
|
||||
memset(&my_metrics, 0, sizeof(my_metrics));
|
||||
memset(metrics, 0, sizeof(Metrics));
|
||||
|
||||
Handle* my_handle = static_cast<Handle*>(handle(0));
|
||||
int err = WebRtcAec_GetMetrics(my_handle, &my_metrics);
|
||||
if (err != apm_->kNoError) {
|
||||
return GetHandleError(my_handle);
|
||||
}
|
||||
|
||||
metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant;
|
||||
metrics->residual_echo_return_loss.average = my_metrics.rerl.average;
|
||||
metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max;
|
||||
metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min;
|
||||
|
||||
metrics->echo_return_loss.instant = my_metrics.erl.instant;
|
||||
metrics->echo_return_loss.average = my_metrics.erl.average;
|
||||
metrics->echo_return_loss.maximum = my_metrics.erl.max;
|
||||
metrics->echo_return_loss.minimum = my_metrics.erl.min;
|
||||
|
||||
metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant;
|
||||
metrics->echo_return_loss_enhancement.average = my_metrics.erle.average;
|
||||
metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max;
|
||||
metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min;
|
||||
|
||||
metrics->a_nlp.instant = my_metrics.aNlp.instant;
|
||||
metrics->a_nlp.average = my_metrics.aNlp.average;
|
||||
metrics->a_nlp.maximum = my_metrics.aNlp.max;
|
||||
metrics->a_nlp.minimum = my_metrics.aNlp.min;
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
bool EchoCancellationImpl::stream_has_echo() const {
|
||||
return stream_has_echo_;
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::Initialize() {
|
||||
int err = ProcessingComponent::Initialize();
|
||||
if (err != apm_->kNoError || !is_component_enabled()) {
|
||||
return err;
|
||||
}
|
||||
|
||||
was_stream_drift_set_ = false;
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::get_version(char* version,
|
||||
int version_len_bytes) const {
|
||||
if (WebRtcAec_get_version(version, version_len_bytes) != 0) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
void* EchoCancellationImpl::CreateHandle() const {
|
||||
Handle* handle = NULL;
|
||||
if (WebRtcAec_Create(&handle) != apm_->kNoError) {
|
||||
handle = NULL;
|
||||
} else {
|
||||
assert(handle != NULL);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::DestroyHandle(void* handle) const {
|
||||
assert(handle != NULL);
|
||||
return WebRtcAec_Free(static_cast<Handle*>(handle));
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::InitializeHandle(void* handle) const {
|
||||
assert(handle != NULL);
|
||||
return WebRtcAec_Init(static_cast<Handle*>(handle),
|
||||
apm_->sample_rate_hz(),
|
||||
device_sample_rate_hz_);
|
||||
}
|
||||
|
||||
/*int EchoCancellationImpl::InitializeHandles(
|
||||
const vector<void*>& handles) const {
|
||||
int err = apm_->kNoError;
|
||||
|
||||
for (size_t i = 0; i < num_handles(); i++) {
|
||||
err = WebRtcAec_Init(static_cast<Handle*>(handles[i]),
|
||||
apm_->SampleRateHz(),
|
||||
device_sample_rate_hz_);
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}*/
|
||||
|
||||
int EchoCancellationImpl::ConfigureHandle(void* handle) const {
|
||||
assert(handle != NULL);
|
||||
AecConfig config;
|
||||
config.metricsMode = metrics_enabled_;
|
||||
config.nlpMode = suppression_level_;
|
||||
config.skewMode = drift_compensation_enabled_;
|
||||
|
||||
return WebRtcAec_set_config(static_cast<Handle*>(handle), config);
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::num_handles_required() const {
|
||||
return apm_->num_output_channels() *
|
||||
apm_->num_reverse_channels();
|
||||
}
|
||||
|
||||
int EchoCancellationImpl::GetHandleError(void* handle) const {
|
||||
assert(handle != NULL);
|
||||
return MapError(WebRtcAec_get_error_code(static_cast<Handle*>(handle)));
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
/*int EchoCancellationImpl::GetConfiguration(void* handle) {
|
||||
if (!initialized_) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
AecConfig config;
|
||||
int err = WebRtcAec_get_config(handle, &config);
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
|
||||
if (config.metricsMode == 0) {
|
||||
metrics_enabled_ = false;
|
||||
} else if (config.metricsMode == 1) {
|
||||
metrics_enabled_ = true;
|
||||
} else {
|
||||
return apm_->kUnspecifiedError;
|
||||
}
|
||||
|
||||
if (config.nlpMode == kAecNlpConservative) {
|
||||
suppression_level_ = kLowSuppression;
|
||||
} else if (config.nlpMode == kAecNlpModerate) {
|
||||
suppression_level_ = kModerateSuppression;
|
||||
} else if (config.nlpMode == kAecNlpAggressive) {
|
||||
suppression_level_ = kHighSuppression;
|
||||
} else {
|
||||
return apm_->kUnspecifiedError;
|
||||
}
|
||||
|
||||
if (config.skewMode == 0) {
|
||||
drift_compensation_enabled_ = false;
|
||||
} else if (config.skewMode == 1) {
|
||||
drift_compensation_enabled_ = true;
|
||||
} else {
|
||||
return apm_->kUnspecifiedError;
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}*/
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_ECHO_CANCELLATION_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_ECHO_CANCELLATION_IMPL_H_
|
||||
|
||||
#include "audio_processing.h"
|
||||
#include "processing_component.h"
|
||||
|
||||
namespace webrtc {
|
||||
class AudioProcessingImpl;
|
||||
class AudioBuffer;
|
||||
|
||||
class EchoCancellationImpl : public EchoCancellation,
|
||||
public ProcessingComponent {
|
||||
public:
|
||||
explicit EchoCancellationImpl(const AudioProcessingImpl* apm);
|
||||
virtual ~EchoCancellationImpl();
|
||||
|
||||
int ProcessRenderAudio(const AudioBuffer* audio);
|
||||
int ProcessCaptureAudio(AudioBuffer* audio);
|
||||
|
||||
// EchoCancellation implementation.
|
||||
virtual bool is_enabled() const;
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual int Initialize();
|
||||
virtual int get_version(char* version, int version_len_bytes) const;
|
||||
|
||||
private:
|
||||
// EchoCancellation implementation.
|
||||
virtual int Enable(bool enable);
|
||||
virtual int enable_drift_compensation(bool enable);
|
||||
virtual bool is_drift_compensation_enabled() const;
|
||||
virtual int set_device_sample_rate_hz(int rate);
|
||||
virtual int device_sample_rate_hz() const;
|
||||
virtual int set_stream_drift_samples(int drift);
|
||||
virtual int stream_drift_samples() const;
|
||||
virtual int set_suppression_level(SuppressionLevel level);
|
||||
virtual SuppressionLevel suppression_level() const;
|
||||
virtual int enable_metrics(bool enable);
|
||||
virtual bool are_metrics_enabled() const;
|
||||
virtual bool stream_has_echo() const;
|
||||
virtual int GetMetrics(Metrics* metrics);
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual void* CreateHandle() const;
|
||||
virtual int InitializeHandle(void* handle) const;
|
||||
//virtual int InitializeHandles(
|
||||
// const std::vector<void*>& handles) const;
|
||||
virtual int ConfigureHandle(void* handle) const;
|
||||
virtual int DestroyHandle(void* handle) const;
|
||||
virtual int num_handles_required() const;
|
||||
|
||||
virtual int GetHandleError(void* handle) const;
|
||||
|
||||
const AudioProcessingImpl* apm_;
|
||||
bool drift_compensation_enabled_;
|
||||
bool metrics_enabled_;
|
||||
SuppressionLevel suppression_level_;
|
||||
int device_sample_rate_hz_;
|
||||
int stream_drift_samples_;
|
||||
bool was_stream_drift_set_;
|
||||
bool stream_has_echo_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_ECHO_CANCELLATION_IMPL_H_
|
||||
278
modules/audio_processing/main/source/echo_control_mobile_impl.cc
Normal file
278
modules/audio_processing/main/source/echo_control_mobile_impl.cc
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "echo_control_mobile_impl.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "critical_section_wrapper.h"
|
||||
#include "echo_control_mobile.h"
|
||||
|
||||
#include "audio_processing_impl.h"
|
||||
#include "audio_buffer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
typedef void Handle;
|
||||
|
||||
EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessingImpl* apm)
|
||||
: ProcessingComponent(apm),
|
||||
apm_(apm),
|
||||
routing_mode_(kSpeakerphone),
|
||||
comfort_noise_enabled_(true) {}
|
||||
|
||||
EchoControlMobileImpl::~EchoControlMobileImpl() {}
|
||||
|
||||
int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) {
|
||||
if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
assert(audio->samples_per_split_channel() <= 160);
|
||||
assert(audio->num_channels() == apm_->num_reverse_channels());
|
||||
|
||||
int err = apm_->kNoError;
|
||||
|
||||
// The ordering convention must be followed to pass to the correct AECM.
|
||||
size_t handle_index = 0;
|
||||
for (int i = 0; i < apm_->num_output_channels(); i++) {
|
||||
for (int j = 0; j < audio->num_channels(); j++) {
|
||||
err = WebRtcAecm_BufferFarend(
|
||||
static_cast<Handle*>(handle(handle_index)),
|
||||
audio->low_pass_split_data(j),
|
||||
static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err); // TODO(ajm): warning possible?
|
||||
}
|
||||
|
||||
handle_index++;
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) {
|
||||
if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
if (!apm_->was_stream_delay_set()) {
|
||||
return apm_->kStreamParameterNotSetError;
|
||||
}
|
||||
|
||||
assert(audio->samples_per_split_channel() <= 160);
|
||||
assert(audio->num_channels() == apm_->num_output_channels());
|
||||
|
||||
int err = apm_->kNoError;
|
||||
|
||||
// The ordering convention must be followed to pass to the correct AECM.
|
||||
size_t handle_index = 0;
|
||||
for (int i = 0; i < audio->num_channels(); i++) {
|
||||
// TODO(ajm): improve how this works, possibly inside AECM.
|
||||
// This is kind of hacked up.
|
||||
WebRtc_Word16* noisy = audio->low_pass_reference(i);
|
||||
WebRtc_Word16* clean = audio->low_pass_split_data(i);
|
||||
if (noisy == NULL) {
|
||||
noisy = clean;
|
||||
clean = NULL;
|
||||
}
|
||||
for (int j = 0; j < apm_->num_reverse_channels(); j++) {
|
||||
err = WebRtcAecm_Process(
|
||||
static_cast<Handle*>(handle(handle_index)),
|
||||
noisy,
|
||||
clean,
|
||||
audio->low_pass_split_data(i),
|
||||
static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
|
||||
apm_->stream_delay_ms());
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err); // TODO(ajm): warning possible?
|
||||
}
|
||||
|
||||
handle_index++;
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int EchoControlMobileImpl::Enable(bool enable) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
// Ensure AEC and AECM are not both enabled.
|
||||
if (enable && apm_->echo_cancellation()->is_enabled()) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
return EnableComponent(enable);
|
||||
}
|
||||
|
||||
bool EchoControlMobileImpl::is_enabled() const {
|
||||
return is_component_enabled();
|
||||
}
|
||||
|
||||
int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
if (mode != kQuietEarpieceOrHeadset &&
|
||||
mode != kEarpiece &&
|
||||
mode != kLoudEarpiece &&
|
||||
mode != kSpeakerphone &&
|
||||
mode != kLoudSpeakerphone) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
routing_mode_ = mode;
|
||||
return Configure();
|
||||
}
|
||||
|
||||
EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode()
|
||||
const {
|
||||
return routing_mode_;
|
||||
}
|
||||
|
||||
int EchoControlMobileImpl::enable_comfort_noise(bool enable) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
comfort_noise_enabled_ = enable;
|
||||
return Configure();
|
||||
}
|
||||
|
||||
bool EchoControlMobileImpl::is_comfort_noise_enabled() const {
|
||||
return comfort_noise_enabled_;
|
||||
}
|
||||
|
||||
int EchoControlMobileImpl::Initialize() {
|
||||
if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
if (apm_->sample_rate_hz() == apm_->kSampleRate32kHz) {
|
||||
// AECM doesn't support super-wideband.
|
||||
return apm_->kBadSampleRateError;
|
||||
}
|
||||
|
||||
return ProcessingComponent::Initialize();
|
||||
}
|
||||
|
||||
int EchoControlMobileImpl::get_version(char* version,
|
||||
int version_len_bytes) const {
|
||||
if (WebRtcAecm_get_version(version, version_len_bytes) != 0) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
void* EchoControlMobileImpl::CreateHandle() const {
|
||||
Handle* handle = NULL;
|
||||
if (WebRtcAecm_Create(&handle) != apm_->kNoError) {
|
||||
handle = NULL;
|
||||
} else {
|
||||
assert(handle != NULL);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int EchoControlMobileImpl::DestroyHandle(void* handle) const {
|
||||
return WebRtcAecm_Free(static_cast<Handle*>(handle));
|
||||
}
|
||||
|
||||
int EchoControlMobileImpl::InitializeHandle(void* handle) const {
|
||||
return WebRtcAecm_Init(static_cast<Handle*>(handle),
|
||||
apm_->sample_rate_hz(),
|
||||
48000); // Dummy value. This isn't actually
|
||||
// required by AECM.
|
||||
}
|
||||
|
||||
/*int EchoControlMobileImpl::InitializeHandles(
|
||||
const vector<void*>& handles) const {
|
||||
int err = apm_->kNoError;
|
||||
|
||||
for (size_t i = 0; i < num_handles(); i++) {
|
||||
err = WebRtcAec_Init(static_cast<Handle*>(handles[i]),
|
||||
apm_->SampleRateHz(),
|
||||
device_sample_rate_hz_);
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}*/
|
||||
|
||||
int EchoControlMobileImpl::ConfigureHandle(void* handle) const {
|
||||
AecmConfig config;
|
||||
config.cngMode = comfort_noise_enabled_;
|
||||
config.echoMode = routing_mode_;
|
||||
|
||||
return WebRtcAecm_set_config(static_cast<Handle*>(handle), config);
|
||||
}
|
||||
|
||||
int EchoControlMobileImpl::num_handles_required() const {
|
||||
return apm_->num_output_channels() *
|
||||
apm_->num_reverse_channels();
|
||||
}
|
||||
|
||||
int EchoControlMobileImpl::TranslateError(int err) const {
|
||||
if (err == AECM_UNSUPPORTED_FUNCTION_ERROR) {
|
||||
return apm_->kUnsupportedFunctionError;
|
||||
} else if (err == AECM_BAD_PARAMETER_ERROR) {
|
||||
return apm_->kBadParameterError;
|
||||
} else if (err == AECM_BAD_PARAMETER_WARNING) {
|
||||
return apm_->kBadStreamParameterWarning;
|
||||
} else {
|
||||
// AECMOBFIX_UNSPECIFIED_ERROR
|
||||
// AECMOBFIX_UNINITIALIZED_ERROR
|
||||
// AECMOBFIX_NULL_POINTER_ERROR
|
||||
return apm_->kUnspecifiedError;
|
||||
}
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
/*int EchoControlMobileImpl::GetConfiguration(void* handle) {
|
||||
if (!initialized_) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
AecConfig config;
|
||||
int err = WebRtcAec_get_config(handle, &config);
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
|
||||
if (config.metricsMode == 0) {
|
||||
metrics_enabled_ = false;
|
||||
} else if (config.metricsMode == 1) {
|
||||
metrics_enabled_ = true;
|
||||
} else {
|
||||
return apm_->kUnspecifiedError;
|
||||
}
|
||||
|
||||
if (config.nlpMode == kAecNlpConservative) {
|
||||
routing_mode_ = kLowSuppression;
|
||||
} else if (config.nlpMode == kAecNlpModerate) {
|
||||
routing_mode_ = kMediumSuppression;
|
||||
} else if (config.nlpMode == kAecNlpAggressive) {
|
||||
routing_mode_ = kHighSuppression;
|
||||
} else {
|
||||
return apm_->kUnspecifiedError;
|
||||
}
|
||||
|
||||
if (config.skewMode == 0) {
|
||||
drift_compensation_enabled_ = false;
|
||||
} else if (config.skewMode == 1) {
|
||||
drift_compensation_enabled_ = true;
|
||||
} else {
|
||||
return apm_->kUnspecifiedError;
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}*/
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_ECHO_CONTROL_MOBILE_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_ECHO_CONTROL_MOBILE_IMPL_H_
|
||||
|
||||
#include "audio_processing.h"
|
||||
#include "processing_component.h"
|
||||
|
||||
namespace webrtc {
|
||||
class AudioProcessingImpl;
|
||||
class AudioBuffer;
|
||||
|
||||
class EchoControlMobileImpl : public EchoControlMobile,
|
||||
public ProcessingComponent {
|
||||
public:
|
||||
explicit EchoControlMobileImpl(const AudioProcessingImpl* apm);
|
||||
virtual ~EchoControlMobileImpl();
|
||||
|
||||
int ProcessRenderAudio(const AudioBuffer* audio);
|
||||
int ProcessCaptureAudio(AudioBuffer* audio);
|
||||
|
||||
// EchoControlMobile implementation.
|
||||
virtual bool is_enabled() const;
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual int Initialize();
|
||||
virtual int get_version(char* version, int version_len_bytes) const;
|
||||
|
||||
private:
|
||||
// EchoControlMobile implementation.
|
||||
virtual int Enable(bool enable);
|
||||
virtual int set_routing_mode(RoutingMode mode);
|
||||
virtual RoutingMode routing_mode() const;
|
||||
virtual int enable_comfort_noise(bool enable);
|
||||
virtual bool is_comfort_noise_enabled() const;
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual void* CreateHandle() const;
|
||||
virtual int InitializeHandle(void* handle) const;
|
||||
//virtual int InitializeHandles(
|
||||
// const std::vector<void*>& handles) const;
|
||||
virtual int ConfigureHandle(void* handle) const;
|
||||
virtual int DestroyHandle(void* handle) const;
|
||||
virtual int num_handles_required() const;
|
||||
virtual int TranslateError(int err) const;
|
||||
|
||||
const AudioProcessingImpl* apm_;
|
||||
RoutingMode routing_mode_;
|
||||
bool comfort_noise_enabled_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_ECHO_CONTROL_MOBILE_IMPL_H_
|
||||
445
modules/audio_processing/main/source/gain_control_impl.cc
Normal file
445
modules/audio_processing/main/source/gain_control_impl.cc
Normal file
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "gain_control_impl.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "critical_section_wrapper.h"
|
||||
#include "gain_control.h"
|
||||
|
||||
#include "audio_processing_impl.h"
|
||||
#include "audio_buffer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
typedef void Handle;
|
||||
|
||||
/*template <class T>
|
||||
class GainControlHandle : public ComponentHandle<T> {
|
||||
public:
|
||||
GainControlHandle();
|
||||
virtual ~GainControlHandle();
|
||||
|
||||
virtual int Create();
|
||||
virtual T* ptr() const;
|
||||
|
||||
private:
|
||||
T* handle;
|
||||
};*/
|
||||
|
||||
namespace {
|
||||
WebRtc_Word16 MapSetting(GainControl::Mode mode) {
|
||||
switch (mode) {
|
||||
case GainControl::kAdaptiveAnalog:
|
||||
return kAgcModeAdaptiveAnalog;
|
||||
break;
|
||||
case GainControl::kAdaptiveDigital:
|
||||
return kAgcModeAdaptiveDigital;
|
||||
break;
|
||||
case GainControl::kFixedDigital:
|
||||
return kAgcModeFixedDigital;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
GainControlImpl::GainControlImpl(const AudioProcessingImpl* apm)
|
||||
: ProcessingComponent(apm),
|
||||
apm_(apm),
|
||||
mode_(kAdaptiveAnalog),
|
||||
minimum_capture_level_(0),
|
||||
maximum_capture_level_(255),
|
||||
limiter_enabled_(true),
|
||||
target_level_dbfs_(3),
|
||||
compression_gain_db_(9),
|
||||
analog_capture_level_(0),
|
||||
was_analog_level_set_(false),
|
||||
stream_is_saturated_(false) {}
|
||||
|
||||
GainControlImpl::~GainControlImpl() {}
|
||||
|
||||
int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) {
|
||||
if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
assert(audio->samples_per_split_channel() <= 160);
|
||||
|
||||
WebRtc_Word16* mixed_data = audio->low_pass_split_data(0);
|
||||
if (audio->num_channels() > 1) {
|
||||
audio->CopyAndMixLowPass(1);
|
||||
mixed_data = audio->mixed_low_pass_data(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_handles(); i++) {
|
||||
int err = WebRtcAgc_AddFarend(
|
||||
static_cast<Handle*>(handle(i)),
|
||||
mixed_data,
|
||||
static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
|
||||
if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
assert(audio->samples_per_split_channel() <= 160);
|
||||
assert(audio->num_channels() == num_handles());
|
||||
|
||||
int err = apm_->kNoError;
|
||||
|
||||
if (mode_ == kAdaptiveAnalog) {
|
||||
for (int i = 0; i < num_handles(); i++) {
|
||||
err = WebRtcAgc_AddMic(
|
||||
static_cast<Handle*>(handle(i)),
|
||||
audio->low_pass_split_data(i),
|
||||
audio->high_pass_split_data(i),
|
||||
static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
}
|
||||
} else if (mode_ == kAdaptiveDigital) {
|
||||
|
||||
for (int i = 0; i < num_handles(); i++) {
|
||||
WebRtc_Word32 capture_level_out = 0;
|
||||
err = WebRtcAgc_VirtualMic(
|
||||
static_cast<Handle*>(handle(i)),
|
||||
audio->low_pass_split_data(i),
|
||||
audio->high_pass_split_data(i),
|
||||
static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
|
||||
//capture_levels_[i],
|
||||
analog_capture_level_,
|
||||
&capture_level_out);
|
||||
capture_levels_[i] = capture_level_out;
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) {
|
||||
if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
|
||||
return apm_->kStreamParameterNotSetError;
|
||||
}
|
||||
|
||||
assert(audio->samples_per_split_channel() <= 160);
|
||||
assert(audio->num_channels() == num_handles());
|
||||
|
||||
stream_is_saturated_ = false;
|
||||
for (int i = 0; i < num_handles(); i++) {
|
||||
WebRtc_Word32 capture_level_out = 0;
|
||||
WebRtc_UWord8 saturation_warning = 0;
|
||||
|
||||
int err = WebRtcAgc_Process(
|
||||
static_cast<Handle*>(handle(i)),
|
||||
audio->low_pass_split_data(i),
|
||||
audio->high_pass_split_data(i),
|
||||
static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
|
||||
audio->low_pass_split_data(i),
|
||||
audio->high_pass_split_data(i),
|
||||
capture_levels_[i],
|
||||
&capture_level_out,
|
||||
apm_->echo_cancellation()->stream_has_echo(),
|
||||
&saturation_warning);
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
|
||||
capture_levels_[i] = capture_level_out;
|
||||
if (saturation_warning == 1) {
|
||||
stream_is_saturated_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode_ == kAdaptiveAnalog) {
|
||||
// Take the analog level to be the average across the handles.
|
||||
analog_capture_level_ = 0;
|
||||
for (int i = 0; i < num_handles(); i++) {
|
||||
analog_capture_level_ += capture_levels_[i];
|
||||
}
|
||||
|
||||
analog_capture_level_ /= num_handles();
|
||||
}
|
||||
|
||||
was_analog_level_set_ = false;
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
// TODO(ajm): ensure this is called under kAdaptiveAnalog.
|
||||
int GainControlImpl::set_stream_analog_level(int level) {
|
||||
was_analog_level_set_ = true;
|
||||
if (level < minimum_capture_level_ || level > maximum_capture_level_) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
if (mode_ == kAdaptiveAnalog) {
|
||||
if (level != analog_capture_level_) {
|
||||
// The analog level has been changed; update our internal levels.
|
||||
capture_levels_.assign(num_handles(), level);
|
||||
}
|
||||
}
|
||||
analog_capture_level_ = level;
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int GainControlImpl::stream_analog_level() {
|
||||
// TODO(ajm): enable this assertion?
|
||||
//assert(mode_ == kAdaptiveAnalog);
|
||||
|
||||
return analog_capture_level_;
|
||||
}
|
||||
|
||||
int GainControlImpl::Enable(bool enable) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
return EnableComponent(enable);
|
||||
}
|
||||
|
||||
bool GainControlImpl::is_enabled() const {
|
||||
return is_component_enabled();
|
||||
}
|
||||
|
||||
int GainControlImpl::set_mode(Mode mode) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
if (mode != kAdaptiveAnalog &&
|
||||
mode != kAdaptiveDigital &&
|
||||
mode != kFixedDigital) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
mode_ = mode;
|
||||
return Initialize();
|
||||
}
|
||||
|
||||
GainControl::Mode GainControlImpl::mode() const {
|
||||
return mode_;
|
||||
}
|
||||
|
||||
int GainControlImpl::set_analog_level_limits(int minimum,
|
||||
int maximum) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
if (minimum < 0) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
if (maximum > 65535) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
if (maximum < minimum) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
minimum_capture_level_ = minimum;
|
||||
maximum_capture_level_ = maximum;
|
||||
|
||||
return Initialize();
|
||||
}
|
||||
|
||||
int GainControlImpl::analog_level_minimum() const {
|
||||
return minimum_capture_level_;
|
||||
}
|
||||
|
||||
int GainControlImpl::analog_level_maximum() const {
|
||||
return maximum_capture_level_;
|
||||
}
|
||||
|
||||
bool GainControlImpl::stream_is_saturated() const {
|
||||
return stream_is_saturated_;
|
||||
}
|
||||
|
||||
int GainControlImpl::set_target_level_dbfs(int level) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
if (level > 31 || level < 0) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
target_level_dbfs_ = level;
|
||||
return Configure();
|
||||
}
|
||||
|
||||
int GainControlImpl::target_level_dbfs() const {
|
||||
return target_level_dbfs_;
|
||||
}
|
||||
|
||||
int GainControlImpl::set_compression_gain_db(int gain) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
if (gain < 0 || gain > 90) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
compression_gain_db_ = gain;
|
||||
return Configure();
|
||||
}
|
||||
|
||||
int GainControlImpl::compression_gain_db() const {
|
||||
return compression_gain_db_;
|
||||
}
|
||||
|
||||
int GainControlImpl::enable_limiter(bool enable) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
limiter_enabled_ = enable;
|
||||
return Configure();
|
||||
}
|
||||
|
||||
bool GainControlImpl::is_limiter_enabled() const {
|
||||
return limiter_enabled_;
|
||||
}
|
||||
|
||||
int GainControlImpl::Initialize() {
|
||||
int err = ProcessingComponent::Initialize();
|
||||
if (err != apm_->kNoError || !is_component_enabled()) {
|
||||
return err;
|
||||
}
|
||||
|
||||
analog_capture_level_ =
|
||||
(maximum_capture_level_ - minimum_capture_level_) >> 1;
|
||||
capture_levels_.assign(num_handles(), analog_capture_level_);
|
||||
was_analog_level_set_ = false;
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int GainControlImpl::get_version(char* version, int version_len_bytes) const {
|
||||
if (WebRtcAgc_Version(version, version_len_bytes) != 0) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
void* GainControlImpl::CreateHandle() const {
|
||||
Handle* handle = NULL;
|
||||
if (WebRtcAgc_Create(&handle) != apm_->kNoError) {
|
||||
handle = NULL;
|
||||
} else {
|
||||
assert(handle != NULL);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int GainControlImpl::DestroyHandle(void* handle) const {
|
||||
return WebRtcAgc_Free(static_cast<Handle*>(handle));
|
||||
}
|
||||
|
||||
int GainControlImpl::InitializeHandle(void* handle) const {
|
||||
return WebRtcAgc_Init(static_cast<Handle*>(handle),
|
||||
minimum_capture_level_,
|
||||
maximum_capture_level_,
|
||||
MapSetting(mode_),
|
||||
apm_->sample_rate_hz());
|
||||
}
|
||||
|
||||
/*int GainControlImpl::InitializeHandles(const vector<void*>& handles)
|
||||
const {
|
||||
int err = apm_->kNoError;
|
||||
|
||||
err = WebRtcAgc_Init(static_cast<Handle*>(handles[0]),
|
||||
minimum_capture_level_,
|
||||
maximum_capture_level_,
|
||||
mode_,
|
||||
apm_->SampleRateHz());
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < num_handles(); i++) {
|
||||
WebRtcAgc_Init(static_cast<Handle*>(handles[i]),
|
||||
minimum_capture_level_,
|
||||
maximum_capture_level_,
|
||||
kFixedDigital,
|
||||
apm_->SampleRateHz());
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}*/
|
||||
|
||||
int GainControlImpl::ConfigureHandle(void* handle) const {
|
||||
WebRtcAgc_config_t config;
|
||||
// TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
|
||||
// change the interface.
|
||||
//assert(target_level_dbfs_ <= 0);
|
||||
//config.targetLevelDbfs = static_cast<WebRtc_Word16>(-target_level_dbfs_);
|
||||
config.targetLevelDbfs = static_cast<WebRtc_Word16>(target_level_dbfs_);
|
||||
config.compressionGaindB =
|
||||
static_cast<WebRtc_Word16>(compression_gain_db_);
|
||||
config.limiterEnable = limiter_enabled_;
|
||||
|
||||
return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
|
||||
}
|
||||
|
||||
int GainControlImpl::num_handles_required() const {
|
||||
return apm_->num_output_channels();
|
||||
}
|
||||
|
||||
/*int GainControlImpl::GetConfiguration() {
|
||||
if (!initialized_) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
WebRtcAgc_config_t config;
|
||||
int err = WebRtcAgc_get_config(handle_, &config);
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
|
||||
if (config.targetLevelDbfs < 0) {
|
||||
return apm_->kUnspecifiedError;
|
||||
}
|
||||
target_level_dbfs_ = config.targetLevelDbfs;
|
||||
|
||||
if (config.compressionGaindB < 0) {
|
||||
return apm_->kUnspecifiedError;
|
||||
}
|
||||
compression_gain_db_ = config.compressionGaindB;
|
||||
|
||||
if (config.limiterEnable == 0) {
|
||||
limiter_enabled_ = false;
|
||||
} else if (config.limiterEnable == 1) {
|
||||
limiter_enabled_ = true;
|
||||
} else {
|
||||
return apm_->kUnspecifiedError;
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}*/
|
||||
|
||||
// TODO(ajm): implement
|
||||
int GainControlImpl::TranslateError(int /*err*/) const {
|
||||
return -1;
|
||||
}
|
||||
} // namespace webrtc
|
||||
82
modules/audio_processing/main/source/gain_control_impl.h
Normal file
82
modules/audio_processing/main/source/gain_control_impl.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_GAIN_CONTROL_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_GAIN_CONTROL_IMPL_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "audio_processing.h"
|
||||
#include "processing_component.h"
|
||||
|
||||
namespace webrtc {
|
||||
class AudioProcessingImpl;
|
||||
class AudioBuffer;
|
||||
|
||||
class GainControlImpl : public GainControl,
|
||||
public ProcessingComponent {
|
||||
public:
|
||||
explicit GainControlImpl(const AudioProcessingImpl* apm);
|
||||
virtual ~GainControlImpl();
|
||||
|
||||
int ProcessRenderAudio(AudioBuffer* audio);
|
||||
int AnalyzeCaptureAudio(AudioBuffer* audio);
|
||||
int ProcessCaptureAudio(AudioBuffer* audio);
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual int Initialize();
|
||||
virtual int get_version(char* version, int version_len_bytes) const;
|
||||
|
||||
// GainControl implementation.
|
||||
virtual bool is_enabled() const;
|
||||
|
||||
private:
|
||||
// GainControl implementation.
|
||||
virtual int Enable(bool enable);
|
||||
virtual int set_stream_analog_level(int level);
|
||||
virtual int stream_analog_level();
|
||||
virtual int set_mode(Mode mode);
|
||||
virtual Mode mode() const;
|
||||
virtual int set_target_level_dbfs(int level);
|
||||
virtual int target_level_dbfs() const;
|
||||
virtual int set_compression_gain_db(int gain);
|
||||
virtual int compression_gain_db() const;
|
||||
virtual int enable_limiter(bool enable);
|
||||
virtual bool is_limiter_enabled() const;
|
||||
virtual int set_analog_level_limits(int minimum, int maximum);
|
||||
virtual int analog_level_minimum() const;
|
||||
virtual int analog_level_maximum() const;
|
||||
virtual bool stream_is_saturated() const;
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual void* CreateHandle() const;
|
||||
virtual int InitializeHandle(void* handle) const;
|
||||
//virtual int InitializeHandles(
|
||||
// const std::vector<void*>& handles) const;
|
||||
virtual int ConfigureHandle(void* handle) const;
|
||||
virtual int DestroyHandle(void* handle) const;
|
||||
virtual int num_handles_required() const;
|
||||
virtual int TranslateError(int err) const;
|
||||
|
||||
const AudioProcessingImpl* apm_;
|
||||
Mode mode_;
|
||||
int minimum_capture_level_;
|
||||
int maximum_capture_level_;
|
||||
bool limiter_enabled_;
|
||||
int target_level_dbfs_;
|
||||
int compression_gain_db_;
|
||||
std::vector<int> capture_levels_;
|
||||
int analog_capture_level_;
|
||||
bool was_analog_level_set_;
|
||||
bool stream_is_saturated_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_GAIN_CONTROL_IMPL_H_
|
||||
195
modules/audio_processing/main/source/high_pass_filter_impl.cc
Normal file
195
modules/audio_processing/main/source/high_pass_filter_impl.cc
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "high_pass_filter_impl.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "critical_section_wrapper.h"
|
||||
#include "typedefs.h"
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "audio_processing_impl.h"
|
||||
#include "audio_buffer.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
const WebRtc_Word16 kFilterCoefficients8kHz[5] =
|
||||
{3798, -7596, 3798, 7807, -3733};
|
||||
|
||||
const WebRtc_Word16 kFilterCoefficients[5] =
|
||||
{4012, -8024, 4012, 8002, -3913};
|
||||
|
||||
struct FilterState {
|
||||
WebRtc_Word16 y[4];
|
||||
WebRtc_Word16 x[2];
|
||||
const WebRtc_Word16* ba;
|
||||
};
|
||||
|
||||
int InitializeFilter(FilterState* hpf, int sample_rate_hz) {
|
||||
assert(hpf != NULL);
|
||||
|
||||
if (sample_rate_hz == AudioProcessingImpl::kSampleRate8kHz) {
|
||||
hpf->ba = kFilterCoefficients8kHz;
|
||||
} else {
|
||||
hpf->ba = kFilterCoefficients;
|
||||
}
|
||||
|
||||
WebRtcSpl_MemSetW16(hpf->x, 0, 2);
|
||||
WebRtcSpl_MemSetW16(hpf->y, 0, 4);
|
||||
|
||||
return AudioProcessing::kNoError;
|
||||
}
|
||||
|
||||
int Filter(FilterState* hpf, WebRtc_Word16* data, int length) {
|
||||
assert(hpf != NULL);
|
||||
|
||||
WebRtc_Word32 tmp_int32 = 0;
|
||||
WebRtc_Word16* y = hpf->y;
|
||||
WebRtc_Word16* x = hpf->x;
|
||||
const WebRtc_Word16* ba = hpf->ba;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
// y[i] = b[0] * x[i] + b[1] * x[i-1] + b[2] * x[i-2]
|
||||
// + -a[1] * y[i-1] + -a[2] * y[i-2];
|
||||
|
||||
tmp_int32 =
|
||||
WEBRTC_SPL_MUL_16_16(y[1], ba[3]); // -a[1] * y[i-1] (low part)
|
||||
tmp_int32 +=
|
||||
WEBRTC_SPL_MUL_16_16(y[3], ba[4]); // -a[2] * y[i-2] (low part)
|
||||
tmp_int32 = (tmp_int32 >> 15);
|
||||
tmp_int32 +=
|
||||
WEBRTC_SPL_MUL_16_16(y[0], ba[3]); // -a[1] * y[i-1] (high part)
|
||||
tmp_int32 +=
|
||||
WEBRTC_SPL_MUL_16_16(y[2], ba[4]); // -a[2] * y[i-2] (high part)
|
||||
tmp_int32 = (tmp_int32 << 1);
|
||||
|
||||
tmp_int32 += WEBRTC_SPL_MUL_16_16(data[i], ba[0]); // b[0]*x[0]
|
||||
tmp_int32 += WEBRTC_SPL_MUL_16_16(x[0], ba[1]); // b[1]*x[i-1]
|
||||
tmp_int32 += WEBRTC_SPL_MUL_16_16(x[1], ba[2]); // b[2]*x[i-2]
|
||||
|
||||
// Update state (input part)
|
||||
x[1] = x[0];
|
||||
x[0] = data[i];
|
||||
|
||||
// Update state (filtered part)
|
||||
y[2] = y[0];
|
||||
y[3] = y[1];
|
||||
y[0] = static_cast<WebRtc_Word16>(tmp_int32 >> 13);
|
||||
y[1] = static_cast<WebRtc_Word16>((tmp_int32 -
|
||||
WEBRTC_SPL_LSHIFT_W32(static_cast<WebRtc_Word32>(y[0]), 13)) << 2);
|
||||
|
||||
// Rounding in Q12, i.e. add 2^11
|
||||
tmp_int32 += 2048;
|
||||
|
||||
// Saturate (to 2^27) so that the HP filtered signal does not overflow
|
||||
tmp_int32 = WEBRTC_SPL_SAT(static_cast<WebRtc_Word32>(134217727),
|
||||
tmp_int32,
|
||||
static_cast<WebRtc_Word32>(-134217728));
|
||||
|
||||
// Convert back to Q0 and use rounding
|
||||
data[i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp_int32, 12);
|
||||
|
||||
}
|
||||
|
||||
return AudioProcessing::kNoError;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
typedef FilterState Handle;
|
||||
|
||||
HighPassFilterImpl::HighPassFilterImpl(const AudioProcessingImpl* apm)
|
||||
: ProcessingComponent(apm),
|
||||
apm_(apm) {}
|
||||
|
||||
HighPassFilterImpl::~HighPassFilterImpl() {}
|
||||
|
||||
int HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) {
|
||||
int err = apm_->kNoError;
|
||||
|
||||
if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
assert(audio->samples_per_split_channel() <= 160);
|
||||
|
||||
for (int i = 0; i < num_handles(); i++) {
|
||||
err = Filter(static_cast<Handle*>(handle(i)),
|
||||
audio->low_pass_split_data(i),
|
||||
audio->samples_per_split_channel());
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
//return TranslateError(err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int HighPassFilterImpl::Enable(bool enable) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
return EnableComponent(enable);
|
||||
}
|
||||
|
||||
bool HighPassFilterImpl::is_enabled() const {
|
||||
return is_component_enabled();
|
||||
}
|
||||
|
||||
int HighPassFilterImpl::get_version(char* version,
|
||||
int version_len_bytes) const {
|
||||
// An empty string is used to indicate no version information.
|
||||
memset(version, 0, version_len_bytes);
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
void* HighPassFilterImpl::CreateHandle() const {
|
||||
return new FilterState;
|
||||
}
|
||||
|
||||
int HighPassFilterImpl::DestroyHandle(void* handle) const {
|
||||
delete static_cast<Handle*>(handle);
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int HighPassFilterImpl::InitializeHandle(void* handle) const {
|
||||
return InitializeFilter(static_cast<Handle*>(handle),
|
||||
apm_->sample_rate_hz());
|
||||
}
|
||||
|
||||
/*int HighPassFilterImpl::InitializeHandles(
|
||||
const vector<void*>& handles) const {
|
||||
int err = apm_->kNoError;
|
||||
|
||||
for (size_t i = 0; i < num_handles(); i++) {
|
||||
err = InitializeFilter(static_cast<Handle*>(handles[i]),
|
||||
apm_->SampleRateHz());
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}*/
|
||||
|
||||
int HighPassFilterImpl::ConfigureHandle(void* /*handle*/) const {
|
||||
return apm_->kNoError; // Not configurable.
|
||||
}
|
||||
|
||||
int HighPassFilterImpl::num_handles_required() const {
|
||||
return apm_->num_output_channels();
|
||||
}
|
||||
|
||||
// TODO(ajm): implement
|
||||
int HighPassFilterImpl::TranslateError(int /*err*/) const {
|
||||
return -1;
|
||||
}
|
||||
} // namespace webrtc
|
||||
54
modules/audio_processing/main/source/high_pass_filter_impl.h
Normal file
54
modules/audio_processing/main/source/high_pass_filter_impl.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_HIGH_PASS_FILTER_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_HIGH_PASS_FILTER_IMPL_H_
|
||||
|
||||
#include "audio_processing.h"
|
||||
#include "processing_component.h"
|
||||
|
||||
namespace webrtc {
|
||||
class AudioProcessingImpl;
|
||||
class AudioBuffer;
|
||||
|
||||
class HighPassFilterImpl : public HighPassFilter,
|
||||
public ProcessingComponent {
|
||||
public:
|
||||
explicit HighPassFilterImpl(const AudioProcessingImpl* apm);
|
||||
virtual ~HighPassFilterImpl();
|
||||
|
||||
int ProcessCaptureAudio(AudioBuffer* audio);
|
||||
|
||||
// HighPassFilter implementation.
|
||||
virtual bool is_enabled() const;
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual int get_version(char* version, int version_len_bytes) const;
|
||||
|
||||
private:
|
||||
// HighPassFilter implementation.
|
||||
virtual int Enable(bool enable);
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual void* CreateHandle() const;
|
||||
virtual int InitializeHandle(void* handle) const;
|
||||
//virtual int InitializeHandles(
|
||||
// const std::vector<void*>& handles) const;
|
||||
virtual int ConfigureHandle(void* handle) const;
|
||||
virtual int DestroyHandle(void* handle) const;
|
||||
virtual int num_handles_required() const;
|
||||
virtual int TranslateError(int err) const;
|
||||
//virtual int GetConfiguration();
|
||||
|
||||
const AudioProcessingImpl* apm_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_HIGH_PASS_FILTER_IMPL_H_
|
||||
197
modules/audio_processing/main/source/level_estimator_impl.cc
Normal file
197
modules/audio_processing/main/source/level_estimator_impl.cc
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "level_estimator_impl.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "critical_section_wrapper.h"
|
||||
|
||||
#include "audio_processing_impl.h"
|
||||
#include "audio_buffer.h"
|
||||
|
||||
// TODO(ajm): implement the underlying level estimator component.
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
typedef void Handle;
|
||||
|
||||
namespace {
|
||||
|
||||
/*int EstimateLevel(AudioBuffer* audio, Handle* my_handle) {
|
||||
assert(audio->samples_per_split_channel() <= 160);
|
||||
|
||||
WebRtc_Word16* mixed_data = audio->low_pass_split_data(0);
|
||||
if (audio->num_channels() > 1) {
|
||||
audio->CopyAndMixLowPass(1);
|
||||
mixed_data = audio->mixed_low_pass_data(0);
|
||||
}
|
||||
|
||||
int err = UpdateLvlEst(my_handle,
|
||||
mixed_data,
|
||||
audio->samples_per_split_channel());
|
||||
if (err != AudioProcessing::kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
|
||||
return AudioProcessing::kNoError;
|
||||
}
|
||||
|
||||
int GetMetricsLocal(Handle* my_handle, LevelEstimator::Metrics* metrics) {
|
||||
level_t levels;
|
||||
memset(&levels, 0, sizeof(levels));
|
||||
|
||||
int err = ExportLevels(my_handle, &levels, 2);
|
||||
if (err != AudioProcessing::kNoError) {
|
||||
return err;
|
||||
}
|
||||
metrics->signal.instant = levels.instant;
|
||||
metrics->signal.average = levels.average;
|
||||
metrics->signal.maximum = levels.max;
|
||||
metrics->signal.minimum = levels.min;
|
||||
|
||||
err = ExportLevels(my_handle, &levels, 1);
|
||||
if (err != AudioProcessing::kNoError) {
|
||||
return err;
|
||||
}
|
||||
metrics->speech.instant = levels.instant;
|
||||
metrics->speech.average = levels.average;
|
||||
metrics->speech.maximum = levels.max;
|
||||
metrics->speech.minimum = levels.min;
|
||||
|
||||
err = ExportLevels(my_handle, &levels, 0);
|
||||
if (err != AudioProcessing::kNoError) {
|
||||
return err;
|
||||
}
|
||||
metrics->noise.instant = levels.instant;
|
||||
metrics->noise.average = levels.average;
|
||||
metrics->noise.maximum = levels.max;
|
||||
metrics->noise.minimum = levels.min;
|
||||
|
||||
return AudioProcessing::kNoError;
|
||||
}*/
|
||||
} // namespace
|
||||
|
||||
LevelEstimatorImpl::LevelEstimatorImpl(const AudioProcessingImpl* apm)
|
||||
: ProcessingComponent(apm),
|
||||
apm_(apm) {}
|
||||
|
||||
LevelEstimatorImpl::~LevelEstimatorImpl() {}
|
||||
|
||||
int LevelEstimatorImpl::AnalyzeReverseStream(AudioBuffer* audio) {
|
||||
return apm_->kUnsupportedComponentError;
|
||||
/*if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
return EstimateLevel(audio, static_cast<Handle*>(handle(1)));*/
|
||||
}
|
||||
|
||||
int LevelEstimatorImpl::ProcessCaptureAudio(AudioBuffer* audio) {
|
||||
return apm_->kUnsupportedComponentError;
|
||||
/*if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
return EstimateLevel(audio, static_cast<Handle*>(handle(0)));*/
|
||||
}
|
||||
|
||||
int LevelEstimatorImpl::Enable(bool enable) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
return apm_->kUnsupportedComponentError;
|
||||
//return EnableComponent(enable);
|
||||
}
|
||||
|
||||
bool LevelEstimatorImpl::is_enabled() const {
|
||||
return is_component_enabled();
|
||||
}
|
||||
|
||||
int LevelEstimatorImpl::GetMetrics(LevelEstimator::Metrics* metrics,
|
||||
LevelEstimator::Metrics* reverse_metrics) {
|
||||
return apm_->kUnsupportedComponentError;
|
||||
/*if (!is_component_enabled()) {
|
||||
return apm_->kNotEnabledError;
|
||||
}
|
||||
|
||||
int err = GetMetricsLocal(static_cast<Handle*>(handle(0)), metrics);
|
||||
if (err != apm_->kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = GetMetricsLocal(static_cast<Handle*>(handle(1)), reverse_metrics);
|
||||
if (err != apm_->kNoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return apm_->kNoError;*/
|
||||
}
|
||||
|
||||
int LevelEstimatorImpl::get_version(char* version,
|
||||
int version_len_bytes) const {
|
||||
// An empty string is used to indicate no version information.
|
||||
memset(version, 0, version_len_bytes);
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
void* LevelEstimatorImpl::CreateHandle() const {
|
||||
Handle* handle = NULL;
|
||||
/*if (CreateLvlEst(&handle) != apm_->kNoError) {
|
||||
handle = NULL;
|
||||
} else {
|
||||
assert(handle != NULL);
|
||||
}*/
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int LevelEstimatorImpl::DestroyHandle(void* handle) const {
|
||||
return apm_->kUnsupportedComponentError;
|
||||
//return FreeLvlEst(static_cast<Handle*>(handle));
|
||||
}
|
||||
|
||||
int LevelEstimatorImpl::InitializeHandle(void* handle) const {
|
||||
return apm_->kUnsupportedComponentError;
|
||||
/*const double kIntervalSeconds = 1.5;
|
||||
return InitLvlEst(static_cast<Handle*>(handle),
|
||||
apm_->sample_rate_hz(),
|
||||
kIntervalSeconds);*/
|
||||
}
|
||||
|
||||
/*int LevelEstimatorImpl::InitializeHandles(
|
||||
const vector<void*>& handles) const {
|
||||
int err = apm_->kNoError;
|
||||
|
||||
for (size_t i = 0; i < num_handles(); i++) {
|
||||
err = InitLvlEst(static_cast<Handle*>(handles[i]), apm_->SampleRateHz());
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}*/
|
||||
|
||||
int LevelEstimatorImpl::ConfigureHandle(void* /*handle*/) const {
|
||||
return apm_->kUnsupportedComponentError;
|
||||
//return apm_->kNoError;
|
||||
}
|
||||
|
||||
int LevelEstimatorImpl::num_handles_required() const {
|
||||
return apm_->kUnsupportedComponentError;
|
||||
//return 2;
|
||||
}
|
||||
|
||||
//int LevelEstimatorImpl::GetConfiguration() {
|
||||
// // There are no configuration accessors.
|
||||
// return apm_->kUnsupportedFunctionError;
|
||||
//}
|
||||
|
||||
} // namespace webrtc
|
||||
55
modules/audio_processing/main/source/level_estimator_impl.h
Normal file
55
modules/audio_processing/main/source/level_estimator_impl.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_LEVEL_ESTIMATOR_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_LEVEL_ESTIMATOR_IMPL_H_
|
||||
|
||||
#include "audio_processing.h"
|
||||
#include "processing_component.h"
|
||||
|
||||
namespace webrtc {
|
||||
class AudioProcessingImpl;
|
||||
class AudioBuffer;
|
||||
|
||||
class LevelEstimatorImpl : public LevelEstimator,
|
||||
public ProcessingComponent {
|
||||
public:
|
||||
explicit LevelEstimatorImpl(const AudioProcessingImpl* apm);
|
||||
virtual ~LevelEstimatorImpl();
|
||||
|
||||
int AnalyzeReverseStream(AudioBuffer* audio);
|
||||
int ProcessCaptureAudio(AudioBuffer* audio);
|
||||
|
||||
// LevelEstimator implementation.
|
||||
virtual bool is_enabled() const;
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual int get_version(char* version, int version_len_bytes) const;
|
||||
|
||||
private:
|
||||
// LevelEstimator implementation.
|
||||
virtual int Enable(bool enable);
|
||||
virtual int GetMetrics(Metrics* metrics, Metrics* reverse_metrics);
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual void* CreateHandle() const;
|
||||
virtual int InitializeHandle(void* handle) const;
|
||||
//virtual int InitializeHandles(
|
||||
// const std::vector<void*>& handles) const;
|
||||
virtual int ConfigureHandle(void* handle) const;
|
||||
virtual int DestroyHandle(void* handle) const;
|
||||
virtual int num_handles_required() const;
|
||||
//virtual int TranslateError(int err) const;
|
||||
|
||||
const AudioProcessingImpl* apm_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_LEVEL_ESTIMATOR_IMPL_H_
|
||||
180
modules/audio_processing/main/source/noise_suppression_impl.cc
Normal file
180
modules/audio_processing/main/source/noise_suppression_impl.cc
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "noise_suppression_impl.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "critical_section_wrapper.h"
|
||||
#if defined(WEBRTC_NS_FLOAT)
|
||||
#include "noise_suppression.h"
|
||||
#elif defined(WEBRTC_NS_FIXED)
|
||||
#include "noise_suppression_x.h"
|
||||
#endif
|
||||
|
||||
#include "audio_processing_impl.h"
|
||||
#include "audio_buffer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
#if defined(WEBRTC_NS_FLOAT)
|
||||
typedef NsHandle Handle;
|
||||
#elif defined(WEBRTC_NS_FIXED)
|
||||
typedef NsxHandle Handle;
|
||||
#endif
|
||||
|
||||
NoiseSuppressionImpl::NoiseSuppressionImpl(const AudioProcessingImpl* apm)
|
||||
: ProcessingComponent(apm),
|
||||
apm_(apm),
|
||||
level_(kModerate) {}
|
||||
|
||||
NoiseSuppressionImpl::~NoiseSuppressionImpl() {}
|
||||
|
||||
int NoiseSuppressionImpl::ProcessCaptureAudio(AudioBuffer* audio) {
|
||||
int err = apm_->kNoError;
|
||||
|
||||
if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
assert(audio->samples_per_split_channel() <= 160);
|
||||
assert(audio->num_channels() == num_handles());
|
||||
|
||||
for (int i = 0; i < num_handles(); i++) {
|
||||
#if defined(WEBRTC_NS_FLOAT)
|
||||
err = WebRtcNs_Process(static_cast<Handle*>(handle(i)),
|
||||
audio->low_pass_split_data(i),
|
||||
audio->high_pass_split_data(i),
|
||||
audio->low_pass_split_data(i),
|
||||
audio->high_pass_split_data(i));
|
||||
#elif defined(WEBRTC_NS_FIXED)
|
||||
err = WebRtcNsx_Process(static_cast<Handle*>(handle(i)),
|
||||
audio->low_pass_split_data(i),
|
||||
audio->high_pass_split_data(i),
|
||||
audio->low_pass_split_data(i),
|
||||
audio->high_pass_split_data(i));
|
||||
#endif
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int NoiseSuppressionImpl::Enable(bool enable) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
return EnableComponent(enable);
|
||||
}
|
||||
|
||||
bool NoiseSuppressionImpl::is_enabled() const {
|
||||
return is_component_enabled();
|
||||
}
|
||||
|
||||
int NoiseSuppressionImpl::set_level(Level level) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
if (level != kLow &&
|
||||
level != kModerate &&
|
||||
level != kHigh &&
|
||||
level != kVeryHigh) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
level_ = level;
|
||||
return Configure();
|
||||
}
|
||||
|
||||
NoiseSuppression::Level NoiseSuppressionImpl::level() const {
|
||||
return level_;
|
||||
}
|
||||
|
||||
int NoiseSuppressionImpl::get_version(char* version,
|
||||
int version_len_bytes) const {
|
||||
#if defined(WEBRTC_NS_FLOAT)
|
||||
if (WebRtcNs_get_version(version, version_len_bytes) != 0)
|
||||
#elif defined(WEBRTC_NS_FIXED)
|
||||
if (WebRtcNsx_get_version(version, version_len_bytes) != 0)
|
||||
#endif
|
||||
{
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
void* NoiseSuppressionImpl::CreateHandle() const {
|
||||
Handle* handle = NULL;
|
||||
#if defined(WEBRTC_NS_FLOAT)
|
||||
if (WebRtcNs_Create(&handle) != apm_->kNoError)
|
||||
#elif defined(WEBRTC_NS_FIXED)
|
||||
if (WebRtcNsx_Create(&handle) != apm_->kNoError)
|
||||
#endif
|
||||
{
|
||||
handle = NULL;
|
||||
} else {
|
||||
assert(handle != NULL);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int NoiseSuppressionImpl::DestroyHandle(void* handle) const {
|
||||
#if defined(WEBRTC_NS_FLOAT)
|
||||
return WebRtcNs_Free(static_cast<Handle*>(handle));
|
||||
#elif defined(WEBRTC_NS_FIXED)
|
||||
return WebRtcNsx_Free(static_cast<Handle*>(handle));
|
||||
#endif
|
||||
}
|
||||
|
||||
int NoiseSuppressionImpl::InitializeHandle(void* handle) const {
|
||||
#if defined(WEBRTC_NS_FLOAT)
|
||||
return WebRtcNs_Init(static_cast<Handle*>(handle), apm_->sample_rate_hz());
|
||||
#elif defined(WEBRTC_NS_FIXED)
|
||||
return WebRtcNsx_Init(static_cast<Handle*>(handle), apm_->sample_rate_hz());
|
||||
#endif
|
||||
}
|
||||
|
||||
/*int NoiseSuppressionImpl::InitializeHandles(
|
||||
const vector<void*>& handles) const {
|
||||
int err = apm_->kNoError;
|
||||
|
||||
for (size_t i = 0; i < num_handles(); i++) {
|
||||
err = WebRtcNs_Init(static_cast<Handle*>(handles[i]), apm_->SampleRateHz());
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}*/
|
||||
|
||||
int NoiseSuppressionImpl::ConfigureHandle(void* handle) const {
|
||||
#if defined(WEBRTC_NS_FLOAT)
|
||||
return WebRtcNs_set_policy(static_cast<Handle*>(handle), level_);
|
||||
#elif defined(WEBRTC_NS_FIXED)
|
||||
return WebRtcNsx_set_policy(static_cast<Handle*>(handle), level_);
|
||||
#endif
|
||||
}
|
||||
|
||||
int NoiseSuppressionImpl::num_handles_required() const {
|
||||
return apm_->num_output_channels();
|
||||
}
|
||||
|
||||
//int NoiseSuppressionImpl::GetConfiguration() {
|
||||
// // There are no configuration accessors.
|
||||
// return apm_->kUnsupportedFunctionError;
|
||||
//}
|
||||
|
||||
// TODO(ajm): implement
|
||||
int NoiseSuppressionImpl::TranslateError(int /*err*/) const {
|
||||
return -1;
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_NOISE_SUPPRESSION_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_NOISE_SUPPRESSION_IMPL_H_
|
||||
|
||||
#include "audio_processing.h"
|
||||
#include "processing_component.h"
|
||||
|
||||
namespace webrtc {
|
||||
class AudioProcessingImpl;
|
||||
class AudioBuffer;
|
||||
|
||||
class NoiseSuppressionImpl : public NoiseSuppression,
|
||||
public ProcessingComponent {
|
||||
public:
|
||||
explicit NoiseSuppressionImpl(const AudioProcessingImpl* apm);
|
||||
virtual ~NoiseSuppressionImpl();
|
||||
|
||||
int ProcessCaptureAudio(AudioBuffer* audio);
|
||||
|
||||
// NoiseSuppression implementation.
|
||||
virtual bool is_enabled() const;
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual int get_version(char* version, int version_len_bytes) const;
|
||||
|
||||
private:
|
||||
// NoiseSuppression implementation.
|
||||
virtual int Enable(bool enable);
|
||||
virtual int set_level(Level level);
|
||||
virtual Level level() const;
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual void* CreateHandle() const;
|
||||
virtual int InitializeHandle(void* handle) const;
|
||||
//virtual int InitializeHandles(
|
||||
// const std::vector<void*>& handles) const;
|
||||
virtual int ConfigureHandle(void* handle) const;
|
||||
virtual int DestroyHandle(void* handle) const;
|
||||
virtual int num_handles_required() const;
|
||||
virtual int TranslateError(int err) const;
|
||||
|
||||
const AudioProcessingImpl* apm_;
|
||||
Level level_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_NOISE_SUPPRESSION_IMPL_H_
|
||||
118
modules/audio_processing/main/source/processing_component.cc
Normal file
118
modules/audio_processing/main/source/processing_component.cc
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "processing_component.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "audio_processing_impl.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
ProcessingComponent::ProcessingComponent(const AudioProcessingImpl* apm)
|
||||
: apm_(apm),
|
||||
initialized_(false),
|
||||
enabled_(false),
|
||||
num_handles_(0) {}
|
||||
|
||||
ProcessingComponent::~ProcessingComponent() {
|
||||
assert(initialized_ == false);
|
||||
}
|
||||
|
||||
int ProcessingComponent::Destroy() {
|
||||
while (!handles_.empty()) {
|
||||
DestroyHandle(handles_.back());
|
||||
handles_.pop_back();
|
||||
}
|
||||
initialized_ = false;
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int ProcessingComponent::EnableComponent(bool enable) {
|
||||
if (enable && !enabled_) {
|
||||
enabled_ = enable; // Must be set before Initialize() is called.
|
||||
|
||||
int err = Initialize();
|
||||
if (err != apm_->kNoError) {
|
||||
enabled_ = false;
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
enabled_ = enable;
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
bool ProcessingComponent::is_component_enabled() const {
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
void* ProcessingComponent::handle(int index) const {
|
||||
assert(index < num_handles_);
|
||||
return handles_[index];
|
||||
}
|
||||
|
||||
int ProcessingComponent::num_handles() const {
|
||||
return num_handles_;
|
||||
}
|
||||
|
||||
int ProcessingComponent::Initialize() {
|
||||
if (!enabled_) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
num_handles_ = num_handles_required();
|
||||
if (num_handles_ > static_cast<int>(handles_.size())) {
|
||||
handles_.resize(num_handles_, NULL);
|
||||
}
|
||||
|
||||
assert(static_cast<int>(handles_.size()) >= num_handles_);
|
||||
for (int i = 0; i < num_handles_; i++) {
|
||||
if (handles_[i] == NULL) {
|
||||
handles_[i] = CreateHandle();
|
||||
if (handles_[i] == NULL) {
|
||||
return apm_->kCreationFailedError;
|
||||
}
|
||||
}
|
||||
|
||||
int err = InitializeHandle(handles_[i]);
|
||||
if (err != apm_->kNoError) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
//int err = InitializeHandles(handles_);
|
||||
//if (err != apm_->kNoError) {
|
||||
// return TranslateError(err);
|
||||
//}
|
||||
|
||||
initialized_ = true;
|
||||
return Configure();
|
||||
}
|
||||
|
||||
int ProcessingComponent::Configure() {
|
||||
if (!initialized_) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
assert(static_cast<int>(handles_.size()) >= num_handles_);
|
||||
for (int i = 0; i < num_handles_; i++) {
|
||||
int err = ConfigureHandle(handles_[i]);
|
||||
if (err != apm_->kNoError) {
|
||||
// Try to get the current valid state.
|
||||
//GetConfiguration();
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
} // namespace webrtc
|
||||
68
modules/audio_processing/main/source/processing_component.h
Normal file
68
modules/audio_processing/main/source/processing_component.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_PROCESSING_COMPONENT_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_PROCESSING_COMPONENT_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "audio_processing.h"
|
||||
|
||||
namespace webrtc {
|
||||
class AudioProcessingImpl;
|
||||
|
||||
/*template <class T>
|
||||
class ComponentHandle {
|
||||
public:
|
||||
ComponentHandle();
|
||||
virtual ~ComponentHandle();
|
||||
|
||||
virtual int Create() = 0;
|
||||
virtual T* ptr() const = 0;
|
||||
};*/
|
||||
|
||||
class ProcessingComponent {
|
||||
public:
|
||||
explicit ProcessingComponent(const AudioProcessingImpl* apm);
|
||||
virtual ~ProcessingComponent();
|
||||
|
||||
virtual int Initialize();
|
||||
virtual int Destroy();
|
||||
virtual int get_version(char* version, int version_len_bytes) const = 0;
|
||||
|
||||
protected:
|
||||
virtual int Configure();
|
||||
int EnableComponent(bool enable);
|
||||
bool is_component_enabled() const;
|
||||
void* handle(int index) const;
|
||||
int num_handles() const;
|
||||
|
||||
// TODO(ajm): do we want this?
|
||||
//virtual int GetConfiguration() = 0;
|
||||
|
||||
private:
|
||||
virtual void* CreateHandle() const = 0;
|
||||
virtual int InitializeHandle(void* handle) const = 0;
|
||||
//virtual int InitializeHandles(
|
||||
// const std::vector<void*>& handles) const = 0;
|
||||
virtual int ConfigureHandle(void* handle) const = 0;
|
||||
virtual int DestroyHandle(void* handle) const = 0;
|
||||
virtual int num_handles_required() const = 0;
|
||||
//virtual int TranslateError(int err) const = 0;
|
||||
|
||||
const AudioProcessingImpl* apm_;
|
||||
std::vector<void*> handles_;
|
||||
bool initialized_;
|
||||
bool enabled_;
|
||||
int num_handles_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_PROCESSING_COMPONENT_H__
|
||||
33
modules/audio_processing/main/source/splitting_filter.cc
Normal file
33
modules/audio_processing/main/source/splitting_filter.cc
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "splitting_filter.h"
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
void SplittingFilterAnalysis(const WebRtc_Word16* in_data,
|
||||
WebRtc_Word16* low_band,
|
||||
WebRtc_Word16* high_band,
|
||||
WebRtc_Word32* filter_state1,
|
||||
WebRtc_Word32* filter_state2)
|
||||
{
|
||||
WebRtcSpl_AnalysisQMF(in_data, low_band, high_band, filter_state1, filter_state2);
|
||||
}
|
||||
|
||||
void SplittingFilterSynthesis(const WebRtc_Word16* low_band,
|
||||
const WebRtc_Word16* high_band,
|
||||
WebRtc_Word16* out_data,
|
||||
WebRtc_Word32* filt_state1,
|
||||
WebRtc_Word32* filt_state2)
|
||||
{
|
||||
WebRtcSpl_SynthesisQMF(low_band, high_band, out_data, filt_state1, filt_state2);
|
||||
}
|
||||
} // namespace webrtc
|
||||
63
modules/audio_processing/main/source/splitting_filter.h
Normal file
63
modules/audio_processing/main/source/splitting_filter.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_SPLITTING_FILTER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_SPLITTING_FILTER_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
namespace webrtc {
|
||||
/*
|
||||
* SplittingFilterbank_analysisQMF(...)
|
||||
*
|
||||
* Splits a super-wb signal into two subbands: 0-8 kHz and 8-16 kHz.
|
||||
*
|
||||
* Input:
|
||||
* - in_data : super-wb audio signal
|
||||
*
|
||||
* Input & Output:
|
||||
* - filt_state1: Filter state for first all-pass filter
|
||||
* - filt_state2: Filter state for second all-pass filter
|
||||
*
|
||||
* Output:
|
||||
* - low_band : The signal from the 0-4 kHz band
|
||||
* - high_band : The signal from the 4-8 kHz band
|
||||
*/
|
||||
void SplittingFilterAnalysis(const WebRtc_Word16* in_data,
|
||||
WebRtc_Word16* low_band,
|
||||
WebRtc_Word16* high_band,
|
||||
WebRtc_Word32* filt_state1,
|
||||
WebRtc_Word32* filt_state2);
|
||||
|
||||
/*
|
||||
* SplittingFilterbank_synthesisQMF(...)
|
||||
*
|
||||
* Combines the two subbands (0-8 and 8-16 kHz) into a super-wb signal.
|
||||
*
|
||||
* Input:
|
||||
* - low_band : The signal with the 0-8 kHz band
|
||||
* - high_band : The signal with the 8-16 kHz band
|
||||
*
|
||||
* Input & Output:
|
||||
* - filt_state1: Filter state for first all-pass filter
|
||||
* - filt_state2: Filter state for second all-pass filter
|
||||
*
|
||||
* Output:
|
||||
* - out_data : super-wb speech signal
|
||||
*/
|
||||
void SplittingFilterSynthesis(const WebRtc_Word16* low_band,
|
||||
const WebRtc_Word16* high_band,
|
||||
WebRtc_Word16* out_data,
|
||||
WebRtc_Word32* filt_state1,
|
||||
WebRtc_Word32* filt_state2);
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_SPLITTING_FILTER_H_
|
||||
225
modules/audio_processing/main/source/voice_detection_impl.cc
Normal file
225
modules/audio_processing/main/source/voice_detection_impl.cc
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "voice_detection_impl.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "critical_section_wrapper.h"
|
||||
#include "webrtc_vad.h"
|
||||
|
||||
#include "audio_processing_impl.h"
|
||||
#include "audio_buffer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
typedef VadInst Handle;
|
||||
|
||||
namespace {
|
||||
WebRtc_Word16 MapSetting(VoiceDetection::Likelihood likelihood) {
|
||||
switch (likelihood) {
|
||||
case VoiceDetection::kVeryLowLikelihood:
|
||||
return 3;
|
||||
break;
|
||||
case VoiceDetection::kLowLikelihood:
|
||||
return 2;
|
||||
break;
|
||||
case VoiceDetection::kModerateLikelihood:
|
||||
return 1;
|
||||
break;
|
||||
case VoiceDetection::kHighLikelihood:
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
VoiceDetectionImpl::VoiceDetectionImpl(const AudioProcessingImpl* apm)
|
||||
: ProcessingComponent(apm),
|
||||
apm_(apm),
|
||||
stream_has_voice_(false),
|
||||
using_external_vad_(false),
|
||||
likelihood_(kLowLikelihood),
|
||||
frame_size_ms_(10),
|
||||
frame_size_samples_(0) {}
|
||||
|
||||
VoiceDetectionImpl::~VoiceDetectionImpl() {}
|
||||
|
||||
int VoiceDetectionImpl::ProcessCaptureAudio(AudioBuffer* audio) {
|
||||
if (!is_component_enabled()) {
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
if (using_external_vad_) {
|
||||
using_external_vad_ = false;
|
||||
return apm_->kNoError;
|
||||
}
|
||||
assert(audio->samples_per_split_channel() <= 160);
|
||||
|
||||
WebRtc_Word16* mixed_data = audio->low_pass_split_data(0);
|
||||
if (audio->num_channels() > 1) {
|
||||
audio->CopyAndMixLowPass(1);
|
||||
mixed_data = audio->mixed_low_pass_data(0);
|
||||
}
|
||||
|
||||
// TODO(ajm): concatenate data in frame buffer here.
|
||||
|
||||
int vad_ret_val;
|
||||
vad_ret_val = WebRtcVad_Process(static_cast<Handle*>(handle(0)),
|
||||
apm_->split_sample_rate_hz(),
|
||||
mixed_data,
|
||||
frame_size_samples_);
|
||||
|
||||
if (vad_ret_val == 0) {
|
||||
stream_has_voice_ = false;
|
||||
} else if (vad_ret_val == 1) {
|
||||
stream_has_voice_ = true;
|
||||
} else {
|
||||
return apm_->kUnspecifiedError;
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int VoiceDetectionImpl::Enable(bool enable) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
return EnableComponent(enable);
|
||||
}
|
||||
|
||||
bool VoiceDetectionImpl::is_enabled() const {
|
||||
return is_component_enabled();
|
||||
}
|
||||
|
||||
int VoiceDetectionImpl::set_stream_has_voice(bool has_voice) {
|
||||
using_external_vad_ = true;
|
||||
stream_has_voice_ = has_voice;
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
bool VoiceDetectionImpl::stream_has_voice() const {
|
||||
// TODO(ajm): enable this assertion?
|
||||
//assert(using_external_vad_ || is_component_enabled());
|
||||
return stream_has_voice_;
|
||||
}
|
||||
|
||||
int VoiceDetectionImpl::set_likelihood(VoiceDetection::Likelihood likelihood) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
if (likelihood != kVeryLowLikelihood &&
|
||||
likelihood != kLowLikelihood &&
|
||||
likelihood != kModerateLikelihood &&
|
||||
likelihood != kHighLikelihood) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
likelihood_ = likelihood;
|
||||
return Configure();
|
||||
}
|
||||
|
||||
VoiceDetection::Likelihood VoiceDetectionImpl::likelihood() const {
|
||||
return likelihood_;
|
||||
}
|
||||
|
||||
int VoiceDetectionImpl::set_frame_size_ms(int size) {
|
||||
CriticalSectionScoped crit_scoped(*apm_->crit());
|
||||
assert(size == 10); // TODO(ajm): remove when supported.
|
||||
if (size != 10 &&
|
||||
size != 20 &&
|
||||
size != 30) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
frame_size_ms_ = size;
|
||||
|
||||
return Initialize();
|
||||
}
|
||||
|
||||
int VoiceDetectionImpl::frame_size_ms() const {
|
||||
return frame_size_ms_;
|
||||
}
|
||||
|
||||
int VoiceDetectionImpl::Initialize() {
|
||||
int err = ProcessingComponent::Initialize();
|
||||
if (err != apm_->kNoError || !is_component_enabled()) {
|
||||
return err;
|
||||
}
|
||||
|
||||
using_external_vad_ = false;
|
||||
frame_size_samples_ = frame_size_ms_ * (apm_->split_sample_rate_hz() / 1000);
|
||||
// TODO(ajm): intialize frame buffer here.
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
int VoiceDetectionImpl::get_version(char* version,
|
||||
int version_len_bytes) const {
|
||||
if (WebRtcVad_get_version(version, version_len_bytes) != 0) {
|
||||
return apm_->kBadParameterError;
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}
|
||||
|
||||
void* VoiceDetectionImpl::CreateHandle() const {
|
||||
Handle* handle = NULL;
|
||||
if (WebRtcVad_Create(&handle) != apm_->kNoError) {
|
||||
handle = NULL;
|
||||
} else {
|
||||
assert(handle != NULL);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int VoiceDetectionImpl::DestroyHandle(void* handle) const {
|
||||
return WebRtcVad_Free(static_cast<Handle*>(handle));
|
||||
}
|
||||
|
||||
int VoiceDetectionImpl::InitializeHandle(void* handle) const {
|
||||
return WebRtcVad_Init(static_cast<Handle*>(handle));
|
||||
}
|
||||
|
||||
/*int VoiceDetectionImpl::InitializeHandles(
|
||||
const vector<void*>& handles) const {
|
||||
int err = apm_->kNoError;
|
||||
|
||||
for (size_t i = 0; i < num_handles(); i++) {
|
||||
err = WebRtcVad_Init(static_cast<Handle*>(handles[i]),
|
||||
apm_->SampleRateHz());
|
||||
if (err != apm_->kNoError) {
|
||||
return TranslateError(err);
|
||||
}
|
||||
}
|
||||
|
||||
return apm_->kNoError;
|
||||
}*/
|
||||
|
||||
int VoiceDetectionImpl::ConfigureHandle(void* handle) const {
|
||||
return WebRtcVad_set_mode(static_cast<Handle*>(handle),
|
||||
MapSetting(likelihood_));
|
||||
}
|
||||
|
||||
int VoiceDetectionImpl::num_handles_required() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
//int VoiceDetectionImpl::GetConfiguration() {
|
||||
// // There are no configuration accessors.
|
||||
// return apm_->kUnsupportedFunctionError;
|
||||
//}
|
||||
|
||||
// TODO(ajm): implement
|
||||
int VoiceDetectionImpl::TranslateError(int /*err*/) const {
|
||||
return -1;
|
||||
}
|
||||
} // namespace webrtc
|
||||
65
modules/audio_processing/main/source/voice_detection_impl.h
Normal file
65
modules/audio_processing/main/source/voice_detection_impl.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_VOICE_DETECTION_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_VOICE_DETECTION_IMPL_H_
|
||||
|
||||
#include "audio_processing.h"
|
||||
#include "processing_component.h"
|
||||
|
||||
namespace webrtc {
|
||||
class AudioProcessingImpl;
|
||||
class AudioBuffer;
|
||||
|
||||
class VoiceDetectionImpl : public VoiceDetection,
|
||||
public ProcessingComponent {
|
||||
public:
|
||||
explicit VoiceDetectionImpl(const AudioProcessingImpl* apm);
|
||||
virtual ~VoiceDetectionImpl();
|
||||
|
||||
int ProcessCaptureAudio(AudioBuffer* audio);
|
||||
|
||||
// VoiceDetection implementation.
|
||||
virtual bool is_enabled() const;
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual int Initialize();
|
||||
virtual int get_version(char* version, int version_len_bytes) const;
|
||||
|
||||
private:
|
||||
// VoiceDetection implementation.
|
||||
virtual int Enable(bool enable);
|
||||
virtual int set_stream_has_voice(bool has_voice);
|
||||
virtual bool stream_has_voice() const;
|
||||
virtual int set_likelihood(Likelihood likelihood);
|
||||
virtual Likelihood likelihood() const;
|
||||
virtual int set_frame_size_ms(int size);
|
||||
virtual int frame_size_ms() const;
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
virtual void* CreateHandle() const;
|
||||
virtual int InitializeHandle(void* handle) const;
|
||||
//virtual int InitializeHandles(
|
||||
// const std::vector<void*>& handles) const;
|
||||
virtual int ConfigureHandle(void* handle) const;
|
||||
virtual int DestroyHandle(void* handle) const;
|
||||
virtual int num_handles_required() const;
|
||||
virtual int TranslateError(int err) const;
|
||||
|
||||
const AudioProcessingImpl* apm_;
|
||||
bool stream_has_voice_;
|
||||
bool using_external_vad_;
|
||||
Likelihood likelihood_;
|
||||
int frame_size_ms_;
|
||||
int frame_size_samples_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_VOICE_DETECTION_IMPL_H_
|
||||
Reference in New Issue
Block a user