X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faudio_output%2Falsa.c;h=ac19bd9fc03ac3675a1cce780dce455e448334bc;hb=0c331abd89659e9a8c104921a8196e84ac65d19c;hp=80dc2ca180b2be8bd7b30f2469098bebe35285ee;hpb=00b95848260cd44f140a05da8aa5baf13580e2d3;p=vlc diff --git a/modules/audio_output/alsa.c b/modules/audio_output/alsa.c index 80dc2ca180..ac19bd9fc0 100644 --- a/modules/audio_output/alsa.c +++ b/modules/audio_output/alsa.c @@ -31,19 +31,23 @@ # 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*/ @@ -62,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 @@ -90,32 +90,35 @@ 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 ); +static void GetDevicesForCard( vlc_object_t *, module_config_t *, int card ); +static void GetDevices( vlc_object_t *, module_config_t * ); /***************************************************************************** * Module descriptor *****************************************************************************/ 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( "alsadev", DEFAULT_ALSA_DEVICE, aout_FindAndRestart, - N_("ALSA Device Name"), NULL, 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(); +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 @@ -186,20 +189,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; @@ -223,7 +226,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 ); @@ -247,10 +250,10 @@ 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" ) ) + if( var_InheritInteger( p_aout, "spdif" ) ) var_Set( p_aout, "audio-device", val ); snd_pcm_close( p_sys->p_snd_pcm ); @@ -263,18 +266,32 @@ 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" ); + GetDevices( VLC_OBJECT(p_aout), NULL ); return; } /* Add final settings to the variable */ var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); - val.b_bool = true; - var_Set( p_aout, "intf-change", val ); + var_SetBool( p_aout, "intf-change", true ); } /***************************************************************************** @@ -314,16 +331,12 @@ static int Open( vlc_object_t *p_this ) p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) ); if( p_sys == NULL ) return VLC_ENOMEM; - p_sys->b_playing = false; - p_sys->start_date = 0; - vlc_cond_init( p_aout, &p_sys->wait ); - vlc_mutex_init( &p_sys->lock ); /* Get device name */ - if( (psz_device = config_GetPsz( p_aout, "alsadev" )) == NULL ) + if( (psz_device = var_InheritString( p_aout, "alsa-audio-device" )) == NULL ) { msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" ); - intf_UserFatal( p_aout, 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 ); @@ -358,14 +371,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; } @@ -431,7 +444,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, 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 ); @@ -442,7 +455,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; @@ -470,7 +483,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, false, _("Audio output failed"), + dialog_Fatal( p_aout, _("Audio output failed"), _("The audio device \"%s\" is already in use."), psz_device ); } @@ -482,7 +495,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, 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 ); @@ -540,14 +553,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; @@ -571,15 +584,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 " \ @@ -588,13 +595,8 @@ static int Open( vlc_object_t *p_this ) } /* 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 ) ); @@ -603,13 +605,8 @@ static int Open( vlc_object_t *p_this ) p_aout->output.i_nb_samples = i_period_size; /* 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 ) ); @@ -624,7 +621,7 @@ static int Open( vlc_object_t *p_this ) { 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 ) ); } @@ -637,13 +634,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 ) ); @@ -682,11 +674,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, 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; } @@ -701,24 +697,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 ); } /***************************************************************************** @@ -730,15 +726,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 = 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 ) @@ -754,34 +747,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_object_alive (p_aout) ) - vlc_cond_wait( &p_sys->wait, &p_sys->lock ); - vlc_mutex_unlock( &p_sys->lock ); - - if( !vlc_object_alive (p_aout) ) - goto cleanup; - + vlc_sem_wait( &p_sys->wait ); mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 ); - while ( vlc_object_alive (p_aout) ) - { + vlc_cleanup_push( pcm_drop, p_sys->p_snd_pcm ); + for(;;) ALSAFill( p_aout ); - } -cleanup: - snd_pcm_drop( p_sys->p_snd_pcm ); - free( p_aout->output.p_sys->p_status ); - return 0; + assert(0); + vlc_cleanup_pop(); } /***************************************************************************** @@ -790,15 +778,17 @@ cleanup: 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" ); @@ -809,8 +799,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" ); @@ -820,7 +809,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" ); @@ -835,31 +824,32 @@ 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 ); if( delay == 0 ) /* workaround buggy alsa drivers */ - if( snd_pcm_delay( p_sys->p_snd_pcm, &delay ) < 0 ) + if( snd_pcm_delay( p_pcm, &delay ) < 0 ) delay = 0; /* FIXME: use a positive minimal delay */ - int i_bytes = snd_pcm_frames_to_bytes( p_sys->p_snd_pcm, delay ); - next_date = mdate() + ( (mtime_t)i_bytes * 1000000 + + 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 ); + * p_aout->output.output.i_frame_length; #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, "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 is in %d microseconds", (int)(next_date - mdate()) ); + msg_Dbg( p_aout, "Next date: in %"PRId64" microseconds", delay_us ); #endif + 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 ) @@ -867,41 +857,59 @@ 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( vlc_object_alive (p_aout) && vlc_object_alive (p_aout->p_libvlc) && - ( 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 ); -} -static void GetDevicesForCard( module_config_t *p_item, int i_card ); -static void GetDevices( module_config_t *p_item ); + vlc_restorecancel(canc); + msleep(p_sys->i_period_time / 2); +} /***************************************************************************** * config variable callback @@ -910,7 +918,9 @@ static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name, vlc_value_t newval, vlc_value_t oldval, void *p_unused ) { 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; @@ -918,6 +928,8 @@ static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name, /* Clear-up the current list */ if( p_item->i_list ) { + int i; + /* Keep the first entrie */ for( i = 1; i < p_item->i_list; i++ ) { @@ -930,17 +942,17 @@ static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name, } p_item->i_list = 1; - GetDevices( p_item ); + GetDevices( p_this, p_item ); /* Signal change to the interface */ p_item->b_dirty = true; return VLC_SUCCESS; - } -static void GetDevicesForCard( module_config_t *p_item, int i_card ) +static void GetDevicesForCard( vlc_object_t *obj, module_config_t *p_item, + int i_card ) { int i_pcm_device = -1; int i_err = 0; @@ -974,55 +986,54 @@ static void GetDevicesForCard( module_config_t *p_item, int i_card ) if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 ) { if( i_err != -ENOENT ) - { - /*printf( "get_devices_for_card(): " - "snd_ctl_pcm_info() " - "failed (%d:%d): %s.\n", i_card, - i_pcm_device, snd_strerror( -i_err ) );*/ - } + msg_Err( obj, "cannot get PCM device %d:%d infos: %s", i_card, + i_pcm_device, snd_strerror( -i_err ) ); 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 ); - - p_item->ppsz_list = - (const char **)realloc( 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->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; - p_item->i_list++; - p_item->ppsz_list[ p_item->i_list ] = NULL; - p_item->ppsz_list_text[ p_item->i_list ] = NULL; + 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; + } + + msg_Dbg( obj, " %s", psz_descr ); + + if( p_item ) + { + p_item->ppsz_list = xrealloc( p_item->ppsz_list, + (p_item->i_list + 2) * sizeof(char *) ); + 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; + p_item->i_list++; + p_item->ppsz_list[ p_item->i_list ] = NULL; + p_item->ppsz_list_text[ p_item->i_list ] = NULL; + } + else + { + free( psz_device ); + free( psz_descr ); + } } snd_ctl_close( p_ctl ); } - -static void GetDevices( module_config_t *p_item ) +static void GetDevices( vlc_object_t *obj, module_config_t *p_item ) { int i_card = -1; - int i_err = 0; + int i_err; - if( ( i_err = snd_card_next( &i_card ) ) != 0 ) - { - /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/ - return; - } + msg_Dbg( obj, "Available alsa output devices:" ); + while( (i_err = snd_card_next( &i_card )) == 0 && i_card > -1 ) + GetDevicesForCard( obj, p_item, i_card ); - while( i_card > -1 ) - { - GetDevicesForCard( p_item, i_card ); - if( ( i_err = snd_card_next( &i_card ) ) != 0 ) - { - /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/ - break; - } - } + if( i_err ) + msg_Err( obj, "cannot enumerate cards: %s", snd_strerror( -i_err ) ); }