--- /home/reimar/MPlayer-cvs/libao2/ao_sdl.c 2004-07-28 14:45:38.000000000 +0200 +++ libao2/ao_sdl.c 2004-08-01 21:34:00.000000000 +0200 @@ -47,66 +47,72 @@ // General purpose Ring-buffering routines -#define BUFFSIZE 4096 -#define NUM_BUFS 8 +#define BUFFSIZE (8 * 4096) -static unsigned char *buffer[NUM_BUFS]; +static unsigned char *buffer; -static unsigned int buf_read=0; -static unsigned int buf_write=0; -static unsigned int buf_read_pos=0; -static unsigned int buf_write_pos=0; +// may only be modified by SDL's playback thread or while it is stopped +static volatile int read_pos; +// may only be modified by mplayer's thread +static volatile int write_pos; #ifdef USE_SDL_INTERNAL_MIXER static unsigned char volume=SDL_MIX_MAXVOLUME; #endif -static int full_buffers=0; -static int buffered_bytes=0; +// may only be called by mplayer's thread +// return value may change between immediately following two calls, +// and the real number of free bytes might be larger! +static int buf_free() { + int free = read_pos - write_pos - 1; + if (free < 0) free += BUFFSIZE; + return free; +} + +// may only be called by SDL's playback thread +// return value may change between immediately following two calls, +// and the real number of buffered bytes might be larger! +static int buf_used() { + int used = write_pos - read_pos; + if (used < 0) used += BUFFSIZE; + return used; +} static int write_buffer(unsigned char* data,int len){ - int len2=0; - int x; - while(len>0){ - if(full_buffers==NUM_BUFS) break; - x=BUFFSIZE-buf_write_pos; - if(x>len) x=len; - memcpy(buffer[buf_write]+buf_write_pos,data+len2,x); - if (buf_write_pos==0) - ++full_buffers; - len2+=x; len-=x; - buffered_bytes+=x; buf_write_pos+=x; - if(buf_write_pos>=BUFFSIZE){ - // block is full, find next! - buf_write=(buf_write+1)%NUM_BUFS; - buf_write_pos=0; - } + int first_len = BUFFSIZE - write_pos; + int free = buf_free(); + if (len > free) len = free; + if (first_len > len) first_len = len; + // till end of buffer + memcpy (&buffer[write_pos], data, first_len); + if (len > first_len) { // we have to wrap around + // remaining part from beginning of buffer + memcpy (buffer, &data[first_len], len - first_len); } - return len2; + write_pos = (write_pos + len) % BUFFSIZE; + return len; } static int read_buffer(unsigned char* data,int len){ - int len2=0; - int x; - while(len>0){ - if(buffered_bytes==0) break; // no more data buffered! - x=BUFFSIZE-buf_read_pos; - if(x>len) x=len; - if (x>buffered_bytes) x=buffered_bytes; + int first_len = BUFFSIZE - read_pos; + int buffered = buf_used(); + if (len > buffered) len = buffered; + if (first_len > len) first_len = len; + // till end of buffer +#ifdef USE_SDL_INTERNAL_MIXER + SDL_MixAudio (data, &buffer[read_pos], first_len, volume); +#else + memcpy (data, &buffer[read_pos], first_len); +#endif + if (len > first_len) { // we have to wrap around + // remaining part from beginning of buffer #ifdef USE_SDL_INTERNAL_MIXER - SDL_MixAudio(data+len2,buffer[buf_read]+buf_read_pos,x,volume); + SDL_MixAudio (&data[first_len], buffer, len - first_len, volume); #else - memcpy(data+len2,buffer[buf_read]+buf_read_pos,x); + memcpy (&data[first_len], buffer, len - first_len); #endif - len2+=x; len-=x; - buffered_bytes-=x; buf_read_pos+=x; - if(buf_read_pos>=BUFFSIZE){ - // block is empty, find next! - buf_read=(buf_read+1)%NUM_BUFS; - --full_buffers; - buf_read_pos=0; - } } - return len2; + read_pos = (read_pos + len) % BUFFSIZE; + return len; } // end ring buffer stuff @@ -167,9 +173,8 @@ /* SDL Audio Specifications */ SDL_AudioSpec aspec, obtained; - int i; /* Allocate ring-buffer memory */ - for(i=0;i 1) ? "Stereo" : "Mono", audio_out_format_name(format)); @@ -271,6 +276,7 @@ mp_msg(MSGT_AO,MSGL_V,"SDL: buf size = %d\n",obtained.size); ao_data.buffersize=obtained.size; + reset(); /* unsilence audio, if callback is ready */ SDL_PauseAudio(0); @@ -280,7 +286,7 @@ // close audio device static void uninit(int immed){ mp_msg(MSGT_AO,MSGL_V,"SDL: Audio Subsystem shutting down!\n"); - while(buffered_bytes > 0) + while(buf_free() < BUFFSIZE - 1) usec_sleep(50000); SDL_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); @@ -291,15 +297,11 @@ //printf("SDL: reset called!\n"); + SDL_PauseAudio(1); /* Reset ring-buffer state */ - buf_read=0; - buf_write=0; - buf_read_pos=0; - buf_write_pos=0; - - full_buffers=0; - buffered_bytes=0; - + read_pos = 0; + write_pos = 0; + SDL_PauseAudio(0); } // stop playing, keep buffers (for pause) @@ -321,7 +323,7 @@ // return: how many bytes can be played without blocking static int get_space(){ - return NUM_BUFS*BUFFSIZE - buffered_bytes; + return buf_free(); } // plays 'len' bytes of 'data' @@ -347,7 +349,8 @@ // return: delay in seconds between first and last sample in buffer static float get_delay(){ - return (float)(buffered_bytes + ao_data.buffersize)/(float)ao_data.bps; + int buffered = BUFFSIZE - 1 - buf_free(); // could be less + return (float)(buffered + ao_data.buffersize)/(float)ao_data.bps; }