media/libsydneyaudio/bug525401_drain_deadlock.patch
author Shawn Wilsher <me@shawnwilsher.com>
Thu, 03 Feb 2011 12:06:06 -0800
branchGECKO20b5_20100831_RELBRANCH
changeset 61899 35056c98e71956ef4fefccd4b29fb304209ae4b9
parent 38762 b876c36242dc3bfd4344caffae55a9590ee1b42d
permissions -rw-r--r--
closing old branch that is no longer used per bug 611030

diff --git a/media/libsydneyaudio/src/sydney_audio_alsa.c b/media/libsydneyaudio/src/sydney_audio_alsa.c
--- a/media/libsydneyaudio/src/sydney_audio_alsa.c
+++ b/media/libsydneyaudio/src/sydney_audio_alsa.c
@@ -315,16 +315,19 @@ sa_stream_resume(sa_stream_t *s) {
 
 
 int
 sa_stream_drain(sa_stream_t *s)
 {
   if (s == NULL || s->output_unit == NULL) {
     return SA_ERROR_NO_INIT;
   }
+  if (snd_pcm_state(s->output_unit) != SND_PCM_STATE_RUNNING) {
+    return SA_ERROR_INVALID;
+  }
   snd_pcm_drain(s->output_unit);
   return SA_SUCCESS;
 }
 
 
 
 /*
  * -----------------------------------------------------------------------------
diff --git a/media/libsydneyaudio/src/sydney_audio_mac.c b/media/libsydneyaudio/src/sydney_audio_mac.c
--- a/media/libsydneyaudio/src/sydney_audio_mac.c
+++ b/media/libsydneyaudio/src/sydney_audio_mac.c
@@ -396,20 +396,20 @@ sa_stream_write(sa_stream_t *s, const vo
 
   /*
    * Once we have our first block of audio data, enable the audio callback
    * function. This doesn't need to be protected by the mutex, because
    * s->playing is not used in the audio callback thread, and it's probably
    * better not to be inside the lock when we enable the audio callback.
    */
   if (!s->playing) {
+    if (AudioOutputUnitStart(s->output_unit) != 0) {
+      return SA_ERROR_SYSTEM;
+    }
     s->playing = TRUE;
-    if (AudioOutputUnitStart(s->output_unit) != 0) {
-      result = SA_ERROR_SYSTEM;
-    }
   }
 
   return result;
 }
 
 
 static OSStatus
 audio_callback(
@@ -553,17 +553,20 @@ sa_stream_pause(sa_stream_t *s) {
   }
 
   /*
    * Don't hold the mutex when stopping the audio device, because it is
    * possible to deadlock with this thread holding mutex then waiting on an
    * internal Core Audio lock, and with the callback thread holding the Core
    * Audio lock and waiting on the mutex.
   */
-  AudioOutputUnitStop(s->output_unit);
+  if (AudioOutputUnitStop(s->output_unit) != 0) {
+    return SA_ERROR_SYSTEM;
+  }
+  s->playing = FALSE;
 
   return SA_SUCCESS;
 }
 
 
 int
 sa_stream_resume(sa_stream_t *s) {
 
@@ -581,17 +584,20 @@ sa_stream_resume(sa_stream_t *s) {
   pthread_mutex_unlock(&s->mutex);
 
   /*
    * Don't hold the mutex when starting the audio device, because it is
    * possible to deadlock with this thread holding mutex then waiting on an
    * internal Core Audio lock, and with the callback thread holding the Core
    * Audio lock and waiting on the mutex.
   */
-  AudioOutputUnitStart(s->output_unit);
+  if (AudioOutputUnitStart(s->output_unit) != 0) {
+    return SA_ERROR_SYSTEM;
+  }
+  s->playing = TRUE;
 
   return SA_SUCCESS;
 }
 
 
 static sa_buf *
 new_buffer(void) {
   sa_buf  * b = malloc(sizeof(sa_buf) + BUF_SIZE);
@@ -607,16 +613,20 @@ new_buffer(void) {
 
 int
 sa_stream_drain(sa_stream_t *s)
 {
   if (s == NULL || s->output_unit == NULL) {
     return SA_ERROR_NO_INIT;
   }
 
+  if (!s->playing) {
+    return SA_ERROR_INVALID;
+  }
+
   while (1) {
     pthread_mutex_lock(&s->mutex);
     sa_buf  * b;
     size_t    used = 0;
     for (b = s->bl_head; b != NULL; b = b->next) {
       used += b->end - b->start;
     }
     pthread_mutex_unlock(&s->mutex);
diff --git a/media/libsydneyaudio/src/sydney_audio_waveapi.c b/media/libsydneyaudio/src/sydney_audio_waveapi.c
--- a/media/libsydneyaudio/src/sydney_audio_waveapi.c
+++ b/media/libsydneyaudio/src/sydney_audio_waveapi.c
@@ -111,16 +111,18 @@ struct sa_stream {
   sa_pcm_format_t	format;   
  
   HWAVEOUT			  hWaveOut;
   HANDLE			    callbackEvent;
   CRITICAL_SECTION  waveCriticalSection;  
   WAVEHDR*			  waveBlocks;  
   volatile int		waveFreeBlockCount;
   int				      waveCurrentBlock;
+
+  int playing;
 };
 
 
 /** Forward definitions of audio api specific functions */
 int allocateBlocks(int size, int count, WAVEHDR** blocks);
 int freeBlocks(WAVEHDR* blocks);
 int openAudio(sa_stream_t *s);
 int closeAudio(sa_stream_t * s);
@@ -157,16 +159,17 @@ int sa_stream_create_pcm(sa_stream_t **s
   }
    
   _s->rwMode = mode;
   _s->format = format;
   _s->rate = rate;
   _s->channels = nchannels;
   _s->deviceName = DEFAULT_DEVICE_NAME;
   _s->device = DEFAULT_DEVICE;
+  _s->playing = 0;
 
   *s = _s; 
   return SA_SUCCESS;
 }
 
 /** Initialise the device */
 int sa_stream_open(sa_stream_t *s) {  
   int status = SA_SUCCESS;
@@ -300,33 +303,41 @@ int sa_stream_get_position(sa_stream_t *
 int sa_stream_resume(sa_stream_t *s) {
   int status;  
   
   ERROR_IF_NO_INIT(s);
 
   status = waveOutRestart(s->hWaveOut);
   HANDLE_WAVE_ERROR(status, "resuming audio playback");
 
+  s->playing = 1;
+
   return SA_SUCCESS;
 }
 /** Pause audio playback (do not empty the buffer) */
 int sa_stream_pause(sa_stream_t *s) {
   int status;
 
   ERROR_IF_NO_INIT(s);
   
   status = waveOutPause(s->hWaveOut);
   HANDLE_WAVE_ERROR(status, "resuming audio playback");
 
+  s->playing = 0;
+
   return SA_SUCCESS;
 }
 /** Block until all audio has been played */
 int sa_stream_drain(sa_stream_t *s) {
   ERROR_IF_NO_INIT(s);
   
+  if (!s->playing) {
+    return SA_ERROR_INVALID;
+  }
+
   /* wait for all blocks to complete */
   EnterCriticalSection(&(s->waveCriticalSection));
   while(s->waveFreeBlockCount < BLOCK_COUNT) {
     LeaveCriticalSection(&(s->waveCriticalSection));
     Sleep(10);
     EnterCriticalSection(&(s->waveCriticalSection));
   }
   LeaveCriticalSection(&(s->waveCriticalSection));
@@ -484,16 +495,18 @@ int closeAudio(sa_stream_t * s) {
     s->waveBlocks = NULL;
   }
 
   status = waveOutClose(s->hWaveOut);    
   if (status != MMSYSERR_NOERROR) {
     result = getSAErrorCode(status);
   }
 
+  s->playing = 0;
+
   DeleteCriticalSection(&(s->waveCriticalSection));
   CloseHandle(s->callbackEvent);
   
   return result;
 }
 /**
  * \brief - writes PCM audio samples to audio device
  * \param s - valid handle to opened sydney stream
@@ -545,16 +558,18 @@ int writeAudio(sa_stream_t *s, LPSTR dat
     /*
      * point to the next block
      */
     (s->waveCurrentBlock)++;
     (s->waveCurrentBlock) %= BLOCK_COUNT;		
 
     current = &(s->waveBlocks[s->waveCurrentBlock]);
     current->dwUser = 0;
+
+    s->playing = 1;
   }
   return SA_SUCCESS;
 }
 
 /**
  * \brief - audio callback function called when next WAVE header is played by audio device
  */
 void CALLBACK waveOutProc(