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
33 #include "audio_out.h"
34 #include "audio_out_internal.h"
35 #include "libaf/af_format.h"
37 #include "osdep/timer.h"
39 #include "libvo/fastmemcpy.h"
41 static ao_info_t info
=
43 "SDLlib audio output",
45 "Felix Buenemann <atmosfear@users.sourceforge.net>",
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
58 #define SAMPLESIZE 1024
61 #define CHUNK_SIZE 4096
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
;
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
;
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
;
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
;
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
);
121 fast_memcpy (data
, &buffer
[read_pos
], first_len
);
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
);
128 fast_memcpy (&data
[first_len
], buffer
, len
- first_len
);
131 read_pos
= (read_pos
+ len
) % BUFFSIZE
;
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
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
;
148 case AOCONTROL_SET_VOLUME
:
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;
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
));
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
)
195 /* The desired audio format (see SDL_AudioSpec) */
198 aspec
.format
= AUDIO_U8
;
200 case AF_FORMAT_S16_LE
:
201 aspec
.format
= AUDIO_S16LSB
;
203 case AF_FORMAT_S16_BE
:
204 aspec
.format
= AUDIO_S16MSB
;
207 aspec
.format
= AUDIO_S8
;
209 case AF_FORMAT_U16_LE
:
210 aspec
.format
= AUDIO_U16LSB
;
212 case AF_FORMAT_U16_BE
:
213 aspec
.format
= AUDIO_U16MSB
;
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. */
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());
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());
249 /* did we got what we wanted ? */
250 ao_data
.channels
=obtained
.channels
;
251 ao_data
.samplerate
=obtained
.freq
;
253 switch(obtained
.format
) {
255 ao_data
.format
= AF_FORMAT_U8
;
258 ao_data
.format
= AF_FORMAT_S16_LE
;
261 ao_data
.format
= AF_FORMAT_S16_BE
;
264 ao_data
.format
= AF_FORMAT_S8
;
267 ao_data
.format
= AF_FORMAT_U16_LE
;
270 ao_data
.format
= AF_FORMAT_U16_BE
;
273 mp_msg(MSGT_AO
,MSGL_WARN
,MSGTR_AO_SDL_UnsupportedAudioFmt
, obtained
.format
);
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
;
282 /* unsilence audio, if callback is ready */
288 // close audio device
289 static void uninit(int immed
){
290 mp_msg(MSGT_AO
,MSGL_V
,"SDL: Audio Subsystem shutting down!\n");
292 usec_sleep(get_delay() * 1000 * 1000);
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");
303 /* Reset ring-buffer state */
309 // stop playing, keep buffers (for pause)
310 static void audio_pause(void)
313 //printf("SDL: audio_pause called!\n");
318 // resume playing, after audio_pause()
319 static void audio_resume(void)
321 //printf("SDL: audio_resume called!\n");
326 // return: how many bytes can be played without blocking
327 static int get_space(void){
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
;
341 /* Audio locking prohibits call of outputaudio */
343 // copy audio stream into ring-buffer
344 ret
= write_buffer(data
, len
);
349 return write_buffer(data
, len
);
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
;