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