1 /*****************************************************************************
2 * aout_sdl.c : audio sdl functions library
3 *****************************************************************************
4 * Copyright (C) 1999, 2000 VideoLAN
6 * Authors: Michel Kaempf <maxx@via.ecp.fr>
7 * Samuel Hocevar <sam@zoy.org>
8 * Pierre Baillet <oct@zoy.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
30 #include <errno.h> /* ENOMEM */
31 #include <fcntl.h> /* open(), O_WRONLY */
32 #include <sys/ioctl.h> /* ioctl() */
33 #include <string.h> /* strerror() */
34 #include <unistd.h> /* write(), close() */
35 #include <stdio.h> /* "intf_msg.h" */
36 #include <stdlib.h> /* calloc(), malloc(), free() */
39 #include "SDL/SDL.h" /* SDL base include */
42 #include "common.h" /* boolean_t, byte_t */
47 #include "audio_output.h" /* aout_thread_t */
49 #include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
55 /*****************************************************************************
56 * aout_sys_t: dsp audio output method descriptor
57 *****************************************************************************
58 * This structure is part of the audio output thread descriptor.
59 * It describes the dsp specific properties of an audio device.
60 *****************************************************************************/
62 /* the overflow limit is used to prevent the fifo from growing too big */
63 #define OVERFLOWLIMIT 100000
65 typedef struct aout_sys_s
73 /*****************************************************************************
75 *****************************************************************************/
76 static int aout_Probe ( probedata_t *p_data );
77 static int aout_Open ( aout_thread_t *p_aout );
78 static int aout_SetFormat ( aout_thread_t *p_aout );
79 static long aout_GetBufInfo ( aout_thread_t *p_aout, long l_buffer_info );
80 static void aout_Play ( aout_thread_t *p_aout,
81 byte_t *buffer, int i_size );
82 static void aout_Close ( aout_thread_t *p_aout );
83 static void SDL_aout_callback(void *userdata, Uint8 *stream, int len);
85 /*****************************************************************************
86 * Functions exported as capabilities. They are declared as static so that
87 * we don't pollute the namespace too much.
88 *****************************************************************************/
89 void aout_getfunctions( function_list_t * p_function_list )
91 p_function_list->pf_probe = aout_Probe;
92 p_function_list->functions.aout.pf_open = aout_Open;
93 p_function_list->functions.aout.pf_setformat = aout_SetFormat;
94 p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
95 p_function_list->functions.aout.pf_play = aout_Play;
96 p_function_list->functions.aout.pf_close = aout_Close;
99 /*****************************************************************************
100 * aout_Probe: probes the audio device and return a score
101 *****************************************************************************
102 * This function tries to open the dps and returns a score to the plugin
103 * manager so that it can select the best plugin.
104 *****************************************************************************/
105 static int aout_Probe( probedata_t *p_data )
107 SDL_AudioSpec *desired, *obtained;
110 if( SDL_Init(SDL_INIT_AUDIO) != 0)
112 intf_DbgMsg( "aout_Probe: SDL init error: %s", SDL_GetError() );
116 /* asks for a minimum audio spec so that we are sure the dsp exists */
117 desired = (SDL_AudioSpec *)malloc( sizeof(SDL_AudioSpec) );
118 obtained = (SDL_AudioSpec *)malloc( sizeof(SDL_AudioSpec) );
120 desired->freq = 11025; /* frequency */
121 desired->format = AUDIO_U8; /* unsigned 8 bits */
122 desired->channels = 2; /* mono */
123 desired->callback = SDL_aout_callback; /* no callback function yet */
124 desired->userdata = NULL; /* null parm for callback */
125 desired->samples = 4096;
128 /* If we were unable to open the device, there is no way we can use
129 * the plugin. Return a score of 0. */
130 if(SDL_OpenAudio( desired, obtained ) < 0)
134 intf_DbgMsg( "aout_Probe: aout sdl error : %s", SDL_GetError() );
140 /* Otherwise, there are good chances we can use this plugin, return 100. */
143 if( TestMethod( AOUT_METHOD_VAR, "sdl" ) )
151 /*****************************************************************************
152 * aout_Open: opens the audio device (the digital sound processor)
153 *****************************************************************************
154 * This function opens the dsp as a usual non-blocking write-only file, and
155 * modifies the p_aout->i_fd with the file's descriptor.
156 *****************************************************************************/
157 static int aout_Open( aout_thread_t *p_aout )
159 SDL_AudioSpec *desired;
160 int i_channels = p_aout->b_stereo?2:1;
162 /* asks for a minimum audio spec so that we are sure the dsp exists */
163 desired = (SDL_AudioSpec *)malloc( sizeof(SDL_AudioSpec) );
165 /* Allocate structure */
167 p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
168 if( p_aout->p_sys == NULL )
170 intf_ErrMsg("aout_Open error: %s", strerror(ENOMEM) );
175 p_aout->p_sys->i_audio_end = 0;
176 p_aout->p_sys->audio_buf = NULL;
178 /* Initialize some variables */
179 p_aout->psz_device = 0;
180 p_aout->i_format = AOUT_FORMAT_DEFAULT;
181 p_aout->i_channels = 1 + main_GetIntVariable( AOUT_STEREO_VAR,
182 AOUT_STEREO_DEFAULT );
183 p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR,
187 desired->freq = p_aout->l_rate;
189 /* TODO: write conversion beetween AOUT_FORMAT_DEFAULT
190 * AND AUDIO* from SDL. */
191 desired->format = AUDIO_S16LSB; /* stereo 16 bits */
192 desired->channels = i_channels;
193 desired->callback = SDL_aout_callback;
194 desired->userdata = p_aout->p_sys;
195 desired->samples = 2048;
197 /* Open the sound device
198 * we just ask the SDL to wrap at the good frequency if the one we
199 * ask for is unavailable. This is done by setting the second parar
202 if( SDL_OpenAudio(desired,NULL) < 0 )
205 intf_ErrMsg( "aout_Open error: can't open audio device: %s",
209 p_aout->p_sys->b_active = 1;
216 /*****************************************************************************
217 * aout_SetFormat: resets the dsp and sets its format
218 *****************************************************************************
219 * This functions resets the DSP device, tries to initialize the output
220 * format with the value contained in the dsp structure, and if this value
221 * could not be set, the default value returned by ioctl is set. It then
222 * does the same for the stereo mode, and for the output rate.
223 *****************************************************************************/
224 static int aout_SetFormat( aout_thread_t *p_aout )
226 /* TODO: finish and clean this */
227 SDL_AudioSpec *desired;
228 int i_stereo = p_aout->b_stereo?2:1;
229 desired = (SDL_AudioSpec *)malloc( sizeof(SDL_AudioSpec) );
231 /* i_format = p_aout->i_format;
233 desired->freq = p_aout->l_rate; /* Set the output rate */
234 desired->format = AUDIO_S16LSB; /* stereo 16 bits */
235 desired->channels = i_stereo;
236 desired->callback = SDL_aout_callback;
237 desired->userdata = p_aout->p_sys;
238 desired->samples = 2048;
240 /* Open the sound device */
243 if( SDL_OpenAudio(desired,NULL) < 0 )
246 p_aout->p_sys->b_active = 0;
249 p_aout->p_sys->b_active = 1;
255 /*****************************************************************************
256 * aout_GetBufInfo: buffer status query
257 *****************************************************************************
258 * returns the number of bytes in the audio buffer compared to the size of
260 *****************************************************************************/
261 static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit )
263 return( p_aout->p_sys->i_audio_end-l_buffer_limit);
267 static void SDL_aout_callback(void *userdata, byte_t *stream, int len)
269 struct aout_sys_s * p_sys = userdata;
270 int end = p_sys->i_audio_end;
272 if(end > OVERFLOWLIMIT)
274 intf_ErrMsg("aout SDL_aout_callback: Overflow.");
275 free(p_sys->audio_buf);
276 p_sys->audio_buf = NULL;
277 p_sys->i_audio_end = 0;
279 // we've gone to slow, increase output freq
282 /* if we are not in underrun */
285 memcpy(stream, p_sys->audio_buf, len);
286 memmove(p_sys->audio_buf, &(p_sys->audio_buf[len]), end-len);
287 p_sys->audio_buf = realloc(p_sys->audio_buf, end-len);
288 p_sys->i_audio_end -= len;
292 /*****************************************************************************
293 * aout_Play: plays a sound samples buffer
294 *****************************************************************************
295 * This function writes a buffer of i_length bytes in the dsp
296 *****************************************************************************/
297 static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
299 byte_t * audio_buf = p_aout->p_sys->audio_buf;
301 SDL_LockAudio(); /* Stop callbacking */
303 audio_buf = realloc(audio_buf, p_aout->p_sys->i_audio_end + i_size);
304 memcpy(&(audio_buf[p_aout->p_sys->i_audio_end]), buffer, i_size);
305 p_aout->p_sys->i_audio_end += i_size;
306 p_aout->p_sys->audio_buf = audio_buf;
309 SDL_UnlockAudio(); /* go on callbacking */
312 /*****************************************************************************
313 * aout_Close: closes the dsp audio device
314 *****************************************************************************/
315 static void aout_Close( aout_thread_t *p_aout )
317 if( p_aout->p_sys->b_active )
319 SDL_PauseAudio(1); /* pause audio */
321 if(p_aout->p_sys->audio_buf != NULL) /* do we have a buffer now ? */
323 free(p_aout->p_sys->audio_buf);
325 p_aout->p_sys->b_active = 0; /* just for sam */
327 free(p_aout->p_sys); /* Close the Output. */