Bug 904784: use a separate critical section for the recording callback r=mwu

This commit is contained in:
Randell Jesup 2013-09-07 23:42:01 -04:00
parent 2093e63d6e
commit 2471dd20e0
2 changed files with 22 additions and 1 deletions

View File

@ -36,6 +36,7 @@ namespace webrtc {
AudioDeviceAndroidOpenSLES::AudioDeviceAndroidOpenSLES(const int32_t id)
: voe_audio_buffer_(NULL),
crit_sect_(*CriticalSectionWrapper::CreateCriticalSection()),
callback_crit_sect_(*CriticalSectionWrapper::CreateCriticalSection()),
id_(id),
sles_engine_(NULL),
sles_player_(NULL),
@ -276,6 +277,7 @@ int32_t AudioDeviceAndroidOpenSLES::MicrophoneIsAvailable(
int32_t AudioDeviceAndroidOpenSLES::InitMicrophone() {
CriticalSectionScoped lock(&crit_sect_);
CriticalSectionScoped callback_lock(&callback_crit_sect_);
if (is_recording_) {
WEBRTC_OPENSL_TRACE(kTraceWarning, kTraceAudioDevice, id_,
" Recording already started");
@ -940,6 +942,7 @@ int32_t AudioDeviceAndroidOpenSLES::InitRecording() {
int32_t AudioDeviceAndroidOpenSLES::StartRecording() {
CriticalSectionScoped lock(&crit_sect_);
CriticalSectionScoped callback_lock(&callback_crit_sect_);
if (!is_rec_initialized_) {
WEBRTC_OPENSL_TRACE(kTraceError, kTraceAudioDevice, id_,
@ -1079,6 +1082,7 @@ int32_t AudioDeviceAndroidOpenSLES::StopRecording() {
}
CriticalSectionScoped lock(&crit_sect_);
CriticalSectionScoped callback_lock(&callback_crit_sect_);
is_rec_initialized_ = false;
is_recording_ = false;
rec_warning_ = 0;
@ -1092,6 +1096,7 @@ bool AudioDeviceAndroidOpenSLES::RecordingIsInitialized() const {
}
bool AudioDeviceAndroidOpenSLES::Recording() const {
CriticalSectionScoped callback_lock(&callback_crit_sect_);
return is_recording_;
}
@ -1366,9 +1371,13 @@ bool AudioDeviceAndroidOpenSLES::RecThreadFuncImpl() {
const unsigned int total_bytes = num_bytes;
int8_t buf[REC_MAX_TEMP_BUF_SIZE_PER_10ms];
// Always grab crit_sect_ first, then callback_crit_sect_
// And vice-versa for releasing
crit_sect_.Enter();
callback_crit_sect_.Enter();
while (is_recording_) {
if (rec_voe_audio_queue_.size() <= 0) {
callback_crit_sect_.Leave();
crit_sect_.Leave();
// Wait for max 40ms for incoming audio data before looping the
// poll and checking for ::Stop() being called (which waits for us
@ -1379,8 +1388,10 @@ bool AudioDeviceAndroidOpenSLES::RecThreadFuncImpl() {
// exit after ::Stop(). This value of 40ms is arbitrary.
rec_timer_.Wait(40);
crit_sect_.Enter();
callback_crit_sect_.Enter();
if (rec_voe_audio_queue_.size() <= 0) {
// still no audio data; check for ::Stop()
callback_crit_sect_.Leave();
crit_sect_.Leave();
return true;
}
@ -1396,10 +1407,13 @@ bool AudioDeviceAndroidOpenSLES::RecThreadFuncImpl() {
voe_audio_buffer_->SetVQEData(playout_delay_, recording_delay_, 0);
// All other implementations UnLock around DeliverRecordedData() only
callback_crit_sect_.Leave();
crit_sect_.Leave();
voe_audio_buffer_->DeliverRecordedData();
crit_sect_.Enter();
callback_crit_sect_.Enter();
}
callback_crit_sect_.Leave();
crit_sect_.Leave();
// if is_recording is false, we either *just* were started, or for some reason
@ -1420,7 +1434,10 @@ void AudioDeviceAndroidOpenSLES::RecorderSimpleBufferQueueCallbackHandler(
int8_t* audio;
{
CriticalSectionScoped lock(&crit_sect_);
// use this instead of crit_sect_ to avoid race against StopRecording()
// (which holds crit_sect, and then waits for the thread that calls
// this to exit, leading to possible deadlock (bug 904784)
CriticalSectionScoped lock(&callback_crit_sect_);
if (!is_recording_) {
return;
}

View File

@ -240,6 +240,10 @@ class AudioDeviceAndroidOpenSLES: public AudioDeviceGeneric {
// Misc
AudioDeviceBuffer* voe_audio_buffer_;
CriticalSectionWrapper& crit_sect_;
// callback_crit_sect_ is used to lock rec_queue and rec_voe_ready_queue
// and also for changing is_recording to false. If you hold this and
// crit_sect_, you must grab crit_sect_ first
CriticalSectionWrapper& callback_crit_sect_;
int32_t id_;
// audio unit