alsa.c 35.4 KB
Newer Older
1 2 3
/*****************************************************************************
 * alsa.c : alsa plugin for vlc
 *****************************************************************************
4
 * Copyright (C) 2000-2001 the VideoLAN team
5
 * $Id$
6 7 8 9
 *
 * Authors: Henri Fallon <henri@videolan.org> - Original Author
 *          Jeffrey Baker <jwbaker@acm.org> - Port to ALSA 1.0 API
 *          John Paul Lorenti <jpl31@columbia.edu> - Device selection
10
 *          Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr> - S/PDIF and aout3
11 12 13 14 15
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
16
 *
17 18 19 20 21 22 23
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 26 27 28 29
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
Rémi Denis-Courmont's avatar
More  
Rémi Denis-Courmont committed
30 31
#include <vlc/vlc.h>

32
#include <errno.h>                                                 /* ENOMEM */
Clément Stenac's avatar
Clément Stenac committed
33
#include <vlc_interface.h>
34

Clément Stenac's avatar
Clément Stenac committed
35
#include <vlc_aout.h>
36

37
/* ALSA part
38
   Note: we use the new API which is available since 0.9.0beta10a. */
39 40
#define ALSA_PCM_NEW_HW_PARAMS_API
#define ALSA_PCM_NEW_SW_PARAMS_API
41 42
#include <alsa/asoundlib.h>

43 44 45 46 47 48 49 50 51
/*****************************************************************************
 * aout_sys_t: ALSA audio output method descriptor
 *****************************************************************************
 * This structure is part of the audio output thread descriptor.
 * It describes the ALSA specific properties of an audio device.
 *****************************************************************************/
struct aout_sys_t
{
    snd_pcm_t         * p_snd_pcm;
52
    unsigned int                 i_period_time;
Arnaud de Bossoreille de Ribou's avatar
Arnaud de Bossoreille de Ribou committed
53

Gildas Bazin's avatar
 
Gildas Bazin committed
54
#ifdef ALSA_DEBUG
55 56
    snd_output_t      * p_snd_stderr;
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
57 58 59 60 61 62

    int b_playing;                                         /* playing status */
    mtime_t start_date;

    vlc_mutex_t lock;
    vlc_cond_t  wait ;
Gildas Bazin's avatar
 
Gildas Bazin committed
63 64

    snd_pcm_status_t *p_status;
65 66
};

67 68
#define A52_FRAME_NB 1536

69
/* These values are in frames.
70
   To convert them to a number of bytes you have to multiply them by the
71
   number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
Sam Hocevar's avatar
Sam Hocevar committed
72
   2 for int16_t). */
Gildas Bazin's avatar
 
Gildas Bazin committed
73
#define ALSA_DEFAULT_PERIOD_SIZE        1024
Gildas Bazin's avatar
 
Gildas Bazin committed
74
#define ALSA_DEFAULT_BUFFER_SIZE        ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
75
#define ALSA_SPDIF_PERIOD_SIZE          A52_FRAME_NB
76
#define ALSA_SPDIF_BUFFER_SIZE          ( ALSA_SPDIF_PERIOD_SIZE << 4 )
77
/* Why << 4 ? --Meuuh */
78
/* Why not ? --Bozo */
79
/* Right. --Meuuh */
80

81
#define DEFAULT_ALSA_DEVICE N_("default")
82

83 84 85 86 87
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int  Open         ( vlc_object_t * );
static void Close        ( vlc_object_t * );
88
static void Play         ( aout_instance_t * );
89 90
static int  ALSAThread   ( aout_instance_t * );
static void ALSAFill     ( aout_instance_t * );
91 92
static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
                                vlc_value_t newval, vlc_value_t oldval, void *p_unused );
93 94 95 96

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
97 98
static char *ppsz_devices[] = { "default" };
static char *ppsz_devices_text[] = { N_("Default") };
99
vlc_module_begin();
100
    set_shortname( "ALSA" );
Gildas Bazin's avatar
 
Gildas Bazin committed
101
    set_description( _("ALSA audio output") );
Clément Stenac's avatar
Clément Stenac committed
102 103
    set_category( CAT_AUDIO );
    set_subcategory( SUBCAT_AUDIO_AOUT );
104
    add_string( "alsadev", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
105
                N_("ALSA Device Name"), NULL, VLC_FALSE );
106 107 108
        change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback );
        change_action_add( FindDevicesCallback, N_("Refresh list") );

Gildas Bazin's avatar
 
Gildas Bazin committed
109
    set_capability( "audio output", 150 );
110 111 112
    set_callbacks( Open, Close );
vlc_module_end();

113 114 115 116 117
/*****************************************************************************
 * 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,
Gildas Bazin's avatar
 
Gildas Bazin committed
118
                   int *pi_snd_pcm_format )
119 120
{
    struct aout_sys_t * p_sys = p_aout->output.p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
121
    vlc_value_t val, text;
Gildas Bazin's avatar
 
Gildas Bazin committed
122
    int i_ret;
123

Gildas Bazin's avatar
 
Gildas Bazin committed
124
    var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
125
    text.psz_string = _("Audio Device");
Gildas Bazin's avatar
 
Gildas Bazin committed
126
    var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
127

Gildas Bazin's avatar
 
Gildas Bazin committed
128 129 130 131
    /* 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 */

132
    /* Now test linear PCM capabilities */
Gildas Bazin's avatar
 
Gildas Bazin committed
133 134 135
    if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
                                 SND_PCM_STREAM_PLAYBACK,
                                 SND_PCM_NONBLOCK ) ) )
136 137 138 139 140 141 142 143 144 145
    {
        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 );
Gildas Bazin's avatar
 
Gildas Bazin committed
146
            var_Destroy( p_aout, "audio-device" );
147 148 149
            return;
        }

150
        if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
Gildas Bazin's avatar
 
Gildas Bazin committed
151
                                           *pi_snd_pcm_format ) < 0 )
152
        {
153 154
            int i_snd_rc = -1;

Gildas Bazin's avatar
 
Gildas Bazin committed
155 156 157
            if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
            {
                *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
158 159 160 161 162 163 164 165 166 167
                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;
Gildas Bazin's avatar
 
Gildas Bazin committed
168
            }
169
        }
170 171 172

        i_channels = aout_FormatNbChannels( &p_aout->output.output );

173
        while ( i_channels > 0 )
174 175 176 177 178 179 180
        {
            if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
                                                   i_channels ) )
            {
                switch ( i_channels )
                {
                case 1:
Gildas Bazin's avatar
 
Gildas Bazin committed
181 182
                    val.i_int = AOUT_VAR_MONO;
                    text.psz_string = N_("Mono");
183
                    var_Change( p_aout, "audio-device",
Gildas Bazin's avatar
 
Gildas Bazin committed
184
                                VLC_VAR_ADDCHOICE, &val, &text );
185 186
                    break;
                case 2:
Gildas Bazin's avatar
 
Gildas Bazin committed
187 188
                    val.i_int = AOUT_VAR_STEREO;
                    text.psz_string = N_("Stereo");
189
                    var_Change( p_aout, "audio-device",
Gildas Bazin's avatar
 
Gildas Bazin committed
190
                                VLC_VAR_ADDCHOICE, &val, &text );
Gildas Bazin's avatar
 
Gildas Bazin committed
191
                    var_Set( p_aout, "audio-device", val );
192 193
                    break;
                case 4:
Gildas Bazin's avatar
 
Gildas Bazin committed
194 195
                    val.i_int = AOUT_VAR_2F2R;
                    text.psz_string = N_("2 Front 2 Rear");
196
                    var_Change( p_aout, "audio-device",
Gildas Bazin's avatar
 
Gildas Bazin committed
197
                                VLC_VAR_ADDCHOICE, &val, &text );
198 199
                    break;
                case 6:
Gildas Bazin's avatar
 
Gildas Bazin committed
200
                    val.i_int = AOUT_VAR_5_1;
201
                    text.psz_string = "5.1";
202
                    var_Change( p_aout, "audio-device",
Gildas Bazin's avatar
 
Gildas Bazin committed
203
                                VLC_VAR_ADDCHOICE, &val, &text );
204 205 206 207 208 209 210
                    break;
                }
            }

            --i_channels;
        }

211 212 213 214 215 216 217 218 219 220 221 222 223 224
        /* 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 = N_("Stereo");
                var_Change( p_aout, "audio-device",
                            VLC_VAR_ADDCHOICE, &val, &text );
                var_Set( p_aout, "audio-device", val );
            }
        }
Clément Stenac's avatar
Clément Stenac committed
225

226 227 228
        /* Close the previously opened device */
        snd_pcm_close( p_sys->p_snd_pcm );
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
229 230 231 232
    else if ( i_ret == -EBUSY )
    {
        msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
    }
233

Gildas Bazin's avatar
 
Gildas Bazin committed
234 235 236 237
    /* Test for S/PDIF device if needed */
    if ( psz_iec_device )
    {
        /* Opening the device should be enough */
Gildas Bazin's avatar
 
Gildas Bazin committed
238 239 240
        if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
                                     SND_PCM_STREAM_PLAYBACK,
                                     SND_PCM_NONBLOCK ) ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
241
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
242 243 244 245
            val.i_int = AOUT_VAR_SPDIF;
            text.psz_string = N_("A/52 over S/PDIF");
            var_Change( p_aout, "audio-device",
                        VLC_VAR_ADDCHOICE, &val, &text );
Gildas Bazin's avatar
 
Gildas Bazin committed
246 247
            if( config_GetInt( p_aout, "spdif" ) )
                var_Set( p_aout, "audio-device", val );
Gildas Bazin's avatar
 
Gildas Bazin committed
248 249

            snd_pcm_close( p_sys->p_snd_pcm );
Gildas Bazin's avatar
 
Gildas Bazin committed
250
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
251 252 253 254 255
        else if ( i_ret == -EBUSY )
        {
            msg_Warn( p_aout, "audio device: %s is already in use",
                      psz_iec_device );
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
256 257
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
258 259 260 261
    var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
    if( val.i_int <= 0 )
    {
        /* Probe() has failed. */
262
        msg_Dbg( p_aout, "failed to find a useable alsa configuration" );
Gildas Bazin's avatar
 
Gildas Bazin committed
263 264 265 266
        var_Destroy( p_aout, "audio-device" );
        return;
    }

267 268
    /* Add final settings to the variable */
    var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
269 270
    val.b_bool = VLC_TRUE;
    var_Set( p_aout, "intf-change", val );
271 272
}

273 274 275
/*****************************************************************************
 * Open: create a handle and open an alsa device
 *****************************************************************************
276 277 278 279
 * This function opens an alsa device, through the alsa API.
 *
 * Note: the only heap-allocated string is psz_device. All the other pointers
 * are references to psz_device or to stack-allocated data.
280 281 282
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
283 284
    aout_instance_t * p_aout = (aout_instance_t *)p_this;
    struct aout_sys_t * p_sys;
285 286 287 288 289 290 291 292 293 294 295 296 297
    vlc_value_t val;

    char psz_default_iec_device[128]; /* Buffer used to store the default
                                         S/PDIF device */
    char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
                                            output */

    int i_vlc_pcm_format; /* Audio format for VLC's data */
    int i_snd_pcm_format; /* Audio format for ALSA's data */

    snd_pcm_uframes_t i_buffer_size = 0;
    snd_pcm_uframes_t i_period_size = 0;
    int i_channels = 0;
298

299 300
    snd_pcm_hw_params_t *p_hw;
    snd_pcm_sw_params_t *p_sw;
Christophe Massiot's avatar
Christophe Massiot committed
301

302
    int i_snd_rc = -1;
303
    unsigned int i_old_rate;
304
    vlc_bool_t b_retry = VLC_TRUE;
305

306
    /* Allocate structures */
307 308
    p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
    if( p_sys == NULL )
309 310
    {
        msg_Err( p_aout, "out of memory" );
311
        return VLC_ENOMEM;
312
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
313 314 315 316
    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 );
317

318
    /* Get device name */
319
    if( (psz_device = config_GetPsz( p_aout, "alsadev" )) == NULL )
320 321
    {
        msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
322 323 324
        intf_UserFatal( p_aout, VLC_FALSE, _("No Audio Device"), 
                        _("No audio device name was given. You might want to " \
                          "enter \"default\".") );
325 326 327
        free( p_sys );
        return VLC_EGENERIC;
    }
328

329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
    /* Choose the IEC device for S/PDIF output:
       if the device is overriden by the user then it will be the one
       otherwise we compute the default device based on the output format. */
    if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
        && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
    {
        snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
                  "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
                  IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
                  IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
                  0,
                  ( p_aout->output.output.i_rate == 48000 ?
                    IEC958_AES3_CON_FS_48000 :
                    ( p_aout->output.output.i_rate == 44100 ?
                      IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
        psz_iec_device = psz_default_iec_device;
    }
    else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
    {
        psz_iec_device = psz_device;
    }
    else
    {
        psz_iec_device = NULL;
    }

    /* Choose the linear PCM format (read the comment above about FPU
       and float32) */
357
    if( vlc_CPU() & CPU_CAPABILITY_FPU )
358
    {
359 360 361
        i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
        i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
    }
362
    else
363 364 365 366 367 368 369 370 371
    {
        i_vlc_pcm_format = AOUT_FMT_S16_NE;
        i_snd_pcm_format = SND_PCM_FORMAT_S16;
    }

    /* If the variable doesn't exist then it's the first time we're called
       and we have to probe the available audio formats and channels */
    if ( var_Type( p_aout, "audio-device" ) == 0 )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
372
        Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
373 374 375 376 377 378 379 380 381
    }

    if ( var_Get( p_aout, "audio-device", &val ) < 0 )
    {
        free( p_sys );
        free( psz_device );
        return VLC_EGENERIC;
    }

382 383
    p_aout->output.output.i_format = i_vlc_pcm_format;
    if ( val.i_int == AOUT_VAR_5_1 )
384 385 386 387 388
    {
        p_aout->output.output.i_physical_channels
            = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
               | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
               | AOUT_CHAN_LFE;
Gildas Bazin's avatar
 
Gildas Bazin committed
389 390
        free( psz_device );
        psz_device = strdup( "surround51" );
391
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
392
    else if ( val.i_int == AOUT_VAR_2F2R )
393 394 395 396
    {
        p_aout->output.output.i_physical_channels
            = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
               | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
Gildas Bazin's avatar
 
Gildas Bazin committed
397 398
        free( psz_device );
        psz_device = strdup( "surround40" );
399
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
400
    else if ( val.i_int == AOUT_VAR_STEREO )
401 402 403 404
    {
        p_aout->output.output.i_physical_channels
            = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
405
    else if ( val.i_int == AOUT_VAR_MONO )
406 407 408
    {
        p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
    }
409
    else if( val.i_int != AOUT_VAR_SPDIF )
410 411
    {
        /* This should not happen ! */
Gildas Bazin's avatar
 
Gildas Bazin committed
412
        msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
413
        free( p_sys );
414 415 416 417
        free( psz_device );
        return VLC_EGENERIC;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
418
#ifdef ALSA_DEBUG
419 420
    snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
#endif
421

422
    /* Open the device */
423
    if ( val.i_int == AOUT_VAR_SPDIF )
424
    {
425 426
        if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
                            SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
427
        {
428 429
            msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
                             psz_iec_device, snd_strerror( i_snd_rc ) );
430 431 432
            intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"), 
                            _("VLC could not open the ALSA device \"%s\" (%s)."),
                            psz_iec_device, snd_strerror( i_snd_rc ) );
433 434 435
            free( p_sys );
            free( psz_device );
            return VLC_EGENERIC;
436
        }
437 438 439
        i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
        i_snd_pcm_format = SND_PCM_FORMAT_S16;
        i_channels = 2;
440

441
        i_vlc_pcm_format = VLC_FOURCC('s','p','d','i');
442 443 444
        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;
445

446
        aout_VolumeNoneInit( p_aout );
447
    }
448
    else
449
    {
450 451
        int i;

Gildas Bazin's avatar
 
Gildas Bazin committed
452 453
        msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );

454 455 456 457 458 459 460 461 462 463 464
        /* Since it seems snd_pcm_close hasen't really released the device at
          the time it returns, probe if the device is available in loop for 1s.
          We cannot use blocking mode since the we would wait indefinitely when
          switching from a dmx device to surround51. */

        for( i = 10; i >= 0; i-- )
        {
            if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
                   SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
            {
                if( i ) msleep( 100000 /* 100ms */ );
465 466 467
                else
                {
                    msg_Err( p_aout, "audio device: %s is already in use",
468
                              psz_device );
469 470 471 472
                    intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"), 
                                    _("The audio device \"%s\" is already in use."),
                                    psz_device );
                }
473 474 475 476 477
                continue;
            }
            break;
        }
        if( i_snd_rc < 0 )
478 479
        {
            msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
480
                             psz_device, snd_strerror( i_snd_rc ) );
481 482 483
            intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"), 
                            _("VLC could not open the ALSA device \"%s\" (%s)."),
                            psz_device, snd_strerror( i_snd_rc ) );
484 485 486 487
            free( p_sys );
            free( psz_device );
            return VLC_EGENERIC;
        }
488 489 490 491

        /* We want blocking mode */
        snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );

492
        i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
493 494 495
        i_channels = aout_FormatNbChannels( &p_aout->output.output );

        p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
496

497
        aout_VolumeSoftInit( p_aout );
498 499
    }

500
    /* Free psz_device so that all the remaining data is stack-allocated */
501
    free( psz_device );
502

503
    p_aout->output.pf_play = Play;
504

505 506 507
    snd_pcm_hw_params_alloca(&p_hw);
    snd_pcm_sw_params_alloca(&p_sw);

508 509 510
    /* Due to some bugs in alsa with some drivers, we need to retry in s16l
       if snd_pcm_hw_params fails in fl32 */
    while ( b_retry )
511
    {
512 513 514 515 516 517
        b_retry = VLC_FALSE;

        /* Get Initial hardware parameters */
        if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
        {
            msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
518
                         snd_strerror( i_snd_rc ) );
519 520
            goto error;
        }
521

522 523
        /* Set format. */
        if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
524
                                                    i_snd_pcm_format ) ) < 0 )
525
        {
526 527 528 529
            if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
            {
                i_snd_pcm_format = SND_PCM_FORMAT_S16;
                i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
530
                                                     p_hw, i_snd_pcm_format );
531 532 533 534 535 536 537
            }
            if ( i_snd_rc < 0 )
            {
                msg_Err( p_aout, "unable to set stream sample size and "
                     "word order (%s)", snd_strerror( i_snd_rc ) );
                goto error;
            }
538
        }
539 540
        if( i_vlc_pcm_format != VLC_FOURCC('s','p','d','i') )
        switch( i_snd_pcm_format )
541
        {
542 543 544 545 546 547
        case SND_PCM_FORMAT_FLOAT:
            i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
            break;
        case SND_PCM_FORMAT_S16:
            i_vlc_pcm_format = AOUT_FMT_S16_NE;
            break;
548
        }
549
        p_aout->output.output.i_format = i_vlc_pcm_format;
550

551
        if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
552
                                    SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
553 554 555 556 557
        {
            msg_Err( p_aout, "unable to set interleaved stream format (%s)",
                             snd_strerror( i_snd_rc ) );
            goto error;
        }
558

559 560
        /* Set channels. */
        if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
561
                                                      i_channels ) ) < 0 )
562 563 564 565 566
        {
            msg_Err( p_aout, "unable to set number of output channels (%s)",
                             snd_strerror( i_snd_rc ) );
            goto error;
        }
567

568 569
        /* Set rate. */
        i_old_rate = p_aout->output.output.i_rate;
570
#ifdef HAVE_ALSA_NEW_API
571
        i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
572 573 574
                                                &p_aout->output.output.i_rate,
                                                NULL );
#else
575
        i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
576 577 578
                                                p_aout->output.output.i_rate,
                                                NULL );
#endif
579 580
        if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
        {
581 582 583
            msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
                "hardware. Using %d Hz instead.\n", i_old_rate, \
                p_aout->output.output.i_rate );
584
        }
585

586
        /* Set buffer size. */
587
#ifdef HAVE_ALSA_NEW_API
588
        if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
589
                                    p_hw, &i_buffer_size ) ) < 0 )
590
#else
591
        if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
592 593
                                    p_hw, i_buffer_size ) ) < 0 )
#endif
594 595
        {
            msg_Err( p_aout, "unable to set buffer size (%s)",
596
                         snd_strerror( i_snd_rc ) );
597 598
            goto error;
        }
599

600
        /* Set period size. */
601
#ifdef HAVE_ALSA_NEW_API
602
        if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
603
                                    p_hw, &i_period_size, NULL ) ) < 0 )
604
#else
605
        if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
606 607
                                    p_hw, i_period_size, NULL ) ) < 0 )
#endif
608 609
        {
            msg_Err( p_aout, "unable to set period size (%s)",
610
                         snd_strerror( i_snd_rc ) );
611 612 613
            goto error;
        }
        p_aout->output.i_nb_samples = i_period_size;
614

615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
        /* Commit hardware parameters. */
        if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
        {
            if ( b_retry == VLC_FALSE &&
                                i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
            {
                b_retry = VLC_TRUE;
                i_snd_pcm_format = SND_PCM_FORMAT_S16;
                p_aout->output.output.i_format = AOUT_FMT_S16_NE;
                msg_Warn( p_aout, "unable to commit hardware configuration "
                                  "with fl32 samples. Retrying with s16l (%s)",                                     snd_strerror( i_snd_rc ) );
            }
            else
            {
                msg_Err( p_aout, "unable to commit hardware configuration (%s)",
630
                         snd_strerror( i_snd_rc ) );
631 632 633
                goto error;
            }
        }
634 635
    }

636
#ifdef HAVE_ALSA_NEW_API
637 638
    if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
                                    &p_sys->i_period_time, NULL ) ) < 0 )
639 640
#else
    if( ( p_sys->i_period_time =
641
                  (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )
642
#endif
643 644 645 646 647
    {
        msg_Err( p_aout, "unable to get period time (%s)",
                         snd_strerror( i_snd_rc ) );
        goto error;
    }
648

649
    /* Get Initial software parameters */
650
    snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
651

652
    i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
653

654 655
    i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
                                                p_aout->output.i_nb_samples );
656

657
    /* Commit software parameters. */
658
    if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
659 660
    {
        msg_Err( p_aout, "unable to set software configuration" );
661
        goto error;
662 663
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
664
#ifdef ALSA_DEBUG
665 666 667 668 669 670 671
    snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
    snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
    snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
    snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
    snd_output_printf( p_sys->p_snd_stderr, "\n" );
#endif

Christophe Massiot's avatar
Christophe Massiot committed
672 673 674 675 676
    /* Create ALSA thread and wait for its readiness. */
    if( vlc_thread_create( p_aout, "aout", ALSAThread,
                           VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
    {
        msg_Err( p_aout, "cannot create ALSA thread (%s)", strerror(errno) );
677
        goto error;
Christophe Massiot's avatar
Christophe Massiot committed
678
    }
679

680
    return 0;
681 682 683

error:
    snd_pcm_close( p_sys->p_snd_pcm );
Gildas Bazin's avatar
 
Gildas Bazin committed
684
#ifdef ALSA_DEBUG
685 686 687 688
    snd_output_close( p_sys->p_snd_stderr );
#endif
    free( p_sys );
    return VLC_EGENERIC;
689 690 691
}

/*****************************************************************************
Christophe Massiot's avatar
Christophe Massiot committed
692
 * Play: nothing to do
693
 *****************************************************************************/
694
static void Play( aout_instance_t *p_aout )
695
{
Gildas Bazin's avatar
 
Gildas Bazin committed
696 697 698 699 700 701 702 703 704 705 706 707 708
    if( !p_aout->output.p_sys->b_playing )
    {
        p_aout->output.p_sys->b_playing = 1;

        /* 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 );
    }
709 710 711
}

/*****************************************************************************
712
 * Close: close the ALSA device
713
 *****************************************************************************/
714
static void Close( vlc_object_t *p_this )
715
{
716 717 718
    aout_instance_t *p_aout = (aout_instance_t *)p_this;
    struct aout_sys_t * p_sys = p_aout->output.p_sys;
    int i_snd_rc;
719

Gildas Bazin's avatar
 
Gildas Bazin committed
720 721 722 723 724
    /* 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 );

725
    vlc_object_kill( p_aout );
726
    vlc_thread_join( p_aout );
Arnaud de Bossoreille de Ribou's avatar
Arnaud de Bossoreille de Ribou committed
727
    p_aout->b_die = VLC_FALSE;
728

729
    i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
730

731 732 733 734
    if( i_snd_rc > 0 )
    {
        msg_Err( p_aout, "failed closing ALSA device (%s)",
                         snd_strerror( i_snd_rc ) );
735 736
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
737
#ifdef ALSA_DEBUG
738 739 740
    snd_output_close( p_sys->p_snd_stderr );
#endif

741
    free( p_sys );
742 743 744
}

/*****************************************************************************
745
 * ALSAThread: asynchronous thread used to DMA the data to the device
746
 *****************************************************************************/
747
static int ALSAThread( aout_instance_t * p_aout )
748
{
749 750 751
    p_aout->output.p_sys->p_status =
        (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());

Gildas Bazin's avatar
 
Gildas Bazin committed
752 753 754 755 756 757 758 759
    /* Wait for the exact time to start playing (avoids resampling) */
    vlc_mutex_lock( &p_aout->output.p_sys->lock );
    if( !p_aout->output.p_sys->start_date )
        vlc_cond_wait( &p_aout->output.p_sys->wait,
                       &p_aout->output.p_sys->lock );
    vlc_mutex_unlock( &p_aout->output.p_sys->lock );

    mwait( p_aout->output.p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
760

761
    while ( !p_aout->b_die )
762
    {
763
        ALSAFill( p_aout );
764
    }
765

766
    free( p_aout->output.p_sys->p_status );
767
    return 0;
768 769 770
}

/*****************************************************************************
771
 * ALSAFill: function used to fill the ALSA buffer as much as possible
772
 *****************************************************************************/
773
static void ALSAFill( aout_instance_t * p_aout )
774
{
775 776
    struct aout_sys_t * p_sys = p_aout->output.p_sys;
    aout_buffer_t * p_buffer;
Gildas Bazin's avatar
 
Gildas Bazin committed
777
    snd_pcm_status_t * p_status = p_sys->p_status;
778
    int i_snd_rc;
Arnaud de Bossoreille de Ribou's avatar
Arnaud de Bossoreille de Ribou committed
779
    mtime_t next_date;
780

781
    /* Fill in the buffer until space or audio output buffer shortage */
782
    {
783
        /* Get the status */
784 785 786 787 788
        i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
        if( i_snd_rc < 0 )
        {
            msg_Err( p_aout, "unable to get the device's status (%s)",
                             snd_strerror( i_snd_rc ) );
Gildas Bazin's avatar
 
Gildas Bazin committed
789 790

            msleep( p_sys->i_period_time >> 1 );
791 792 793
            return;
        }

794
        /* Handle buffer underruns and reget the status */
795 796
        if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
        {
797
            /* Prepare the device */
798
            i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
799

800 801
            if( i_snd_rc == 0 )
            {
Clément Stenac's avatar
Clément Stenac committed
802
                msg_Dbg( p_aout, "recovered from buffer underrun" );
803 804

                /* Reget the status */
805 806 807
                i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
                if( i_snd_rc < 0 )
                {
Gildas Bazin's avatar
 
Gildas Bazin committed
808 809 810 811
                    msg_Err( p_aout, "unable to get the device's status after "
                             "recovery (%s)", snd_strerror( i_snd_rc ) );

                    msleep( p_sys->i_period_time >> 1 );
812 813 814 815 816 817
                    return;
                }
            }
            else
            {
                msg_Err( p_aout, "unable to recover from buffer underrun" );
Gildas Bazin's avatar
 
Gildas Bazin committed
818 819

                msleep( p_sys->i_period_time >> 1 );
820 821 822
                return;
            }

Gildas Bazin's avatar
 
Gildas Bazin committed
823 824 825 826 827 828 829
            /* Underrun, try to recover as quickly as possible */
            next_date = mdate();
        }
        else
        {
            /* Here the device should be either in the RUNNING state.
             * p_status is valid. */
830

831 832
#if 0
    /* This apparently does not work correctly in Alsa 1.0.11 */
Gildas Bazin's avatar
 
Gildas Bazin committed
833 834
            snd_pcm_status_get_tstamp( p_status, &ts_next );
            next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
835 836 837
            if( next_date )
            {
                next_date += (mtime_t)snd_pcm_status_get_delay(p_status)
838 839 840
                        * 1000000 / p_aout->output.output.i_rate;
            }
            else
841
#endif
842 843 844
            {
                /* With screwed ALSA drivers the timestamp is always zero;
                 * use another method then */
845
                snd_pcm_sframes_t delay = 0;
846

847 848 849
                snd_pcm_delay( p_sys->p_snd_pcm, &delay );
                next_date = mdate() + (mtime_t)(delay) * 1000000 /
                          p_aout->output.output.i_rate
850
                        * p_aout->output.output.i_frame_length;
851
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
852
        }
853

Arnaud de Bossoreille de Ribou's avatar
Arnaud de Bossoreille de Ribou committed
854
        p_buffer = aout_OutputNextBuffer( p_aout, next_date,
855
                        (p_aout->output.output.i_format ==
Arnaud de Bossoreille de Ribou's avatar
Arnaud de Bossoreille de Ribou committed
856
                         VLC_FOURCC('s','p','d','i')) );
857

Gildas Bazin's avatar
 
Gildas Bazin committed
858
        /* Audio output buffer shortage -> stop the fill process and wait */
Arnaud de Bossoreille de Ribou's avatar
Arnaud de Bossoreille de Ribou committed
859
        if( p_buffer == NULL )
Gildas Bazin's avatar
 
Gildas Bazin committed
860 861
        {
            msleep( p_sys->i_period_time >> 1 );
Arnaud de Bossoreille de Ribou's avatar
Arnaud de Bossoreille de Ribou committed
862
            return;
Gildas Bazin's avatar
 
Gildas Bazin committed
863
        }
864

Arnaud de Bossoreille de Ribou's avatar
Arnaud de Bossoreille de Ribou committed
865 866
        i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
                                   p_buffer->i_nb_samples );
867

Arnaud de Bossoreille de Ribou's avatar
Arnaud de Bossoreille de Ribou committed
868
        if( i_snd_rc < 0 )
869
        {
Arnaud de Bossoreille de Ribou's avatar
Arnaud de Bossoreille de Ribou committed
870 871
            msg_Err( p_aout, "write failed (%s)",
                             snd_strerror( i_snd_rc ) );
872
        }
Arnaud de Bossoreille de Ribou's avatar
Arnaud de Bossoreille de Ribou committed
873 874

        aout_BufferFree( p_buffer );
875
    }
876
}
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988