audio output: add a new AO driver API
[mplayer.git] / libao2 / ao_sdl.c
blobe9ae7298d55acc415e73439f265e4fc3e197d2cc
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"
30 #include "audio_out.h"
31 #include "audio_out_internal.h"
32 #include "libaf/af_format.h"
33 #ifdef CONFIG_SDL_SDL_H
34 #include <SDL/SDL.h>
35 #else
36 #include <SDL.h>
37 #endif
38 #include "osdep/timer.h"
40 #include "libavutil/fifo.h"
42 static const ao_info_t info =
44 "SDLlib audio output",
45 "sdl",
46 "Felix Buenemann <atmosfear@users.sourceforge.net>",
50 LIBAO_EXTERN(sdl)
52 // turn this on if you want to use the slower SDL_MixAudio
53 #undef USE_SDL_INTERNAL_MIXER
55 // Samplesize used by the SDLlib AudioSpec struct
56 #if defined(__MINGW32__) || defined(__CYGWIN__) || defined(__AMIGAOS4__)
57 #define SAMPLESIZE 2048
58 #else
59 #define SAMPLESIZE 1024
60 #endif
62 #define CHUNK_SIZE 4096
63 #define NUM_CHUNKS 8
64 #define BUFFSIZE (NUM_CHUNKS * CHUNK_SIZE)
66 static AVFifoBuffer *buffer;
68 #ifdef USE_SDL_INTERNAL_MIXER
69 static unsigned char volume=SDL_MIX_MAXVOLUME;
70 #endif
72 static int write_buffer(unsigned char* data,int len){
73 int free = av_fifo_space(buffer);
74 if (len > free) len = free;
75 return av_fifo_generic_write(buffer, data, len, NULL);
78 #ifdef USE_SDL_INTERNAL_MIXER
79 static void mix_audio(void *dst, void *src, int len) {
80 SDL_MixAudio(dst, src, len, volume);
82 #endif
84 static int read_buffer(unsigned char* data,int len){
85 int buffered = av_fifo_size(buffer);
86 if (len > buffered) len = buffered;
87 #ifdef USE_SDL_INTERNAL_MIXER
88 av_fifo_generic_read(buffer, data, len, mix_audio);
89 #else
90 av_fifo_generic_read(buffer, data, len, NULL);
91 #endif
92 return len;
95 // end ring buffer stuff
98 // to set/get/query special features/parameters
99 static int control(int cmd,void *arg){
100 #ifdef USE_SDL_INTERNAL_MIXER
101 switch (cmd) {
102 case AOCONTROL_GET_VOLUME:
104 ao_control_vol_t* vol = (ao_control_vol_t*)arg;
105 vol->left = vol->right = volume * 100 / SDL_MIX_MAXVOLUME;
106 return CONTROL_OK;
108 case AOCONTROL_SET_VOLUME:
110 int diff;
111 ao_control_vol_t* vol = (ao_control_vol_t*)arg;
112 diff = (vol->left+vol->right) / 2;
113 volume = diff * SDL_MIX_MAXVOLUME / 100;
114 return CONTROL_OK;
117 #endif
118 return CONTROL_UNKNOWN;
121 // SDL Callback function
122 static void outputaudio(void *unused, Uint8 *stream, int len)
124 //SDL_MixAudio(stream, read_buffer(buffers, len), len, SDL_MIX_MAXVOLUME);
125 //if(!full_buffers) printf("SDL: Buffer underrun!\n");
127 read_buffer(stream, len);
128 //printf("SDL: Full Buffers: %i\n", full_buffers);
131 // open & setup audio device
132 // return: 1=success 0=fail
133 static int init(int rate,int channels,int format,int flags){
135 /* SDL Audio Specifications */
136 SDL_AudioSpec aspec, obtained;
138 /* Allocate ring-buffer memory */
139 buffer = av_fifo_alloc(BUFFSIZE);
141 mp_tmsg(MSGT_AO,MSGL_INFO,"[AO SDL] Samplerate: %iHz Channels: %s Format %s\n", rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
143 if(ao_subdevice) {
144 setenv("SDL_AUDIODRIVER", ao_subdevice, 1);
145 mp_tmsg(MSGT_AO,MSGL_INFO,"[AO SDL] using %s audio driver.\n", ao_subdevice);
148 ao_data.channels=channels;
149 ao_data.samplerate=rate;
150 ao_data.format=format;
152 ao_data.bps=channels*rate;
153 if(format != AF_FORMAT_U8 && format != AF_FORMAT_S8)
154 ao_data.bps*=2;
156 /* The desired audio format (see SDL_AudioSpec) */
157 switch(format) {
158 case AF_FORMAT_U8:
159 aspec.format = AUDIO_U8;
160 break;
161 case AF_FORMAT_S16_LE:
162 aspec.format = AUDIO_S16LSB;
163 break;
164 case AF_FORMAT_S16_BE:
165 aspec.format = AUDIO_S16MSB;
166 break;
167 case AF_FORMAT_S8:
168 aspec.format = AUDIO_S8;
169 break;
170 case AF_FORMAT_U16_LE:
171 aspec.format = AUDIO_U16LSB;
172 break;
173 case AF_FORMAT_U16_BE:
174 aspec.format = AUDIO_U16MSB;
175 break;
176 default:
177 aspec.format = AUDIO_S16LSB;
178 ao_data.format = AF_FORMAT_S16_LE;
179 mp_tmsg(MSGT_AO,MSGL_WARN,"[AO SDL] Unsupported audio format: 0x%x.\n", format);
182 /* The desired audio frequency in samples-per-second. */
183 aspec.freq = rate;
185 /* Number of channels (mono/stereo) */
186 aspec.channels = channels;
188 /* 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 */
189 aspec.samples = SAMPLESIZE;
191 /* 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:
192 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. */
193 aspec.callback = outputaudio;
195 /* This pointer is passed as the first parameter to the callback function. */
196 aspec.userdata = NULL;
198 /* initialize the SDL Audio system */
199 if (SDL_Init (SDL_INIT_AUDIO/*|SDL_INIT_NOPARACHUTE*/)) {
200 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO SDL] SDL Audio initialization failed: %s\n", SDL_GetError());
201 return 0;
204 /* Open the audio device and start playing sound! */
205 if(SDL_OpenAudio(&aspec, &obtained) < 0) {
206 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO SDL] Unable to open audio: %s\n", SDL_GetError());
207 return 0;
210 /* did we got what we wanted ? */
211 ao_data.channels=obtained.channels;
212 ao_data.samplerate=obtained.freq;
214 switch(obtained.format) {
215 case AUDIO_U8 :
216 ao_data.format = AF_FORMAT_U8;
217 break;
218 case AUDIO_S16LSB :
219 ao_data.format = AF_FORMAT_S16_LE;
220 break;
221 case AUDIO_S16MSB :
222 ao_data.format = AF_FORMAT_S16_BE;
223 break;
224 case AUDIO_S8 :
225 ao_data.format = AF_FORMAT_S8;
226 break;
227 case AUDIO_U16LSB :
228 ao_data.format = AF_FORMAT_U16_LE;
229 break;
230 case AUDIO_U16MSB :
231 ao_data.format = AF_FORMAT_U16_BE;
232 break;
233 default:
234 mp_tmsg(MSGT_AO,MSGL_WARN,"[AO SDL] Unsupported audio format: 0x%x.\n", obtained.format);
235 return 0;
238 mp_msg(MSGT_AO,MSGL_V,"SDL: buf size = %d\n",obtained.size);
239 ao_data.buffersize=obtained.size;
240 ao_data.outburst = CHUNK_SIZE;
242 /* unsilence audio, if callback is ready */
243 SDL_PauseAudio(0);
245 return 1;
248 // close audio device
249 static void uninit(int immed){
250 mp_msg(MSGT_AO,MSGL_V,"SDL: Audio Subsystem shutting down!\n");
251 if (!immed)
252 usec_sleep(get_delay() * 1000 * 1000);
253 SDL_CloseAudio();
254 SDL_QuitSubSystem(SDL_INIT_AUDIO);
255 av_fifo_free(buffer);
258 // stop playing and empty buffers (for seeking/pause)
259 static void reset(void){
261 //printf("SDL: reset called!\n");
263 SDL_PauseAudio(1);
264 /* Reset ring-buffer state */
265 av_fifo_reset(buffer);
266 SDL_PauseAudio(0);
269 // stop playing, keep buffers (for pause)
270 static void audio_pause(void)
273 //printf("SDL: audio_pause called!\n");
274 SDL_PauseAudio(1);
278 // resume playing, after audio_pause()
279 static void audio_resume(void)
281 //printf("SDL: audio_resume called!\n");
282 SDL_PauseAudio(0);
286 // return: how many bytes can be played without blocking
287 static int get_space(void){
288 return av_fifo_space(buffer);
291 // plays 'len' bytes of 'data'
292 // it should round it down to outburst*n
293 // return: number of bytes played
294 static int play(void* data,int len,int flags){
296 if (!(flags & AOPLAY_FINAL_CHUNK))
297 len = (len/ao_data.outburst)*ao_data.outburst;
298 #if 0
299 int ret;
301 /* Audio locking prohibits call of outputaudio */
302 SDL_LockAudio();
303 // copy audio stream into ring-buffer
304 ret = write_buffer(data, len);
305 SDL_UnlockAudio();
307 return ret;
308 #else
309 return write_buffer(data, len);
310 #endif
313 // return: delay in seconds between first and last sample in buffer
314 static float get_delay(void){
315 int buffered = av_fifo_size(buffer); // could be less
316 return (float)(buffered + ao_data.buffersize)/(float)ao_data.bps;