[vlc-devel] [PATCH 1/2] audiotrack: fix too unstable delay

Thomas Guillem thomas at gllm.fr
Wed Feb 25 19:29:08 CET 2015


It was impossible to calculate a stable delay from 2 different threads.
Calculate audiotrack delay and the Queue delay from JNIThread.  All JNIThread
commands are now executed in locked state.
---
 modules/audio_output/audiotrack.c | 85 +++++++++++++++++++++++++--------------
 1 file changed, 54 insertions(+), 31 deletions(-)

diff --git a/modules/audio_output/audiotrack.c b/modules/audio_output/audiotrack.c
index 7b2646f..e1e0b8b 100644
--- a/modules/audio_output/audiotrack.c
+++ b/modules/audio_output/audiotrack.c
@@ -72,7 +72,6 @@ struct aout_sys_t {
     bool b_thread_run; /* is thread alive */
     THREAD_CMD_QUEUE thread_cmd_queue; /* thread cmd queue */
     uint32_t i_samples_queued; /* number of samples queued */
-    uint32_t i_audiotrack_delay; /* audiotrack delay in samples */
 };
 
 /* Soft volume helper */
@@ -99,6 +98,7 @@ struct thread_cmd
         CMD_STOP,
         CMD_PLAY,
         CMD_PAUSE,
+        CMD_TIME_GET,
         CMD_FLUSH,
         CMD_DONE,
     } id;
@@ -122,6 +122,10 @@ struct thread_cmd
             int i_ret;
             audio_sample_format_t *p_fmt;
         } start;
+        struct {
+            int i_ret;
+            mtime_t i_delay;
+        } time_get;
     } out;
     void ( *pf_destroy )( struct thread_cmd * );
 };
@@ -403,7 +407,7 @@ ThreadCmd_FlushQueue( aout_sys_t *p_sys )
 }
 
 static void
-JNIThread_InitDelay( JNIEnv *env, audio_output_t *p_aout, uint32_t *p_delay )
+JNIThread_InitDelay( JNIEnv *env, audio_output_t *p_aout )
 {
     aout_sys_t *p_sys = p_aout->sys;
 
@@ -424,11 +428,11 @@ JNIThread_InitDelay( JNIEnv *env, audio_output_t *p_aout, uint32_t *p_delay )
         } while( p_sys->i_pos_initial != i_last_pos );
     }
     p_sys->i_samples_written = 0;
-    *p_delay = 0;
+    p_sys->i_samples_queued = 0;
 }
 
-static void
-JNIThread_SetDelay( JNIEnv *env, audio_output_t *p_aout, uint32_t *p_delay )
+static int
+JNIThread_TimeGet( JNIEnv *env, audio_output_t *p_aout, mtime_t *p_delay )
 {
     aout_sys_t *p_sys = p_aout->sys;
     bool b_frame_delay_set = false;
@@ -487,11 +491,18 @@ JNIThread_SetDelay( JNIEnv *env, audio_output_t *p_aout, uint32_t *p_delay )
 
         uint32_t i_head_pos = JNI_AT_CALL_INT( getPlaybackHeadPosition );
         i_frame_pos = i_head_pos - p_sys->i_pos_initial;
-        b_frame_delay_set = true;
+        if (i_frame_pos > 0)
+            b_frame_delay_set = true;
     }
 
     if( b_frame_delay_set && p_sys->i_samples_written > i_frame_pos )
-        *p_delay = p_sys->i_samples_written - i_frame_pos;
+    {
+        uint32_t i_audiotrack_delay = p_sys->i_samples_written - i_frame_pos;
+
+        *p_delay = FRAMES_TO_US( p_sys->i_samples_queued + i_audiotrack_delay );
+        return 0;
+    } else
+        return -1;
 }
 
 static int
@@ -691,6 +702,7 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
 
         i_offset += i_ret;
     }
+    p_sys->i_samples_queued -= p_buffer->i_nb_samples;
     p_sys->i_samples_written += p_buffer->i_nb_samples;
     return VLC_SUCCESS;
 }
@@ -756,7 +768,6 @@ JNIThread( void *data )
     aout_sys_t *p_sys = p_aout->sys;
     bool b_error = false;
     bool b_paused = false;
-    uint32_t i_audiotrack_delay = 0;
     JNIEnv* env;
 
     jni_attach_thread( &env, THREAD_NAME );
@@ -782,16 +793,20 @@ JNIThread( void *data )
             vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
             continue;
         }
-
-        TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
-
         if( p_cmd->id == CMD_PLAY )
         {
-            p_sys->i_samples_queued -= p_cmd->in.play.p_buffer->i_nb_samples;
-            vlc_cond_signal( &p_sys->cond );
+            /* Yield the current thread. Give room for others commands.
+             * Especially TimeGet that is called very often */
+            mtime_t i_wait =
+                FRAMES_TO_US( p_cmd->in.play.p_buffer->i_nb_samples ) / 2
+            vlc_cond_timedwait( &p_sys->cond, &p_sys->mutex, mdate() + i_wait );
+            p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue );
+            if( p_cmd == NULL )
+                break;
         }
 
-        vlc_mutex_unlock( &p_sys->mutex );
+        TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
+
         /* process a command */
         switch( p_cmd->id )
         {
@@ -804,14 +819,14 @@ JNIThread( void *data )
                 p_sys->fmt = *p_cmd->in.start.p_fmt;
                 p_cmd->out.start.i_ret =
                         JNIThread_Start( env, p_aout );
-                JNIThread_InitDelay( env, p_aout, &i_audiotrack_delay );
+                JNIThread_InitDelay( env, p_aout );
                 p_cmd->out.start.p_fmt = &p_sys->fmt;
                 b_paused = false;
                 break;
             case CMD_STOP:
                 assert( p_sys->p_audiotrack );
                 JNIThread_Stop( env, p_aout );
-                JNIThread_InitDelay( env, p_aout, &i_audiotrack_delay );
+                JNIThread_InitDelay( env, p_aout );
                 b_paused = false;
                 b_error = false;
                 break;
@@ -821,7 +836,6 @@ JNIThread( void *data )
                     break;
                 b_error = JNIThread_Play( env, p_aout,
                                           p_cmd->in.play.p_buffer ) != VLC_SUCCESS;
-                JNIThread_SetDelay( env, p_aout, &i_audiotrack_delay );
                 break;
             case CMD_PAUSE:
                 assert( p_sys->p_audiotrack );
@@ -832,13 +846,21 @@ JNIThread( void *data )
                                  p_cmd->in.pause.i_date );
                 b_paused = p_cmd->in.pause.b_pause;
                 break;
+            case CMD_TIME_GET:
+                assert( p_sys->p_audiotrack );
+                if( b_error )
+                    break;
+                p_cmd->out.time_get.i_ret =
+                        JNIThread_TimeGet( env, p_aout,
+                                           &p_cmd->out.time_get.i_delay );
+                break;
             case CMD_FLUSH:
                 assert( p_sys->p_audiotrack );
                 if( b_error )
                     break;
                 JNIThread_Flush( env, p_aout,
                                  p_cmd->in.flush.b_wait );
-                JNIThread_InitDelay( env, p_aout, &i_audiotrack_delay );
+                JNIThread_InitDelay( env, p_aout );
                 break;
             default:
                 vlc_assert_unreachable();
@@ -846,10 +868,6 @@ JNIThread( void *data )
         if( p_sys->b_audiotrack_exception )
             b_error = true;
 
-        vlc_mutex_lock( &p_sys->mutex );
-
-        p_sys->i_audiotrack_delay = i_audiotrack_delay;
-
         p_cmd->id = CMD_DONE;
         if( p_cmd->pf_destroy )
             p_cmd->pf_destroy( p_cmd );
@@ -909,7 +927,6 @@ Stop( audio_output_t *p_aout )
 
     vlc_mutex_lock( &p_sys->mutex );
 
-    p_sys->i_samples_queued = 0;
     ThreadCmd_FlushQueue( p_sys );
 
     p_cmd = ThreadCmd_New( CMD_STOP );
@@ -993,7 +1010,6 @@ Flush( audio_output_t *p_aout, bool b_wait )
 
     vlc_mutex_lock( &p_sys->mutex );
 
-    p_sys->i_samples_queued = 0;
     ThreadCmd_FlushQueue( p_sys );
 
     p_cmd = ThreadCmd_New( CMD_FLUSH );
@@ -1015,16 +1031,23 @@ static int
 TimeGet( audio_output_t *p_aout, mtime_t *restrict p_delay )
 {
     aout_sys_t *p_sys = p_aout->sys;
-    int i_ret;
+    struct thread_cmd *p_cmd;
+    int i_ret = -1;
 
     vlc_mutex_lock( &p_sys->mutex );
-    if( p_sys->i_samples_queued != 0 )
+
+    p_cmd = ThreadCmd_New( CMD_TIME_GET );
+    if( p_cmd)
     {
-        *p_delay = FRAMES_TO_US( p_sys->i_samples_queued +
-                                 p_sys->i_audiotrack_delay );
-        i_ret = 0;
-    } else
-        i_ret = -1;
+        ThreadCmd_InsertHead( p_sys, p_cmd );
+        ThreadCmd_Wait( p_sys, p_cmd );
+
+        i_ret = p_cmd->out.time_get.i_ret;
+        *p_delay = p_cmd->out.time_get.i_delay;
+
+        free( p_cmd );
+    }
+
     vlc_mutex_unlock( &p_sys->mutex );
 
     return i_ret;
-- 
2.1.3




More information about the vlc-devel mailing list