blob: 60744a83eb98436baf4248314210c08161dc5d0a [file] [log] [blame]
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_processing/gain_control_impl.h"
#include <assert.h>
#include "webrtc/modules/audio_processing/audio_buffer.h"
#include "webrtc/modules/audio_processing/agc/legacy/gain_control.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
namespace webrtc {
typedef void Handle;
namespace {
int16_t MapSetting(GainControl::Mode mode) {
switch (mode) {
case GainControl::kAdaptiveAnalog:
return kAgcModeAdaptiveAnalog;
case GainControl::kAdaptiveDigital:
return kAgcModeAdaptiveDigital;
case GainControl::kFixedDigital:
return kAgcModeFixedDigital;
}
assert(false);
return -1;
}
} // namespace
GainControlImpl::GainControlImpl(const AudioProcessing* apm,
CriticalSectionWrapper* crit)
: ProcessingComponent(),
apm_(apm),
crit_(crit),
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);
for (int i = 0; i < num_handles(); i++) {
Handle* my_handle = static_cast<Handle*>(handle(i));
int err = WebRtcAgc_AddFarend(
my_handle,
audio->mixed_low_pass_data(),
static_cast<int16_t>(audio->samples_per_split_channel()));
if (err != apm_->kNoError) {
return GetHandleError(my_handle);
}
}
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) {
capture_levels_.assign(num_handles(), analog_capture_level_);
for (int i = 0; i < num_handles(); i++) {
Handle* my_handle = static_cast<Handle*>(handle(i));
err = WebRtcAgc_AddMic(
my_handle,
audio->split_bands(i)[kBand0To8kHz],
audio->split_bands(i)[kBand8To16kHz],
static_cast<int16_t>(audio->samples_per_split_channel()));
if (err != apm_->kNoError) {
return GetHandleError(my_handle);
}
}
} else if (mode_ == kAdaptiveDigital) {
for (int i = 0; i < num_handles(); i++) {
Handle* my_handle = static_cast<Handle*>(handle(i));
int32_t capture_level_out = 0;
err = WebRtcAgc_VirtualMic(
my_handle,
audio->split_bands(i)[kBand0To8kHz],
audio->split_bands(i)[kBand8To16kHz],
static_cast<int16_t>(audio->samples_per_split_channel()),
analog_capture_level_,
&capture_level_out);
capture_levels_[i] = capture_level_out;
if (err != apm_->kNoError) {
return GetHandleError(my_handle);
}
}
}
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++) {
Handle* my_handle = static_cast<Handle*>(handle(i));
int32_t capture_level_out = 0;
uint8_t saturation_warning = 0;
int err = WebRtcAgc_Process(
my_handle,
audio->split_bands_const(i)[kBand0To8kHz],
audio->split_bands_const(i)[kBand8To16kHz],
static_cast<int16_t>(audio->samples_per_split_channel()),
audio->split_bands(i)[kBand0To8kHz],
audio->split_bands(i)[kBand8To16kHz],
capture_levels_[i],
&capture_level_out,
apm_->echo_cancellation()->stream_has_echo(),
&saturation_warning);
if (err != apm_->kNoError) {
return GetHandleError(my_handle);
}
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;
}
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(crit_);
return EnableComponent(enable);
}
bool GainControlImpl::is_enabled() const {
return is_component_enabled();
}
int GainControlImpl::set_mode(Mode mode) {
CriticalSectionScoped crit_scoped(crit_);
if (MapSetting(mode) == -1) {
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(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(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(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(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;
}
capture_levels_.assign(num_handles(), analog_capture_level_);
return apm_->kNoError;
}
void* GainControlImpl::CreateHandle() const {
Handle* handle = NULL;
if (WebRtcAgc_Create(&handle) != apm_->kNoError) {
handle = NULL;
} else {
assert(handle != NULL);
}
return handle;
}
void GainControlImpl::DestroyHandle(void* handle) const {
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_->proc_sample_rate_hz());
}
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<int16_t>(-target_level_dbfs_);
config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
config.compressionGaindB =
static_cast<int16_t>(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::GetHandleError(void* handle) const {
// The AGC has no get_error() function.
// (Despite listing errors in its interface...)
assert(handle != NULL);
return apm_->kUnspecifiedError;
}
} // namespace webrtc