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 <stdio.h> /* "intf_msg.h" */
30 #include <stdlib.h> /* calloc(), malloc(), free() */
32 #include <sys/asoundlib.h>
34 #include <videolan/vlc.h>
36 #include "audio_output.h" /* aout_thread_t */
38 typedef struct aout_sys_s
40 snd_pcm_t * p_pcm_handle;
45 /*****************************************************************************
47 *****************************************************************************/
48 static int aout_Open ( aout_thread_t *p_aout );
49 static int aout_SetFormat ( aout_thread_t *p_aout );
50 static int aout_GetBufInfo ( aout_thread_t *p_aout, int i_buffer_info );
51 static void aout_Play ( aout_thread_t *p_aout,
52 byte_t *buffer, int i_size );
53 static void aout_Close ( aout_thread_t *p_aout );
55 /*****************************************************************************
56 * Functions exported as capabilities. They are declared as static so that
57 * we don't pollute the namespace too much.
58 *****************************************************************************/
59 void _M( aout_getfunctions )( function_list_t * p_function_list )
61 p_function_list->functions.aout.pf_open = aout_Open;
62 p_function_list->functions.aout.pf_setformat = aout_SetFormat;
63 p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
64 p_function_list->functions.aout.pf_play = aout_Play;
65 p_function_list->functions.aout.pf_close = aout_Close;
68 /*****************************************************************************
69 * aout_Open : creates a handle and opens an alsa device
70 *****************************************************************************
71 * This function opens an alsa device, through the alsa API
72 *****************************************************************************/
73 static int aout_Open( aout_thread_t *p_aout )
77 /* allocate structure */
78 p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
79 if( p_aout->p_sys == NULL )
81 intf_ErrMsg( "aout error: unable to allocate memory (%s)",
86 /* open audio device */
87 if( ( i_ret = snd_pcm_open_preferred( &p_aout->p_sys->p_pcm_handle,
88 &p_aout->p_sys->i_card,
89 &p_aout->p_sys->i_device,
90 SND_PCM_OPEN_PLAYBACK ) ) < 0 )
92 intf_ErrMsg( "aout error: unable to open audio device (%s)",
93 snd_strerror( i_ret ) );
94 free( p_aout->p_sys );
99 if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->p_sys->p_pcm_handle,
100 PLUGIN_DISABLE_MMAP ) ) < 0 )
102 intf_ErrMsg( "aout error: unable to disable mmap (%s)",
103 snd_strerror( i_ret ) );
104 aout_Close( p_aout );
105 free( p_aout->p_sys );
113 /*****************************************************************************
114 * aout_SetFormat : set the audio output format
115 *****************************************************************************
116 * This function prepares the device, sets the rate, format, the mode
117 * ("play as soon as you have data"), and buffer information.
118 *****************************************************************************/
119 static int aout_SetFormat( aout_thread_t *p_aout )
122 int i_bytes_per_sample;
123 snd_pcm_channel_info_t pi;
124 snd_pcm_channel_params_t pp;
126 memset( &pi, 0, sizeof(pi) );
127 memset( &pp, 0, sizeof(pp) );
129 pi.channel = SND_PCM_CHANNEL_PLAYBACK;
130 if( ( i_ret = snd_pcm_plugin_info( p_aout->p_sys->p_pcm_handle,
133 intf_ErrMsg( "aout error: unable to get plugin info (%s)",
134 snd_strerror( i_ret ) );
138 pp.mode = SND_PCM_MODE_BLOCK;
139 pp.channel = SND_PCM_CHANNEL_PLAYBACK;
140 pp.start_mode = SND_PCM_START_FULL;
141 pp.stop_mode = SND_PCM_STOP_STOP;
143 pp.buf.block.frags_max = 1;
144 pp.buf.block.frags_min = 1;
146 pp.format.interleave = 1;
147 pp.format.rate = p_aout->i_rate;
148 pp.format.voices = p_aout->i_channels;
150 switch( p_aout->i_format )
152 case AOUT_FMT_S16_LE:
153 pp.format.format = SND_PCM_SFMT_S16_LE;
154 i_bytes_per_sample = 2;
158 pp.format.format = SND_PCM_SFMT_S16_BE;
159 i_bytes_per_sample = 2;
163 pp.buf.block.frag_size =
164 (((s64)p_aout->i_rate * AOUT_BUFFER_DURATION) / 1000000) *
165 p_aout->i_channels * i_bytes_per_sample;
168 if( ( i_ret = snd_pcm_plugin_params( p_aout->p_sys->p_pcm_handle,
171 intf_ErrMsg( "aout error: unable to set parameters (%s)",
172 snd_strerror( i_ret ) );
176 /* prepare channel */
177 if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
178 SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
180 intf_ErrMsg( "aout error: unable to prepare channel (%s)",
181 snd_strerror( i_ret ) );
188 /*****************************************************************************
189 * aout_BufInfo: buffer status query
190 *****************************************************************************
191 * This function returns the number of used byte in the queue.
192 * It also deals with errors : indeed if the device comes to run out
193 * of data to play, it switches to the "underrun" status. It has to
194 * be flushed and re-prepared
195 *****************************************************************************/
196 static int aout_GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
199 snd_pcm_channel_status_t status;
201 /* get current pcm status */
202 memset( &status, 0, sizeof(status) );
203 if( ( i_ret = snd_pcm_plugin_status( p_aout->p_sys->p_pcm_handle,
206 intf_ErrMsg( "aout error: unable to get device status (%s)",
207 snd_strerror( i_ret ) );
211 /* check for underrun */
212 switch( status.status )
214 case SND_PCM_STATUS_READY:
215 case SND_PCM_STATUS_UNDERRUN:
216 if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
217 SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
219 intf_ErrMsg( "aout error: unable to prepare channel (%s)",
220 snd_strerror( i_ret ) );
225 return( status.count );
228 /*****************************************************************************
229 * aout_Play : plays a sample
230 *****************************************************************************
231 * Plays a sample using the snd_pcm_write function from the alsa API
232 *****************************************************************************/
233 static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
237 if( ( i_ret = snd_pcm_plugin_write( p_aout->p_sys->p_pcm_handle,
239 (size_t) i_size ) ) <= 0 )
241 intf_ErrMsg( "aout error: unable to write data (%s)",
242 snd_strerror( i_ret ) );
246 /*****************************************************************************
247 * aout_Close : close the audio device
248 *****************************************************************************/
249 static void aout_Close( aout_thread_t *p_aout )
253 if( ( i_ret = snd_pcm_close( p_aout->p_sys->p_pcm_handle ) ) < 0 )
255 intf_ErrMsg( "aout error: unable to close audio device (%s)",
256 snd_strerror( i_ret ) );
259 free( p_aout->p_sys );