1 /*****************************************************************************
2 * aout_qnx.c : Alsa functions library
3 *****************************************************************************
4 * Copyright (C) 2000 VideoLAN
6 * Authors: Henri Fallon <henri@videolan.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
21 *****************************************************************************/
23 #define MODULE_NAME qnx
24 #include "modules_inner.h"
26 /*****************************************************************************
28 *****************************************************************************/
32 #include <errno.h> /* ENOMEM */
33 #include <string.h> /* strerror() */
34 #include <stdio.h> /* "intf_msg.h" */
35 #include <stdlib.h> /* calloc(), malloc(), free() */
37 #include <sys/asoundlib.h>
40 #include "common.h" /* boolean_t, byte_t */
45 #include "audio_output.h" /* aout_thread_t */
47 #include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
51 #include "modules_export.h"
53 typedef struct alsa_device_s
58 typedef struct alsa_card_s
63 /* here we store plugin dependant informations */
65 typedef struct aout_sys_s
67 snd_pcm_t * p_alsa_handle;
68 alsa_device_t s_alsa_device;
69 alsa_card_t s_alsa_card;
70 snd_pcm_channel_params_t s_alsa_channel_params;
71 snd_pcm_format_t s_alsa_format;
74 /*****************************************************************************
76 *****************************************************************************/
77 static int aout_Probe ( probedata_t *p_data );
78 static int aout_Open ( aout_thread_t *p_aout );
79 static int aout_SetFormat ( aout_thread_t *p_aout );
80 static long aout_GetBufInfo ( aout_thread_t *p_aout, long l_buffer_info );
81 static void aout_Play ( aout_thread_t *p_aout,
82 byte_t *buffer, int i_size );
83 static void aout_Close ( aout_thread_t *p_aout );
85 /*****************************************************************************
86 * Functions exported as capabilities. They are declared as static so that
87 * we don't pollute the namespace too much.
88 *****************************************************************************/
89 void _M( aout_getfunctions )( function_list_t * p_function_list )
91 p_function_list->pf_probe = aout_Probe;
92 p_function_list->functions.aout.pf_open = aout_Open;
93 p_function_list->functions.aout.pf_setformat = aout_SetFormat;
94 p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
95 p_function_list->functions.aout.pf_play = aout_Play;
96 p_function_list->functions.aout.pf_close = aout_Close;
99 /*****************************************************************************
100 * aout_Probe: probes the audio device and return a score
101 *****************************************************************************
102 * This function tries to open the dps and returns a score to the plugin
103 * manager so that it can make its choice.
104 *****************************************************************************/
105 static int aout_Probe( probedata_t *p_data )
107 int i_open_return, i_close_return;
108 aout_sys_t local_sys;
109 /* This is the same as the beginning of the aout_Open */
112 local_sys.s_alsa_device.i_num = 0;
113 local_sys.s_alsa_card.i_num = 0;
116 i_open_return = snd_pcm_open( &(local_sys.p_alsa_handle),
117 local_sys.s_alsa_card.i_num,
118 local_sys.s_alsa_device.i_num,
119 SND_PCM_OPEN_PLAYBACK );
122 intf_WarnMsg( 2, "aout info: could not probe ALSA device (%s)",
123 snd_strerror( i_open_return ) );
128 i_close_return = snd_pcm_close( local_sys.p_alsa_handle );
132 intf_ErrMsg( "aout error: could not close ALSA device (%s)",
133 snd_strerror( i_close_return ) );
137 if( TestMethod( AOUT_METHOD_VAR, "qnx" ) )
142 /* And return score */
146 /*****************************************************************************
147 * aout_Open : creates a handle and opens an alsa device
148 *****************************************************************************
149 * This function opens an alsa device, through the alsa API
150 *****************************************************************************/
151 static int aout_Open( aout_thread_t *p_aout )
155 /* Allocate structures */
156 p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
157 if( p_aout->p_sys == NULL )
159 intf_ErrMsg( "aout error: failed allocating memory for ALSA (%s)",
165 p_aout->p_sys->s_alsa_device.i_num = 0;
166 p_aout->p_sys->s_alsa_card.i_num = 0;
167 /* FIXME : why not other format ? */
168 p_aout->i_format = AOUT_FMT_S16_LE;
169 /* FIXME : why always 2 channels ?*/
170 p_aout->i_channels = 2;
171 p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR, AOUT_RATE_DEFAULT );
174 if( ( i_open_returns = snd_pcm_open( &(p_aout->p_sys->p_alsa_handle),
175 p_aout->p_sys->s_alsa_card.i_num,
176 p_aout->p_sys->s_alsa_device.i_num,
177 SND_PCM_OPEN_PLAYBACK ) ) )
179 intf_ErrMsg( "aout error: could not open ALSA device (%s)",
180 snd_strerror(i_open_returns) );
184 intf_DbgMsg( "aout info: ALSA device successfully opened" );
189 /*****************************************************************************
190 * aout_SetFormat : sets the alsa output format
191 *****************************************************************************
192 * This function prepares the device, sets the rate, format, the mode
193 * ("play as soon as you have data"), and buffer information.
194 *****************************************************************************/
195 static int aout_SetFormat( aout_thread_t *p_aout )
198 int i_set_param_returns;
199 int i_prepare_playback_returns;
200 int i_playback_go_returns;
202 /* Fill with zeros */
203 memset( &p_aout->p_sys->s_alsa_channel_params, 0,
204 sizeof( p_aout->p_sys->s_alsa_channel_params ) );
206 /* Fill the s_alsa_channel_params structure */
208 /* Tranfer mode and direction*/
209 p_aout->p_sys->s_alsa_channel_params.channel = SND_PCM_CHANNEL_PLAYBACK ;
210 p_aout->p_sys->s_alsa_channel_params.mode = SND_PCM_MODE_STREAM;
212 /* Format and rate */
213 p_aout->p_sys->s_alsa_channel_params.format.interleave = 1;
214 if( p_aout->i_format == AOUT_FMT_S16_LE )
216 p_aout->p_sys->s_alsa_channel_params.format.format =
221 p_aout->p_sys->s_alsa_channel_params.format.format =
224 p_aout->p_sys->s_alsa_channel_params.format.rate = p_aout->l_rate;
225 p_aout->p_sys->s_alsa_channel_params.format.voices = p_aout->i_channels ;
227 /* When to start playing and when to stop */
228 p_aout->p_sys->s_alsa_channel_params.start_mode = SND_PCM_START_DATA;
229 p_aout->p_sys->s_alsa_channel_params.stop_mode = SND_PCM_STOP_STOP;
231 /* Buffer information . I have chosen the stream mode here
232 * instead of the block mode. I don't know whether i'm wrong
233 * but it seemed more logical */
234 /* TODO : find the best value to put here. Probably depending
235 * on many parameters */
236 p_aout->p_sys->s_alsa_channel_params.buf.stream.queue_size = 131072;
238 p_aout->p_sys->s_alsa_channel_params.buf.stream.fill = SND_PCM_FILL_NONE ;
239 p_aout->p_sys->s_alsa_channel_params.buf.stream.max_fill = 0 ;
241 /* Now we pass this to the driver */
242 i_set_param_returns = snd_pcm_channel_params(
243 p_aout->p_sys->p_alsa_handle,
244 &(p_aout->p_sys->s_alsa_channel_params) );
246 if( i_set_param_returns )
248 intf_ErrMsg( "aout error: unable to set parameters (%s)",
249 snd_strerror( i_set_param_returns ) );
253 /* we shall now prepare the channel */
254 i_prepare_playback_returns =
255 snd_pcm_playback_prepare( p_aout->p_sys->p_alsa_handle );
257 if( i_prepare_playback_returns )
259 intf_ErrMsg( "aout error: unable to prepare channel (%s)",
260 snd_strerror( i_set_param_returns ) );
265 i_playback_go_returns =
266 snd_pcm_playback_go( p_aout->p_sys->p_alsa_handle );
267 if( i_playback_go_returns )
269 intf_ErrMsg( "aout error: unable to prepare channel (bis) (%s)",
270 snd_strerror( i_set_param_returns ) );
274 p_aout->i_latency = 0;
279 /*****************************************************************************
280 * aout_BufInfo: buffer status query
281 *****************************************************************************
282 * This function returns the number of used byte in the queue.
283 * It also deals with errors : indeed if the device comes to run out
284 * of data to play, it switches to the "underrun" status. It has to
285 * be flushed and re-prepared
286 *****************************************************************************/
287 static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit )
289 snd_pcm_channel_status_t alsa_channel_status;
290 int i_alsa_get_status_returns;
292 memset( &alsa_channel_status, 0, sizeof( alsa_channel_status ) );
294 i_alsa_get_status_returns = snd_pcm_channel_status(
295 p_aout->p_sys->p_alsa_handle, &alsa_channel_status );
297 if( i_alsa_get_status_returns )
299 intf_ErrMsg( "aout error: failed getting alsa buffer info (%s)",
300 snd_strerror ( i_alsa_get_status_returns ) );
304 switch( alsa_channel_status.status )
306 case SND_PCM_STATUS_NOTREADY:
308 intf_ErrMsg( "aout error: status NOT READY" );
312 case SND_PCM_STATUS_UNDERRUN:
314 int i_prepare_returns;
315 intf_ErrMsg( "aout error: status UNDERRUN ... resetting queue ");
316 i_prepare_returns = snd_pcm_playback_prepare(
317 p_aout->p_sys->p_alsa_handle );
318 if ( i_prepare_returns )
320 intf_ErrMsg( "aout error: could not flush (%s)",
321 snd_strerror(i_prepare_returns) );
327 return( alsa_channel_status.count );
330 /*****************************************************************************
331 * aout_Play : plays a sample
332 *****************************************************************************
333 * Plays a sample using the snd_pcm_write function from the alsa API
334 *****************************************************************************/
335 static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
339 i_write_returns = (int) snd_pcm_write (
340 p_aout->p_sys->p_alsa_handle, (void *) buffer, (size_t) i_size );
342 if( i_write_returns <= 0 )
344 intf_ErrMsg( "aout error: writing blocks failed (%s)",
345 snd_strerror( i_write_returns ) );
349 /*****************************************************************************
350 * aout_Close : close the Alsa device
351 *****************************************************************************/
352 static void aout_Close( aout_thread_t *p_aout )
356 i_close_returns = snd_pcm_close( p_aout->p_sys->p_alsa_handle );
358 if( i_close_returns )
360 intf_ErrMsg( "aout error: failed closing ALSA device (%s)",
361 snd_strerror( i_close_returns ) );
363 free( p_aout->p_sys );
365 intf_DbgMsg( "aout: ALSA device closed" );