972
|
1 /*
|
|
2 * ao_sdl.c - libao2 SDLlib Audio Output Driver for MPlayer
|
|
3 *
|
|
4 * This driver is under the same license as MPlayer.
|
|
5 * (http://mplayer.sf.net)
|
|
6 *
|
|
7 * Copyleft 2001 by Felix Bünemann (atmosfear@users.sf.net)
|
|
8 *
|
|
9 * Thanks to Arpi for nice ringbuffer-code!
|
|
10 *
|
|
11 */
|
|
12
|
966
|
13 #include <stdio.h>
|
|
14
|
|
15 #include "audio_out.h"
|
|
16 #include "audio_out_internal.h"
|
|
17
|
972
|
18 #include "../libvo/fastmemcpy.h"
|
|
19
|
966
|
20 static ao_info_t info =
|
|
21 {
|
|
22 "SDLlib audio output",
|
|
23 "sdl",
|
|
24 "Felix Buenemann <atmosfear@users.sourceforge.net>",
|
|
25 ""
|
|
26 };
|
|
27
|
|
28 LIBAO_EXTERN(sdl)
|
|
29
|
|
30 // there are some globals:
|
|
31 // ao_samplerate
|
|
32 // ao_channels
|
|
33 // ao_format
|
|
34 // ao_bps
|
|
35 // ao_outburst
|
|
36 // ao_buffersize
|
|
37
|
983
|
38 extern int verbose;
|
|
39 /* audio driver to be used by SDLlib */
|
|
40 char *sdl_adriver;
|
|
41
|
972
|
42 // Samplesize used by the SDLlib AudioSpec struct
|
|
43 #define SAMPLESIZE 512
|
|
44
|
|
45 // General purpose Ring-buffering routines
|
|
46
|
974
|
47 #define BUFFSIZE 4096
|
|
48 #define NUM_BUFS 16
|
972
|
49
|
|
50 static unsigned char *buffer[NUM_BUFS];
|
|
51
|
|
52 static unsigned int buf_read=0;
|
|
53 static unsigned int buf_write=0;
|
|
54 static unsigned int buf_read_pos=0;
|
|
55 static unsigned int buf_write_pos=0;
|
|
56
|
|
57 static int full_buffers=0;
|
|
58 static int buffered_bytes=0;
|
|
59
|
|
60 static int write_buffer(unsigned char* data,int len){
|
|
61 int len2=0;
|
|
62 int x;
|
|
63 while(len>0){
|
|
64 if(full_buffers==NUM_BUFS) break;
|
|
65 x=BUFFSIZE-buf_write_pos;
|
|
66 if(x>len) x=len;
|
|
67 memcpy(buffer[buf_write]+buf_write_pos,data+len2,x);
|
|
68 len2+=x; len-=x;
|
|
69 buffered_bytes+=x; buf_write_pos+=x;
|
|
70 if(buf_write_pos>=BUFFSIZE){
|
|
71 // block is full, find next!
|
|
72 buf_write=(buf_write+1)%NUM_BUFS;
|
|
73 ++full_buffers;
|
|
74 buf_write_pos=0;
|
|
75 }
|
|
76 }
|
|
77 return len2;
|
|
78 }
|
|
79
|
|
80 static int read_buffer(unsigned char* data,int len){
|
|
81 int len2=0;
|
|
82 int x;
|
|
83 while(len>0){
|
|
84 if(full_buffers==0) break; // no more data buffered!
|
|
85 x=BUFFSIZE-buf_read_pos;
|
|
86 if(x>len) x=len;
|
|
87 memcpy(data+len2,buffer[buf_read]+buf_read_pos,x);
|
|
88 len2+=x; len-=x;
|
|
89 buffered_bytes-=x; buf_read_pos+=x;
|
|
90 if(buf_read_pos>=BUFFSIZE){
|
|
91 // block is empty, find next!
|
|
92 buf_read=(buf_read+1)%NUM_BUFS;
|
|
93 --full_buffers;
|
|
94 buf_read_pos=0;
|
|
95 }
|
|
96 }
|
|
97 return len2;
|
|
98 }
|
|
99
|
|
100 // end ring buffer stuff
|
966
|
101
|
|
102 #ifdef __FreeBSD__
|
|
103 #include <SDL11/SDL.h>
|
|
104 #else
|
|
105 #include <SDL/SDL.h>
|
|
106 #endif
|
|
107
|
|
108 // to set/get/query special features/parameters
|
|
109 static int control(int cmd,int arg){
|
|
110 return -1;
|
|
111 }
|
|
112
|
972
|
113 // SDL Callback function
|
|
114 void outputaudio(void *unused, Uint8 *stream, int len) {
|
|
115 //SDL_MixAudio(stream, read_buffer(buffers, len), len, SDL_MIX_MAXVOLUME);
|
|
116 read_buffer(stream, len);
|
966
|
117 }
|
|
118
|
|
119 // open & setup audio device
|
|
120 // return: 1=success 0=fail
|
|
121 static int init(int rate,int channels,int format,int flags){
|
|
122
|
972
|
123 /* SDL Audio Specifications */
|
|
124 SDL_AudioSpec aspec;
|
|
125
|
|
126 int i;
|
|
127 /* Allocate ring-buffer memory */
|
983
|
128 for(i=0;i<NUM_BUFS;i++) buffer[i]=(unsigned char *) malloc(BUFFSIZE);
|
972
|
129
|
|
130 printf("SDL: Samplerate: %iHz Channels: %s Format %iBit\n", rate, (channels > 1) ? "Stereo" : "Mono", format);
|
983
|
131
|
|
132 if(sdl_adriver) {
|
|
133 setenv("SDL_AUDIODRIVER", sdl_adriver, 1);
|
|
134 printf("SDL: using %s audio driver\n", sdl_adriver);
|
|
135 }
|
|
136
|
966
|
137
|
|
138 /* The desired audio frequency in samples-per-second. */
|
|
139 aspec.freq = rate;
|
|
140
|
|
141 /* The desired audio format (see SDL_AudioSpec) */
|
972
|
142 aspec.format = (format == 16) ? AUDIO_S16 : AUDIO_U8;
|
966
|
143
|
|
144 /* Number of channels (mono/stereo) */
|
|
145 aspec.channels = channels;
|
|
146
|
|
147 /* 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 */
|
972
|
148 aspec.samples = SAMPLESIZE;
|
966
|
149
|
|
150 /* 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:
|
|
151 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. */
|
972
|
152 aspec.callback = outputaudio;
|
966
|
153
|
|
154 /* This pointer is passed as the first parameter to the callback function. */
|
|
155 aspec.userdata = NULL;
|
|
156
|
972
|
157 /* initialize the SDL Audio system */
|
|
158 if (SDL_Init (SDL_INIT_AUDIO/*|SDL_INIT_NOPARACHUTE*/)) {
|
|
159 printf("SDL: Initializing of SDL Audio failed: %s.\n", SDL_GetError());
|
|
160 return 0;
|
|
161 }
|
|
162
|
966
|
163 /* Open the audio device and start playing sound! */
|
|
164 if(SDL_OpenAudio(&aspec, NULL) < 0) {
|
|
165 printf("SDL: Unable to open audio: %s\n", SDL_GetError());
|
|
166 return(0);
|
|
167 }
|
|
168
|
983
|
169 if(verbose) printf("SDL: buf size = %d\n",aspec.size);
|
975
|
170 if(ao_buffersize==-1) ao_buffersize=aspec.size;
|
974
|
171
|
966
|
172 /* unsilence audio, if callback is ready */
|
|
173 SDL_PauseAudio(0);
|
|
174
|
|
175 return 1;
|
|
176 }
|
|
177
|
|
178 // close audio device
|
|
179 static void uninit(){
|
983
|
180 if(verbose) printf("SDL: Audio Subsystem shutting down!\n");
|
966
|
181 SDL_CloseAudio();
|
972
|
182 SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
966
|
183 }
|
|
184
|
|
185 // stop playing and empty buffers (for seeking/pause)
|
|
186 static void reset(){
|
972
|
187
|
|
188 /* Reset ring-buffer state */
|
|
189 buf_read=0;
|
|
190 buf_write=0;
|
|
191 buf_read_pos=0;
|
|
192 buf_write_pos=0;
|
|
193
|
|
194 full_buffers=0;
|
|
195 buffered_bytes=0;
|
966
|
196
|
|
197 }
|
|
198
|
|
199 // return: how many bytes can be played without blocking
|
|
200 static int get_space(){
|
972
|
201 return (NUM_BUFS-full_buffers)*BUFFSIZE - buf_write_pos;
|
966
|
202 }
|
|
203
|
|
204 // plays 'len' bytes of 'data'
|
|
205 // it should round it down to outburst*n
|
|
206 // return: number of bytes played
|
|
207 static int play(void* data,int len,int flags){
|
972
|
208
|
985
|
209 #if 0
|
972
|
210 int ret;
|
966
|
211
|
972
|
212 /* Audio locking prohibits call of outputaudio */
|
966
|
213 SDL_LockAudio();
|
972
|
214 // copy audio stream into ring-buffer
|
|
215 ret = write_buffer(data, len);
|
966
|
216 SDL_UnlockAudio();
|
|
217
|
972
|
218 return ret;
|
|
219 #else
|
|
220 return write_buffer(data, len);
|
|
221 #endif
|
966
|
222 }
|
|
223
|
|
224 // return: how many unplayed bytes are in the buffer
|
|
225 static int get_delay(){
|
974
|
226 return buffered_bytes + ao_buffersize;
|
966
|
227 }
|
|
228
|
|
229
|
|
230
|
|
231
|
|
232
|
|
233
|