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 /*****************************************************************************
26 *****************************************************************************/
27 #include <errno.h> /* ENOMEM */
28 #include <string.h> /* strerror() */
29 #include <stdlib.h> /* calloc(), malloc(), free() */
34 #include <sys/asoundlib.h>
38 snd_pcm_t * p_pcm_handle;
43 /*****************************************************************************
45 *****************************************************************************/
46 static int aout_Open ( aout_thread_t *p_aout );
47 static int aout_SetFormat ( aout_thread_t *p_aout );
48 static int aout_GetBufInfo ( aout_thread_t *p_aout, int i_buffer_info );
49 static void aout_Play ( aout_thread_t *p_aout,
50 byte_t *buffer, int i_size );
51 static void aout_Close ( aout_thread_t *p_aout );
53 /*****************************************************************************
54 * Functions exported as capabilities. They are declared as static so that
55 * we don't pollute the namespace too much.
56 *****************************************************************************/
57 void _M( aout_getfunctions )( function_list_t * p_function_list )
59 p_function_list->functions.aout.pf_open = aout_Open;
60 p_function_list->functions.aout.pf_setformat = aout_SetFormat;
61 p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
62 p_function_list->functions.aout.pf_play = aout_Play;
63 p_function_list->functions.aout.pf_close = aout_Close;
66 /*****************************************************************************
67 * aout_Open : creates a handle and opens an alsa device
68 *****************************************************************************
69 * This function opens an alsa device, through the alsa API
70 *****************************************************************************/
71 static int aout_Open( aout_thread_t *p_aout )
75 /* allocate structure */
76 p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
77 if( p_aout->p_sys == NULL )
79 msg_Err( p_aout, "out of memory" );
83 /* open audio device */
84 if( ( i_ret = snd_pcm_open_preferred( &p_aout->p_sys->p_pcm_handle,
85 &p_aout->p_sys->i_card,
86 &p_aout->p_sys->i_device,
87 SND_PCM_OPEN_PLAYBACK ) ) < 0 )
89 msg_Err( p_aout, "unable to open audio device (%s)",
90 snd_strerror( i_ret ) );
91 free( p_aout->p_sys );
96 if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->p_sys->p_pcm_handle,
97 PLUGIN_DISABLE_MMAP ) ) < 0 )
99 msg_Err( p_aout, "unable to disable mmap (%s)", snd_strerror(i_ret) );
100 aout_Close( p_aout );
101 free( p_aout->p_sys );
109 /*****************************************************************************
110 * aout_SetFormat : set the audio output format
111 *****************************************************************************
112 * This function prepares the device, sets the rate, format, the mode
113 * ("play as soon as you have data"), and buffer information.
114 *****************************************************************************/
115 static int aout_SetFormat( aout_thread_t *p_aout )
118 int i_bytes_per_sample;
119 snd_pcm_channel_info_t pi;
120 snd_pcm_channel_params_t pp;
122 memset( &pi, 0, sizeof(pi) );
123 memset( &pp, 0, sizeof(pp) );
125 pi.channel = SND_PCM_CHANNEL_PLAYBACK;
126 if( ( i_ret = snd_pcm_plugin_info( p_aout->p_sys->p_pcm_handle,
129 msg_Err( p_aout, "unable to get plugin info (%s)",
130 snd_strerror( i_ret ) );
134 pp.mode = SND_PCM_MODE_BLOCK;
135 pp.channel = SND_PCM_CHANNEL_PLAYBACK;
136 pp.start_mode = SND_PCM_START_FULL;
137 pp.stop_mode = SND_PCM_STOP_STOP;
139 pp.buf.block.frags_max = 1;
140 pp.buf.block.frags_min = 1;
142 pp.format.interleave = 1;
143 pp.format.rate = p_aout->i_rate;
144 pp.format.voices = p_aout->i_channels;
146 switch( p_aout->i_format )
148 case AOUT_FMT_S16_LE:
149 pp.format.format = SND_PCM_SFMT_S16_LE;
150 i_bytes_per_sample = 2;
154 pp.format.format = SND_PCM_SFMT_S16_BE;
155 i_bytes_per_sample = 2;
159 pp.buf.block.frag_size =
160 (((s64)p_aout->i_rate * AOUT_BUFFER_DURATION) / 1000000) *
161 p_aout->i_channels * i_bytes_per_sample;
164 if( ( i_ret = snd_pcm_plugin_params( p_aout->p_sys->p_pcm_handle,
167 msg_Err( p_aout, "unable to set parameters (%s)", snd_strerror(i_ret) );
171 /* prepare channel */
172 if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
173 SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
175 msg_Err( p_aout, "unable to prepare channel (%s)",
176 snd_strerror( i_ret ) );
183 /*****************************************************************************
184 * aout_BufInfo: buffer status query
185 *****************************************************************************
186 * This function returns the number of used byte in the queue.
187 * It also deals with errors : indeed if the device comes to run out
188 * of data to play, it switches to the "underrun" status. It has to
189 * be flushed and re-prepared
190 *****************************************************************************/
191 static int aout_GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
194 snd_pcm_channel_status_t status;
196 /* get current pcm status */
197 memset( &status, 0, sizeof(status) );
198 if( ( i_ret = snd_pcm_plugin_status( p_aout->p_sys->p_pcm_handle,
201 msg_Err( p_aout, "unable to get device status (%s)",
202 snd_strerror( i_ret ) );
206 /* check for underrun */
207 switch( status.status )
209 case SND_PCM_STATUS_READY:
210 case SND_PCM_STATUS_UNDERRUN:
211 if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
212 SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
214 msg_Err( p_aout, "unable to prepare channel (%s)",
215 snd_strerror( i_ret ) );
220 return( status.count );
223 /*****************************************************************************
224 * aout_Play : plays a sample
225 *****************************************************************************
226 * Plays a sample using the snd_pcm_write function from the alsa API
227 *****************************************************************************/
228 static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
232 if( ( i_ret = snd_pcm_plugin_write( p_aout->p_sys->p_pcm_handle,
234 (size_t) i_size ) ) <= 0 )
236 msg_Err( p_aout, "unable to write data (%s)", snd_strerror(i_ret) );
240 /*****************************************************************************
241 * aout_Close : close the audio device
242 *****************************************************************************/
243 static void aout_Close( aout_thread_t *p_aout )
247 if( ( i_ret = snd_pcm_close( p_aout->p_sys->p_pcm_handle ) ) < 0 )
249 msg_Err( p_aout, "unable to close audio device (%s)",
250 snd_strerror( i_ret ) );
253 free( p_aout->p_sys );