X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faudio_output%2Falsa.c;h=36b8c9a9904ce5f7e1598f76cffc57f98ef12134;hb=745c790b436ed55581d249c62f5451e5842652b6;hp=a90e2fde0a85a0bba929bc67819793e1e41538fd;hpb=9af57553c9e93a62d2f9b68f78d0420053fbffa2;p=vlc diff --git a/modules/audio_output/alsa.c b/modules/audio_output/alsa.c index a90e2fde0a..36b8c9a990 100644 --- a/modules/audio_output/alsa.c +++ b/modules/audio_output/alsa.c @@ -27,18 +27,29 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include #include /* ENOMEM */ -#include +#include #include +#include /* ALSA part Note: we use the new API which is available since 0.9.0beta10a. */ #define ALSA_PCM_NEW_HW_PARAMS_API #define ALSA_PCM_NEW_SW_PARAMS_API #include +#include + +/*#define ALSA_DEBUG*/ /***************************************************************************** * aout_sys_t: ALSA audio output method descriptor @@ -55,13 +66,9 @@ struct aout_sys_t snd_output_t * p_snd_stderr; #endif - int b_playing; /* playing status */ - mtime_t start_date; - - vlc_mutex_t lock; - vlc_cond_t wait ; - - snd_pcm_status_t *p_status; + mtime_t start_date; + vlc_thread_t thread; + vlc_sem_t wait; }; #define A52_FRAME_NB 1536 @@ -83,32 +90,33 @@ struct aout_sys_t /***************************************************************************** * Local prototypes *****************************************************************************/ -static int Open ( vlc_object_t * ); -static void Close ( vlc_object_t * ); -static void Play ( aout_instance_t * ); -static int ALSAThread ( aout_instance_t * ); -static void ALSAFill ( aout_instance_t * ); +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); +static void Play ( aout_instance_t * ); +static void* ALSAThread ( void * ); +static void ALSAFill ( aout_instance_t * ); static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name, vlc_value_t newval, vlc_value_t oldval, void *p_unused ); /***************************************************************************** * Module descriptor *****************************************************************************/ -static const char *ppsz_devices[] = { "default" }; -static const char *ppsz_devices_text[] = { N_("Default") }; -vlc_module_begin(); - set_shortname( "ALSA" ); - set_description( _("ALSA audio output") ); - set_category( CAT_AUDIO ); - set_subcategory( SUBCAT_AUDIO_AOUT ); - add_string( "alsadev", DEFAULT_ALSA_DEVICE, aout_FindAndRestart, - N_("ALSA Device Name"), NULL, VLC_FALSE ); - change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback ); - change_action_add( FindDevicesCallback, N_("Refresh list") ); - - set_capability( "audio output", 150 ); - set_callbacks( Open, Close ); -vlc_module_end(); +static const char *const ppsz_devices[] = { "default" }; +static const char *const ppsz_devices_text[] = { N_("Default") }; +vlc_module_begin () + set_shortname( "ALSA" ) + set_description( N_("ALSA audio output") ) + set_category( CAT_AUDIO ) + set_subcategory( SUBCAT_AUDIO_AOUT ) + add_string( "alsa-audio-device", DEFAULT_ALSA_DEVICE, aout_FindAndRestart, + N_("ALSA Device Name"), NULL, false ) + add_deprecated_alias( "alsadev" ) /* deprecated since 0.9.3 */ + change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback ) + change_action_add( FindDevicesCallback, N_("Refresh list") ) + + set_capability( "audio output", 150 ) + set_callbacks( Open, Close ) +vlc_module_end () /***************************************************************************** * Probe: probe the audio device for available formats and channels @@ -179,20 +187,20 @@ static void Probe( aout_instance_t * p_aout, { case 1: val.i_int = AOUT_VAR_MONO; - text.psz_string = N_("Mono"); + text.psz_string = _("Mono"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); break; case 2: val.i_int = AOUT_VAR_STEREO; - text.psz_string = N_("Stereo"); + text.psz_string = _("Stereo"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); var_Set( p_aout, "audio-device", val ); break; case 4: val.i_int = AOUT_VAR_2F2R; - text.psz_string = N_("2 Front 2 Rear"); + text.psz_string = _("2 Front 2 Rear"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); break; @@ -216,7 +224,7 @@ static void Probe( aout_instance_t * p_aout, if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 )) { val.i_int = AOUT_VAR_STEREO; - text.psz_string = N_("Stereo"); + text.psz_string = (char*)N_("Stereo"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); var_Set( p_aout, "audio-device", val ); @@ -240,7 +248,7 @@ static void Probe( aout_instance_t * p_aout, SND_PCM_NONBLOCK ) ) ) { val.i_int = AOUT_VAR_SPDIF; - text.psz_string = N_("A/52 over S/PDIF"); + text.psz_string = (char*)N_("A/52 over S/PDIF"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); if( config_GetInt( p_aout, "spdif" ) ) @@ -256,18 +264,31 @@ static void Probe( aout_instance_t * p_aout, } var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL ); +#if (SND_LIB_VERSION <= 0x010015) +# warning Please update alsa-lib to version > 1.0.21a. + var_Create( p_aout->p_libvlc, "alsa-working", VLC_VAR_BOOL ); + if( val.i_int <= 0 ) + { + if( var_GetBool( p_aout->p_libvlc, "alsa-working" ) ) + dialog_FatalWait( p_aout, "ALSA version problem", + "VLC failed to re-initialize your sound output device.\n" + "Please update alsa-lib to version 1.0.22 or higher " + "to fix this issue." ); + } + else + var_SetBool( p_aout->p_libvlc, "alsa-working", true ); +#endif if( val.i_int <= 0 ) { /* Probe() has failed. */ - msg_Dbg( p_aout, "failed to find a useable alsa configuration" ); + msg_Dbg( p_aout, "failed to find a usable ALSA configuration" ); var_Destroy( p_aout, "audio-device" ); return; } /* Add final settings to the variable */ var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); - val.b_bool = VLC_TRUE; - var_Set( p_aout, "intf-change", val ); + var_SetBool( p_aout, "intf-change", true ); } /***************************************************************************** @@ -301,25 +322,18 @@ static int Open( vlc_object_t *p_this ) int i_snd_rc = -1; unsigned int i_old_rate; - vlc_bool_t b_retry = VLC_TRUE; + bool b_retry = true; /* Allocate structures */ p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) ); if( p_sys == NULL ) - { - msg_Err( p_aout, "out of memory" ); return VLC_ENOMEM; - } - p_sys->b_playing = VLC_FALSE; - p_sys->start_date = 0; - vlc_cond_init( p_aout, &p_sys->wait ); - vlc_mutex_init( p_aout, &p_sys->lock ); /* Get device name */ - if( (psz_device = config_GetPsz( p_aout, "alsadev" )) == NULL ) + if( (psz_device = config_GetPsz( p_aout, "alsa-audio-device" )) == NULL ) { msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" ); - intf_UserFatal( p_aout, VLC_FALSE, _("No Audio Device"), + dialog_Fatal( p_aout, _("No Audio Device"), "%s", _("No audio device name was given. You might want to " \ "enter \"default\".") ); free( p_sys ); @@ -354,14 +368,14 @@ static int Open( vlc_object_t *p_this ) /* Choose the linear PCM format (read the comment above about FPU and float32) */ - if( vlc_CPU() & CPU_CAPABILITY_FPU ) + if( HAVE_FPU ) { - i_vlc_pcm_format = VLC_FOURCC('f','l','3','2'); + i_vlc_pcm_format = VLC_CODEC_FL32; i_snd_pcm_format = SND_PCM_FORMAT_FLOAT; } else { - i_vlc_pcm_format = AOUT_FMT_S16_NE; + i_vlc_pcm_format = VLC_CODEC_S16N; i_snd_pcm_format = SND_PCM_FORMAT_S16; } @@ -427,7 +441,7 @@ static int Open( vlc_object_t *p_this ) { msg_Err( p_aout, "cannot open ALSA device `%s' (%s)", psz_iec_device, snd_strerror( i_snd_rc ) ); - intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"), + dialog_Fatal( p_aout, _("Audio output failed"), _("VLC could not open the ALSA device \"%s\" (%s)."), psz_iec_device, snd_strerror( i_snd_rc ) ); free( p_sys ); @@ -438,7 +452,7 @@ static int Open( vlc_object_t *p_this ) i_snd_pcm_format = SND_PCM_FORMAT_S16; i_channels = 2; - i_vlc_pcm_format = VLC_FOURCC('s','p','d','i'); + i_vlc_pcm_format = VLC_CODEC_SPDIFL; p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; @@ -466,7 +480,7 @@ static int Open( vlc_object_t *p_this ) { msg_Err( p_aout, "audio device: %s is already in use", psz_device ); - intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"), + dialog_Fatal( p_aout, _("Audio output failed"), _("The audio device \"%s\" is already in use."), psz_device ); } @@ -478,7 +492,7 @@ static int Open( vlc_object_t *p_this ) { msg_Err( p_aout, "cannot open ALSA device `%s' (%s)", psz_device, snd_strerror( i_snd_rc ) ); - intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"), + dialog_Fatal( p_aout, _("Audio output failed"), _("VLC could not open the ALSA device \"%s\" (%s)."), psz_device, snd_strerror( i_snd_rc ) ); free( p_sys ); @@ -509,7 +523,7 @@ static int Open( vlc_object_t *p_this ) if snd_pcm_hw_params fails in fl32 */ while ( b_retry ) { - b_retry = VLC_FALSE; + b_retry = false; /* Get Initial hardware parameters */ if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 ) @@ -536,14 +550,14 @@ static int Open( vlc_object_t *p_this ) goto error; } } - if( i_vlc_pcm_format != VLC_FOURCC('s','p','d','i') ) + if( i_vlc_pcm_format != VLC_CODEC_SPDIFL ) switch( i_snd_pcm_format ) { case SND_PCM_FORMAT_FLOAT: - i_vlc_pcm_format = VLC_FOURCC('f','l','3','2'); + i_vlc_pcm_format = VLC_CODEC_FL32; break; case SND_PCM_FORMAT_S16: - i_vlc_pcm_format = AOUT_FMT_S16_NE; + i_vlc_pcm_format = VLC_CODEC_S16N; break; } p_aout->output.output.i_format = i_vlc_pcm_format; @@ -567,15 +581,9 @@ static int Open( vlc_object_t *p_this ) /* Set rate. */ i_old_rate = p_aout->output.output.i_rate; -#ifdef HAVE_ALSA_NEW_API i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw, &p_aout->output.output.i_rate, NULL ); -#else - i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw, - p_aout->output.output.i_rate, - NULL ); -#endif if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate ) { msg_Warn( p_aout, "The rate %d Hz is not supported by your " \ @@ -583,28 +591,9 @@ static int Open( vlc_object_t *p_this ) p_aout->output.output.i_rate ); } - /* Set buffer 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 ) -#else - 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 buffer size (%s)", - snd_strerror( i_snd_rc ) ); - goto error; - } - /* Set period 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 ) -#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 ) -#endif { msg_Err( p_aout, "unable to set period size (%s)", snd_strerror( i_snd_rc ) ); @@ -612,15 +601,24 @@ static int Open( vlc_object_t *p_this ) } p_aout->output.i_nb_samples = i_period_size; +/* Set buffer size. */ + if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm, + p_hw, &i_buffer_size ) ) < 0 ) + { + msg_Err( p_aout, "unable to set buffer size (%s)", + snd_strerror( i_snd_rc ) ); + goto error; + } + /* Commit hardware parameters. */ if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 ) { - if ( b_retry == VLC_FALSE && + if ( b_retry == false && i_snd_pcm_format == SND_PCM_FORMAT_FLOAT) { - b_retry = VLC_TRUE; + b_retry = true; i_snd_pcm_format = SND_PCM_FORMAT_S16; - p_aout->output.output.i_format = AOUT_FMT_S16_NE; + p_aout->output.output.i_format = VLC_CODEC_S16N; msg_Warn( p_aout, "unable to commit hardware configuration " "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) ); } @@ -633,13 +631,8 @@ static int Open( vlc_object_t *p_this ) } } -#ifdef HAVE_ALSA_NEW_API if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw, &p_sys->i_period_time, NULL ) ) < 0 ) -#else - if( ( p_sys->i_period_time = - (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 ) -#endif { msg_Err( p_aout, "unable to get period time (%s)", snd_strerror( i_snd_rc ) ); @@ -678,11 +671,15 @@ static int Open( vlc_object_t *p_this ) snd_output_printf( p_sys->p_snd_stderr, "\n" ); #endif + p_sys->start_date = 0; + vlc_sem_init( &p_sys->wait, 0 ); + /* Create ALSA thread and wait for its readiness. */ - if( vlc_thread_create( p_aout, "aout", ALSAThread, - VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) ) + if( vlc_clone( &p_sys->thread, ALSAThread, p_aout, + VLC_THREAD_PRIORITY_OUTPUT ) ) { msg_Err( p_aout, "cannot create ALSA thread (%m)" ); + vlc_sem_destroy( &p_sys->wait ); goto error; } @@ -697,24 +694,24 @@ error: return VLC_EGENERIC; } +static void PlayIgnore( aout_instance_t *p_aout ) +{ /* Already playing - nothing to do */ + (void) p_aout; +} + /***************************************************************************** - * Play: nothing to do + * Play: start playback *****************************************************************************/ static void Play( aout_instance_t *p_aout ) { - if( !p_aout->output.p_sys->b_playing ) - { - p_aout->output.p_sys->b_playing = 1; + p_aout->output.pf_play = PlayIgnore; - /* get the playing date of the first aout buffer */ - p_aout->output.p_sys->start_date = - aout_FifoFirstDate( p_aout, &p_aout->output.fifo ); + /* get the playing date of the first aout buffer */ + p_aout->output.p_sys->start_date = + aout_FifoFirstDate( p_aout, &p_aout->output.fifo ); - /* wake up the audio output thread */ - vlc_mutex_lock( &p_aout->output.p_sys->lock ); - vlc_cond_signal( &p_aout->output.p_sys->wait ); - vlc_mutex_unlock( &p_aout->output.p_sys->lock ); - } + /* wake up the audio output thread */ + sem_post( &p_aout->output.p_sys->wait ); } /***************************************************************************** @@ -726,15 +723,12 @@ static void Close( vlc_object_t *p_this ) struct aout_sys_t * p_sys = p_aout->output.p_sys; int i_snd_rc; - /* make sure the audio output thread is waken up */ - vlc_mutex_lock( &p_aout->output.p_sys->lock ); - vlc_cond_signal( &p_aout->output.p_sys->wait ); - vlc_mutex_unlock( &p_aout->output.p_sys->lock ); - - vlc_object_kill( p_aout ); - vlc_thread_join( p_aout ); - p_aout->b_die = VLC_FALSE; + /* Make sure that the thread will stop once it is waken up */ + vlc_cancel( p_sys->thread ); + vlc_join( p_sys->thread, NULL ); + vlc_sem_destroy( &p_sys->wait ); + /* */ i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm ); if( i_snd_rc > 0 ) @@ -750,30 +744,29 @@ static void Close( vlc_object_t *p_this ) free( p_sys ); } +static void pcm_drop(void *pcm) +{ + snd_pcm_drop(pcm); +} + /***************************************************************************** * ALSAThread: asynchronous thread used to DMA the data to the device *****************************************************************************/ -static int ALSAThread( aout_instance_t * p_aout ) +static void* ALSAThread( void *data ) { + aout_instance_t * p_aout = data; struct aout_sys_t * p_sys = p_aout->output.p_sys; - p_sys->p_status = (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof()); /* Wait for the exact time to start playing (avoids resampling) */ - vlc_mutex_lock( &p_sys->lock ); - while( !p_sys->start_date ) - vlc_cond_wait( &p_sys->wait, &p_sys->lock ); - vlc_mutex_unlock( &p_sys->lock ); - + vlc_sem_wait( &p_sys->wait ); mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 ); - while ( !p_aout->b_die ) - { + vlc_cleanup_push( pcm_drop, p_sys->p_snd_pcm ); + for(;;) ALSAFill( p_aout ); - } - snd_pcm_drop( p_sys->p_snd_pcm ); - free( p_aout->output.p_sys->p_status ); - return 0; + assert(0); + vlc_cleanup_pop(); } /***************************************************************************** @@ -782,15 +775,17 @@ static int ALSAThread( aout_instance_t * p_aout ) static void ALSAFill( aout_instance_t * p_aout ) { struct aout_sys_t * p_sys = p_aout->output.p_sys; - aout_buffer_t * p_buffer; - snd_pcm_status_t * p_status = p_sys->p_status; + snd_pcm_t *p_pcm = p_sys->p_snd_pcm; + snd_pcm_status_t * p_status; int i_snd_rc; mtime_t next_date; + int canc = vlc_savecancel(); /* Fill in the buffer until space or audio output buffer shortage */ /* Get the status */ - i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status ); + snd_pcm_status_alloca(&p_status); + i_snd_rc = snd_pcm_status( p_pcm, p_status ); if( i_snd_rc < 0 ) { msg_Err( p_aout, "cannot get device status" ); @@ -801,8 +796,7 @@ static void ALSAFill( aout_instance_t * p_aout ) if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN ) { /* Prepare the device */ - i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm ); - + i_snd_rc = snd_pcm_prepare( p_pcm ); if( i_snd_rc ) { msg_Err( p_aout, "cannot recover from buffer underrun" ); @@ -812,7 +806,7 @@ static void ALSAFill( aout_instance_t * p_aout ) msg_Dbg( p_aout, "recovered from buffer underrun" ); /* Get the new status */ - i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status ); + i_snd_rc = snd_pcm_status( p_pcm, p_status ); if( i_snd_rc < 0 ) { msg_Err( p_aout, "cannot get device status after recovery" ); @@ -824,34 +818,35 @@ static void ALSAFill( aout_instance_t * p_aout ) } else { - /* Here the device should be in RUNNING state. - * p_status is valid. */ + /* Here the device should be in RUNNING state, p_status is valid. */ + snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status ); + if( delay == 0 ) /* workaround buggy alsa drivers */ + if( snd_pcm_delay( p_pcm, &delay ) < 0 ) + delay = 0; /* FIXME: use a positive minimal delay */ + + size_t i_bytes = snd_pcm_frames_to_bytes( p_pcm, delay ); + mtime_t delay_us = CLOCK_FREQ * i_bytes + / 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 (%zu 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: in %"PRId64" microseconds", delay_us ); #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; - } + next_date = mdate() + delay_us; } - p_buffer = aout_OutputNextBuffer( p_aout, next_date, - (p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i')) ); + block_t *p_buffer = aout_OutputNextBuffer( p_aout, next_date, + (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) ); /* Audio output buffer shortage -> stop the fill process and wait */ if( p_buffer == NULL ) @@ -859,37 +854,58 @@ static void ALSAFill( aout_instance_t * p_aout ) for (;;) { - i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer, - p_buffer->i_nb_samples ); - if( i_snd_rc != -ESTRPIPE ) - break; + int n = snd_pcm_poll_descriptors_count(p_pcm); + struct pollfd ufd[n]; + unsigned short revents; + + snd_pcm_poll_descriptors(p_pcm, ufd, n); + do + { + vlc_restorecancel(canc); + poll(ufd, n, -1); + canc = vlc_savecancel(); + snd_pcm_poll_descriptors_revents(p_pcm, ufd, n, &revents); + } + while(!revents); + + if(revents & POLLOUT) + { + i_snd_rc = snd_pcm_writei( p_pcm, p_buffer->p_buffer, + p_buffer->i_nb_samples ); + if( i_snd_rc != -ESTRPIPE ) + break; + } /* a suspend event occurred * (stream is suspended and waiting for an application recovery) */ msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." ); - while( !p_aout->b_die && !p_aout->p_libvlc->b_die && - ( i_snd_rc = snd_pcm_resume( p_sys->p_snd_pcm ) ) == -EAGAIN ) + while( ( i_snd_rc = snd_pcm_resume( p_pcm ) ) == -EAGAIN ) { - msleep( 1000000 ); + vlc_restorecancel(canc); + msleep(CLOCK_FREQ); /* device still suspended, wait... */ + canc = vlc_savecancel(); } if( i_snd_rc < 0 ) - /* Device does not supprot resuming, restart it */ - i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm ); + /* Device does not support resuming, restart it */ + i_snd_rc = snd_pcm_prepare( p_pcm ); } if( i_snd_rc < 0 ) msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) ); - aout_BufferFree( p_buffer ); + vlc_restorecancel(canc); + block_Release( p_buffer ); return; error: if( i_snd_rc < 0 ) msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) ); - msleep( p_sys->i_period_time >> 1 ); + + vlc_restorecancel(canc); + msleep(p_sys->i_period_time / 2); } static void GetDevicesForCard( module_config_t *p_item, int i_card ); @@ -903,6 +919,9 @@ static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name, { module_config_t *p_item; int i; + (void)newval; + (void)oldval; + (void)p_unused; p_item = config_FindConfig( p_this, psz_name ); if( !p_item ) return VLC_SUCCESS; @@ -925,10 +944,9 @@ static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name, GetDevices( p_item ); /* Signal change to the interface */ - p_item->b_dirty = VLC_TRUE; + p_item->b_dirty = true; return VLC_SUCCESS; - } @@ -975,15 +993,18 @@ static void GetDevicesForCard( module_config_t *p_item, int i_card ) continue; } - asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ); - asprintf( &psz_descr, "%s: %s (%s)", psz_card_name, - snd_pcm_info_get_name(p_pcm_info), psz_device ); + if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 ) + break; + if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name, + snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 ) + { + free( psz_device ); + break; + } - p_item->ppsz_list = - (const char **)realloc( p_item->ppsz_list, + p_item->ppsz_list = xrealloc( p_item->ppsz_list, (p_item->i_list + 2) * sizeof(char *) ); - p_item->ppsz_list_text = - (const char **)realloc( p_item->ppsz_list_text, + p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text, (p_item->i_list + 2) * sizeof(char *) ); p_item->ppsz_list[ p_item->i_list ] = psz_device; p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;