Bug 899159: clean up record issues in webrtc OpenSLES code + wallpaper r=padenot,derf,mwu
authorRandell Jesup <rjesup@jesup.org>
Thu, 05 Sep 2013 15:34:05 -0400
changeset 158684 a058786a8080dd4acf48399c66989ee302a122dc
parent 158683 5acaf91e82183e92fae9bfca2deb889a8fbd355d
child 158685 5de2c664c0febc57484c6ea5f40ceebed786c0ad
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot, derf, mwu
bugs899159
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 899159: clean up record issues in webrtc OpenSLES code + wallpaper r=padenot,derf,mwu More to be done upstream and then will replace this
media/webrtc/trunk/webrtc/modules/audio_device/audio_device_opensles.cc
--- a/media/webrtc/trunk/webrtc/modules/audio_device/audio_device_opensles.cc
+++ b/media/webrtc/trunk/webrtc/modules/audio_device/audio_device_opensles.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();
 
@@ -1247,44 +1248,50 @@ int32_t AudioDeviceAndroidOpenSLES::Play
 int32_t AudioDeviceAndroidOpenSLES::CPULoad(
     uint16_t& 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;
 }
 
 int32_t AudioDeviceAndroidOpenSLES::SetLoudspeakerStatus(bool enable) {
   loundspeaker_on_ = enable;
   return 0;
 }
 
@@ -1346,89 +1353,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;
+  int8_t 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;
-    int8_t 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;
       }
-
-      int8_t* 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();
+    int8_t* 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;
-    int8_t* 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;
+  int8_t* 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
 
-    int32_t 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.
+  int32_t 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);
   }
@@ -1453,16 +1488,17 @@ int32_t AudioDeviceAndroidOpenSLES::Init
   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