10l: Fix compilation without VDPAU.
[mplayer/glamo.git] / libao2 / ao_sdl.c
blob329486b272f8d9cad611aebf200a1aaf27004a14
1 /*
2 * SDLlib audio output driver for MPlayer
4 * Copyleft 2001 by Felix Bünemann (atmosfear@users.sf.net)
6 * This file is part of MPlayer.
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * along with MPlayer; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "config.h"
28 #include "mp_msg.h"
29 #include "help_mp.h"
31 #include "audio_out.h"
32 #include "audio_out_internal.h"
33 #include "libaf/af_format.h"
34 #include <SDL.h>
35 #include "osdep/timer.h"
37 #include "libavutil/fifo.h"
39 static const ao_info_t info =
41 "SDLlib audio output",
42 "sdl",
43 "Felix Buenemann <atmosfear@users.sourceforge.net>",
47 LIBAO_EXTERN(sdl)
49 // turn this on if you want to use the slower SDL_MixAudio
50 #undef USE_SDL_INTERNAL_MIXER
52 // Samplesize used by the SDLlib AudioSpec struct
53 #if defined(__MINGW32__) || defined(__CYGWIN__) || defined(__AMIGAOS4__)
54 #define SAMPLESIZE 2048
55 #else
56 #define SAMPLESIZE 1024
57 #endif
59 #define CHUNK_SIZE 4096
60 #define NUM_CHUNKS 8
61 #define BUFFSIZE (NUM_CHUNKS * CHUNK_SIZE)
63 static AVFifoBuffer *buffer;
65 #ifdef USE_SDL_INTERNAL_MIXER
66 static unsigned char volume=SDL_MIX_MAXVOLUME;
67 #endif
69 static int write_buffer(unsigned char* data,int len){
70 int free = av_fifo_space(buffer);
71 if (len > free) len = free;
72 return av_fifo_generic_write(buffer, data, len, NULL);
75 #ifdef USE_SDL_INTERNAL_MIXER
76 static void mix_audio(void *dst, void *src, int len) {
77 SDL_MixAudio(dst, src, len, volume);
79 #endif
81 static int read_buffer(unsigned char* data,int len){
82 int buffered = av_fifo_size(buffer);
83 if (len > buffered) len = buffered;
84 #ifdef USE_SDL_INTERNAL_MIXER
85 av_fifo_generic_read(buffer, data, len, mix_audio);
86 #else
87 av_fifo_generic_read(buffer, data, len, NULL);
88 #endif
89 return len;
92 // end ring buffer stuff
95 // to set/get/query special features/parameters
96 static int control(int cmd,void *arg){
97 #ifdef USE_SDL_INTERNAL_MIXER
98 switch (cmd) {
99 case AOCONTROL_GET_VOLUME:
101 ao_control_vol_t* vol = (ao_control_vol_t*)arg;
102 vol->left = vol->right = volume * 100 / SDL_MIX_MAXVOLUME;
103 return CONTROL_OK;
105 case AOCONTROL_SET_VOLUME:
107 int diff;
108 ao_control_vol_t* vol = (ao_control_vol_t*)arg;
109 diff = (vol->left+vol->right) / 2;
110 volume = diff * SDL_MIX_MAXVOLUME / 100;
111 return CONTROL_OK;
114 #endif
115 return CONTROL_UNKNOWN;
118 // SDL Callback function
119 void outputaudio(void *unused, Uint8 *stream, int len) {
120 //SDL_MixAudio(stream, read_buffer(buffers, len), len, SDL_MIX_MAXVOLUME);
121 //if(!full_buffers) printf("SDL: Buffer underrun!\n");
123 read_buffer(stream, len);
124 //printf("SDL: Full Buffers: %i\n", full_buffers);
127 // open & setup audio device
128 // return: 1=success 0=fail
129 static int init(int rate,int channels,int format,int flags){
131 /* SDL Audio Specifications */
132 SDL_AudioSpec aspec, obtained;
134 /* Allocate ring-buffer memory */
135 buffer = av_fifo_alloc(BUFFSIZE);
137 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_SDL_INFO, rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
139 if(ao_subdevice) {
140 setenv("SDL_AUDIODRIVER", ao_subdevice, 1);
141 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_SDL_DriverInfo, ao_subdevice);
144 ao_data.channels=channels;
145 ao_data.samplerate=rate;
146 ao_data.format=format;
148 ao_data.bps=channels*rate;
149 if(format != AF_FORMAT_U8 && format != AF_FORMAT_S8)
150 ao_data.bps*=2;
152 /* The desired audio format (see SDL_AudioSpec) */
153 switch(format) {
154 case AF_FORMAT_U8:
155 aspec.format = AUDIO_U8;
156 break;
157 case AF_FORMAT_S16_LE:
158 aspec.format = AUDIO_S16LSB;
159 break;
160 case AF_FORMAT_S16_BE:
161 aspec.format = AUDIO_S16MSB;
162 break;
163 case AF_FORMAT_S8:
164 aspec.format = AUDIO_S8;
165 break;
166 case AF_FORMAT_U16_LE:
167 aspec.format = AUDIO_U16LSB;
168 break;
169 case AF_FORMAT_U16_BE:
170 aspec.format = AUDIO_U16MSB;
171 break;
172 default:
173 aspec.format = AUDIO_S16LSB;
174 ao_data.format = AF_FORMAT_S16_LE;
175 mp_msg(MSGT_AO,MSGL_WARN,MSGTR_AO_SDL_UnsupportedAudioFmt, format);
178 /* The desired audio frequency in samples-per-second. */
179 aspec.freq = rate;
181 /* Number of channels (mono/stereo) */
182 aspec.channels = channels;
184 /* The desired size of the audio buffer in samples. This number should be a power of two, and may be adjusted by the audio driver to a value more suitable for the hardware. Good values seem to range between 512 and 8192 inclusive, depending on the application and CPU speed. Smaller values yield faster response time, but can lead to underflow if the application is doing heavy processing and cannot fill the audio buffer in time. A stereo sample consists of both right and left channels in LR ordering. Note that the number of samples is directly related to time by the following formula: ms = (samples*1000)/freq */
185 aspec.samples = SAMPLESIZE;
187 /* This should be set to a function that will be called when the audio device is ready for more data. It is passed a pointer to the audio buffer, and the length in bytes of the audio buffer. This function usually runs in a separate thread, and so you should protect data structures that it accesses by calling SDL_LockAudio and SDL_UnlockAudio in your code. The callback prototype is:
188 void callback(void *userdata, Uint8 *stream, int len); userdata is the pointer stored in userdata field of the SDL_AudioSpec. stream is a pointer to the audio buffer you want to fill with information and len is the length of the audio buffer in bytes. */
189 aspec.callback = outputaudio;
191 /* This pointer is passed as the first parameter to the callback function. */
192 aspec.userdata = NULL;
194 /* initialize the SDL Audio system */
195 if (SDL_Init (SDL_INIT_AUDIO/*|SDL_INIT_NOPARACHUTE*/)) {
196 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_SDL_CantInit, SDL_GetError());
197 return 0;
200 /* Open the audio device and start playing sound! */
201 if(SDL_OpenAudio(&aspec, &obtained) < 0) {
202 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_SDL_CantOpenAudio, SDL_GetError());
203 return 0;
206 /* did we got what we wanted ? */
207 ao_data.channels=obtained.channels;
208 ao_data.samplerate=obtained.freq;
210 switch(obtained.format) {
211 case AUDIO_U8 :
212 ao_data.format = AF_FORMAT_U8;
213 break;
214 case AUDIO_S16LSB :
215 ao_data.format = AF_FORMAT_S16_LE;
216 break;
217 case AUDIO_S16MSB :
218 ao_data.format = AF_FORMAT_S16_BE;
219 break;
220 case AUDIO_S8 :
221 ao_data.format = AF_FORMAT_S8;
222 break;
223 case AUDIO_U16LSB :
224 ao_data.format = AF_FORMAT_U16_LE;
225 break;
226 case AUDIO_U16MSB :
227 ao_data.format = AF_FORMAT_U16_BE;
228 break;
229 default:
230 mp_msg(MSGT_AO,MSGL_WARN,MSGTR_AO_SDL_UnsupportedAudioFmt, obtained.format);
231 return 0;
234 mp_msg(MSGT_AO,MSGL_V,"SDL: buf size = %d\n",obtained.size);
235 ao_data.buffersize=obtained.size;
236 ao_data.outburst = CHUNK_SIZE;
238 /* unsilence audio, if callback is ready */
239 SDL_PauseAudio(0);
241 return 1;
244 // close audio device
245 static void uninit(int immed){
246 mp_msg(MSGT_AO,MSGL_V,"SDL: Audio Subsystem shutting down!\n");
247 if (!immed)
248 usec_sleep(get_delay() * 1000 * 1000);
249 SDL_CloseAudio();
250 SDL_QuitSubSystem(SDL_INIT_AUDIO);
251 av_fifo_free(buffer);
254 // stop playing and empty buffers (for seeking/pause)
255 static void reset(void){
257 //printf("SDL: reset called!\n");
259 SDL_PauseAudio(1);
260 /* Reset ring-buffer state */
261 av_fifo_reset(buffer);
262 SDL_PauseAudio(0);
265 // stop playing, keep buffers (for pause)
266 static void audio_pause(void)
269 //printf("SDL: audio_pause called!\n");
270 SDL_PauseAudio(1);
274 // resume playing, after audio_pause()
275 static void audio_resume(void)
277 //printf("SDL: audio_resume called!\n");
278 SDL_PauseAudio(0);
282 // return: how many bytes can be played without blocking
283 static int get_space(void){
284 return av_fifo_space(buffer);
287 // plays 'len' bytes of 'data'
288 // it should round it down to outburst*n
289 // return: number of bytes played
290 static int play(void* data,int len,int flags){
292 if (!(flags & AOPLAY_FINAL_CHUNK))
293 len = (len/ao_data.outburst)*ao_data.outburst;
294 #if 0
295 int ret;
297 /* Audio locking prohibits call of outputaudio */
298 SDL_LockAudio();
299 // copy audio stream into ring-buffer
300 ret = write_buffer(data, len);
301 SDL_UnlockAudio();
303 return ret;
304 #else
305 return write_buffer(data, len);
306 #endif
309 // return: delay in seconds between first and last sample in buffer
310 static float get_delay(void){
311 int buffered = av_fifo_size(buffer); // could be less
312 return (float)(buffered + ao_data.buffersize)/(float)ao_data.bps;