Index: webrtc/modules/audio_processing/echo_control_mobile_impl.cc |
diff --git a/webrtc/modules/audio_processing/echo_control_mobile_impl.cc b/webrtc/modules/audio_processing/echo_control_mobile_impl.cc |
index a32c77c1420cdbbc62032bc38bc1cb3119d89b6f..5ff7bd728d2a9a51dbe56b096697e45d96dfa746 100644 |
--- a/webrtc/modules/audio_processing/echo_control_mobile_impl.cc |
+++ b/webrtc/modules/audio_processing/echo_control_mobile_impl.cc |
@@ -15,7 +15,6 @@ |
#include "webrtc/modules/audio_processing/aecm/echo_control_mobile.h" |
#include "webrtc/modules/audio_processing/audio_buffer.h" |
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
#include "webrtc/system_wrappers/include/logging.h" |
namespace webrtc { |
@@ -69,14 +68,20 @@ size_t EchoControlMobile::echo_path_size_bytes() { |
} |
EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessing* apm, |
- CriticalSectionWrapper* crit) |
+ rtc::CriticalSection* crit_render, |
+ rtc::CriticalSection* crit_capture) |
: ProcessingComponent(), |
apm_(apm), |
- crit_(crit), |
+ crit_render_(crit_render), |
+ crit_capture_(crit_capture), |
routing_mode_(kSpeakerphone), |
comfort_noise_enabled_(true), |
external_echo_path_(NULL), |
- render_queue_element_max_size_(0) {} |
+ render_queue_element_max_size_(0) { |
+ RTC_DCHECK(apm); |
+ RTC_DCHECK(crit_render); |
+ RTC_DCHECK(crit_capture); |
+} |
EchoControlMobileImpl::~EchoControlMobileImpl() { |
if (external_echo_path_ != NULL) { |
@@ -86,15 +91,16 @@ EchoControlMobileImpl::~EchoControlMobileImpl() { |
} |
int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { |
+ rtc::CritScope cs_render(crit_render_); |
+ |
if (!is_component_enabled()) { |
- return apm_->kNoError; |
+ return AudioProcessing::kNoError; |
} |
assert(audio->num_frames_per_band() <= 160); |
assert(audio->num_channels() == apm_->num_reverse_channels()); |
- int err = apm_->kNoError; |
- |
+ int err = AudioProcessing::kNoError; |
// The ordering convention must be followed to pass to the correct AECM. |
size_t handle_index = 0; |
render_queue_buffer_.clear(); |
@@ -105,7 +111,7 @@ int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { |
my_handle, audio->split_bands_const(j)[kBand0To8kHz], |
audio->num_frames_per_band()); |
- if (err != apm_->kNoError) |
+ if (err != AudioProcessing::kNoError) |
return MapError(err); // TODO(ajm): warning possible?); |
// Buffer the samples in the render queue. |
@@ -120,18 +126,21 @@ int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { |
// 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 apm_->kNoError; |
+ 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 AEC. |
void EchoControlMobileImpl::ReadQueuedRenderData() { |
+ rtc::CritScope cs_capture(crit_capture_); |
+ |
if (!is_component_enabled()) { |
return; |
} |
@@ -156,18 +165,20 @@ void EchoControlMobileImpl::ReadQueuedRenderData() { |
} |
int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) { |
+ rtc::CritScope cs_capture(crit_capture_); |
+ |
if (!is_component_enabled()) { |
- return apm_->kNoError; |
+ return AudioProcessing::kNoError; |
} |
if (!apm_->was_stream_delay_set()) { |
- return apm_->kStreamParameterNotSetError; |
+ return AudioProcessing::kStreamParameterNotSetError; |
} |
assert(audio->num_frames_per_band() <= 160); |
assert(audio->num_channels() == apm_->num_output_channels()); |
- int err = apm_->kNoError; |
+ int err = AudioProcessing::kNoError; |
// The ordering convention must be followed to pass to the correct AECM. |
size_t handle_index = 0; |
@@ -190,86 +201,99 @@ int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) { |
audio->num_frames_per_band(), |
apm_->stream_delay_ms()); |
- if (err != apm_->kNoError) |
+ if (err != AudioProcessing::kNoError) |
return MapError(err); |
handle_index++; |
} |
} |
- return apm_->kNoError; |
+ return AudioProcessing::kNoError; |
} |
int EchoControlMobileImpl::Enable(bool enable) { |
- CriticalSectionScoped crit_scoped(crit_); |
// Ensure AEC and AECM are not both enabled. |
+ rtc::CritScope cs_render(crit_render_); |
+ rtc::CritScope cs_capture(crit_capture_); |
+ // The is_enabled call is safe from a deadlock perspective |
+ // as both locks are allready held in the correct order. |
if (enable && apm_->echo_cancellation()->is_enabled()) { |
- return apm_->kBadParameterError; |
+ return AudioProcessing::kBadParameterError; |
} |
return EnableComponent(enable); |
} |
bool EchoControlMobileImpl::is_enabled() const { |
+ rtc::CritScope cs(crit_capture_); |
return is_component_enabled(); |
} |
int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) { |
- CriticalSectionScoped crit_scoped(crit_); |
if (MapSetting(mode) == -1) { |
- return apm_->kBadParameterError; |
+ return AudioProcessing::kBadParameterError; |
} |
- routing_mode_ = mode; |
+ { |
+ rtc::CritScope cs(crit_capture_); |
+ routing_mode_ = mode; |
+ } |
return Configure(); |
} |
EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode() |
const { |
+ rtc::CritScope cs(crit_capture_); |
return routing_mode_; |
} |
int EchoControlMobileImpl::enable_comfort_noise(bool enable) { |
- CriticalSectionScoped crit_scoped(crit_); |
- comfort_noise_enabled_ = enable; |
+ { |
+ rtc::CritScope cs(crit_capture_); |
+ comfort_noise_enabled_ = enable; |
+ } |
return Configure(); |
} |
bool EchoControlMobileImpl::is_comfort_noise_enabled() const { |
+ rtc::CritScope cs(crit_capture_); |
return comfort_noise_enabled_; |
} |
int EchoControlMobileImpl::SetEchoPath(const void* echo_path, |
size_t size_bytes) { |
- CriticalSectionScoped crit_scoped(crit_); |
- if (echo_path == NULL) { |
- return apm_->kNullPointerError; |
- } |
- if (size_bytes != echo_path_size_bytes()) { |
- // Size mismatch |
- return apm_->kBadParameterError; |
- } |
+ { |
+ rtc::CritScope cs_render(crit_render_); |
+ rtc::CritScope cs_capture(crit_capture_); |
+ if (echo_path == NULL) { |
+ return AudioProcessing::kNullPointerError; |
+ } |
+ if (size_bytes != echo_path_size_bytes()) { |
+ // Size mismatch |
+ return AudioProcessing::kBadParameterError; |
+ } |
- if (external_echo_path_ == NULL) { |
- external_echo_path_ = new unsigned char[size_bytes]; |
+ if (external_echo_path_ == NULL) { |
+ external_echo_path_ = new unsigned char[size_bytes]; |
+ } |
+ memcpy(external_echo_path_, echo_path, size_bytes); |
} |
- memcpy(external_echo_path_, echo_path, size_bytes); |
return Initialize(); |
} |
int EchoControlMobileImpl::GetEchoPath(void* echo_path, |
size_t size_bytes) const { |
- CriticalSectionScoped crit_scoped(crit_); |
+ rtc::CritScope cs(crit_capture_); |
if (echo_path == NULL) { |
- return apm_->kNullPointerError; |
+ return AudioProcessing::kNullPointerError; |
} |
if (size_bytes != echo_path_size_bytes()) { |
// Size mismatch |
- return apm_->kBadParameterError; |
+ return AudioProcessing::kBadParameterError; |
} |
if (!is_component_enabled()) { |
- return apm_->kNotEnabledError; |
+ return AudioProcessing::kNotEnabledError; |
} |
// Get the echo path from the first channel |
@@ -278,27 +302,30 @@ int EchoControlMobileImpl::GetEchoPath(void* echo_path, |
if (err != 0) |
return MapError(err); |
- return apm_->kNoError; |
+ return AudioProcessing::kNoError; |
} |
int EchoControlMobileImpl::Initialize() { |
- if (!is_component_enabled()) { |
- return apm_->kNoError; |
+ { |
+ rtc::CritScope cs_capture(crit_capture_); |
+ if (!is_component_enabled()) { |
+ return AudioProcessing::kNoError; |
+ } |
} |
- if (apm_->proc_sample_rate_hz() > apm_->kSampleRate16kHz) { |
+ if (apm_->proc_sample_rate_hz() > AudioProcessing::kSampleRate16kHz) { |
LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates"; |
- return apm_->kBadSampleRateError; |
+ return AudioProcessing::kBadSampleRateError; |
} |
int err = ProcessingComponent::Initialize(); |
- if (err != apm_->kNoError) { |
+ if (err != AudioProcessing::kNoError) { |
return err; |
} |
AllocateRenderQueue(); |
- return apm_->kNoError; |
+ return AudioProcessing::kNoError; |
} |
void EchoControlMobileImpl::AllocateRenderQueue() { |
@@ -306,6 +333,9 @@ void EchoControlMobileImpl::AllocateRenderQueue() { |
static_cast<size_t>(1), |
kMaxAllowedValuesOfSamplesPerFrame * num_handles_required()); |
+ rtc::CritScope cs_render(crit_render_); |
+ rtc::CritScope cs_capture(crit_capture_); |
+ |
// Reallocate the queue if the queue item size is too small to fit the |
// data to put in the queue. |
if (render_queue_element_max_size_ < new_render_queue_element_max_size) { |
@@ -330,10 +360,14 @@ void* EchoControlMobileImpl::CreateHandle() const { |
} |
void EchoControlMobileImpl::DestroyHandle(void* handle) const { |
+ // This method is only called in a non-concurrent manner during APM |
+ // destruction. |
WebRtcAecm_Free(static_cast<Handle*>(handle)); |
} |
int EchoControlMobileImpl::InitializeHandle(void* handle) const { |
+ rtc::CritScope cs_render(crit_render_); |
+ rtc::CritScope cs_capture(crit_capture_); |
assert(handle != NULL); |
Handle* my_handle = static_cast<Handle*>(handle); |
if (WebRtcAecm_Init(my_handle, apm_->proc_sample_rate_hz()) != 0) { |
@@ -347,10 +381,12 @@ int EchoControlMobileImpl::InitializeHandle(void* handle) const { |
} |
} |
- return apm_->kNoError; |
+ return AudioProcessing::kNoError; |
} |
int EchoControlMobileImpl::ConfigureHandle(void* handle) const { |
+ rtc::CritScope cs_render(crit_render_); |
+ rtc::CritScope cs_capture(crit_capture_); |
AecmConfig config; |
config.cngMode = comfort_noise_enabled_; |
config.echoMode = MapSetting(routing_mode_); |
@@ -359,11 +395,13 @@ int EchoControlMobileImpl::ConfigureHandle(void* handle) const { |
} |
int EchoControlMobileImpl::num_handles_required() const { |
+ // Not locked as it only relies on APM public API which is threadsafe. |
return apm_->num_output_channels() * |
apm_->num_reverse_channels(); |
} |
int EchoControlMobileImpl::GetHandleError(void* handle) const { |
+ // Not locked as it does not rely on anything in the state. |
assert(handle != NULL); |
return AudioProcessing::kUnspecifiedError; |
} |