Use SetErrorMode so Windows will not show all kinds of error dialogs
[mplayer/glamo.git] / libao2 / ao_sdl.c
blob97a70d4adf3c0ee7433593bd603602e7ff74b9bd
1 /*
2 * SDLlib audio output driver for MPlayer
4 * Copyleft 2001 by Felix Bünemann (atmosfear@users.sf.net)
6 * Thanks to Arpi for nice ringbuffer-code!
8 * This file is part of MPlayer.
10 * MPlayer 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 * MPlayer 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 along
21 * along with MPlayer; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
29 #include "config.h"
30 #include "mp_msg.h"
31 #include "help_mp.h"
33 #include "audio_out.h"
34 #include "audio_out_internal.h"
35 #include "libaf/af_format.h"
36 #include <SDL.h>
37 #include "osdep/timer.h"
39 #include "libvo/fastmemcpy.h"
41 static ao_info_t info =
43 "SDLlib audio output",
44 "sdl",
45 "Felix Buenemann <atmosfear@users.sourceforge.net>",
49 LIBAO_EXTERN(sdl)
51 // turn this on if you want to use the slower SDL_MixAudio
52 #undef USE_SDL_INTERNAL_MIXER
54 // Samplesize used by the SDLlib AudioSpec struct
55 #if defined(__MINGW32__) || defined(__CYGWIN__) || defined(__AMIGAOS4__)
56 #define SAMPLESIZE 2048
57 #else
58 #define SAMPLESIZE 1024
59 #endif
61 #define CHUNK_SIZE 4096
62 #define NUM_CHUNKS 8
63 // This type of ring buffer may never fill up completely, at least
64 // one byte must always be unused.
65 // For performance reasons (alignment etc.) one whole chunk always stays
66 // empty, not only one byte.
67 #define BUFFSIZE ((NUM_CHUNKS + 1) * CHUNK_SIZE)
69 static unsigned char *buffer;
71 // may only be modified by SDL's playback thread or while it is stopped
72 static volatile int read_pos;
73 // may only be modified by mplayer's thread
74 static volatile int write_pos;
75 #ifdef USE_SDL_INTERNAL_MIXER
76 static unsigned char volume=SDL_MIX_MAXVOLUME;
77 #endif
79 // may only be called by mplayer's thread
80 // return value may change between immediately following two calls,
81 // and the real number of free bytes might be larger!
82 static int buf_free(void) {
83 int free = read_pos - write_pos - CHUNK_SIZE;
84 if (free < 0) free += BUFFSIZE;
85 return free;
88 // may only be called by SDL's playback thread
89 // return value may change between immediately following two calls,
90 // and the real number of buffered bytes might be larger!
91 static int buf_used(void) {
92 int used = write_pos - read_pos;
93 if (used < 0) used += BUFFSIZE;
94 return used;
97 static int write_buffer(unsigned char* data,int len){
98 int first_len = BUFFSIZE - write_pos;
99 int free = buf_free();
100 if (len > free) len = free;
101 if (first_len > len) first_len = len;
102 // till end of buffer
103 fast_memcpy (&buffer[write_pos], data, first_len);
104 if (len > first_len) { // we have to wrap around
105 // remaining part from beginning of buffer
106 fast_memcpy (buffer, &data[first_len], len - first_len);
108 write_pos = (write_pos + len) % BUFFSIZE;
109 return len;
112 static int read_buffer(unsigned char* data,int len){
113 int first_len = BUFFSIZE - read_pos;
114 int buffered = buf_used();
115 if (len > buffered) len = buffered;
116 if (first_len > len) first_len = len;
117 // till end of buffer
118 #ifdef USE_SDL_INTERNAL_MIXER
119 SDL_MixAudio (data, &buffer[read_pos], first_len, volume);
120 #else
121 fast_memcpy (data, &buffer[read_pos], first_len);
122 #endif
123 if (len > first_len) { // we have to wrap around
124 // remaining part from beginning of buffer
125 #ifdef USE_SDL_INTERNAL_MIXER
126 SDL_MixAudio (&data[first_len], buffer, len - first_len, volume);
127 #else
128 fast_memcpy (&data[first_len], buffer, len - first_len);
129 #endif
131 read_pos = (read_pos + len) % BUFFSIZE;
132 return len;
135 // end ring buffer stuff
138 // to set/get/query special features/parameters
139 static int control(int cmd,void *arg){
140 #ifdef USE_SDL_INTERNAL_MIXER
141 switch (cmd) {
142 case AOCONTROL_GET_VOLUME:
144 ao_control_vol_t* vol = (ao_control_vol_t*)arg;
145 vol->left = vol->right = volume * 100 / SDL_MIX_MAXVOLUME;
146 return CONTROL_OK;
148 case AOCONTROL_SET_VOLUME:
150 int diff;
151 ao_control_vol_t* vol = (ao_control_vol_t*)arg;
152 diff = (vol->left+vol->right) / 2;
153 volume = diff * SDL_MIX_MAXVOLUME / 100;
154 return CONTROL_OK;
157 #endif
158 return CONTROL_UNKNOWN;
161 // SDL Callback function
162 void outputaudio(void *unused, Uint8 *stream, int len) {
163 //SDL_MixAudio(stream, read_buffer(buffers, len), len, SDL_MIX_MAXVOLUME);
164 //if(!full_buffers) printf("SDL: Buffer underrun!\n");
166 read_buffer(stream, len);
167 //printf("SDL: Full Buffers: %i\n", full_buffers);
170 // open & setup audio device
171 // return: 1=success 0=fail
172 static int init(int rate,int channels,int format,int flags){
174 /* SDL Audio Specifications */
175 SDL_AudioSpec aspec, obtained;
177 /* Allocate ring-buffer memory */
178 buffer = (unsigned char *) malloc(BUFFSIZE);
180 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_SDL_INFO, rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
182 if(ao_subdevice) {
183 setenv("SDL_AUDIODRIVER", ao_subdevice, 1);
184 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_SDL_DriverInfo, ao_subdevice);
187 ao_data.channels=channels;
188 ao_data.samplerate=rate;
189 ao_data.format=format;
191 ao_data.bps=channels*rate;
192 if(format != AF_FORMAT_U8 && format != AF_FORMAT_S8)
193 ao_data.bps*=2;
195 /* The desired audio format (see SDL_AudioSpec) */
196 switch(format) {
197 case AF_FORMAT_U8:
198 aspec.format = AUDIO_U8;
199 break;
200 case AF_FORMAT_S16_LE:
201 aspec.format = AUDIO_S16LSB;
202 break;
203 case AF_FORMAT_S16_BE:
204 aspec.format = AUDIO_S16MSB;
205 break;
206 case AF_FORMAT_S8:
207 aspec.format = AUDIO_S8;
208 break;
209 case AF_FORMAT_U16_LE:
210 aspec.format = AUDIO_U16LSB;
211 break;
212 case AF_FORMAT_U16_BE:
213 aspec.format = AUDIO_U16MSB;
214 break;
215 default:
216 aspec.format = AUDIO_S16LSB;
217 ao_data.format = AF_FORMAT_S16_LE;
218 mp_msg(MSGT_AO,MSGL_WARN,MSGTR_AO_SDL_UnsupportedAudioFmt, format);
221 /* The desired audio frequency in samples-per-second. */
222 aspec.freq = rate;
224 /* Number of channels (mono/stereo) */
225 aspec.channels = channels;
227 /* 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 */
228 aspec.samples = SAMPLESIZE;
230 /* 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:
231 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. */
232 aspec.callback = outputaudio;
234 /* This pointer is passed as the first parameter to the callback function. */
235 aspec.userdata = NULL;
237 /* initialize the SDL Audio system */
238 if (SDL_Init (SDL_INIT_AUDIO/*|SDL_INIT_NOPARACHUTE*/)) {
239 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_SDL_CantInit, SDL_GetError());
240 return 0;
243 /* Open the audio device and start playing sound! */
244 if(SDL_OpenAudio(&aspec, &obtained) < 0) {
245 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_SDL_CantOpenAudio, SDL_GetError());
246 return 0;
249 /* did we got what we wanted ? */
250 ao_data.channels=obtained.channels;
251 ao_data.samplerate=obtained.freq;
253 switch(obtained.format) {
254 case AUDIO_U8 :
255 ao_data.format = AF_FORMAT_U8;
256 break;
257 case AUDIO_S16LSB :
258 ao_data.format = AF_FORMAT_S16_LE;
259 break;
260 case AUDIO_S16MSB :
261 ao_data.format = AF_FORMAT_S16_BE;
262 break;
263 case AUDIO_S8 :
264 ao_data.format = AF_FORMAT_S8;
265 break;
266 case AUDIO_U16LSB :
267 ao_data.format = AF_FORMAT_U16_LE;
268 break;
269 case AUDIO_U16MSB :
270 ao_data.format = AF_FORMAT_U16_BE;
271 break;
272 default:
273 mp_msg(MSGT_AO,MSGL_WARN,MSGTR_AO_SDL_UnsupportedAudioFmt, obtained.format);
274 return 0;
277 mp_msg(MSGT_AO,MSGL_V,"SDL: buf size = %d\n",obtained.size);
278 ao_data.buffersize=obtained.size;
279 ao_data.outburst = CHUNK_SIZE;
281 reset();
282 /* unsilence audio, if callback is ready */
283 SDL_PauseAudio(0);
285 return 1;
288 // close audio device
289 static void uninit(int immed){
290 mp_msg(MSGT_AO,MSGL_V,"SDL: Audio Subsystem shutting down!\n");
291 if (!immed)
292 usec_sleep(get_delay() * 1000 * 1000);
293 SDL_CloseAudio();
294 SDL_QuitSubSystem(SDL_INIT_AUDIO);
297 // stop playing and empty buffers (for seeking/pause)
298 static void reset(void){
300 //printf("SDL: reset called!\n");
302 SDL_PauseAudio(1);
303 /* Reset ring-buffer state */
304 read_pos = 0;
305 write_pos = 0;
306 SDL_PauseAudio(0);
309 // stop playing, keep buffers (for pause)
310 static void audio_pause(void)
313 //printf("SDL: audio_pause called!\n");
314 SDL_PauseAudio(1);
318 // resume playing, after audio_pause()
319 static void audio_resume(void)
321 //printf("SDL: audio_resume called!\n");
322 SDL_PauseAudio(0);
326 // return: how many bytes can be played without blocking
327 static int get_space(void){
328 return buf_free();
331 // plays 'len' bytes of 'data'
332 // it should round it down to outburst*n
333 // return: number of bytes played
334 static int play(void* data,int len,int flags){
336 if (!(flags & AOPLAY_FINAL_CHUNK))
337 len = (len/ao_data.outburst)*ao_data.outburst;
338 #if 0
339 int ret;
341 /* Audio locking prohibits call of outputaudio */
342 SDL_LockAudio();
343 // copy audio stream into ring-buffer
344 ret = write_buffer(data, len);
345 SDL_UnlockAudio();
347 return ret;
348 #else
349 return write_buffer(data, len);
350 #endif
353 // return: delay in seconds between first and last sample in buffer
354 static float get_delay(void){
355 int buffered = BUFFSIZE - CHUNK_SIZE - buf_free(); // could be less
356 return (float)(buffered + ao_data.buffersize)/(float)ao_data.bps;