diff options
Diffstat (limited to 'webrtc/modules/audio_processing/gain_control_impl.cc')
-rw-r--r-- | webrtc/modules/audio_processing/gain_control_impl.cc | 218 |
1 files changed, 161 insertions, 57 deletions
diff --git a/webrtc/modules/audio_processing/gain_control_impl.cc b/webrtc/modules/audio_processing/gain_control_impl.cc index 3b1537e796..04a6c7ba29 100644 --- a/webrtc/modules/audio_processing/gain_control_impl.cc +++ b/webrtc/modules/audio_processing/gain_control_impl.cc @@ -14,7 +14,6 @@ #include "webrtc/modules/audio_processing/audio_buffer.h" #include "webrtc/modules/audio_processing/agc/legacy/gain_control.h" -#include "webrtc/system_wrappers/include/critical_section_wrapper.h" namespace webrtc { @@ -33,60 +32,113 @@ int16_t MapSetting(GainControl::Mode mode) { assert(false); return -1; } + +// Maximum length that a frame of samples can have. +static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; +// Maximum number of frames to buffer in the render queue. +// TODO(peah): Decrease this once we properly handle hugely unbalanced +// reverse and forward call numbers. +static const size_t kMaxNumFramesToBuffer = 100; + } // 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) {} + rtc::CriticalSection* crit_render, + rtc::CriticalSection* crit_capture) + : ProcessingComponent(), + apm_(apm), + crit_render_(crit_render), + crit_capture_(crit_capture), + 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), + render_queue_element_max_size_(0) { + RTC_DCHECK(apm); + RTC_DCHECK(crit_render); + RTC_DCHECK(crit_capture); +} GainControlImpl::~GainControlImpl() {} int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) { + rtc::CritScope cs(crit_render_); if (!is_component_enabled()) { - return apm_->kNoError; + return AudioProcessing::kNoError; } assert(audio->num_frames_per_band() <= 160); - for (int i = 0; i < num_handles(); i++) { + render_queue_buffer_.resize(0); + for (size_t 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(), - audio->num_frames_per_band()); + int err = + WebRtcAgc_GetAddFarendError(my_handle, audio->num_frames_per_band()); - if (err != apm_->kNoError) { + if (err != AudioProcessing::kNoError) return GetHandleError(my_handle); - } + + // Buffer the samples in the render queue. + render_queue_buffer_.insert( + render_queue_buffer_.end(), audio->mixed_low_pass_data(), + (audio->mixed_low_pass_data() + audio->num_frames_per_band())); + } + + // Insert the samples into the queue. + if (!render_signal_queue_->Insert(&render_queue_buffer_)) { + // The data queue is full and needs to be emptied. + ReadQueuedRenderData(); + + // Retry the insert (should always work). + RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); + } + + return AudioProcessing::kNoError; +} + +// Read chunks of data that were received and queued on the render side from +// a queue. All the data chunks are buffered into the farend signal of the AGC. +void GainControlImpl::ReadQueuedRenderData() { + rtc::CritScope cs(crit_capture_); + + if (!is_component_enabled()) { + return; } - return apm_->kNoError; + while (render_signal_queue_->Remove(&capture_queue_buffer_)) { + size_t buffer_index = 0; + const size_t num_frames_per_band = + capture_queue_buffer_.size() / num_handles(); + for (size_t i = 0; i < num_handles(); i++) { + Handle* my_handle = static_cast<Handle*>(handle(i)); + WebRtcAgc_AddFarend(my_handle, &capture_queue_buffer_[buffer_index], + num_frames_per_band); + + buffer_index += num_frames_per_band; + } + } } int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { + rtc::CritScope cs(crit_capture_); + if (!is_component_enabled()) { - return apm_->kNoError; + return AudioProcessing::kNoError; } assert(audio->num_frames_per_band() <= 160); assert(audio->num_channels() == num_handles()); - int err = apm_->kNoError; + int err = AudioProcessing::kNoError; if (mode_ == kAdaptiveAnalog) { capture_levels_.assign(num_handles(), analog_capture_level_); - for (int i = 0; i < num_handles(); i++) { + for (size_t i = 0; i < num_handles(); i++) { Handle* my_handle = static_cast<Handle*>(handle(i)); err = WebRtcAgc_AddMic( my_handle, @@ -94,13 +146,13 @@ int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { audio->num_bands(), audio->num_frames_per_band()); - if (err != apm_->kNoError) { + if (err != AudioProcessing::kNoError) { return GetHandleError(my_handle); } } } else if (mode_ == kAdaptiveDigital) { - for (int i = 0; i < num_handles(); i++) { + for (size_t i = 0; i < num_handles(); i++) { Handle* my_handle = static_cast<Handle*>(handle(i)); int32_t capture_level_out = 0; @@ -114,34 +166,38 @@ int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { capture_levels_[i] = capture_level_out; - if (err != apm_->kNoError) { + if (err != AudioProcessing::kNoError) { return GetHandleError(my_handle); } } } - return apm_->kNoError; + return AudioProcessing::kNoError; } int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) { + rtc::CritScope cs(crit_capture_); + if (!is_component_enabled()) { - return apm_->kNoError; + return AudioProcessing::kNoError; } if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) { - return apm_->kStreamParameterNotSetError; + return AudioProcessing::kStreamParameterNotSetError; } assert(audio->num_frames_per_band() <= 160); assert(audio->num_channels() == num_handles()); stream_is_saturated_ = false; - for (int i = 0; i < num_handles(); i++) { + for (size_t 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; + // The call to stream_has_echo() is ok from a deadlock perspective + // as the capture lock is allready held. int err = WebRtcAgc_Process( my_handle, audio->split_bands_const(i), @@ -153,7 +209,7 @@ int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) { apm_->echo_cancellation()->stream_has_echo(), &saturation_warning); - if (err != apm_->kNoError) { + if (err != AudioProcessing::kNoError) { return GetHandleError(my_handle); } @@ -166,7 +222,7 @@ int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) { 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++) { + for (size_t i = 0; i < num_handles(); i++) { analog_capture_level_ += capture_levels_[i]; } @@ -174,22 +230,24 @@ int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) { } was_analog_level_set_ = false; - return apm_->kNoError; + return AudioProcessing::kNoError; } // TODO(ajm): ensure this is called under kAdaptiveAnalog. int GainControlImpl::set_stream_analog_level(int level) { - CriticalSectionScoped crit_scoped(crit_); + rtc::CritScope cs(crit_capture_); + was_analog_level_set_ = true; if (level < minimum_capture_level_ || level > maximum_capture_level_) { - return apm_->kBadParameterError; + return AudioProcessing::kBadParameterError; } analog_capture_level_ = level; - return apm_->kNoError; + return AudioProcessing::kNoError; } int GainControlImpl::stream_analog_level() { + rtc::CritScope cs(crit_capture_); // TODO(ajm): enable this assertion? //assert(mode_ == kAdaptiveAnalog); @@ -197,18 +255,21 @@ int GainControlImpl::stream_analog_level() { } int GainControlImpl::Enable(bool enable) { - CriticalSectionScoped crit_scoped(crit_); + rtc::CritScope cs_render(crit_render_); + rtc::CritScope cs_capture(crit_capture_); return EnableComponent(enable); } bool GainControlImpl::is_enabled() const { + rtc::CritScope cs(crit_capture_); return is_component_enabled(); } int GainControlImpl::set_mode(Mode mode) { - CriticalSectionScoped crit_scoped(crit_); + rtc::CritScope cs_render(crit_render_); + rtc::CritScope cs_capture(crit_capture_); if (MapSetting(mode) == -1) { - return apm_->kBadParameterError; + return AudioProcessing::kBadParameterError; } mode_ = mode; @@ -216,22 +277,23 @@ int GainControlImpl::set_mode(Mode mode) { } GainControl::Mode GainControlImpl::mode() const { + rtc::CritScope cs(crit_capture_); return mode_; } int GainControlImpl::set_analog_level_limits(int minimum, int maximum) { - CriticalSectionScoped crit_scoped(crit_); + rtc::CritScope cs(crit_capture_); if (minimum < 0) { - return apm_->kBadParameterError; + return AudioProcessing::kBadParameterError; } if (maximum > 65535) { - return apm_->kBadParameterError; + return AudioProcessing::kBadParameterError; } if (maximum < minimum) { - return apm_->kBadParameterError; + return AudioProcessing::kBadParameterError; } minimum_capture_level_ = minimum; @@ -241,21 +303,24 @@ int GainControlImpl::set_analog_level_limits(int minimum, } int GainControlImpl::analog_level_minimum() const { + rtc::CritScope cs(crit_capture_); return minimum_capture_level_; } int GainControlImpl::analog_level_maximum() const { + rtc::CritScope cs(crit_capture_); return maximum_capture_level_; } bool GainControlImpl::stream_is_saturated() const { + rtc::CritScope cs(crit_capture_); return stream_is_saturated_; } int GainControlImpl::set_target_level_dbfs(int level) { - CriticalSectionScoped crit_scoped(crit_); + rtc::CritScope cs(crit_capture_); if (level > 31 || level < 0) { - return apm_->kBadParameterError; + return AudioProcessing::kBadParameterError; } target_level_dbfs_ = level; @@ -263,13 +328,14 @@ int GainControlImpl::set_target_level_dbfs(int level) { } int GainControlImpl::target_level_dbfs() const { + rtc::CritScope cs(crit_capture_); return target_level_dbfs_; } int GainControlImpl::set_compression_gain_db(int gain) { - CriticalSectionScoped crit_scoped(crit_); + rtc::CritScope cs(crit_capture_); if (gain < 0 || gain > 90) { - return apm_->kBadParameterError; + return AudioProcessing::kBadParameterError; } compression_gain_db_ = gain; @@ -277,27 +343,59 @@ int GainControlImpl::set_compression_gain_db(int gain) { } int GainControlImpl::compression_gain_db() const { + rtc::CritScope cs(crit_capture_); return compression_gain_db_; } int GainControlImpl::enable_limiter(bool enable) { - CriticalSectionScoped crit_scoped(crit_); + rtc::CritScope cs(crit_capture_); limiter_enabled_ = enable; return Configure(); } bool GainControlImpl::is_limiter_enabled() const { + rtc::CritScope cs(crit_capture_); return limiter_enabled_; } int GainControlImpl::Initialize() { int err = ProcessingComponent::Initialize(); - if (err != apm_->kNoError || !is_component_enabled()) { + if (err != AudioProcessing::kNoError || !is_component_enabled()) { return err; } - capture_levels_.assign(num_handles(), analog_capture_level_); - return apm_->kNoError; + AllocateRenderQueue(); + + rtc::CritScope cs_capture(crit_capture_); + const int n = num_handles(); + RTC_CHECK_GE(n, 0) << "Bad number of handles: " << n; + + capture_levels_.assign(n, analog_capture_level_); + return AudioProcessing::kNoError; +} + +void GainControlImpl::AllocateRenderQueue() { + const size_t new_render_queue_element_max_size = + std::max<size_t>(static_cast<size_t>(1), + kMaxAllowedValuesOfSamplesPerFrame * num_handles()); + + rtc::CritScope cs_render(crit_render_); + rtc::CritScope cs_capture(crit_capture_); + + if (render_queue_element_max_size_ < new_render_queue_element_max_size) { + render_queue_element_max_size_ = new_render_queue_element_max_size; + std::vector<int16_t> template_queue_element(render_queue_element_max_size_); + + render_signal_queue_.reset( + new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>( + kMaxNumFramesToBuffer, template_queue_element, + RenderQueueItemVerifier<int16_t>(render_queue_element_max_size_))); + + render_queue_buffer_.resize(render_queue_element_max_size_); + capture_queue_buffer_.resize(render_queue_element_max_size_); + } else { + render_signal_queue_->Clear(); + } } void* GainControlImpl::CreateHandle() const { @@ -309,6 +407,9 @@ void GainControlImpl::DestroyHandle(void* handle) const { } int GainControlImpl::InitializeHandle(void* handle) const { + rtc::CritScope cs_render(crit_render_); + rtc::CritScope cs_capture(crit_capture_); + return WebRtcAgc_Init(static_cast<Handle*>(handle), minimum_capture_level_, maximum_capture_level_, @@ -317,6 +418,8 @@ int GainControlImpl::InitializeHandle(void* handle) const { } int GainControlImpl::ConfigureHandle(void* handle) const { + rtc::CritScope cs_render(crit_render_); + rtc::CritScope cs_capture(crit_capture_); WebRtcAgcConfig config; // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we // change the interface. @@ -330,14 +433,15 @@ int GainControlImpl::ConfigureHandle(void* handle) const { return WebRtcAgc_set_config(static_cast<Handle*>(handle), config); } -int GainControlImpl::num_handles_required() const { - return apm_->num_output_channels(); +size_t GainControlImpl::num_handles_required() const { + // Not locked as it only relies on APM public API which is threadsafe. + return apm_->num_proc_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; + return AudioProcessing::kUnspecifiedError; } } // namespace webrtc |