Bug 899159: (beta 24 version) clean up record issues in webrtc OpenSLES code + wallpaper r=padenot,derf,mwu a=bajaj on a CLOSED TREE
authorRandell Jesup <rjesup@jesup.org>
Thu, 05 Sep 2013 15:34:05 -0400
changeset 258563 447a856a89bf457e621e93cdb9536ab7c52764a8
parent 258562 aaa392740eea3ccb8a6e7aa6f75fd2d7674562ac
child 258564 111306ce572fd0bc2bb4607e82f6ee4430da1b54
push id4700
push userryanvm@gmail.com
push dateTue, 21 Apr 2015 23:53:16 +0000
treeherdermozilla-beta@d27c9211ebb3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot, derf, mwu, bajaj
bugs899159
milestone24.0
Bug 899159: (beta 24 version) clean up record issues in webrtc OpenSLES code + wallpaper r=padenot,derf,mwu a=bajaj on a CLOSED TREE
media/webrtc/trunk/webrtc/modules/audio_device/android/audio_device_opensles_android.cc
--- a/media/webrtc/trunk/webrtc/modules/audio_device/android/audio_device_opensles_android.cc
+++ b/media/webrtc/trunk/webrtc/modules/audio_device/android/audio_device_opensles_android.cc
@@ -62,26 +62,27 @@ AudioDeviceAndroidOpenSLES::AudioDeviceA
       is_play_initialized_(false),
       is_mic_initialized_(false),
       is_speaker_initialized_(false),
       playout_delay_(0),
       recording_delay_(0),
       agc_enabled_(false),
       rec_thread_(NULL),
       rec_timer_(*EventWrapper::Create()),
-      mic_sampling_rate_(N_REC_SAMPLES_PER_SEC * 1000),
-      speaker_sampling_rate_(N_PLAY_SAMPLES_PER_SEC * 1000),
+      mic_sampling_rate_(N_REC_SAMPLES_PER_SEC),
+      speaker_sampling_rate_(N_PLAY_SAMPLES_PER_SEC),
       max_speaker_vol_(0),
       min_speaker_vol_(0),
       loundspeaker_on_(false),
       opensles_lib_(0) {
   WEBRTC_OPENSL_TRACE(kTraceMemory, kTraceAudioDevice, id, "%s created",
                       __FUNCTION__);
   memset(rec_buf_, 0, sizeof(rec_buf_));
   memset(play_buf_, 0, sizeof(play_buf_));
+  UpdateRecordingDelay();
 }
 
 AudioDeviceAndroidOpenSLES::~AudioDeviceAndroidOpenSLES() {
   WEBRTC_OPENSL_TRACE(kTraceMemory, kTraceAudioDevice, id_, "%s destroyed",
                       __FUNCTION__);
 
   Terminate();
 
@@ -1246,44 +1247,50 @@ WebRtc_Word32 AudioDeviceAndroidOpenSLES
 WebRtc_Word32 AudioDeviceAndroidOpenSLES::CPULoad(
     WebRtc_UWord16& load) const {
   WEBRTC_OPENSL_TRACE(kTraceWarning, kTraceAudioDevice, id_,
                       "  API call not supported on this platform");
   return -1;
 }
 
 bool AudioDeviceAndroidOpenSLES::PlayoutWarning() const {
+  CriticalSectionScoped lock(&crit_sect_);
   return (play_warning_ > 0);
 }
 
 bool AudioDeviceAndroidOpenSLES::PlayoutError() const {
+  CriticalSectionScoped lock(&crit_sect_);
   return (play_error_ > 0);
 }
 
 bool AudioDeviceAndroidOpenSLES::RecordingWarning() const {
+  CriticalSectionScoped lock(&crit_sect_);
   return (rec_warning_ > 0);
 }
 
 bool AudioDeviceAndroidOpenSLES::RecordingError() const {
+  CriticalSectionScoped lock(&crit_sect_);
   return (rec_error_ > 0);
 }
 
 void AudioDeviceAndroidOpenSLES::ClearPlayoutWarning() {
   play_warning_ = 0;
 }
 
 void AudioDeviceAndroidOpenSLES::ClearPlayoutError() {
   play_error_ = 0;
 }
 
 void AudioDeviceAndroidOpenSLES::ClearRecordingWarning() {
+  CriticalSectionScoped lock(&crit_sect_);
   rec_warning_ = 0;
 }
 
 void AudioDeviceAndroidOpenSLES::ClearRecordingError() {
+  CriticalSectionScoped lock(&crit_sect_);
   rec_error_ = 0;
 }
 
 WebRtc_Word32 AudioDeviceAndroidOpenSLES::SetLoudspeakerStatus(bool enable) {
   loundspeaker_on_ = enable;
   return 0;
 }
 
@@ -1345,89 +1352,117 @@ void AudioDeviceAndroidOpenSLES::Recorde
     SLAndroidSimpleBufferQueueItf queue_itf,
     void* p_context) {
   AudioDeviceAndroidOpenSLES* audio_device =
       static_cast<AudioDeviceAndroidOpenSLES*>(p_context);
   audio_device->RecorderSimpleBufferQueueCallbackHandler(queue_itf);
 }
 
 bool AudioDeviceAndroidOpenSLES::RecThreadFuncImpl() {
-  if (is_recording_) {
-    // TODO(leozwang): Add seting correct scheduling and thread priority.
+  // TODO(leozwang): Add seting correct scheduling and thread priority.
+
+  const unsigned int num_samples = mic_sampling_rate_ / 100;
+  const unsigned int num_bytes =
+    N_REC_CHANNELS * num_samples * sizeof(int16_t);
+  const unsigned int total_bytes = num_bytes;
+  WebRtc_Word8 buf[REC_MAX_TEMP_BUF_SIZE_PER_10ms];
 
-    const unsigned int num_samples = mic_sampling_rate_ / 100;
-    const unsigned int num_bytes =
-        N_REC_CHANNELS * num_samples * sizeof(int16_t);
-    const unsigned int total_bytes = num_bytes;
-    WebRtc_Word8 buf[REC_MAX_TEMP_BUF_SIZE_PER_10ms];
-
-    {
-      CriticalSectionScoped lock(&crit_sect_);
+  crit_sect_.Enter();
+  while (is_recording_) {
+    if (rec_voe_audio_queue_.size() <= 0) {
+      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
+      // to return).  Actual time between audio callbacks will vary, but
+      // is based on AudioRecord min buffer sizes, which may be 15-80ms
+      // or more, depending on sampling frequency, but typically will be
+      // 25ish ms at 44100Hz.  We also don't want to take "too long" to
+      // exit after ::Stop().  This value of 40ms is arbitrary.
+      rec_timer_.Wait(40);
+      crit_sect_.Enter();
       if (rec_voe_audio_queue_.size() <= 0) {
-        rec_timer_.Wait(1);
+        // still no audio data; check for ::Stop()
+        crit_sect_.Leave();
         return true;
       }
-
-      WebRtc_Word8* audio = rec_voe_audio_queue_.front();
-      rec_voe_audio_queue_.pop();
-      memcpy(buf, audio, total_bytes);
-      memset(audio, 0, total_bytes);
-      rec_voe_ready_queue_.push(audio);
     }
 
-    UpdateRecordingDelay();
+    WebRtc_Word8* audio = rec_voe_audio_queue_.front();
+    rec_voe_audio_queue_.pop();
+    memcpy(buf, audio, total_bytes);
+    memset(audio, 0, total_bytes);
+    rec_voe_ready_queue_.push(audio);
+
     voe_audio_buffer_->SetRecordedBuffer(buf, num_samples);
     voe_audio_buffer_->SetVQEData(playout_delay_, recording_delay_, 0);
+
+    // All other implementations UnLock around DeliverRecordedData() only
+    crit_sect_.Leave();
     voe_audio_buffer_->DeliverRecordedData();
+    crit_sect_.Enter();
   }
+  crit_sect_.Leave();
+
+  // if is_recording is false, we either *just* were started, or for some reason
+  // Stop() failed to get us to return for 10 seconds - and when we return here,
+  // Stop will kill us anyways.
+  rec_timer_.Wait(1);
 
   return true;
 }
 
 void AudioDeviceAndroidOpenSLES::RecorderSimpleBufferQueueCallbackHandler(
     SLAndroidSimpleBufferQueueItf queue_itf) {
-  if (is_recording_) {
-    const unsigned int num_samples = mic_sampling_rate_ / 100;
-    const unsigned int num_bytes =
-        N_REC_CHANNELS * num_samples * sizeof(int16_t);
-    const unsigned int total_bytes = num_bytes;
-    WebRtc_Word8* audio;
 
-    {
-      CriticalSectionScoped lock(&crit_sect_);
-      audio = rec_queue_.front();
-      rec_queue_.pop();
-      rec_voe_audio_queue_.push(audio);
+  const unsigned int num_samples = mic_sampling_rate_ / 100;
+  const unsigned int num_bytes =
+    N_REC_CHANNELS * num_samples * sizeof(int16_t);
+  const unsigned int total_bytes = num_bytes;
+  WebRtc_Word8* audio;
 
-      if (rec_voe_ready_queue_.size() <= 0) {
-        // Log Error.
-        rec_error_ = 1;
-        WEBRTC_OPENSL_TRACE(kTraceError, kTraceAudioDevice, id_,
-                            "  Audio Rec thread buffers underrun");
-      } else {
-        audio = rec_voe_ready_queue_.front();
-        rec_voe_ready_queue_.pop();
-      }
+  {
+    CriticalSectionScoped lock(&crit_sect_);
+    if (!is_recording_) {
+      return;
     }
+    audio = rec_queue_.front();
+    rec_queue_.pop();
+    rec_voe_audio_queue_.push(audio);
+    rec_timer_.Set(); // wake up record thread to process it
 
-    WebRtc_Word32 res = (*queue_itf)->Enqueue(queue_itf,
-                                              audio,
-                                              total_bytes);
-    if (res != SL_RESULT_SUCCESS) {
-      WEBRTC_OPENSL_TRACE(kTraceWarning, kTraceAudioDevice, id_,
-                          "  recorder callback Enqueue failed, %d", res);
-      rec_warning_ = 1;
+    if (rec_voe_ready_queue_.size() <= 0) {
+      // Log Error.
+      rec_error_ = 1;
+      WEBRTC_OPENSL_TRACE(kTraceError, kTraceAudioDevice, id_,
+                          "  Audio Rec thread buffers underrun");
+      // This isn't good, but continuing (as it used to) is even worse.
+      // Worst case we end up with buffers building up at the other end or
+      // starved.  To be fixed in full rewrite from upstream.
       return;
     } else {
-      rec_queue_.push(audio);
+      audio = rec_voe_ready_queue_.front();
+      rec_voe_ready_queue_.pop();
     }
+  }
 
-    // TODO(leozwang): OpenSL ES doesn't support AudioRecorder
-    // volume control now, add it when it's ready.
+  WebRtc_Word32 res = (*queue_itf)->Enqueue(queue_itf,
+                                            audio,
+                                            total_bytes);
+  if (res != SL_RESULT_SUCCESS) {
+    WEBRTC_OPENSL_TRACE(kTraceWarning, kTraceAudioDevice, id_,
+                        "  recorder callback Enqueue failed, %d", res);
+    CriticalSectionScoped lock(&crit_sect_);
+    rec_warning_ = 1;
+    return;
+  } else {
+    rec_queue_.push(audio);
   }
+
+  // TODO(leozwang): OpenSL ES doesn't support AudioRecorder
+  // volume control now, add it when it's ready.
 }
 
 void AudioDeviceAndroidOpenSLES::CheckErr(SLresult res) {
   if (res != SL_RESULT_SUCCESS) {
     WEBRTC_OPENSL_TRACE(kTraceError, kTraceAudioDevice, id_,
                         "  AudioDeviceAndroidOpenSLES::CheckErr(%lu)", res);
     exit(-1);
   }
@@ -1452,16 +1487,17 @@ WebRtc_Word32 AudioDeviceAndroidOpenSLES
   if (sles_engine_ == NULL) {
     WEBRTC_OPENSL_TRACE(kTraceError, kTraceAudioDevice, id_,
                         "  SL Object is NULL");
     return -1;
   }
 
   mic_sampling_rate_ = N_REC_SAMPLES_PER_SEC;
   speaker_sampling_rate_ = N_PLAY_SAMPLES_PER_SEC;
+  UpdateRecordingDelay();
 
   WEBRTC_OPENSL_TRACE(kTraceStateInfo, kTraceAudioDevice, id_,
                       "  mic sample rate (%d), speaker sample rate (%d)",
                       mic_sampling_rate_, speaker_sampling_rate_);
   return 0;
 }
 
 }  // namespace webrtc