]> git.sesse.net Git - vlc/blob - plugins/qnx/aout_qnx.c
13c9fce064a8259065c3a87aaa6ce919dd850b72
[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 <stdlib.h>                            /* calloc(), malloc(), free() */
30
31 #include <vlc/vlc.h>
32 #include <vlc/aout.h>
33
34 #include <sys/asoundlib.h>
35
36 struct aout_sys_s
37 {
38     snd_pcm_t  * p_pcm_handle;
39     int          i_card;
40     int          i_device;
41 };
42
43 /*****************************************************************************
44  * Local prototypes
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 );
52
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 )
58 {
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;
64 }
65
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 )
72 {
73     int i_ret;
74
75     /* allocate structure */
76     p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
77     if( p_aout->p_sys == NULL )
78     {
79         msg_Err( p_aout, "out of memory" );
80         return( 1 );
81     }
82
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 )
88     {
89         msg_Err( p_aout, "unable to open audio device (%s)",
90                          snd_strerror( i_ret ) );
91         free( p_aout->p_sys );
92         return( 1 );
93     }
94
95     /* disable mmap */
96     if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->p_sys->p_pcm_handle,
97                                               PLUGIN_DISABLE_MMAP ) ) < 0 )
98     {
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 );
102         return( 1 );
103     }
104
105     return( 0 );
106 }
107
108
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 )
116 {
117     int i_ret;
118     int i_bytes_per_sample;
119     snd_pcm_channel_info_t pi;
120     snd_pcm_channel_params_t pp;
121
122     memset( &pi, 0, sizeof(pi) );
123     memset( &pp, 0, sizeof(pp) );
124
125     pi.channel = SND_PCM_CHANNEL_PLAYBACK;
126     if( ( i_ret = snd_pcm_plugin_info( p_aout->p_sys->p_pcm_handle,
127                                        &pi ) ) < 0 )
128     {
129         msg_Err( p_aout, "unable to get plugin info (%s)",
130                          snd_strerror( i_ret ) );
131         return( 1 );
132     }
133
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;
138
139     pp.buf.block.frags_max   = 1;
140     pp.buf.block.frags_min   = 1;
141     
142     pp.format.interleave     = 1;
143     pp.format.rate           = p_aout->i_rate;
144     pp.format.voices         = p_aout->i_channels;
145
146     switch( p_aout->i_format )
147     {
148         case AOUT_FMT_S16_LE:
149             pp.format.format = SND_PCM_SFMT_S16_LE;
150             i_bytes_per_sample = 2;
151             break;
152
153         default:
154             pp.format.format = SND_PCM_SFMT_S16_BE;
155             i_bytes_per_sample = 2;
156             break;
157     }
158
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;
162
163     /* set parameters */
164     if( ( i_ret = snd_pcm_plugin_params( p_aout->p_sys->p_pcm_handle,
165                                          &pp ) ) < 0 )
166     {
167         msg_Err( p_aout, "unable to set parameters (%s)", snd_strerror(i_ret) );
168         return( 1 );
169     }
170
171     /* prepare channel */
172     if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
173                                           SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
174     {
175         msg_Err( p_aout, "unable to prepare channel (%s)",
176                          snd_strerror( i_ret ) );
177         return( 1 );
178     }
179
180     return( 0 );
181 }
182
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 )
192 {
193     int i_ret;
194     snd_pcm_channel_status_t status;
195
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,
199                                          &status ) ) < 0 )
200     {
201         msg_Err( p_aout, "unable to get device status (%s)",
202                          snd_strerror( i_ret ) );
203         return( -1 );
204     }
205
206     /* check for underrun */
207     switch( status.status )
208     {
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 )
213             {
214                 msg_Err( p_aout, "unable to prepare channel (%s)",
215                                  snd_strerror( i_ret ) );
216             }
217             break;
218     }
219
220     return( status.count );
221 }
222
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 )
229 {
230     int i_ret;
231
232     if( ( i_ret = snd_pcm_plugin_write( p_aout->p_sys->p_pcm_handle,
233                                         (void *) buffer, 
234                                         (size_t) i_size ) ) <= 0 )
235     {
236         msg_Err( p_aout, "unable to write data (%s)", snd_strerror(i_ret) );
237     }
238 }
239
240 /*****************************************************************************
241  * aout_Close : close the audio device
242  *****************************************************************************/
243 static void aout_Close( aout_thread_t *p_aout )
244 {
245     int i_ret;
246
247     if( ( i_ret = snd_pcm_close( p_aout->p_sys->p_pcm_handle ) ) < 0 )
248     {
249         msg_Err( p_aout, "unable to close audio device (%s)",
250                          snd_strerror( i_ret ) );
251     }
252
253     free( p_aout->p_sys );
254 }