]> git.sesse.net Git - vlc/blob - plugins/qnx/aout_qnx.c
* Fixed a quite old bug in the audio output which made the sound stutter
[vlc] / plugins / qnx / aout_qnx.c
1 /*****************************************************************************
2  * aout_qnx.c : QNX audio output 
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  *
6  * Authors: Henri Fallon <henri@videolan.org>
7  *          Jon Lech Johansen <jon-vl@nanocrew.net>
8  * 
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.
13  * 
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
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() */
31
32 #include <sys/asoundlib.h>
33
34 #include <videolan/vlc.h>
35
36 #include "audio_output.h"                                   /* aout_thread_t */
37
38 typedef struct aout_sys_s
39 {
40     snd_pcm_t  * p_pcm_handle;
41     int          i_card;
42     int          i_device;
43 } aout_sys_t;
44
45 /*****************************************************************************
46  * Local prototypes
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 );
54
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 )
60 {
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;
66 }
67
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 )
74 {
75     int i_ret;
76
77     /* allocate structure */
78     p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
79     if( p_aout->p_sys == NULL )
80     {
81         intf_ErrMsg( "aout error: unable to allocate memory (%s)",
82                      strerror( ENOMEM ) );
83         return( 1 );
84     }
85
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 )
91     {
92         intf_ErrMsg( "aout error: unable to open audio device (%s)",
93                       snd_strerror( i_ret ) );
94         free( p_aout->p_sys );
95         return( 1 );
96     }
97
98     /* disable mmap */
99     if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->p_sys->p_pcm_handle,
100                                               PLUGIN_DISABLE_MMAP ) ) < 0 )
101     {
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 );
106         return( 1 );
107     }
108
109     return( 0 );
110 }
111
112
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 )
120 {
121     int i_ret;
122     int i_bytes_per_sample;
123     snd_pcm_channel_info_t pi;
124     snd_pcm_channel_params_t pp;
125
126     memset( &pi, 0, sizeof(pi) );
127     memset( &pp, 0, sizeof(pp) );
128
129     pi.channel = SND_PCM_CHANNEL_PLAYBACK;
130     if( ( i_ret = snd_pcm_plugin_info( p_aout->p_sys->p_pcm_handle,
131                                        &pi ) ) < 0 )
132     {
133         intf_ErrMsg( "aout error: unable to get plugin info (%s)",
134                      snd_strerror( i_ret ) );
135         return( 1 );
136     }
137
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;
142
143     pp.buf.block.frags_max   = 1;
144     pp.buf.block.frags_min   = 1;
145     
146     pp.format.interleave     = 1;
147     pp.format.rate           = p_aout->i_rate;
148     pp.format.voices         = p_aout->i_channels;
149
150     switch( p_aout->i_format )
151     {
152         case AOUT_FMT_S16_LE:
153             pp.format.format = SND_PCM_SFMT_S16_LE;
154             i_bytes_per_sample = 2;
155             break;
156
157         default:
158             pp.format.format = SND_PCM_SFMT_S16_BE;
159             i_bytes_per_sample = 2;
160             break;
161     }
162
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;
166
167     /* set parameters */
168     if( ( i_ret = snd_pcm_plugin_params( p_aout->p_sys->p_pcm_handle,
169                                          &pp ) ) < 0 )
170     {
171         intf_ErrMsg( "aout error: unable to set parameters (%s)",
172                      snd_strerror( i_ret ) );
173         return( 1 );
174     }
175
176     /* prepare channel */
177     if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
178                                           SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
179     {
180         intf_ErrMsg( "aout error: unable to prepare channel (%s)",
181                      snd_strerror( i_ret ) );
182         return( 1 );
183     }
184
185     return( 0 );
186 }
187
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 )
197 {
198     int i_ret;
199     snd_pcm_channel_status_t status;
200
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,
204                                          &status ) ) < 0 )
205     {
206         intf_ErrMsg( "aout error: unable to get device status (%s)",
207                      snd_strerror( i_ret ) );
208         return( -1 );
209     }
210
211     /* check for underrun */
212     switch( status.status )
213     {
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 )
218             {
219                 intf_ErrMsg( "aout error: unable to prepare channel (%s)",
220                              snd_strerror( i_ret ) );
221             }
222             break;
223     }
224
225     return( status.count );
226 }
227
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 )
234 {
235     int i_ret;
236
237     if( ( i_ret = snd_pcm_plugin_write( p_aout->p_sys->p_pcm_handle,
238                                         (void *) buffer, 
239                                         (size_t) i_size ) ) <= 0 )
240     {
241         intf_ErrMsg( "aout error: unable to write data (%s)",
242                      snd_strerror( i_ret ) );
243     }
244 }
245
246 /*****************************************************************************
247  * aout_Close : close the audio device
248  *****************************************************************************/
249 static void aout_Close( aout_thread_t *p_aout )
250 {
251     int i_ret;
252
253     if( ( i_ret = snd_pcm_close( p_aout->p_sys->p_pcm_handle ) ) < 0 )
254     {
255         intf_ErrMsg( "aout error: unable to close audio device (%s)",
256                      snd_strerror( i_ret ) );
257     }
258
259     free( p_aout->p_sys );
260 }