* ./evc/plugins.vcp.in: fixed plugin entry points for WinCE.
[vlc.git] / modules / audio_output / alsa.c
1 /*****************************************************************************
2  * alsa.c : alsa plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2001 VideoLAN
5  * $Id: alsa.c,v 1.15 2002/10/22 20:55:27 sam Exp $
6  *
7  * Authors: Henri Fallon <henri@videolan.org> - Original Author
8  *          Jeffrey Baker <jwbaker@acm.org> - Port to ALSA 1.0 API
9  *          John Paul Lorenti <jpl31@columbia.edu> - Device selection
10  *          Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr> - S/PDIF and aout3
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <errno.h>                                                 /* ENOMEM */
31 #include <string.h>                                            /* strerror() */
32 #include <stdlib.h>                            /* calloc(), malloc(), free() */
33
34 #include <vlc/vlc.h>
35
36 #include <vlc/aout.h>
37
38 #include "aout_internal.h"
39
40 /* ALSA part */
41 #include <alsa/asoundlib.h>
42
43 /*****************************************************************************
44  * aout_sys_t: ALSA audio output method descriptor
45  *****************************************************************************
46  * This structure is part of the audio output thread descriptor.
47  * It describes the ALSA specific properties of an audio device.
48  *****************************************************************************/
49 struct aout_sys_t
50 {
51     snd_pcm_t         * p_snd_pcm;
52     int                 i_period_time;
53
54 #ifdef DEBUG
55     snd_output_t      * p_snd_stderr;
56 #endif
57 };
58
59 #define A52_FRAME_NB 1536
60
61 /* These values are in frames.
62    To convert them to a number of bytes you have to multiply them by the
63    number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
64    2 for s16). */
65 #define ALSA_DEFAULT_PERIOD_SIZE        2048
66 #define ALSA_DEFAULT_BUFFER_SIZE        ( ALSA_DEFAULT_PERIOD_SIZE << 4 )
67 #define ALSA_SPDIF_PERIOD_SIZE          A52_FRAME_NB
68 #define ALSA_SPDIF_BUFFER_SIZE          ( ALSA_SPDIF_PERIOD_SIZE << 4 )
69 /* Why << 4 ? --Meuuh */
70
71 /*****************************************************************************
72  * Local prototypes
73  *****************************************************************************/
74 static int  Open         ( vlc_object_t * );
75 static void Close        ( vlc_object_t * );
76 static void Play         ( aout_instance_t * );
77 static int  ALSAThread   ( aout_instance_t * );
78 static void ALSAFill     ( aout_instance_t * );
79
80 /*****************************************************************************
81  * Module descriptor
82  *****************************************************************************/
83 vlc_module_begin();
84     add_category_hint( N_("ALSA"), NULL );
85     add_string( "alsa-device", "default", aout_FindAndRestart,
86                 N_("device name"), NULL );
87     set_description( _("ALSA audio module") );
88     set_capability( "audio output", 50 );
89     set_callbacks( Open, Close );
90 vlc_module_end();
91
92 /*****************************************************************************
93  * Open: create a handle and open an alsa device
94  *****************************************************************************
95  * This function opens an alsa device, through the alsa API
96  *****************************************************************************/
97 static int Open( vlc_object_t *p_this )
98 {
99     aout_instance_t * p_aout = (aout_instance_t *)p_this;
100     struct aout_sys_t * p_sys;
101     char * psz_device;
102     int i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
103     int i_format = SND_PCM_FORMAT_S16;
104
105     snd_pcm_hw_params_t *p_hw;
106     snd_pcm_sw_params_t *p_sw;
107
108     int i_snd_rc = -1;
109
110     /* Allocate structures */
111     p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
112     if( p_sys == NULL )
113     {
114         msg_Err( p_aout, "out of memory" );
115         return -1;
116     }
117
118     /* Get device name */
119     if( (psz_device = config_GetPsz( p_aout, "dspdev" )) == NULL )
120     {
121         msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
122         free( p_sys );
123         return VLC_EGENERIC;
124     }
125
126 #ifdef DEBUG
127     snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
128 #endif
129
130     /* Open the device */
131     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
132           && !strcmp( "default", psz_device ) )
133     {
134         /* ALSA doesn't understand "default" for S/PDIF. Cheat a little. */
135         char psz_iecdev[128];
136
137         if ( !strcmp( "default", psz_device ) )
138         {
139             snprintf( psz_iecdev, sizeof(psz_iecdev),
140                  "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
141                  IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
142                  IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
143                  0,
144                  (p_aout->output.output.i_rate == 48000 ?
145                   IEC958_AES3_CON_FS_48000 :
146                   (p_aout->output.output.i_rate == 44100 ?
147                    IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000)) );
148         }
149         else
150         {
151             strncat( psz_iecdev, psz_device, sizeof(psz_iecdev) );
152         }
153
154         if ( (i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iecdev,
155                            SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0 )
156         {
157             /* No S/PDIF. */
158             msg_Warn( p_aout, "cannot open S/PDIF ALSA device `%s' (%s)",
159                       psz_device, snd_strerror(i_snd_rc) );
160             p_aout->output.output.i_format = VLC_FOURCC('f','l','3','2');
161         }
162         else
163         {
164             i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
165             i_format = SND_PCM_FORMAT_S16;
166
167             p_aout->output.i_nb_samples = ALSA_SPDIF_PERIOD_SIZE;
168             p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
169             p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
170             p_aout->output.output.i_frame_length = A52_FRAME_NB;
171
172             aout_VolumeNoneInit( p_aout );
173         }
174     }
175
176     if ( !AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
177     {
178         if ( (i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
179                            SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0 )
180         {
181             msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
182                              psz_device, snd_strerror(i_snd_rc) );
183             free( p_sys );
184             free( psz_device );
185             return VLC_EGENERIC;
186         }
187
188         if ( p_aout->p_libvlc->i_cpu & CPU_CAPABILITY_FPU )
189         {
190             p_aout->output.output.i_format = VLC_FOURCC('f','l','3','2');
191             i_format = SND_PCM_FORMAT_FLOAT;
192         }
193         else
194         {
195             p_aout->output.output.i_format = AOUT_FMT_S16_NE;
196             i_format = SND_PCM_FORMAT_S16;
197         }
198
199         i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
200         p_aout->output.i_nb_samples = ALSA_DEFAULT_PERIOD_SIZE;
201
202         aout_VolumeSoftInit( p_aout );
203     }
204
205     free( psz_device );
206     p_aout->output.pf_play = Play;
207
208     snd_pcm_hw_params_alloca(&p_hw);
209     snd_pcm_sw_params_alloca(&p_sw);
210
211     if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
212     {
213         msg_Err( p_aout, "unable to retrieve initial hardware parameters" );
214         goto error;
215     }
216
217     /* Set format. */
218     if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw, i_format ) < 0 )
219     {
220         msg_Err( p_aout, "unable to set stream sample size and word order" );
221         goto error;
222     }
223
224     if ( !AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
225     {
226         int i_nb_channels;
227
228         if ( snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
229                                        SND_PCM_ACCESS_RW_INTERLEAVED ) < 0 )
230         {
231             msg_Err( p_aout, "unable to set interleaved stream format" );
232             goto error;
233         }
234
235         /* Set channels. */
236         i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
237
238         if ( (i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm,
239                                  p_hw, i_nb_channels )) < 0 )
240         {
241             msg_Err( p_aout, "unable to set number of output channels" );
242             goto error;
243         }
244         if ( i_snd_rc != i_nb_channels )
245         {
246             switch ( i_snd_rc )
247             {
248             case 1: p_aout->output.output.i_channels = AOUT_CHAN_MONO; break;
249             case 2: p_aout->output.output.i_channels = AOUT_CHAN_STEREO; break;
250             case 4: p_aout->output.output.i_channels = AOUT_CHAN_2F2R; break;
251             default:
252                 msg_Err( p_aout, "Unsupported downmixing (%d)", i_snd_rc );
253                 goto error;
254             }
255         }
256
257         /* Set rate. */
258         if ( (i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm,
259                                  p_hw, p_aout->output.output.i_rate,
260                                  NULL )) < 0 )
261         {
262             msg_Err( p_aout, "unable to set sample rate" );
263             goto error;
264         }
265         p_aout->output.output.i_rate = i_snd_rc;
266     }
267
268     /* Set buffer size. */
269     i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm, p_hw,
270                                                        i_buffer_size );
271     if( i_snd_rc < 0 )
272     {
273         msg_Err( p_aout, "unable to set buffer size" );
274         goto error;
275     }
276
277     /* Set period size. */
278     i_snd_rc = snd_pcm_hw_params_set_period_size_near(
279                   p_sys->p_snd_pcm, p_hw, p_aout->output.i_nb_samples, NULL );
280     if( i_snd_rc < 0 )
281     {
282         msg_Err( p_aout, "unable to set period size" );
283         goto error;
284     }
285     p_aout->output.i_nb_samples = i_snd_rc;
286
287     /* Write hardware configuration. */
288     if ( snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) < 0 )
289     {
290         msg_Err( p_aout, "unable to set hardware configuration" );
291         goto error;
292     }
293
294     p_sys->i_period_time = snd_pcm_hw_params_get_period_time( p_hw, NULL );
295
296     snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
297     i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
298
299     i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
300                                                 p_aout->output.i_nb_samples );
301
302     /* Write software configuration. */
303     if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
304     {
305         msg_Err( p_aout, "unable to set software configuration" );
306         goto error;
307     }
308
309 #ifdef DEBUG
310     snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
311     snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
312     snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
313     snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
314     snd_output_printf( p_sys->p_snd_stderr, "\n" );
315 #endif
316
317     /* Create ALSA thread and wait for its readiness. */
318     if( vlc_thread_create( p_aout, "aout", ALSAThread,
319                            VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
320     {
321         msg_Err( p_aout, "cannot create ALSA thread (%s)", strerror(errno) );
322         goto error;
323     }
324
325     return 0;
326
327 error:
328     snd_pcm_close( p_sys->p_snd_pcm );
329 #ifdef DEBUG
330     snd_output_close( p_sys->p_snd_stderr );
331 #endif
332     free( p_sys );
333     return VLC_EGENERIC;
334 }
335
336 /*****************************************************************************
337  * Play: nothing to do
338  *****************************************************************************/
339 static void Play( aout_instance_t *p_aout )
340 {
341 }
342
343 /*****************************************************************************
344  * Close: close the ALSA device
345  *****************************************************************************/
346 static void Close( vlc_object_t *p_this )
347 {
348     aout_instance_t *p_aout = (aout_instance_t *)p_this;
349     struct aout_sys_t * p_sys = p_aout->output.p_sys;
350     int i_snd_rc;
351
352     p_aout->b_die = 1;
353     vlc_thread_join( p_aout );
354
355     i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
356
357     if( i_snd_rc > 0 )
358     {
359         msg_Err( p_aout, "failed closing ALSA device (%s)",
360                          snd_strerror( i_snd_rc ) );
361     }
362
363 #ifdef DEBUG
364     snd_output_close( p_sys->p_snd_stderr );
365 #endif
366
367     free( p_sys );
368 }
369
370 /*****************************************************************************
371  * ALSAThread: asynchronous thread used to DMA the data to the device
372  *****************************************************************************/
373 static int ALSAThread( aout_instance_t * p_aout )
374 {
375     struct aout_sys_t * p_sys = p_aout->output.p_sys;
376
377     while ( !p_aout->b_die )
378     {
379         ALSAFill( p_aout );
380
381         /* Sleep during less than one period to avoid a lot of buffer
382            underruns */
383
384         /* Why do we need to sleep ? --Meuuh */
385         msleep( p_sys->i_period_time >> 2 );
386     }
387
388     return 0;
389 }
390
391 /*****************************************************************************
392  * ALSAFill: function used to fill the ALSA buffer as much as possible
393  *****************************************************************************/
394 static void ALSAFill( aout_instance_t * p_aout )
395 {
396     struct aout_sys_t * p_sys = p_aout->output.p_sys;
397
398     aout_buffer_t * p_buffer;
399     snd_pcm_status_t * p_status;
400     snd_timestamp_t ts_next;
401     int i_snd_rc;
402     snd_pcm_uframes_t i_avail;
403
404     snd_pcm_status_alloca( &p_status );
405
406     /* Wait for the device's readiness (ie. there is enough space in the
407        buffer to write at least one complete chunk) */
408     i_snd_rc = snd_pcm_wait( p_sys->p_snd_pcm, THREAD_SLEEP );
409     if( i_snd_rc < 0 )
410     {
411         msg_Err( p_aout, "ALSA device not ready !!! (%s)",
412                          snd_strerror( i_snd_rc ) );
413         return;
414     }
415
416     /* Fill in the buffer until space or audio output buffer shortage */
417     for ( ; ; )
418     {
419         /* Get the status */
420         i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
421         if( i_snd_rc < 0 )
422         {
423             msg_Err( p_aout, "unable to get the device's status (%s)",
424                              snd_strerror( i_snd_rc ) );
425             return;
426         }
427
428         /* Handle buffer underruns and reget the status */
429         if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
430         {
431             /* Prepare the device */
432             i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
433
434             if( i_snd_rc == 0 )
435             {
436                 msg_Warn( p_aout, "recovered from buffer underrun" );
437
438                 /* Reget the status */
439                 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
440                 if( i_snd_rc < 0 )
441                 {
442                     msg_Err( p_aout,
443                         "unable to get the device's status after recovery (%s)",
444                         snd_strerror( i_snd_rc ) );
445                     return;
446                 }
447             }
448             else
449             {
450                 msg_Err( p_aout, "unable to recover from buffer underrun" );
451                 return;
452             }
453         }
454
455         /* Here the device should be either in the RUNNING state either in
456            the PREPARE state. p_status is valid. */
457
458         /* Try to write only if there is enough space */
459         i_avail = snd_pcm_status_get_avail( p_status );
460
461         if( i_avail >= p_aout->output.i_nb_samples )
462         {
463             mtime_t next_date;
464             snd_pcm_status_get_tstamp( p_status, &ts_next );
465             next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
466
467             p_buffer = aout_OutputNextBuffer( p_aout, next_date,
468                         (p_aout->output.output.i_format !=
469                             VLC_FOURCC('s','p','d','i')) );
470
471             /* Audio output buffer shortage -> stop the fill process and
472                wait in ALSAThread */
473             if( p_buffer == NULL )
474                 return;
475
476             i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
477                                        p_buffer->i_nb_bytes );
478
479             if( i_snd_rc < 0 )
480             {
481                 msg_Err( p_aout, "write failed (%s)",
482                                  snd_strerror( i_snd_rc ) );
483             }
484
485             aout_BufferFree( p_buffer );
486         }
487     }
488 }
489