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
31 #include "audio_out.h"
32 #include "audio_out_internal.h"
33 #include "libaf/af_format.h"
35 #include "osdep/timer.h"
37 #include "libavutil/fifo.h"
39 static const ao_info_t info
=
41 "SDLlib audio output",
43 "Felix Buenemann <atmosfear@users.sourceforge.net>",
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
56 #define SAMPLESIZE 1024
59 #define CHUNK_SIZE 4096
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
;
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
);
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 return av_fifo_generic_read(buffer
, data
, len
, mix_audio
);
87 return av_fifo_generic_read(buffer
, data
, len
, NULL
);
91 // end ring buffer stuff
94 // to set/get/query special features/parameters
95 static int control(int cmd
,void *arg
){
96 #ifdef USE_SDL_INTERNAL_MIXER
98 case AOCONTROL_GET_VOLUME
:
100 ao_control_vol_t
* vol
= (ao_control_vol_t
*)arg
;
101 vol
->left
= vol
->right
= volume
* 100 / SDL_MIX_MAXVOLUME
;
104 case AOCONTROL_SET_VOLUME
:
107 ao_control_vol_t
* vol
= (ao_control_vol_t
*)arg
;
108 diff
= (vol
->left
+vol
->right
) / 2;
109 volume
= diff
* SDL_MIX_MAXVOLUME
/ 100;
114 return CONTROL_UNKNOWN
;
117 // SDL Callback function
118 static void outputaudio(void *unused
, Uint8
*stream
, int len
) {
119 //SDL_MixAudio(stream, read_buffer(buffers, len), len, SDL_MIX_MAXVOLUME);
120 //if(!full_buffers) printf("SDL: Buffer underrun!\n");
122 read_buffer(stream
, len
);
123 //printf("SDL: Full Buffers: %i\n", full_buffers);
126 // open & setup audio device
127 // return: 1=success 0=fail
128 static int init(int rate
,int channels
,int format
,int flags
){
130 /* SDL Audio Specifications */
131 SDL_AudioSpec aspec
, obtained
;
133 /* Allocate ring-buffer memory */
134 buffer
= av_fifo_alloc(BUFFSIZE
);
136 mp_msg(MSGT_AO
,MSGL_INFO
,MSGTR_AO_SDL_INFO
, rate
, (channels
> 1) ? "Stereo" : "Mono", af_fmt2str_short(format
));
139 setenv("SDL_AUDIODRIVER", ao_subdevice
, 1);
140 mp_msg(MSGT_AO
,MSGL_INFO
,MSGTR_AO_SDL_DriverInfo
, ao_subdevice
);
143 ao_data
.channels
=channels
;
144 ao_data
.samplerate
=rate
;
145 ao_data
.format
=format
;
147 ao_data
.bps
=channels
*rate
;
148 if(format
!= AF_FORMAT_U8
&& format
!= AF_FORMAT_S8
)
151 /* The desired audio format (see SDL_AudioSpec) */
154 aspec
.format
= AUDIO_U8
;
156 case AF_FORMAT_S16_LE
:
157 aspec
.format
= AUDIO_S16LSB
;
159 case AF_FORMAT_S16_BE
:
160 aspec
.format
= AUDIO_S16MSB
;
163 aspec
.format
= AUDIO_S8
;
165 case AF_FORMAT_U16_LE
:
166 aspec
.format
= AUDIO_U16LSB
;
168 case AF_FORMAT_U16_BE
:
169 aspec
.format
= AUDIO_U16MSB
;
172 aspec
.format
= AUDIO_S16LSB
;
173 ao_data
.format
= AF_FORMAT_S16_LE
;
174 mp_msg(MSGT_AO
,MSGL_WARN
,MSGTR_AO_SDL_UnsupportedAudioFmt
, format
);
177 /* The desired audio frequency in samples-per-second. */
180 /* Number of channels (mono/stereo) */
181 aspec
.channels
= channels
;
183 /* 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 */
184 aspec
.samples
= SAMPLESIZE
;
186 /* 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:
187 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. */
188 aspec
.callback
= outputaudio
;
190 /* This pointer is passed as the first parameter to the callback function. */
191 aspec
.userdata
= NULL
;
193 /* initialize the SDL Audio system */
194 if (SDL_Init (SDL_INIT_AUDIO
/*|SDL_INIT_NOPARACHUTE*/)) {
195 mp_msg(MSGT_AO
,MSGL_ERR
,MSGTR_AO_SDL_CantInit
, SDL_GetError());
199 /* Open the audio device and start playing sound! */
200 if(SDL_OpenAudio(&aspec
, &obtained
) < 0) {
201 mp_msg(MSGT_AO
,MSGL_ERR
,MSGTR_AO_SDL_CantOpenAudio
, SDL_GetError());
205 /* did we got what we wanted ? */
206 ao_data
.channels
=obtained
.channels
;
207 ao_data
.samplerate
=obtained
.freq
;
209 switch(obtained
.format
) {
211 ao_data
.format
= AF_FORMAT_U8
;
214 ao_data
.format
= AF_FORMAT_S16_LE
;
217 ao_data
.format
= AF_FORMAT_S16_BE
;
220 ao_data
.format
= AF_FORMAT_S8
;
223 ao_data
.format
= AF_FORMAT_U16_LE
;
226 ao_data
.format
= AF_FORMAT_U16_BE
;
229 mp_msg(MSGT_AO
,MSGL_WARN
,MSGTR_AO_SDL_UnsupportedAudioFmt
, obtained
.format
);
233 mp_msg(MSGT_AO
,MSGL_V
,"SDL: buf size = %d\n",obtained
.size
);
234 ao_data
.buffersize
=obtained
.size
;
235 ao_data
.outburst
= CHUNK_SIZE
;
237 /* unsilence audio, if callback is ready */
243 // close audio device
244 static void uninit(int immed
){
245 mp_msg(MSGT_AO
,MSGL_V
,"SDL: Audio Subsystem shutting down!\n");
247 usec_sleep(get_delay() * 1000 * 1000);
249 SDL_QuitSubSystem(SDL_INIT_AUDIO
);
250 av_fifo_free(buffer
);
253 // stop playing and empty buffers (for seeking/pause)
254 static void reset(void){
256 //printf("SDL: reset called!\n");
259 /* Reset ring-buffer state */
260 av_fifo_reset(buffer
);
264 // stop playing, keep buffers (for pause)
265 static void audio_pause(void)
268 //printf("SDL: audio_pause called!\n");
273 // resume playing, after audio_pause()
274 static void audio_resume(void)
276 //printf("SDL: audio_resume called!\n");
281 // return: how many bytes can be played without blocking
282 static int get_space(void){
283 return av_fifo_space(buffer
);
286 // plays 'len' bytes of 'data'
287 // it should round it down to outburst*n
288 // return: number of bytes played
289 static int play(void* data
,int len
,int flags
){
291 if (!(flags
& AOPLAY_FINAL_CHUNK
))
292 len
= (len
/ao_data
.outburst
)*ao_data
.outburst
;
296 /* Audio locking prohibits call of outputaudio */
298 // copy audio stream into ring-buffer
299 ret
= write_buffer(data
, len
);
304 return write_buffer(data
, len
);
308 // return: delay in seconds between first and last sample in buffer
309 static float get_delay(void){
310 int buffered
= av_fifo_size(buffer
); // could be less
311 return (float)(buffered
+ ao_data
.buffersize
)/(float)ao_data
.bps
;