]> git.sesse.net Git - vlc/blob - plugins/alsa/aout_alsa.c
. this is a coding style patch which removes all "foo(bar){" constructions
[vlc] / plugins / alsa / aout_alsa.c
1 /*****************************************************************************
2  * aout_alsa.c : Alsa functions library
3  *****************************************************************************
4  * Copyright (C) 2000 VideoLAN
5  *
6  * Authors:
7  *  Henri Fallon <henri@videolan.org>
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #include "defs.h"
29
30 #include <errno.h>                                                 /* ENOMEM */
31 #include <string.h>                                            /* strerror() */
32 #include <stdio.h>                                           /* "intf_msg.h" */
33 #include <stdlib.h>                            /* calloc(), malloc(), free() */
34
35 #include <sys/asoundlib.h>
36 #include <linux/asound.h>
37
38 #include "config.h"
39 #include "common.h"                                     /* boolean_t, byte_t */
40 #include "threads.h"
41 #include "mtime.h"
42 #include "plugins.h"
43
44 #include "audio_output.h"                                   /* aout_thread_t */
45
46 #include "intf_msg.h"                        /* intf_DbgMsg(), intf_ErrMsg() */
47 #include "main.h"
48
49
50
51
52 typedef struct alsa_device_s
53 {
54     int i_num;
55 } alsa_device_t;
56
57 typedef struct alsa_card_s
58 {
59     int i_num;
60 } alsa_card_t;
61
62 /* here we store plugin dependant informations */
63
64 typedef struct aout_sys_s
65 {
66     snd_pcm_t         * p_alsa_handle;
67     alsa_device_t       s_alsa_device;
68     alsa_card_t         s_alsa_card;
69     snd_pcm_channel_params_t s_alsa_channel_params;
70     snd_pcm_format_t    s_alsa_format;
71 } aout_sys_t;
72
73
74
75 /*****************************************************************************
76  * aout_AlsaOpen : creates a handle and opens an alsa device
77  *****************************************************************************/
78
79 int aout_AlsaOpen( aout_thread_t *p_aout )
80 {
81
82     int i_open_returns;
83     
84     /* Allocate structures */
85     p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
86     if( p_aout->p_sys == NULL )
87     {
88         intf_ErrMsg( "Alsa Plugin : Could not allocate memory" );
89         intf_ErrMsg( "error: %s", strerror(ENOMEM) );
90         return( 1 );
91     }
92
93     /* Initialize  */
94     p_aout->p_sys->s_alsa_device.i_num = 0;
95     p_aout->p_sys->s_alsa_card.i_num = 0;
96     /* FIXME : why not other format ? */
97     p_aout->i_format = AOUT_FMT_S16_LE;   
98     /* FIXME : why always 2 channels ?*/
99     p_aout->i_channels = 2;
100     p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR, AOUT_RATE_DEFAULT );
101     
102     /* Open device */
103     if ( ( i_open_returns = snd_pcm_open( &(p_aout->p_sys->p_alsa_handle),
104                 p_aout->p_sys->s_alsa_card.i_num,
105                 p_aout->p_sys->s_alsa_device.i_num,
106                 SND_PCM_OPEN_PLAYBACK ) ) )
107     {
108         intf_ErrMsg ( "Could not open alsa device; exit = %i",
109                       i_open_returns );
110         intf_ErrMsg ( "This means : %s", snd_strerror(i_open_returns) );
111         return ( 1 );
112     }
113
114     intf_DbgMsg("Alsa plugin : Alsa device successfully opened");
115     return ( 0 );
116 }
117
118
119 /*****************************************************************************
120  * aout_AlsaSetFormat : sets the alsa output format
121  *****************************************************************************/
122
123 int aout_AlsaSetFormat ( aout_thread_t *p_aout )
124 {
125     
126     int i_set_param_returns;
127     int i_prepare_playback_returns;
128     int i_playback_go_returns;
129
130     /* Fill with zeros */
131     memset(&p_aout->p_sys->s_alsa_channel_params,0,
132             sizeof(p_aout->p_sys->s_alsa_channel_params));
133     
134     /* Fill the s_alsa_channel_params structure */
135
136     /* Tranfer mode and direction*/    
137     p_aout->p_sys->s_alsa_channel_params.channel = SND_PCM_CHANNEL_PLAYBACK ;
138     p_aout->p_sys->s_alsa_channel_params.mode = SND_PCM_MODE_STREAM;
139     
140     /* Format and rate */
141     p_aout->p_sys->s_alsa_channel_params.format.interleave = 1;
142     if ( p_aout->i_format == AOUT_FMT_S16_LE )
143         p_aout->p_sys->s_alsa_channel_params.format.format = 
144             SND_PCM_SFMT_S16_LE;
145     else
146         p_aout->p_sys->s_alsa_channel_params.format.format = 
147             SND_PCM_SFMT_S16_BE;
148     p_aout->p_sys->s_alsa_channel_params.format.rate = p_aout->l_rate;
149     p_aout->p_sys->s_alsa_channel_params.format.voices = p_aout->i_channels ;
150     
151     /* When to start playing and when to stop */
152     p_aout->p_sys->s_alsa_channel_params.start_mode = SND_PCM_START_DATA;
153     p_aout->p_sys->s_alsa_channel_params.stop_mode = SND_PCM_STOP_STOP;
154
155     /* Buffer information . I have chosen the stream mode here
156      * instead of the block mode. I don't know whether i'm wrong 
157      * but it seemed more logical */
158     /* TODO : find the best value to put here. Probably depending
159      * on many parameters */
160     p_aout->p_sys->s_alsa_channel_params.buf.stream.queue_size = 131072; 
161     
162     p_aout->p_sys->s_alsa_channel_params.buf.stream.fill = SND_PCM_FILL_NONE ;
163     p_aout->p_sys->s_alsa_channel_params.buf.stream.max_fill = 0 ; 
164   
165     /* Now we pass this to the driver */
166     i_set_param_returns = snd_pcm_channel_params ( 
167             p_aout->p_sys->p_alsa_handle, 
168             &(p_aout->p_sys->s_alsa_channel_params) );
169     
170     if ( i_set_param_returns )
171     {
172         intf_ErrMsg ( "ALSA_PLUGIN : Unable to set parameters; exit = %i",
173                 i_set_param_returns );
174         intf_ErrMsg( "This means : %s",
175                 snd_strerror( i_set_param_returns ) );
176         return ( 1 );
177     }
178
179     /* we shall now prepare the channel */
180     i_prepare_playback_returns = 
181         snd_pcm_playback_prepare ( p_aout->p_sys->p_alsa_handle );
182
183     if ( i_prepare_playback_returns )
184     {
185         intf_ErrMsg ( "ALSA_PLUGIN : Unable to prepare channel : exit = %i",
186                 i_prepare_playback_returns );
187         intf_ErrMsg( "This means : %s",
188                 snd_strerror( i_set_param_returns ) );
189
190         return ( 1 );
191     }
192     
193    /* then we may go */
194    i_playback_go_returns =
195        snd_pcm_playback_go ( p_aout->p_sys->p_alsa_handle );
196     if ( i_playback_go_returns )
197     {
198         intf_ErrMsg ( "ALSA_PLUGIN : Unable to prepare channel (bis) : 
199                 exit  = %i", i_playback_go_returns );
200         intf_ErrMsg( "This means : %s",
201                 snd_strerror( i_set_param_returns ) );
202         return ( 1 );
203     }
204     return ( 0 );
205 }
206
207 /*****************************************************************************
208  * aout_AlsaReset: resets the dsp
209  *****************************************************************************/
210 int aout_AlsaReset ( aout_thread_t *p_aout )
211 {
212     /* TODO : put something in here, such as close and open again 
213      * or check status, drain, flush, .... */ 
214     return ( 0 );
215 }
216
217 /*****************************************************************************
218  * aout_AlsaSetChannels: sets mono, stereo and other modes
219  *****************************************************************************/
220 int aout_AlsaSetChannels ( aout_thread_t *p_aout )
221 {
222     /* TODO : normally, nothing
223      * everything should be done in the AlsaSetFormat, as far a I understand
224      * the alsa documentation
225      */
226     return ( 0 );
227 }
228
229 /*****************************************************************************
230  * aout_AlsaSetRate: sets the audio output rate
231  *****************************************************************************
232  * As in the previous function, the rate is supposed to be set in the
233  * AlsaSetFormat function
234  *****************************************************************************/
235 int aout_AlsaSetRate ( aout_thread_t *p_aout )
236 {
237     return ( 0 );
238 }
239
240 /*****************************************************************************
241  * aout_AlsaGetBufInfo: buffer status query
242  *****************************************************************************/
243 long aout_AlsaGetBufInfo ( aout_thread_t *p_aout, long l_buffer_limit )
244 {
245     snd_pcm_channel_status_t alsa_channel_status;
246     int i_alsa_get_status_returns;
247     
248     memset (&alsa_channel_status, 0, sizeof(alsa_channel_status));
249    
250     i_alsa_get_status_returns = snd_pcm_channel_status ( 
251             p_aout->p_sys->p_alsa_handle, &alsa_channel_status );
252
253     if ( i_alsa_get_status_returns )
254     {
255         intf_ErrMsg ( "Error getting alsa buffer info; exit=%i",
256                 i_alsa_get_status_returns );
257         intf_ErrMsg ( "This means : %s",
258                 snd_strerror ( i_alsa_get_status_returns ) );
259         return ( 1 );
260     }
261
262     switch (alsa_channel_status.status)
263     {
264         case SND_PCM_STATUS_NOTREADY : intf_ErrMsg("Status NOT READY");
265                                        break;
266         case SND_PCM_STATUS_UNDERRUN : {
267                                        int i_prepare_returns;
268                                        intf_ErrMsg(
269                                   "Status UNDERRUN ... reseting queue");
270                                        i_prepare_returns = 
271                                            snd_pcm_playback_prepare(
272                                                p_aout->p_sys->p_alsa_handle );
273                                        if ( i_prepare_returns )
274                                        {
275                                            intf_ErrMsg(
276                                   "Error : could not flush : %i",
277                                   i_prepare_returns);
278                                            intf_ErrMsg(
279                                   "This means : %s",
280                                   snd_strerror(i_prepare_returns));
281                                        }
282                                        break;
283                                        }
284     } 
285     return (  alsa_channel_status.count );
286 }
287
288 /*****************************************************************************
289  * aout_AlsaPlaySamples
290  *****************************************************************************/
291 void aout_AlsaPlaySamples ( aout_thread_t *p_aout, byte_t *buffer, int i_size )
292 {
293     int i_write_returns;
294
295     i_write_returns = (int) snd_pcm_write (
296             p_aout->p_sys->p_alsa_handle, (void *)buffer, (size_t) i_size );
297
298     if ( i_write_returns <= 0 )
299     {
300         intf_ErrMsg ( "Error writing blocks; exit=%i", i_write_returns );
301         intf_ErrMsg ( "This means : %s", snd_strerror( i_write_returns ) );
302     }
303 }
304
305 /*****************************************************************************
306  * aout_AlsaClose : close the Alsa device
307  *****************************************************************************/
308 void aout_AlsaClose ( aout_thread_t *p_aout )
309 {
310     int i_close_returns;
311
312     i_close_returns = snd_pcm_close ( p_aout->p_sys->p_alsa_handle );
313
314     if ( i_close_returns )
315     {
316         intf_ErrMsg( "Error closing alsa device; exit=%i",i_close_returns );
317         intf_ErrMsg( "This means : %s",snd_strerror( i_close_returns ) );
318     }
319     free(p_aout->p_sys);
320     
321     intf_DbgMsg( "Alsa plugin : Alsa device closed");
322 }