2011-07-07 08:21:25 +00:00
|
|
|
/*
|
2012-01-30 09:39:08 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2011-07-07 08:21:25 +00:00
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "modules/audio_processing/gain_control_impl.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2018-10-23 12:03:01 +02:00
|
|
|
#include <cstdint>
|
|
|
|
|
|
2018-06-19 10:50:11 +02:00
|
|
|
#include "absl/types/optional.h"
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "modules/audio_processing/agc/legacy/gain_control.h"
|
|
|
|
|
#include "modules/audio_processing/audio_buffer.h"
|
2018-10-23 12:03:01 +02:00
|
|
|
#include "modules/audio_processing/include/audio_processing.h"
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
2018-10-23 12:03:01 +02:00
|
|
|
#include "rtc_base/checks.h"
|
2019-11-22 12:11:40 +01:00
|
|
|
#include "rtc_base/logging.h"
|
2019-11-23 00:14:31 +01:00
|
|
|
#include "system_wrappers/include/field_trial.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
|
|
|
|
|
typedef void Handle;
|
|
|
|
|
|
|
|
|
|
namespace {
|
2013-04-10 07:50:54 +00:00
|
|
|
int16_t MapSetting(GainControl::Mode mode) {
|
2011-07-07 08:21:25 +00:00
|
|
|
switch (mode) {
|
|
|
|
|
case GainControl::kAdaptiveAnalog:
|
|
|
|
|
return kAgcModeAdaptiveAnalog;
|
|
|
|
|
case GainControl::kAdaptiveDigital:
|
|
|
|
|
return kAgcModeAdaptiveDigital;
|
|
|
|
|
case GainControl::kFixedDigital:
|
|
|
|
|
return kAgcModeFixedDigital;
|
|
|
|
|
}
|
2017-01-12 02:24:27 -08:00
|
|
|
RTC_NOTREACHED();
|
2012-02-06 11:06:01 +00:00
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
// Checks whether the legacy digital gain application should be used.
|
|
|
|
|
bool UseLegacyDigitalGainApplier() {
|
|
|
|
|
return field_trial::IsEnabled("WebRTC-UseLegacyDigitalGainApplier");
|
|
|
|
|
}
|
2015-11-16 23:52:25 -08:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
// Floating point variant of WebRtcAgc_Process.
|
|
|
|
|
void ApplyDigitalGain(const int32_t gains[11],
|
|
|
|
|
size_t num_bands,
|
|
|
|
|
float* const* out) {
|
|
|
|
|
constexpr float kScaling = 1.f / 65536.f;
|
|
|
|
|
constexpr int kNumSubSections = 16;
|
|
|
|
|
constexpr float kOneByNumSubSections = 1.f / kNumSubSections;
|
|
|
|
|
|
|
|
|
|
float gains_scaled[11];
|
|
|
|
|
for (int k = 0; k < 11; ++k) {
|
|
|
|
|
gains_scaled[k] = gains[k] * kScaling;
|
2016-03-10 21:09:04 -08:00
|
|
|
}
|
|
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
for (size_t b = 0; b < num_bands; ++b) {
|
|
|
|
|
float* out_band = out[b];
|
|
|
|
|
for (int k = 0, sample = 0; k < 10; ++k) {
|
|
|
|
|
const float delta =
|
|
|
|
|
(gains_scaled[k + 1] - gains_scaled[k]) * kOneByNumSubSections;
|
|
|
|
|
float gain = gains_scaled[k];
|
|
|
|
|
for (int n = 0; n < kNumSubSections; ++n, ++sample) {
|
|
|
|
|
RTC_DCHECK_EQ(k * kNumSubSections + n, sample);
|
|
|
|
|
out_band[sample] *= gain;
|
|
|
|
|
out_band[sample] =
|
|
|
|
|
std::min(32767.f, std::max(-32768.f, out_band[sample]));
|
|
|
|
|
gain += delta;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-10 21:09:04 -08:00
|
|
|
}
|
2019-11-23 00:14:31 +01:00
|
|
|
}
|
2016-03-10 21:09:04 -08:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
} // namespace
|
2016-03-10 21:09:04 -08:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
struct GainControlImpl::MonoAgcState {
|
|
|
|
|
MonoAgcState() {
|
|
|
|
|
state = WebRtcAgc_Create();
|
|
|
|
|
RTC_CHECK(state);
|
2016-03-10 21:09:04 -08:00
|
|
|
}
|
|
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
~MonoAgcState() {
|
|
|
|
|
RTC_DCHECK(state);
|
|
|
|
|
WebRtcAgc_Free(state);
|
2016-03-10 21:09:04 -08:00
|
|
|
}
|
|
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
MonoAgcState(const MonoAgcState&) = delete;
|
|
|
|
|
MonoAgcState& operator=(const MonoAgcState&) = delete;
|
|
|
|
|
int32_t gains[11];
|
|
|
|
|
Handle* state;
|
2016-03-10 21:09:04 -08:00
|
|
|
};
|
|
|
|
|
|
2016-10-28 03:12:11 -07:00
|
|
|
int GainControlImpl::instance_counter_ = 0;
|
|
|
|
|
|
2019-03-27 13:28:08 +01:00
|
|
|
GainControlImpl::GainControlImpl()
|
|
|
|
|
: data_dumper_(new ApmDataDumper(instance_counter_)),
|
2019-11-23 00:14:31 +01:00
|
|
|
use_legacy_gain_applier_(UseLegacyDigitalGainApplier()),
|
2015-11-16 23:52:25 -08:00
|
|
|
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),
|
2019-03-27 13:28:08 +01:00
|
|
|
stream_is_saturated_(false) {}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
GainControlImpl::~GainControlImpl() = default;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-10-25 05:42:20 -07:00
|
|
|
void GainControlImpl::ProcessRenderAudio(
|
|
|
|
|
rtc::ArrayView<const int16_t> packed_render_audio) {
|
2019-11-23 00:14:31 +01:00
|
|
|
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
|
|
|
|
WebRtcAgc_AddFarend(mono_agcs_[ch]->state, packed_render_audio.data(),
|
2016-10-25 05:42:20 -07:00
|
|
|
packed_render_audio.size());
|
2015-11-16 23:52:25 -08:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-10-25 05:42:20 -07:00
|
|
|
void GainControlImpl::PackRenderAudioBuffer(
|
2019-11-22 18:22:04 +01:00
|
|
|
const AudioBuffer& audio,
|
2016-10-25 05:42:20 -07:00
|
|
|
std::vector<int16_t>* packed_buffer) {
|
2019-11-22 18:22:04 +01:00
|
|
|
RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
|
2019-11-23 00:14:31 +01:00
|
|
|
std::array<int16_t, AudioBuffer::kMaxSplitFrameLength>
|
|
|
|
|
mixed_16_kHz_render_data;
|
|
|
|
|
rtc::ArrayView<const int16_t> mixed_16_kHz_render(
|
|
|
|
|
mixed_16_kHz_render_data.data(), audio.num_frames_per_band());
|
2019-11-22 18:22:04 +01:00
|
|
|
if (audio.num_channels() == 1) {
|
|
|
|
|
FloatS16ToS16(audio.split_bands_const(0)[kBand0To8kHz],
|
2019-11-23 00:14:31 +01:00
|
|
|
audio.num_frames_per_band(), mixed_16_kHz_render_data.data());
|
2019-08-15 12:15:46 +02:00
|
|
|
} else {
|
2019-11-22 18:22:04 +01:00
|
|
|
const int num_channels = static_cast<int>(audio.num_channels());
|
|
|
|
|
for (size_t i = 0; i < audio.num_frames_per_band(); ++i) {
|
2019-11-23 00:14:31 +01:00
|
|
|
int32_t sum = 0;
|
|
|
|
|
for (int ch = 0; ch < num_channels; ++ch) {
|
|
|
|
|
sum += FloatS16ToS16(audio.split_channels_const(kBand0To8kHz)[ch][i]);
|
2019-08-15 12:15:46 +02:00
|
|
|
}
|
2019-11-23 00:14:31 +01:00
|
|
|
mixed_16_kHz_render_data[i] = sum / num_channels;
|
2019-08-15 12:15:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-25 05:42:20 -07:00
|
|
|
packed_buffer->clear();
|
2019-11-23 00:14:31 +01:00
|
|
|
packed_buffer->insert(
|
|
|
|
|
packed_buffer->end(), mixed_16_kHz_render.data(),
|
|
|
|
|
(mixed_16_kHz_render.data() + audio.num_frames_per_band()));
|
2015-11-16 23:52:25 -08:00
|
|
|
}
|
|
|
|
|
|
2019-11-22 18:22:04 +01:00
|
|
|
int GainControlImpl::AnalyzeCaptureAudio(const AudioBuffer& audio) {
|
2016-03-15 02:28:08 -07:00
|
|
|
RTC_DCHECK(num_proc_channels_);
|
2019-11-22 18:22:04 +01:00
|
|
|
RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
|
|
|
|
|
RTC_DCHECK_EQ(audio.num_channels(), *num_proc_channels_);
|
2019-11-23 00:14:31 +01:00
|
|
|
RTC_DCHECK_LE(*num_proc_channels_, mono_agcs_.size());
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2019-08-20 09:19:21 +02:00
|
|
|
int16_t split_band_data[AudioBuffer::kMaxNumBands]
|
|
|
|
|
[AudioBuffer::kMaxSplitFrameLength];
|
|
|
|
|
int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
|
|
|
|
|
split_band_data[0], split_band_data[1], split_band_data[2]};
|
|
|
|
|
|
2011-07-07 08:21:25 +00:00
|
|
|
if (mode_ == kAdaptiveAnalog) {
|
2019-11-23 00:14:31 +01:00
|
|
|
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
|
|
|
|
capture_levels_[ch] = analog_capture_level_;
|
2019-08-20 09:19:21 +02:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
audio.ExportSplitChannelData(ch, split_bands);
|
2019-08-20 09:19:21 +02:00
|
|
|
|
|
|
|
|
int err =
|
2019-11-23 00:14:31 +01:00
|
|
|
WebRtcAgc_AddMic(mono_agcs_[ch]->state, split_bands,
|
2019-11-22 18:22:04 +01:00
|
|
|
audio.num_bands(), audio.num_frames_per_band());
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-11-28 12:35:15 -08:00
|
|
|
if (err != AudioProcessing::kNoError) {
|
2016-03-10 21:09:04 -08:00
|
|
|
return AudioProcessing::kUnspecifiedError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (mode_ == kAdaptiveDigital) {
|
2019-11-23 00:14:31 +01:00
|
|
|
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
2013-04-10 07:50:54 +00:00
|
|
|
int32_t capture_level_out = 0;
|
2019-08-20 09:19:21 +02:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
audio.ExportSplitChannelData(ch, split_bands);
|
2019-08-20 09:19:21 +02:00
|
|
|
|
|
|
|
|
int err =
|
2019-11-23 00:14:31 +01:00
|
|
|
WebRtcAgc_VirtualMic(mono_agcs_[ch]->state, split_bands,
|
2019-11-22 18:22:04 +01:00
|
|
|
audio.num_bands(), audio.num_frames_per_band(),
|
2019-08-20 09:19:21 +02:00
|
|
|
analog_capture_level_, &capture_level_out);
|
|
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
capture_levels_[ch] = capture_level_out;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-11-28 12:35:15 -08:00
|
|
|
if (err != AudioProcessing::kNoError) {
|
2016-03-10 21:09:04 -08:00
|
|
|
return AudioProcessing::kUnspecifiedError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-28 12:35:15 -08:00
|
|
|
return AudioProcessing::kNoError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-03-15 02:28:08 -07:00
|
|
|
int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
|
|
|
|
|
bool stream_has_echo) {
|
2011-07-07 08:21:25 +00:00
|
|
|
if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
|
2015-11-28 12:35:15 -08:00
|
|
|
return AudioProcessing::kStreamParameterNotSetError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-03-15 02:28:08 -07:00
|
|
|
RTC_DCHECK(num_proc_channels_);
|
2019-08-20 09:19:21 +02:00
|
|
|
RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength,
|
|
|
|
|
audio->num_frames_per_band());
|
2016-03-15 02:28:08 -07:00
|
|
|
RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
stream_is_saturated_ = false;
|
2019-11-23 00:14:31 +01:00
|
|
|
bool error_reported = false;
|
|
|
|
|
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
2019-08-20 09:19:21 +02:00
|
|
|
int16_t split_band_data[AudioBuffer::kMaxNumBands]
|
|
|
|
|
[AudioBuffer::kMaxSplitFrameLength];
|
|
|
|
|
int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
|
|
|
|
|
split_band_data[0], split_band_data[1], split_band_data[2]};
|
2019-11-23 00:14:31 +01:00
|
|
|
audio->ExportSplitChannelData(ch, split_bands);
|
2019-08-20 09:19:21 +02:00
|
|
|
|
2015-11-28 12:35:15 -08:00
|
|
|
// The call to stream_has_echo() is ok from a deadlock perspective
|
|
|
|
|
// as the capture lock is allready held.
|
2019-11-23 00:14:31 +01:00
|
|
|
int32_t new_capture_level = 0;
|
|
|
|
|
uint8_t saturation_warning = 0;
|
|
|
|
|
int err_analyze = WebRtcAgc_Analyze(
|
|
|
|
|
mono_agcs_[ch]->state, split_bands, audio->num_bands(),
|
|
|
|
|
audio->num_frames_per_band(), capture_levels_[ch], &new_capture_level,
|
|
|
|
|
stream_has_echo, &saturation_warning, mono_agcs_[ch]->gains);
|
|
|
|
|
capture_levels_[ch] = new_capture_level;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
error_reported = error_reported || err_analyze != AudioProcessing::kNoError;
|
2019-08-20 09:19:21 +02:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
stream_is_saturated_ = stream_is_saturated_ || saturation_warning == 1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
// Choose the minimun gain for application
|
|
|
|
|
size_t index_to_apply = 0;
|
|
|
|
|
for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
|
|
|
|
|
if (mono_agcs_[index_to_apply]->gains[10] < mono_agcs_[ch]->gains[10]) {
|
|
|
|
|
index_to_apply = ch;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2019-11-23 00:14:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (use_legacy_gain_applier_) {
|
|
|
|
|
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
|
|
|
|
int16_t split_band_data[AudioBuffer::kMaxNumBands]
|
|
|
|
|
[AudioBuffer::kMaxSplitFrameLength];
|
|
|
|
|
int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
|
|
|
|
|
split_band_data[0], split_band_data[1], split_band_data[2]};
|
|
|
|
|
audio->ExportSplitChannelData(ch, split_bands);
|
2016-03-10 21:09:04 -08:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
int err_process = WebRtcAgc_Process(
|
|
|
|
|
mono_agcs_[ch]->state, mono_agcs_[index_to_apply]->gains, split_bands,
|
|
|
|
|
audio->num_bands(), split_bands);
|
|
|
|
|
RTC_DCHECK_EQ(err_process, 0);
|
|
|
|
|
|
|
|
|
|
audio->ImportSplitChannelData(ch, split_bands);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
|
|
|
|
ApplyDigitalGain(mono_agcs_[index_to_apply]->gains, audio->num_bands(),
|
|
|
|
|
audio->split_bands(ch));
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-03-15 02:28:08 -07:00
|
|
|
RTC_DCHECK_LT(0ul, *num_proc_channels_);
|
2011-07-07 08:21:25 +00:00
|
|
|
if (mode_ == kAdaptiveAnalog) {
|
2019-11-23 00:14:31 +01:00
|
|
|
// Take the analog level to be the minimum accross all channels.
|
|
|
|
|
analog_capture_level_ = capture_levels_[0];
|
|
|
|
|
for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
|
|
|
|
|
analog_capture_level_ =
|
|
|
|
|
std::min(analog_capture_level_, capture_levels_[ch]);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2019-11-23 00:14:31 +01:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
if (error_reported) {
|
|
|
|
|
return AudioProcessing::kUnspecifiedError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
was_analog_level_set_ = false;
|
2019-11-23 00:14:31 +01:00
|
|
|
|
2015-11-28 12:35:15 -08:00
|
|
|
return AudioProcessing::kNoError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-04-28 14:58:32 -07:00
|
|
|
|
2011-07-07 08:21:25 +00:00
|
|
|
// TODO(ajm): ensure this is called under kAdaptiveAnalog.
|
|
|
|
|
int GainControlImpl::set_stream_analog_level(int level) {
|
2016-10-28 03:12:11 -07:00
|
|
|
data_dumper_->DumpRaw("gain_control_set_stream_analog_level", 1, &level);
|
2015-11-28 12:35:15 -08:00
|
|
|
|
2011-07-07 08:21:25 +00:00
|
|
|
was_analog_level_set_ = true;
|
|
|
|
|
if (level < minimum_capture_level_ || level > maximum_capture_level_) {
|
2015-11-28 12:35:15 -08:00
|
|
|
return AudioProcessing::kBadParameterError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
analog_capture_level_ = level;
|
|
|
|
|
|
2015-11-28 12:35:15 -08:00
|
|
|
return AudioProcessing::kNoError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2019-03-27 13:28:08 +01:00
|
|
|
int GainControlImpl::stream_analog_level() const {
|
2016-10-28 03:12:11 -07:00
|
|
|
data_dumper_->DumpRaw("gain_control_stream_analog_level", 1,
|
|
|
|
|
&analog_capture_level_);
|
2011-07-07 08:21:25 +00:00
|
|
|
return analog_capture_level_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int GainControlImpl::set_mode(Mode mode) {
|
|
|
|
|
if (MapSetting(mode) == -1) {
|
2015-11-28 12:35:15 -08:00
|
|
|
return AudioProcessing::kBadParameterError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mode_ = mode;
|
2016-03-15 02:28:08 -07:00
|
|
|
RTC_DCHECK(num_proc_channels_);
|
|
|
|
|
RTC_DCHECK(sample_rate_hz_);
|
|
|
|
|
Initialize(*num_proc_channels_, *sample_rate_hz_);
|
2016-03-10 21:09:04 -08:00
|
|
|
return AudioProcessing::kNoError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int GainControlImpl::set_analog_level_limits(int minimum, int maximum) {
|
2019-11-23 00:14:31 +01:00
|
|
|
if (minimum < 0 || maximum > 65535 || maximum < minimum) {
|
2015-11-28 12:35:15 -08:00
|
|
|
return AudioProcessing::kBadParameterError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
minimum_capture_level_ = minimum;
|
|
|
|
|
maximum_capture_level_ = maximum;
|
2016-03-24 12:52:02 -07:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
RTC_DCHECK(num_proc_channels_);
|
|
|
|
|
RTC_DCHECK(sample_rate_hz_);
|
|
|
|
|
Initialize(*num_proc_channels_, *sample_rate_hz_);
|
2016-03-10 21:09:04 -08:00
|
|
|
return AudioProcessing::kNoError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int GainControlImpl::set_target_level_dbfs(int level) {
|
|
|
|
|
if (level > 31 || level < 0) {
|
2015-11-28 12:35:15 -08:00
|
|
|
return AudioProcessing::kBadParameterError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2019-02-11 13:39:46 +01:00
|
|
|
target_level_dbfs_ = level;
|
2011-07-07 08:21:25 +00:00
|
|
|
return Configure();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int GainControlImpl::set_compression_gain_db(int gain) {
|
|
|
|
|
if (gain < 0 || gain > 90) {
|
2019-11-22 12:11:40 +01:00
|
|
|
RTC_LOG(LS_ERROR) << "set_compression_gain_db(" << gain << ") failed.";
|
2015-11-28 12:35:15 -08:00
|
|
|
return AudioProcessing::kBadParameterError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2019-02-11 13:39:46 +01:00
|
|
|
compression_gain_db_ = gain;
|
2011-07-07 08:21:25 +00:00
|
|
|
return Configure();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int GainControlImpl::enable_limiter(bool enable) {
|
2019-02-11 13:39:46 +01:00
|
|
|
limiter_enabled_ = enable;
|
2011-07-07 08:21:25 +00:00
|
|
|
return Configure();
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-15 02:28:08 -07:00
|
|
|
void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
|
2016-10-28 03:12:11 -07:00
|
|
|
data_dumper_->InitiateNewSetOfRecordings();
|
2016-03-15 02:28:08 -07:00
|
|
|
|
2019-11-26 09:23:45 +01:00
|
|
|
RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000 ||
|
|
|
|
|
sample_rate_hz == 48000);
|
|
|
|
|
|
2017-11-17 14:34:48 +01:00
|
|
|
num_proc_channels_ = num_proc_channels;
|
|
|
|
|
sample_rate_hz_ = sample_rate_hz;
|
2016-03-15 02:28:08 -07:00
|
|
|
|
2019-11-23 00:14:31 +01:00
|
|
|
mono_agcs_.resize(*num_proc_channels_);
|
|
|
|
|
capture_levels_.resize(*num_proc_channels_);
|
|
|
|
|
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
|
|
|
|
if (!mono_agcs_[ch]) {
|
|
|
|
|
mono_agcs_[ch].reset(new MonoAgcState());
|
2016-03-10 21:09:04 -08:00
|
|
|
}
|
2019-11-23 00:14:31 +01:00
|
|
|
|
|
|
|
|
int error = WebRtcAgc_Init(mono_agcs_[ch]->state, minimum_capture_level_,
|
|
|
|
|
maximum_capture_level_, MapSetting(mode_),
|
|
|
|
|
*sample_rate_hz_);
|
|
|
|
|
RTC_DCHECK_EQ(error, 0);
|
|
|
|
|
capture_levels_[ch] = analog_capture_level_;
|
2016-03-10 21:09:04 -08:00
|
|
|
}
|
2015-11-16 23:52:25 -08:00
|
|
|
|
2016-03-10 21:09:04 -08:00
|
|
|
Configure();
|
2015-11-16 23:52:25 -08:00
|
|
|
}
|
|
|
|
|
|
2016-03-10 21:09:04 -08:00
|
|
|
int GainControlImpl::Configure() {
|
2014-12-18 09:11:33 +00:00
|
|
|
WebRtcAgcConfig config;
|
2011-07-07 08:21:25 +00:00
|
|
|
// TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
|
|
|
|
|
// change the interface.
|
2016-09-14 05:23:22 -07:00
|
|
|
// RTC_DCHECK_LE(target_level_dbfs_, 0);
|
2013-04-10 07:50:54 +00:00
|
|
|
// 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_);
|
2011-07-07 08:21:25 +00:00
|
|
|
config.limiterEnable = limiter_enabled_;
|
|
|
|
|
|
2016-03-10 21:09:04 -08:00
|
|
|
int error = AudioProcessing::kNoError;
|
2019-11-23 00:14:31 +01:00
|
|
|
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
|
|
|
|
int error_ch = WebRtcAgc_set_config(mono_agcs_[ch]->state, config);
|
|
|
|
|
if (error_ch != AudioProcessing::kNoError) {
|
|
|
|
|
error = error_ch;
|
2016-03-10 21:09:04 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return error;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
} // namespace webrtc
|