decoder: work around race whereby pause kicks during lip-sync
authorRémi Denis-Courmont <remi@remlab.net>
Mon, 23 Apr 2012 19:45:23 +0000 (22:45 +0300)
committerRémi Denis-Courmont <remi@remlab.net>
Thu, 3 May 2012 19:51:54 +0000 (22:51 +0300)
DecoderWaitDate() releases the lock and thus state can change.
In particular, the aout can be destroyed, or paused or resumed.
So those checks must be done after DecoderWaitDate().

There may be a cleaner way to do this, but it will likely be more
invasive. This patch fixes #5825 and probably #6369 too.

src/input/decoder.c

index e043448..b68df6f 100644 (file)
@@ -1188,13 +1188,14 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio,
 
     for( ;; )
     {
 
     for( ;; )
     {
-        bool b_has_more = false;
-        bool b_reject;
-        DecoderWaitUnblock( p_dec, &b_reject );
+        bool b_has_more = false, b_paused, b_reject;
 
 
+        DecoderWaitUnblock( p_dec, &b_reject );
         if( p_owner->b_buffering )
             break;
 
         if( p_owner->b_buffering )
             break;
 
+        b_paused = p_owner->b_paused;
+
         /* */
         if( p_owner->buffer.p_audio )
         {
         /* */
         if( p_owner->buffer.p_audio )
         {
@@ -1214,15 +1215,19 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio,
         DecoderFixTs( p_dec, &p_audio->i_pts, NULL, &p_audio->i_length,
                       &i_rate, AOUT_MAX_ADVANCE_TIME );
 
         DecoderFixTs( p_dec, &p_audio->i_pts, NULL, &p_audio->i_length,
                       &i_rate, AOUT_MAX_ADVANCE_TIME );
 
-        if( !p_aout ||
-            p_audio->i_pts <= VLC_TS_INVALID ||
-            i_rate < INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE ||
-            i_rate > INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE )
+        if( p_audio->i_pts <= VLC_TS_INVALID
+         || i_rate < INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE
+         || i_rate > INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE )
             b_reject = true;
 
         DecoderWaitDate( p_dec, &b_reject,
                          p_audio->i_pts - AOUT_MAX_PREPARE_TIME );
 
             b_reject = true;
 
         DecoderWaitDate( p_dec, &b_reject,
                          p_audio->i_pts - AOUT_MAX_PREPARE_TIME );
 
+        if( unlikely(p_owner->b_paused != b_paused) )
+            continue; /* race with input thread? retry... */
+        if( p_aout == NULL )
+            b_reject = true;
+
         if( !b_reject )
         {
             assert( !p_owner->b_paused );
         if( !b_reject )
         {
             assert( !p_owner->b_paused );