Mercurial > mplayer.hg
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 |