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 SetFormat ( aout_thread_t * );
47 static int GetBufInfo ( aout_thread_t *, int );
48 static void Play ( aout_thread_t *, byte_t *, int );
50 /*****************************************************************************
51 * Open : creates a handle and opens an alsa device
52 *****************************************************************************
53 * This function opens an alsa device, through the alsa API
54 *****************************************************************************/
55 int E_(OpenAudio)( vlc_object_t *p_this )
57 aout_thread_t *p_aout = (aout_thread_t *)p_this;
60 /* allocate structure */
61 p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
62 if( p_aout->p_sys == NULL )
64 msg_Err( p_aout, "out of memory" );
68 /* open audio device */
69 if( ( i_ret = snd_pcm_open_preferred( &p_aout->p_sys->p_pcm_handle,
70 &p_aout->p_sys->i_card,
71 &p_aout->p_sys->i_device,
72 SND_PCM_OPEN_PLAYBACK ) ) < 0 )
74 msg_Err( p_aout, "unable to open audio device (%s)",
75 snd_strerror( i_ret ) );
76 free( p_aout->p_sys );
81 if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->p_sys->p_pcm_handle,
82 PLUGIN_DISABLE_MMAP ) ) < 0 )
84 msg_Err( p_aout, "unable to disable mmap (%s)", snd_strerror(i_ret) );
86 free( p_aout->p_sys );
90 p_aout->pf_setformat = SetFormat;
91 p_aout->pf_getbufinfo = GetBufInfo;
92 p_aout->pf_play = Play;
97 /*****************************************************************************
98 * SetFormat : set the audio output format
99 *****************************************************************************
100 * This function prepares the device, sets the rate, format, the mode
101 * ("play as soon as you have data"), and buffer information.
102 *****************************************************************************/
103 static int SetFormat( aout_thread_t *p_aout )
106 int i_bytes_per_sample;
107 snd_pcm_channel_info_t pi;
108 snd_pcm_channel_params_t pp;
110 memset( &pi, 0, sizeof(pi) );
111 memset( &pp, 0, sizeof(pp) );
113 pi.channel = SND_PCM_CHANNEL_PLAYBACK;
114 if( ( i_ret = snd_pcm_plugin_info( p_aout->p_sys->p_pcm_handle,
117 msg_Err( p_aout, "unable to get plugin info (%s)",
118 snd_strerror( i_ret ) );
122 pp.mode = SND_PCM_MODE_BLOCK;
123 pp.channel = SND_PCM_CHANNEL_PLAYBACK;
124 pp.start_mode = SND_PCM_START_FULL;
125 pp.stop_mode = SND_PCM_STOP_STOP;
127 pp.buf.block.frags_max = 1;
128 pp.buf.block.frags_min = 1;
130 pp.format.interleave = 1;
131 pp.format.rate = p_aout->i_rate;
132 pp.format.voices = p_aout->i_channels;
134 switch( p_aout->i_format )
136 case AOUT_FMT_S16_LE:
137 pp.format.format = SND_PCM_SFMT_S16_LE;
138 i_bytes_per_sample = 2;
142 pp.format.format = SND_PCM_SFMT_S16_BE;
143 i_bytes_per_sample = 2;
147 pp.buf.block.frag_size =
148 (((s64)p_aout->i_rate * AOUT_BUFFER_DURATION) / 1000000) *
149 p_aout->i_channels * i_bytes_per_sample;
152 if( ( i_ret = snd_pcm_plugin_params( p_aout->p_sys->p_pcm_handle,
155 msg_Err( p_aout, "unable to set parameters (%s)", snd_strerror(i_ret) );
159 /* prepare channel */
160 if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
161 SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
163 msg_Err( p_aout, "unable to prepare channel (%s)",
164 snd_strerror( i_ret ) );
171 /*****************************************************************************
172 * GetBufInfo: buffer status query
173 *****************************************************************************
174 * This function returns the number of used byte in the queue.
175 * It also deals with errors : indeed if the device comes to run out
176 * of data to play, it switches to the "underrun" status. It has to
177 * be flushed and re-prepared
178 *****************************************************************************/
179 static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
182 snd_pcm_channel_status_t status;
184 /* get current pcm status */
185 memset( &status, 0, sizeof(status) );
186 if( ( i_ret = snd_pcm_plugin_status( p_aout->p_sys->p_pcm_handle,
189 msg_Err( p_aout, "unable to get device status (%s)",
190 snd_strerror( i_ret ) );
194 /* check for underrun */
195 switch( status.status )
197 case SND_PCM_STATUS_READY:
198 case SND_PCM_STATUS_UNDERRUN:
199 if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
200 SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
202 msg_Err( p_aout, "unable to prepare channel (%s)",
203 snd_strerror( i_ret ) );
208 return( status.count );
211 /*****************************************************************************
212 * Play : plays a sample
213 *****************************************************************************
214 * Plays a sample using the snd_pcm_write function from the alsa API
215 *****************************************************************************/
216 static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
220 if( ( i_ret = snd_pcm_plugin_write( p_aout->p_sys->p_pcm_handle,
222 (size_t) i_size ) ) <= 0 )
224 msg_Err( p_aout, "unable to write data (%s)", snd_strerror(i_ret) );
228 /*****************************************************************************
229 * CloseAudio: close the audio device
230 *****************************************************************************/
231 static void E_(CloseAudio) ( vlc_object_t *p_this )
233 aout_thread_t *p_aout = (aout_thread_t *)p_this;
236 if( ( i_ret = snd_pcm_close( p_aout->p_sys->p_pcm_handle ) ) < 0 )
238 msg_Err( p_aout, "unable to close audio device (%s)",
239 snd_strerror( i_ret ) );
242 free( p_aout->p_sys );