sync with en/mplayer.1 rev. 30611
[mplayer/glamo.git] / libao2 / ao_sdl.c
blob914e05eca7c5e35a55571fcec806dee8e37c0152
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 #ifdef CONFIG_SDL_SDL_H
35 #include <SDL/SDL.h>
36 #else
37 #include <SDL.h>
38 #endif
39 #include "osdep/timer.h"
41 #include "libavutil/fifo.h"
43 static const ao_info_t info =
45 "SDLlib audio output",
46 "sdl",
47 "Felix Buenemann <atmosfear@users.sourceforge.net>",
51 LIBAO_EXTERN(sdl)
53 // turn this on if you want to use the slower SDL_MixAudio
54 #undef USE_SDL_INTERNAL_MIXER
56 // Samplesize used by the SDLlib AudioSpec struct
57 #if defined(__MINGW32__) || defined(__CYGWIN__) || defined(__AMIGAOS4__)
58 #define SAMPLESIZE 2048
59 #else
60 #define SAMPLESIZE 1024
61 #endif
63 #define CHUNK_SIZE 4096
64 #define NUM_CHUNKS 8
65 #define BUFFSIZE (NUM_CHUNKS * CHUNK_SIZE)
67 static AVFifoBuffer *buffer;
69 #ifdef USE_SDL_INTERNAL_MIXER
70 static unsigned char volume=SDL_MIX_MAXVOLUME;
71 #endif
73 static int write_buffer(unsigned char* data,int len){
74 int free = av_fifo_space(buffer);
75 if (len > free) len = free;
76 return av_fifo_generic_write(buffer, data, len, NULL);
79 #ifdef USE_SDL_INTERNAL_MIXER
80 static void mix_audio(void *dst, void *src, int len) {
81 SDL_MixAudio(dst, src, len, volume);
83 #endif
85 static int read_buffer(unsigned char* data,int len){
86 int buffered = av_fifo_size(buffer);
87 if (len > buffered) len = buffered;
88 #ifdef USE_SDL_INTERNAL_MIXER
89 av_fifo_generic_read(buffer, data, len, mix_audio);
90 #else
91 av_fifo_generic_read(buffer, data, len, NULL);
92 #endif
93 return len;
96 // end ring buffer stuff
99 // to set/get/query special features/parameters
100 static int control(int cmd,void *arg){
101 #ifdef USE_SDL_INTERNAL_MIXER
102 switch (cmd) {
103 case AOCONTROL_GET_VOLUME:
105 ao_control_vol_t* vol = (ao_control_vol_t*)arg;
106 vol->left = vol->right = volume * 100 / SDL_MIX_MAXVOLUME;
107 return CONTROL_OK;
109 case AOCONTROL_SET_VOLUME:
111 int diff;
112 ao_control_vol_t* vol = (ao_control_vol_t*)arg;
113 diff = (vol->left+vol->right) / 2;
114 volume = diff * SDL_MIX_MAXVOLUME / 100;
115 return CONTROL_OK;
118 #endif
119 return CONTROL_UNKNOWN;
122 // SDL Callback function
123 static void outputaudio(void *unused, Uint8 *stream, int len)
125 //SDL_MixAudio(stream, read_buffer(buffers, len), len, SDL_MIX_MAXVOLUME);
126 //if(!full_buffers) printf("SDL: Buffer underrun!\n");
128 read_buffer(stream, len);
129 //printf("SDL: Full Buffers: %i\n", full_buffers);
132 // open & setup audio device
133 // return: 1=success 0=fail
134 static int init(int rate,int channels,int format,int flags){
136 /* SDL Audio Specifications */
137 SDL_AudioSpec aspec, obtained;
139 /* Allocate ring-buffer memory */
140 buffer = av_fifo_alloc(BUFFSIZE);
142 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_SDL_INFO, rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
144 if(ao_subdevice) {
145 setenv("SDL_AUDIODRIVER", ao_subdevice, 1);
146 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_SDL_DriverInfo, ao_subdevice);
149 ao_data.channels=channels;
150 ao_data.samplerate=rate;
151 ao_data.format=format;
153 ao_data.bps=channels*rate;
154 if(format != AF_FORMAT_U8 && format != AF_FORMAT_S8)
155 ao_data.bps*=2;
157 /* The desired audio format (see SDL_AudioSpec) */
158 switch(format) {
159 case AF_FORMAT_U8:
160 aspec.format = AUDIO_U8;
161 break;
162 case AF_FORMAT_S16_LE:
163 aspec.format = AUDIO_S16LSB;
164 break;
165 case AF_FORMAT_S16_BE:
166 aspec.format = AUDIO_S16MSB;
167 break;
168 case AF_FORMAT_S8:
169 aspec.format = AUDIO_S8;
170 break;
171 case AF_FORMAT_U16_LE:
172 aspec.format = AUDIO_U16LSB;
173 break;
174 case AF_FORMAT_U16_BE:
175 aspec.format = AUDIO_U16MSB;
176 break;
177 default:
178 aspec.format = AUDIO_S16LSB;
179 ao_data.format = AF_FORMAT_S16_LE;
180 mp_msg(MSGT_AO,MSGL_WARN,MSGTR_AO_SDL_UnsupportedAudioFmt, format);
183 /* The desired audio frequency in samples-per-second. */
184 aspec.freq = rate;
186 /* Number of channels (mono/stereo) */
187 aspec.channels = channels;
189 /* 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 */
190 aspec.samples = SAMPLESIZE;
192 /* 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:
193 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. */
194 aspec.callback = outputaudio;
196 /* This pointer is passed as the first parameter to the callback function. */
197 aspec.userdata = NULL;
199 /* initialize the SDL Audio system */
200 if (SDL_Init (SDL_INIT_AUDIO/*|SDL_INIT_NOPARACHUTE*/)) {
201 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_SDL_CantInit, SDL_GetError());
202 return 0;
205 /* Open the audio device and start playing sound! */
206 if(SDL_OpenAudio(&aspec, &obtained) < 0) {
207 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_SDL_CantOpenAudio, SDL_GetError());
208 return 0;
211 /* did we got what we wanted ? */
212 ao_data.channels=obtained.channels;
213 ao_data.samplerate=obtained.freq;
215 switch(obtained.format) {
216 case AUDIO_U8 :
217 ao_data.format = AF_FORMAT_U8;
218 break;
219 case AUDIO_S16LSB :
220 ao_data.format = AF_FORMAT_S16_LE;
221 break;
222 case AUDIO_S16MSB :
223 ao_data.format = AF_FORMAT_S16_BE;
224 break;
225 case AUDIO_S8 :
226 ao_data.format = AF_FORMAT_S8;
227 break;
228 case AUDIO_U16LSB :
229 ao_data.format = AF_FORMAT_U16_LE;
230 break;
231 case AUDIO_U16MSB :
232 ao_data.format = AF_FORMAT_U16_BE;
233 break;
234 default:
235 mp_msg(MSGT_AO,MSGL_WARN,MSGTR_AO_SDL_UnsupportedAudioFmt, obtained.format);
236 return 0;
239 mp_msg(MSGT_AO,MSGL_V,"SDL: buf size = %d\n",obtained.size);
240 ao_data.buffersize=obtained.size;
241 ao_data.outburst = CHUNK_SIZE;
243 /* unsilence audio, if callback is ready */
244 SDL_PauseAudio(0);
246 return 1;
249 // close audio device
250 static void uninit(int immed){
251 mp_msg(MSGT_AO,MSGL_V,"SDL: Audio Subsystem shutting down!\n");
252 if (!immed)
253 usec_sleep(get_delay() * 1000 * 1000);
254 SDL_CloseAudio();
255 SDL_QuitSubSystem(SDL_INIT_AUDIO);
256 av_fifo_free(buffer);
259 // stop playing and empty buffers (for seeking/pause)
260 static void reset(void){
262 //printf("SDL: reset called!\n");
264 SDL_PauseAudio(1);
265 /* Reset ring-buffer state */
266 av_fifo_reset(buffer);
267 SDL_PauseAudio(0);
270 // stop playing, keep buffers (for pause)
271 static void audio_pause(void)
274 //printf("SDL: audio_pause called!\n");
275 SDL_PauseAudio(1);
279 // resume playing, after audio_pause()
280 static void audio_resume(void)
282 //printf("SDL: audio_resume called!\n");
283 SDL_PauseAudio(0);
287 // return: how many bytes can be played without blocking
288 static int get_space(void){
289 return av_fifo_space(buffer);
292 // plays 'len' bytes of 'data'
293 // it should round it down to outburst*n
294 // return: number of bytes played
295 static int play(void* data,int len,int flags){
297 if (!(flags & AOPLAY_FINAL_CHUNK))
298 len = (len/ao_data.outburst)*ao_data.outburst;
299 #if 0
300 int ret;
302 /* Audio locking prohibits call of outputaudio */
303 SDL_LockAudio();
304 // copy audio stream into ring-buffer
305 ret = write_buffer(data, len);
306 SDL_UnlockAudio();
308 return ret;
309 #else
310 return write_buffer(data, len);
311 #endif
314 // return: delay in seconds between first and last sample in buffer
315 static float get_delay(void){
316 int buffered = av_fifo_size(buffer); // could be less
317 return (float)(buffered + ao_data.buffersize)/(float)ao_data.bps;