comparison libao2/ao_sdl.c @ 13832:2f8cfe66dbfd

Different buffering scheme, avoiding possible races (SDL is using threads!).
author reimar
date Sun, 31 Oct 2004 21:02:47 +0000
parents c1955840883d
children 48ce49693b3c
comparison
equal deleted inserted replaced
13831:719c3c818335 13832:2f8cfe66dbfd
44 #define SAMPLESIZE 2048 44 #define SAMPLESIZE 2048
45 #else 45 #else
46 #define SAMPLESIZE 1024 46 #define SAMPLESIZE 1024
47 #endif 47 #endif
48 48
49 // General purpose Ring-buffering routines 49 #define CHUNK_SIZE 4096
50 50 #define NUM_CHUNKS 8
51 #define BUFFSIZE 4096 51 // This type of ring buffer may never fill up completely, at least
52 #define NUM_BUFS 8 52 // one byte must always be unused.
53 53 // For performance reasons (alignment etc.) one whole chunk always stays
54 static unsigned char *buffer[NUM_BUFS]; 54 // empty, not only one byte.
55 55 #define BUFFSIZE ((NUM_CHUNKS + 1) * CHUNK_SIZE)
56 static unsigned int buf_read=0; 56
57 static unsigned int buf_write=0; 57 static unsigned char *buffer;
58 static unsigned int buf_read_pos=0; 58
59 static unsigned int buf_write_pos=0; 59 // may only be modified by SDL's playback thread or while it is stopped
60 static volatile int read_pos;
61 // may only be modified by mplayer's thread
62 static volatile int write_pos;
60 #ifdef USE_SDL_INTERNAL_MIXER 63 #ifdef USE_SDL_INTERNAL_MIXER
61 static unsigned char volume=SDL_MIX_MAXVOLUME; 64 static unsigned char volume=SDL_MIX_MAXVOLUME;
62 #endif 65 #endif
63 static int full_buffers=0; 66
64 static int buffered_bytes=0; 67 // may only be called by mplayer's thread
65 68 // return value may change between immediately following two calls,
69 // and the real number of free bytes might be larger!
70 static int buf_free() {
71 int free = read_pos - write_pos - CHUNK_SIZE;
72 if (free < 0) free += BUFFSIZE;
73 return free;
74 }
75
76 // may only be called by SDL's playback thread
77 // return value may change between immediately following two calls,
78 // and the real number of buffered bytes might be larger!
79 static int buf_used() {
80 int used = write_pos - read_pos;
81 if (used < 0) used += BUFFSIZE;
82 return used;
83 }
66 84
67 static int write_buffer(unsigned char* data,int len){ 85 static int write_buffer(unsigned char* data,int len){
68 int len2=0; 86 int first_len = BUFFSIZE - write_pos;
69 int x; 87 int free = buf_free();
70 while(len>0){ 88 if (len > free) len = free;
71 if(full_buffers==NUM_BUFS) break; 89 if (first_len > len) first_len = len;
72 x=BUFFSIZE-buf_write_pos; 90 // till end of buffer
73 if(x>len) x=len; 91 memcpy (&buffer[write_pos], data, first_len);
74 memcpy(buffer[buf_write]+buf_write_pos,data+len2,x); 92 if (len > first_len) { // we have to wrap around
75 if (buf_write_pos==0) 93 // remaining part from beginning of buffer
76 ++full_buffers; 94 memcpy (buffer, &data[first_len], len - first_len);
77 len2+=x; len-=x;
78 buffered_bytes+=x; buf_write_pos+=x;
79 if(buf_write_pos>=BUFFSIZE){
80 // block is full, find next!
81 buf_write=(buf_write+1)%NUM_BUFS;
82 buf_write_pos=0;
83 }
84 } 95 }
85 return len2; 96 write_pos = (write_pos + len) % BUFFSIZE;
97 return len;
86 } 98 }
87 99
88 static int read_buffer(unsigned char* data,int len){ 100 static int read_buffer(unsigned char* data,int len){
89 int len2=0; 101 int first_len = BUFFSIZE - read_pos;
90 int x; 102 int buffered = buf_used();
91 while(len>0){ 103 if (len > buffered) len = buffered;
92 if(buffered_bytes==0) break; // no more data buffered! 104 if (first_len > len) first_len = len;
93 x=BUFFSIZE-buf_read_pos; 105 // till end of buffer
94 if(x>len) x=len;
95 if (x>buffered_bytes) x=buffered_bytes;
96 #ifdef USE_SDL_INTERNAL_MIXER 106 #ifdef USE_SDL_INTERNAL_MIXER
97 SDL_MixAudio(data+len2,buffer[buf_read]+buf_read_pos,x,volume); 107 SDL_MixAudio (data, &buffer[read_pos], first_len, volume);
98 #else 108 #else
99 memcpy(data+len2,buffer[buf_read]+buf_read_pos,x); 109 memcpy (data, &buffer[read_pos], first_len);
100 #endif 110 #endif
101 len2+=x; len-=x; 111 if (len > first_len) { // we have to wrap around
102 buffered_bytes-=x; buf_read_pos+=x; 112 // remaining part from beginning of buffer
103 if(buf_read_pos>=BUFFSIZE){ 113 #ifdef USE_SDL_INTERNAL_MIXER
104 // block is empty, find next! 114 SDL_MixAudio (&data[first_len], buffer, len - first_len, volume);
105 buf_read=(buf_read+1)%NUM_BUFS; 115 #else
106 --full_buffers; 116 memcpy (&data[first_len], buffer, len - first_len);
107 buf_read_pos=0; 117 #endif
108 }
109 } 118 }
110 return len2; 119 read_pos = (read_pos + len) % BUFFSIZE;
120 return len;
111 } 121 }
112 122
113 // end ring buffer stuff 123 // end ring buffer stuff
114 124
115 #if defined(__MINGW32__) || defined(HPUX) || defined(sgi) || (defined(sun) && defined(__svr4__)) 125 #if defined(__MINGW32__) || defined(HPUX) || defined(sgi) || (defined(sun) && defined(__svr4__))
166 static int init(int rate,int channels,int format,int flags){ 176 static int init(int rate,int channels,int format,int flags){
167 177
168 /* SDL Audio Specifications */ 178 /* SDL Audio Specifications */
169 SDL_AudioSpec aspec, obtained; 179 SDL_AudioSpec aspec, obtained;
170 180
171 int i;
172 /* Allocate ring-buffer memory */ 181 /* Allocate ring-buffer memory */
173 for(i=0;i<NUM_BUFS;i++) buffer[i]=(unsigned char *) malloc(BUFFSIZE); 182 buffer = (unsigned char *) malloc(BUFFSIZE);
174 183
175 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_SDL_INFO, rate, (channels > 1) ? "Stereo" : "Mono", audio_out_format_name(format)); 184 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_SDL_INFO, rate, (channels > 1) ? "Stereo" : "Mono", audio_out_format_name(format));
176 185
177 if(ao_subdevice) { 186 if(ao_subdevice) {
178 setenv("SDL_AUDIODRIVER", ao_subdevice, 1); 187 setenv("SDL_AUDIODRIVER", ao_subdevice, 1);
270 } 279 }
271 280
272 mp_msg(MSGT_AO,MSGL_V,"SDL: buf size = %d\n",obtained.size); 281 mp_msg(MSGT_AO,MSGL_V,"SDL: buf size = %d\n",obtained.size);
273 ao_data.buffersize=obtained.size; 282 ao_data.buffersize=obtained.size;
274 283
284 reset();
275 /* unsilence audio, if callback is ready */ 285 /* unsilence audio, if callback is ready */
276 SDL_PauseAudio(0); 286 SDL_PauseAudio(0);
277 287
278 return 1; 288 return 1;
279 } 289 }
280 290
281 // close audio device 291 // close audio device
282 static void uninit(int immed){ 292 static void uninit(int immed){
283 mp_msg(MSGT_AO,MSGL_V,"SDL: Audio Subsystem shutting down!\n"); 293 mp_msg(MSGT_AO,MSGL_V,"SDL: Audio Subsystem shutting down!\n");
284 while(buffered_bytes > 0) 294 while(buf_free() < BUFFSIZE - CHUNK_SIZE)
285 usec_sleep(50000); 295 usec_sleep(50000);
286 SDL_CloseAudio(); 296 SDL_CloseAudio();
287 SDL_QuitSubSystem(SDL_INIT_AUDIO); 297 SDL_QuitSubSystem(SDL_INIT_AUDIO);
288 } 298 }
289 299
290 // stop playing and empty buffers (for seeking/pause) 300 // stop playing and empty buffers (for seeking/pause)
291 static void reset(){ 301 static void reset(){
292 302
293 //printf("SDL: reset called!\n"); 303 //printf("SDL: reset called!\n");
294 304
305 SDL_PauseAudio(1);
295 /* Reset ring-buffer state */ 306 /* Reset ring-buffer state */
296 buf_read=0; 307 read_pos = 0;
297 buf_write=0; 308 write_pos = 0;
298 buf_read_pos=0; 309 SDL_PauseAudio(0);
299 buf_write_pos=0;
300
301 full_buffers=0;
302 buffered_bytes=0;
303
304 } 310 }
305 311
306 // stop playing, keep buffers (for pause) 312 // stop playing, keep buffers (for pause)
307 static void audio_pause() 313 static void audio_pause()
308 { 314 {
320 } 326 }
321 327
322 328
323 // return: how many bytes can be played without blocking 329 // return: how many bytes can be played without blocking
324 static int get_space(){ 330 static int get_space(){
325 return NUM_BUFS*BUFFSIZE - buffered_bytes; 331 return buf_free();
326 } 332 }
327 333
328 // plays 'len' bytes of 'data' 334 // plays 'len' bytes of 'data'
329 // it should round it down to outburst*n 335 // it should round it down to outburst*n
330 // return: number of bytes played 336 // return: number of bytes played
346 #endif 352 #endif
347 } 353 }
348 354
349 // return: delay in seconds between first and last sample in buffer 355 // return: delay in seconds between first and last sample in buffer
350 static float get_delay(){ 356 static float get_delay(){
351 return (float)(buffered_bytes + ao_data.buffersize)/(float)ao_data.bps; 357 int buffered = BUFFSIZE - CHUNK_SIZE - buf_free(); // could be less
352 } 358 return (float)(buffered + ao_data.buffersize)/(float)ao_data.bps;
353 359 }
354 360
355 361
356 362
357 363
358 364
365