+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
+ *****************************************************************************/
+static void Probe( aout_instance_t * p_aout,
+ const char * psz_device, const char * psz_iec_device,
+ int *pi_snd_pcm_format )
+{
+ struct aout_sys_t * p_sys = p_aout->output.p_sys;
+ vlc_value_t val, text;
+ int i_ret;
+
+ var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
+ text.psz_string = _("Audio Device");
+ var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
+
+ /* We'll open the audio device in non blocking mode so we can just exit
+ * when it is already in use, but for the real stuff we'll still use
+ * the blocking mode */
+
+ /* Now test linear PCM capabilities */
+ if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
+ SND_PCM_STREAM_PLAYBACK,
+ SND_PCM_NONBLOCK ) ) )
+ {
+ int i_channels;
+ snd_pcm_hw_params_t * p_hw;
+ snd_pcm_hw_params_alloca (&p_hw);
+
+ if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
+ {
+ msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
+ ", disabling linear PCM audio" );
+ snd_pcm_close( p_sys->p_snd_pcm );
+ var_Destroy( p_aout, "audio-device" );
+ return;
+ }
+
+ if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
+ *pi_snd_pcm_format ) < 0 )
+ {
+ int i_snd_rc = -1;
+
+ if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
+ {
+ *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
+ i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
+ p_hw, *pi_snd_pcm_format );
+ }
+ if ( i_snd_rc < 0 )
+ {
+ msg_Warn( p_aout, "unable to set stream sample size and "
+ "word order, disabling linear PCM audio" );
+ snd_pcm_close( p_sys->p_snd_pcm );
+ var_Destroy( p_aout, "audio-device" );
+ return;
+ }
+ }
+
+ i_channels = aout_FormatNbChannels( &p_aout->output.output );
+
+ while ( i_channels > 0 )
+ {
+ if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
+ i_channels ) )
+ {
+ switch ( i_channels )
+ {
+ case 1:
+ val.i_int = AOUT_VAR_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 = _("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 = _("2 Front 2 Rear");
+ var_Change( p_aout, "audio-device",
+ VLC_VAR_ADDCHOICE, &val, &text );
+ break;
+ case 6:
+ val.i_int = AOUT_VAR_5_1;
+ text.psz_string = "5.1";
+ var_Change( p_aout, "audio-device",
+ VLC_VAR_ADDCHOICE, &val, &text );
+ break;
+ }
+ }
+
+ --i_channels;
+ }
+
+ /* Special case for mono on stereo only boards */
+ i_channels = aout_FormatNbChannels( &p_aout->output.output );
+ var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
+ if( val.i_int <= 0 && i_channels == 1 )
+ {
+ if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
+ {
+ val.i_int = AOUT_VAR_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 );
+ }
+ }
+
+ /* Close the previously opened device */
+ snd_pcm_close( p_sys->p_snd_pcm );
+ }
+ else if ( i_ret == -EBUSY )
+ {
+ msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
+ }
+
+ /* Test for S/PDIF device if needed */
+ if ( psz_iec_device )
+ {
+ /* Opening the device should be enough */
+ if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
+ SND_PCM_STREAM_PLAYBACK,
+ SND_PCM_NONBLOCK ) ) )
+ {
+ val.i_int = AOUT_VAR_SPDIF;
+ text.psz_string = (char*)N_("A/52 over S/PDIF");
+ var_Change( p_aout, "audio-device",
+ VLC_VAR_ADDCHOICE, &val, &text );
+ if( var_InheritInteger( p_aout, "spdif" ) )
+ var_Set( p_aout, "audio-device", val );
+
+ snd_pcm_close( p_sys->p_snd_pcm );
+ }
+ else if ( i_ret == -EBUSY )
+ {
+ msg_Warn( p_aout, "audio device: %s is already in use",
+ psz_iec_device );
+ }
+ }
+
+ 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 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 );
+ var_SetBool( p_aout, "intf-change", true );
+}