]> git.sesse.net Git - vlc/blob - plugins/qnx/aout_qnx.c
Some heavy changes today:
[vlc] / plugins / qnx / aout_qnx.c
1 /*****************************************************************************
2  * aout_qnx.c : QNX audio output 
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  *
6  * Authors: Henri Fallon <henri@videolan.org>
7  *          Jon Lech Johansen <jon-vl@nanocrew.net>
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 #include <errno.h>                                                 /* ENOMEM */
28 #include <string.h>                                            /* strerror() */
29 #include <stdio.h>                                           /* "intf_msg.h" */
30 #include <stdlib.h>                            /* calloc(), malloc(), free() */
31
32 #include <sys/asoundlib.h>
33
34 #include <videolan/vlc.h>
35
36 #include "audio_output.h"                                   /* aout_thread_t */
37
38 typedef struct aout_sys_s
39 {
40     snd_pcm_t  * p_pcm_handle;
41     int          i_card;
42     int          i_device;
43 } aout_sys_t;
44
45 /*****************************************************************************
46  * Local prototypes
47  *****************************************************************************/
48 static int     aout_Probe       ( probedata_t *p_data );
49 static int     aout_Open        ( aout_thread_t *p_aout );
50 static int     aout_SetFormat   ( aout_thread_t *p_aout );
51 static long    aout_GetBufInfo  ( aout_thread_t *p_aout, long l_buffer_info );
52 static void    aout_Play        ( aout_thread_t *p_aout,
53                                   byte_t *buffer, int i_size );
54 static void    aout_Close       ( aout_thread_t *p_aout );
55
56 /*****************************************************************************
57  * Functions exported as capabilities. They are declared as static so that
58  * we don't pollute the namespace too much.
59  *****************************************************************************/
60 void _M( aout_getfunctions )( function_list_t * p_function_list )
61 {
62     p_function_list->pf_probe = aout_Probe;
63     p_function_list->functions.aout.pf_open = aout_Open;
64     p_function_list->functions.aout.pf_setformat = aout_SetFormat;
65     p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
66     p_function_list->functions.aout.pf_play = aout_Play;
67     p_function_list->functions.aout.pf_close = aout_Close;
68 }
69
70 /*****************************************************************************
71  * aout_Probe: probes the audio device and return a score
72  *****************************************************************************
73  * This function tries to open the dps and returns a score to the plugin
74  * manager so that it can make its choice.
75  *****************************************************************************/
76 static int aout_Probe( probedata_t *p_data )
77 {
78     int i_ret;
79     aout_sys_t adev;
80
81     /* open audio device */
82     if( ( i_ret = snd_pcm_open_preferred( &adev.p_pcm_handle,
83                                           &adev.i_card, &adev.i_device,
84                                           SND_PCM_OPEN_PLAYBACK ) ) < 0 )
85     {
86         intf_WarnMsg( 2, "aout error: unable to open audio device (%s)",
87                       snd_strerror( i_ret ) );
88         return( 0 );
89     }
90
91     /* close audio device */
92     if( ( i_ret = snd_pcm_close( adev.p_pcm_handle ) ) < 0 )
93     {
94         intf_WarnMsg( 2, "aout error: unable to close audio device (%s)",
95                       snd_strerror( i_ret ) );
96         return( 0 );
97     }
98
99     if( TestMethod( AOUT_METHOD_VAR, "qnx" ) )
100     {
101         return( 999 );
102     }
103
104     /* return score */
105     return( 50 );
106 }    
107
108 /*****************************************************************************
109  * aout_Open : creates a handle and opens an alsa device
110  *****************************************************************************
111  * This function opens an alsa device, through the alsa API
112  *****************************************************************************/
113 static int aout_Open( aout_thread_t *p_aout )
114 {
115     int i_ret;
116
117     /* allocate structure */
118     p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
119     if( p_aout->p_sys == NULL )
120     {
121         intf_ErrMsg( "aout error: unable to allocate memory (%s)",
122                      strerror( ENOMEM ) );
123         return( 1 );
124     }
125
126     /* initialize  */
127     p_aout->i_format   = AOUT_FORMAT_DEFAULT;
128     p_aout->i_channels = main_GetIntVariable( AOUT_STEREO_VAR,
129                                               AOUT_STEREO_DEFAULT ) + 1;
130     p_aout->l_rate     = main_GetIntVariable( AOUT_RATE_VAR,
131                                               AOUT_RATE_DEFAULT );
132
133     /* open audio device */
134     if( ( i_ret = snd_pcm_open_preferred( &p_aout->p_sys->p_pcm_handle,
135                                           &p_aout->p_sys->i_card,
136                                           &p_aout->p_sys->i_device,
137                                           SND_PCM_OPEN_PLAYBACK ) ) < 0 )
138     {
139         intf_ErrMsg( "aout error: unable to open audio device (%s)",
140                       snd_strerror( i_ret ) );
141         return( 1 );
142     }
143
144     /* disable mmap */
145     if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->p_sys->p_pcm_handle,
146                                               PLUGIN_DISABLE_MMAP ) ) < 0 )
147     {
148         intf_ErrMsg( "aout error: unable to disable mmap (%s)",
149                      snd_strerror( i_ret ) );
150         aout_Close( p_aout );
151         return( 1 );
152     }
153
154     return( 0 );
155 }
156
157
158 /*****************************************************************************
159  * aout_SetFormat : set the audio output format 
160  *****************************************************************************
161  * This function prepares the device, sets the rate, format, the mode
162  * ("play as soon as you have data"), and buffer information.
163  *****************************************************************************/
164 static int aout_SetFormat( aout_thread_t *p_aout )
165 {
166     int i_ret;
167     int i_bytes_per_sample;
168     snd_pcm_channel_info_t pi;
169     snd_pcm_channel_params_t pp;
170
171     memset( &pi, 0, sizeof(pi) );
172     memset( &pp, 0, sizeof(pp) );
173
174     pi.channel = SND_PCM_CHANNEL_PLAYBACK;
175     if( ( i_ret = snd_pcm_plugin_info( p_aout->p_sys->p_pcm_handle,
176                                        &pi ) ) < 0 )
177     {
178         intf_ErrMsg( "aout error: unable to get plugin info (%s)",
179                      snd_strerror( i_ret ) );
180         return( 1 );
181     }
182
183     pp.mode       = SND_PCM_MODE_BLOCK;
184     pp.channel    = SND_PCM_CHANNEL_PLAYBACK;
185     pp.start_mode = SND_PCM_START_FULL;
186     pp.stop_mode  = SND_PCM_STOP_STOP;
187
188     pp.buf.block.frags_max   = 1;
189     pp.buf.block.frags_min   = 1;
190     
191     pp.format.interleave     = 1;
192     pp.format.rate           = p_aout->l_rate;
193     pp.format.voices         = p_aout->i_channels;
194
195     switch( p_aout->i_format )
196     {
197         case AOUT_FMT_S16_LE:
198             pp.format.format = SND_PCM_SFMT_S16_LE;
199             i_bytes_per_sample = 2;
200             break;
201
202         default:
203             pp.format.format = SND_PCM_SFMT_S16_BE;
204             i_bytes_per_sample = 2;
205             break;
206     }
207
208     pp.buf.block.frag_size =
209         (((s64)p_aout->l_rate * AOUT_BUFFER_DURATION) / 1000000) *
210         p_aout->i_channels * i_bytes_per_sample;
211
212     /* set parameters */
213     if( ( i_ret = snd_pcm_plugin_params( p_aout->p_sys->p_pcm_handle,
214                                          &pp ) ) < 0 )
215     {
216         intf_ErrMsg( "aout error: unable to set parameters (%s)",
217                      snd_strerror( i_ret ) );
218         return( 1 );
219     }
220
221     /* prepare channel */
222     if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
223                                           SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
224     {
225         intf_ErrMsg( "aout error: unable to prepare channel (%s)",
226                      snd_strerror( i_ret ) );
227         return( 1 );
228     }
229
230     p_aout->i_latency = 0;
231
232     return( 0 );
233 }
234
235 /*****************************************************************************
236  * aout_BufInfo: buffer status query
237  *****************************************************************************
238  * This function returns the number of used byte in the queue.
239  * It also deals with errors : indeed if the device comes to run out
240  * of data to play, it switches to the "underrun" status. It has to
241  * be flushed and re-prepared
242  *****************************************************************************/
243 static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit )
244 {
245     int i_ret;
246     snd_pcm_channel_status_t status;
247
248     /* get current pcm status */
249     memset( &status, 0, sizeof(status) );
250     if( ( i_ret = snd_pcm_plugin_status( p_aout->p_sys->p_pcm_handle,
251                                          &status ) ) < 0 )
252     {
253         intf_ErrMsg( "aout error: unable to get device status (%s)",
254                      snd_strerror( i_ret ) );
255         return( -1 );
256     }
257
258     /* check for underrun */
259     switch( status.status )
260     {
261         case SND_PCM_STATUS_READY:
262         case SND_PCM_STATUS_UNDERRUN:
263             if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
264                                           SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
265             {
266                 intf_ErrMsg( "aout error: unable to prepare channel (%s)",
267                              snd_strerror( i_ret ) );
268             }
269             break;
270     }
271
272     return( status.count );
273 }
274
275 /*****************************************************************************
276  * aout_Play : plays a sample
277  *****************************************************************************
278  * Plays a sample using the snd_pcm_write function from the alsa API
279  *****************************************************************************/
280 static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
281 {
282     int i_ret;
283
284     if( ( i_ret = snd_pcm_plugin_write( p_aout->p_sys->p_pcm_handle,
285                                         (void *) buffer, 
286                                         (size_t) i_size ) ) <= 0 )
287     {
288         intf_ErrMsg( "aout error: unable to write data (%s)",
289                      snd_strerror( i_ret ) );
290     }
291 }
292
293 /*****************************************************************************
294  * aout_Close : close the audio device
295  *****************************************************************************/
296 static void aout_Close( aout_thread_t *p_aout )
297 {
298     int i_ret;
299
300     if( ( i_ret = snd_pcm_close( p_aout->p_sys->p_pcm_handle ) ) < 0 )
301     {
302         intf_ErrMsg( "aout error: unable to close audio device (%s)",
303                      snd_strerror( i_ret ) );
304     }
305
306     free( p_aout->p_sys );
307 }