Update to MPlayer SVN rev 28973 and FFmpeg SVN rev 17997.
[vaapi:challenzhous-mplayer.git] / libao2 / ao_sdl.c
1 /*
2  * SDLlib audio output driver for MPlayer
3  *
4  * Copyleft 2001 by Felix B√ľnemann (atmosfear@users.sf.net)
5  *
6  * This file is part of MPlayer.
7  *
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.
12  *
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.
17  *
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
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "config.h"
28 #include "mp_msg.h"
29 #include "help_mp.h"
30
31 #include "audio_out.h"
32 #include "audio_out_internal.h"
33 #include "libaf/af_format.h"
34 #include <SDL.h>
35 #include "osdep/timer.h"
36
37 #include "libavutil/fifo.h"
38
39 static const ao_info_t info = 
40 {
41         "SDLlib audio output",
42         "sdl",
43         "Felix Buenemann <atmosfear@users.sourceforge.net>",
44         ""
45 };
46
47 LIBAO_EXTERN(sdl)
48
49 // turn this on if you want to use the slower SDL_MixAudio
50 #undef USE_SDL_INTERNAL_MIXER
51
52 // Samplesize used by the SDLlib AudioSpec struct
53 #if defined(__MINGW32__) || defined(__CYGWIN__) || defined(__AMIGAOS4__)
54 #define SAMPLESIZE 2048
55 #else
56 #define SAMPLESIZE 1024
57 #endif
58
59 #define CHUNK_SIZE 4096
60 #define NUM_CHUNKS 8
61 #define BUFFSIZE (NUM_CHUNKS * CHUNK_SIZE)
62
63 static AVFifoBuffer *buffer;
64
65 #ifdef USE_SDL_INTERNAL_MIXER
66 static unsigned char volume=SDL_MIX_MAXVOLUME;
67 #endif
68
69 static int write_buffer(unsigned char* data,int len){
70   int free = BUFFSIZE - av_fifo_size(buffer);
71   if (len > free) len = free;
72   return av_fifo_generic_write(buffer, data, len, NULL);
73 }
74
75 #ifdef USE_SDL_INTERNAL_MIXER
76 static void mix_audio(void *dst, void *src, int len) {
77   SDL_MixAudio(dst, src, len, volume);
78 }
79 #endif
80
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);
86 #else
87   return av_fifo_generic_read(buffer, data, len, NULL);
88 #endif
89 }
90
91 // end ring buffer stuff
92
93
94 // to set/get/query special features/parameters
95 static int control(int cmd,void *arg){
96 #ifdef USE_SDL_INTERNAL_MIXER
97         switch (cmd) {
98                 case AOCONTROL_GET_VOLUME:
99                 {
100                         ao_control_vol_t* vol = (ao_control_vol_t*)arg;
101                         vol->left = vol->right = volume * 100 / SDL_MIX_MAXVOLUME;
102                         return CONTROL_OK;
103                 }
104                 case AOCONTROL_SET_VOLUME:
105                 {
106                         int diff;
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;
110                         return CONTROL_OK;
111                 }
112         }
113 #endif
114         return CONTROL_UNKNOWN;
115 }
116
117 // SDL Callback function
118 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");
121
122         read_buffer(stream, len);
123         //printf("SDL: Full Buffers: %i\n", full_buffers);
124 }
125
126 // open & setup audio device
127 // return: 1=success 0=fail
128 static int init(int rate,int channels,int format,int flags){
129
130         /* SDL Audio Specifications */
131         SDL_AudioSpec aspec, obtained;
132         
133         /* Allocate ring-buffer memory */
134         buffer = av_fifo_alloc(BUFFSIZE);
135
136         mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_SDL_INFO, rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
137
138         if(ao_subdevice) {
139                 setenv("SDL_AUDIODRIVER", ao_subdevice, 1);
140                 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_SDL_DriverInfo, ao_subdevice);
141         }
142
143         ao_data.channels=channels;
144         ao_data.samplerate=rate;
145         ao_data.format=format;
146
147         ao_data.bps=channels*rate;
148         if(format != AF_FORMAT_U8 && format != AF_FORMAT_S8)
149           ao_data.bps*=2;
150         
151         /* The desired audio format (see SDL_AudioSpec) */
152         switch(format) {
153             case AF_FORMAT_U8:
154                 aspec.format = AUDIO_U8;
155             break;
156             case AF_FORMAT_S16_LE:
157                 aspec.format = AUDIO_S16LSB;
158             break;
159             case AF_FORMAT_S16_BE:
160                 aspec.format = AUDIO_S16MSB;
161             break;
162             case AF_FORMAT_S8:
163                 aspec.format = AUDIO_S8;
164             break;
165             case AF_FORMAT_U16_LE:
166                 aspec.format = AUDIO_U16LSB;
167             break;
168             case AF_FORMAT_U16_BE:
169                 aspec.format = AUDIO_U16MSB;
170             break;
171             default:
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);
175         }
176
177         /* The desired audio frequency in samples-per-second. */
178         aspec.freq     = rate;
179
180         /* Number of channels (mono/stereo) */
181         aspec.channels = channels;
182
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;
185
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;
189
190         /* This pointer is passed as the first parameter to the callback function. */
191         aspec.userdata = NULL;
192
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());
196                 return 0;
197         }
198
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());
202                 return 0;
203         } 
204
205         /* did we got what we wanted ? */
206         ao_data.channels=obtained.channels;
207         ao_data.samplerate=obtained.freq;
208
209         switch(obtained.format) {
210             case AUDIO_U8 :
211                 ao_data.format = AF_FORMAT_U8;
212             break;
213             case AUDIO_S16LSB :
214                 ao_data.format = AF_FORMAT_S16_LE;
215             break;
216             case AUDIO_S16MSB :
217                 ao_data.format = AF_FORMAT_S16_BE;
218             break;
219             case AUDIO_S8 :
220                 ao_data.format = AF_FORMAT_S8;
221             break;
222             case AUDIO_U16LSB :
223                 ao_data.format = AF_FORMAT_U16_LE;
224             break;
225             case AUDIO_U16MSB :
226                 ao_data.format = AF_FORMAT_U16_BE;
227             break;
228             default:
229                 mp_msg(MSGT_AO,MSGL_WARN,MSGTR_AO_SDL_UnsupportedAudioFmt, obtained.format);
230                 return 0;
231         }
232
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;
236         
237         /* unsilence audio, if callback is ready */
238         SDL_PauseAudio(0);
239
240         return 1;
241 }
242
243 // close audio device
244 static void uninit(int immed){
245         mp_msg(MSGT_AO,MSGL_V,"SDL: Audio Subsystem shutting down!\n");
246         if (!immed)
247           usec_sleep(get_delay() * 1000 * 1000);
248         SDL_CloseAudio();
249         SDL_QuitSubSystem(SDL_INIT_AUDIO);
250         av_fifo_free(buffer);
251 }
252
253 // stop playing and empty buffers (for seeking/pause)
254 static void reset(void){
255
256         //printf("SDL: reset called!\n");       
257
258         SDL_PauseAudio(1);
259         /* Reset ring-buffer state */
260         av_fifo_reset(buffer);
261         SDL_PauseAudio(0);
262 }
263
264 // stop playing, keep buffers (for pause)
265 static void audio_pause(void)
266 {
267
268         //printf("SDL: audio_pause called!\n"); 
269         SDL_PauseAudio(1);
270         
271 }
272
273 // resume playing, after audio_pause()
274 static void audio_resume(void)
275 {
276         //printf("SDL: audio_resume called!\n");        
277         SDL_PauseAudio(0);
278 }
279
280
281 // return: how many bytes can be played without blocking
282 static int get_space(void){
283     return BUFFSIZE - av_fifo_size(buffer);
284 }
285
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){
290
291         if (!(flags & AOPLAY_FINAL_CHUNK))
292         len = (len/ao_data.outburst)*ao_data.outburst;
293 #if 0   
294         int ret;
295
296         /* Audio locking prohibits call of outputaudio */
297         SDL_LockAudio();
298         // copy audio stream into ring-buffer 
299         ret = write_buffer(data, len);
300         SDL_UnlockAudio();
301
302         return ret;
303 #else
304         return write_buffer(data, len);
305 #endif
306 }
307
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;
312 }
313
314
315
316
317
318