]> git.sesse.net Git - vlc/blobdiff - modules/audio_output/alsa.c
alsa: sets period size before buffer size, patch by Matthias P. Nowak
[vlc] / modules / audio_output / alsa.c
index a90e2fde0a85a0bba929bc67819793e1e41538fd..dbcb02bc1a6b01d71961a844e3222e84d9811216 100644 (file)
@@ -40,6 +40,8 @@
 #define ALSA_PCM_NEW_SW_PARAMS_API
 #include <alsa/asoundlib.h>
 
+/*#define ALSA_DEBUG*/
+
 /*****************************************************************************
  * aout_sys_t: ALSA audio output method descriptor
  *****************************************************************************
@@ -583,34 +585,34 @@ static int Open( vlc_object_t *p_this )
                 p_aout->output.output.i_rate );
         }
 
-        /* Set buffer size. */
+        /* Set period size. */
 #ifdef HAVE_ALSA_NEW_API
-        if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
-                                    p_hw, &i_buffer_size ) ) < 0 )
+        if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
+                                    p_hw, &i_period_size, NULL ) ) < 0 )
 #else
-        if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
-                                    p_hw, i_buffer_size ) ) < 0 )
+        if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
+                                    p_hw, i_period_size, NULL ) ) < 0 )
 #endif
         {
-            msg_Err( p_aout, "unable to set buffer size (%s)",
+            msg_Err( p_aout, "unable to set period size (%s)",
                          snd_strerror( i_snd_rc ) );
             goto error;
         }
+        p_aout->output.i_nb_samples = i_period_size;
 
-        /* Set period size. */
+/* Set buffer size. */
 #ifdef HAVE_ALSA_NEW_API
-        if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
-                                    p_hw, &i_period_size, NULL ) ) < 0 )
+        if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
+                                    p_hw, &i_buffer_size ) ) < 0 )
 #else
-        if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
-                                    p_hw, i_period_size, NULL ) ) < 0 )
+        if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
+                                    p_hw, i_buffer_size ) ) < 0 )
 #endif
         {
-            msg_Err( p_aout, "unable to set period size (%s)",
+            msg_Err( p_aout, "unable to set buffer size (%s)",
                          snd_strerror( i_snd_rc ) );
             goto error;
         }
-        p_aout->output.i_nb_samples = i_period_size;
 
         /* Commit hardware parameters. */
         if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
@@ -760,10 +762,13 @@ static int ALSAThread( aout_instance_t * p_aout )
 
     /* Wait for the exact time to start playing (avoids resampling) */
     vlc_mutex_lock( &p_sys->lock );
-    while( !p_sys->start_date )
+    while( !p_sys->start_date && !p_aout->b_die )
         vlc_cond_wait( &p_sys->wait, &p_sys->lock );
     vlc_mutex_unlock( &p_sys->lock );
 
+    if( p_aout->b_die )
+       goto cleanup;
+
     mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
 
     while ( !p_aout->b_die )
@@ -771,6 +776,7 @@ static int ALSAThread( aout_instance_t * p_aout )
         ALSAFill( p_aout );
     }
 
+cleanup:
     snd_pcm_drop( p_sys->p_snd_pcm );
     free( p_aout->output.p_sys->p_status );
     return 0;
@@ -826,28 +832,26 @@ static void ALSAFill( aout_instance_t * p_aout )
     {
         /* Here the device should be in RUNNING state.
          * p_status is valid. */
+        snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
+        int i_bytes = snd_pcm_frames_to_bytes( p_sys->p_snd_pcm, delay );
+        next_date = mdate() + ( (mtime_t)i_bytes * 1000000
+                / p_aout->output.output.i_bytes_per_frame
+                / p_aout->output.output.i_rate
+                * p_aout->output.output.i_frame_length );
 
-#if 0
-        /* This apparently does not work correctly in Alsa 1.0.11 */
-        snd_pcm_status_get_tstamp( p_status, &ts_next );
-        next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
-        if( next_date )
-        {
-            next_date += (mtime_t)snd_pcm_status_get_delay(p_status)
-                    * 1000000 / p_aout->output.output.i_rate;
-        }
-        else
+#ifdef ALSA_DEBUG
+        snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
+        if( state != SND_PCM_STATE_RUNNING )
+            msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
+
+        msg_Dbg( p_aout, "Delay is %ld frames (%d bytes)", delay, i_bytes );
+
+        msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
+        msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
+        msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
+
+        msg_Dbg( p_aout, "Next date is in %d microseconds", (int)(next_date - mdate()) );
 #endif
-        {
-            /* With screwed ALSA drivers the timestamp is always zero;
-             * use another method then */
-            snd_pcm_sframes_t delay = 0;
-
-            snd_pcm_delay( p_sys->p_snd_pcm, &delay );
-            next_date = mdate() + (mtime_t)(delay) * 1000000
-                        / p_aout->output.output.i_rate
-                        * p_aout->output.output.i_frame_length;
-        }
     }
 
     p_buffer = aout_OutputNextBuffer( p_aout, next_date,