1 /*****************************************************************************
2 * aout_qnx.c : QNX audio output
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
6 * Authors: Henri Fallon <henri@videolan.org>
7 * Jon Lech Johansen <jon-vl@nanocrew.net>
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.
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.
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 *****************************************************************************/
24 #define MODULE_NAME qnx
25 #include "modules_inner.h"
27 /*****************************************************************************
29 *****************************************************************************/
33 #include <errno.h> /* ENOMEM */
34 #include <string.h> /* strerror() */
35 #include <stdio.h> /* "intf_msg.h" */
36 #include <stdlib.h> /* calloc(), malloc(), free() */
38 #include <sys/asoundlib.h>
40 #include "common.h" /* boolean_t, byte_t */
41 #include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
46 #include "audio_output.h" /* aout_thread_t */
49 #include "modules_export.h"
51 typedef struct aout_sys_s
53 snd_pcm_t * p_pcm_handle;
58 /*****************************************************************************
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 );
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 )
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;
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 )
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 )
99 intf_WarnMsg( 2, "aout error: unable to open audio device (%s)",
100 snd_strerror( i_ret ) );
104 /* close audio device */
105 if( ( i_ret = snd_pcm_close( adev.p_pcm_handle ) ) < 0 )
107 intf_WarnMsg( 2, "aout error: unable to close audio device (%s)",
108 snd_strerror( i_ret ) );
112 if( TestMethod( AOUT_METHOD_VAR, "qnx" ) )
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 )
130 /* allocate structure */
131 p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
132 if( p_aout->p_sys == NULL )
134 intf_ErrMsg( "aout error: unable to allocate memory (%s)",
135 strerror( ENOMEM ) );
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,
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 )
152 intf_ErrMsg( "aout error: unable to open audio device (%s)",
153 snd_strerror( i_ret ) );
158 if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->p_sys->p_pcm_handle,
159 PLUGIN_DISABLE_MMAP ) ) < 0 )
161 intf_ErrMsg( "aout error: unable to disable mmap (%s)",
162 snd_strerror( i_ret ) );
163 aout_Close( p_aout );
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 )
180 int i_bytes_per_sample;
181 snd_pcm_channel_info_t pi;
182 snd_pcm_channel_params_t pp;
184 memset( &pi, 0, sizeof(pi) );
185 memset( &pp, 0, sizeof(pp) );
187 pi.channel = SND_PCM_CHANNEL_PLAYBACK;
188 if( ( i_ret = snd_pcm_plugin_info( p_aout->p_sys->p_pcm_handle,
191 intf_ErrMsg( "aout error: unable to get plugin info (%s)",
192 snd_strerror( i_ret ) );
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;
201 pp.buf.block.frags_max = 1;
202 pp.buf.block.frags_min = 1;
204 pp.format.interleave = 1;
205 pp.format.rate = p_aout->l_rate;
206 pp.format.voices = p_aout->i_channels;
208 switch( p_aout->i_format )
210 case AOUT_FMT_S16_LE:
211 pp.format.format = SND_PCM_SFMT_S16_LE;
212 i_bytes_per_sample = 2;
216 pp.format.format = SND_PCM_SFMT_S16_BE;
217 i_bytes_per_sample = 2;
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;
226 if( ( i_ret = snd_pcm_plugin_params( p_aout->p_sys->p_pcm_handle,
229 intf_ErrMsg( "aout error: unable to set parameters (%s)",
230 snd_strerror( i_ret ) );
234 /* prepare channel */
235 if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
236 SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
238 intf_ErrMsg( "aout error: unable to prepare channel (%s)",
239 snd_strerror( i_ret ) );
243 p_aout->i_latency = 0;
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 )
259 snd_pcm_channel_status_t status;
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,
266 intf_ErrMsg( "aout error: unable to get device status (%s)",
267 snd_strerror( i_ret ) );
271 /* check for underrun */
272 switch( status.status )
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 )
279 intf_ErrMsg( "aout error: unable to prepare channel (%s)",
280 snd_strerror( i_ret ) );
285 return( status.count );
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 )
297 if( ( i_ret = snd_pcm_plugin_write( p_aout->p_sys->p_pcm_handle,
299 (size_t) i_size ) ) <= 0 )
301 intf_ErrMsg( "aout error: unable to write data (%s)",
302 snd_strerror( i_ret ) );
306 /*****************************************************************************
307 * aout_Close : close the audio device
308 *****************************************************************************/
309 static void aout_Close( aout_thread_t *p_aout )
313 if( ( i_ret = snd_pcm_close( p_aout->p_sys->p_pcm_handle ) ) < 0 )
315 intf_ErrMsg( "aout error: unable to close audio device (%s)",
316 snd_strerror( i_ret ) );
319 free( p_aout->p_sys );