diff options
Diffstat (limited to 'libao2/ao_dsound.c')
-rw-r--r-- | libao2/ao_dsound.c | 72 |
1 files changed, 43 insertions, 29 deletions
diff --git a/libao2/ao_dsound.c b/libao2/ao_dsound.c index 63cc02e92c..f1fc0dd00a 100644 --- a/libao2/ao_dsound.c +++ b/libao2/ao_dsound.c @@ -121,8 +121,10 @@ static int min_free_space = 0; ///if the free space is below this val ///there will always be at least this amout of free space to prevent ///get_space() from returning wrong values when buffer is 100% full. ///will be replaced with nBlockAlign in init() +static int underrun_check = 0; ///0 or last reported free space (underrun detection) static int device_num = 0; ///wanted device number static GUID device; ///guid of the device +static int audio_volume; /***************************************************************************************/ @@ -314,6 +316,8 @@ static int write_buffer(unsigned char *data, int len) LPVOID lpvPtr2; DWORD dwBytes2; + underrun_check = 0; + // Lock the buffer res = IDirectSoundBuffer_Lock(hdsbuf,write_offset, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); // If the buffer was lost, restore and retry lock. @@ -391,16 +395,16 @@ static int control(int cmd, void *arg) switch (cmd) { case AOCONTROL_GET_VOLUME: { ao_control_vol_t* vol = (ao_control_vol_t*)arg; - IDirectSoundBuffer_GetVolume(hdsbuf, &volume); - vol->left = vol->right = pow(10.0, (float)(volume+10000) / 5000.0); - //printf("ao_dsound: volume: %f\n",vol->left); + vol->left = vol->right = audio_volume; return CONTROL_OK; } case AOCONTROL_SET_VOLUME: { ao_control_vol_t* vol = (ao_control_vol_t*)arg; - volume = (DWORD)(log10(vol->right) * 5000.0) - 10000; + volume = audio_volume = vol->right; + if (volume < 1) + volume = 1; + volume = (DWORD)(log10(volume) * 5000.0) - 10000; IDirectSoundBuffer_SetVolume(hdsbuf, volume); - //printf("ao_dsound: volume: %f\n",vol->left); return CONTROL_OK; } } @@ -420,6 +424,9 @@ static int init(int rate, int channels, int format, int flags) int res; if (!InitDirectSound()) return 0; + global_ao->no_persistent_volume = true; + audio_volume = 100; + // ok, now create the buffers WAVEFORMATEXTENSIBLE wformat; DSBUFFERDESC dsbpridesc; @@ -542,6 +549,7 @@ static void reset(void) // reset directsound buffer IDirectSoundBuffer_SetCurrentPosition(hdsbuf, 0); write_offset=0; + underrun_check=0; } /** @@ -566,22 +574,16 @@ static void audio_resume(void) */ static void uninit(int immed) { - if(immed)reset(); - else{ - DWORD status; - IDirectSoundBuffer_Play(hdsbuf, 0, 0, 0); - while(!IDirectSoundBuffer_GetStatus(hdsbuf,&status) && (status&DSBSTATUS_PLAYING)) - usec_sleep(20000); - } + if (!immed) + usec_sleep(get_delay() * 1000000); + reset(); + DestroyBuffer(); UninitDirectSound(); } -/** -\brief find out how many bytes can be written into the audio buffer without -\return free space in bytes, has to return 0 if the buffer is almost full -*/ -static int get_space(void) +// return exact number of free (safe to write) bytes +static int check_free_buffer_size(void) { int space; DWORD play_offset; @@ -593,6 +595,28 @@ static int get_space(void) // write_cursor is the position after which it is assumed to be save to write data // write_offset is the postion where we actually write the data to if(space > buffer_size)space -= buffer_size; // write_offset < play_offset + // Check for buffer underruns. An underrun happens if DirectSound + // started to play old data beyond the current write_offset. Detect this + // by checking whether the free space shrinks, even though no data was + // written (i.e. no write_buffer). Doesn't always work, but the only + // reason we need this is to deal with the situation when playback ends, + // and the buffer is only half-filled. + if (space < underrun_check) { + // there's no useful data in the buffers + space = buffer_size; + reset(); + } + underrun_check = space; + return space; +} + +/** +\brief find out how many bytes can be written into the audio buffer without +\return free space in bytes, has to return 0 if the buffer is almost full +*/ +static int get_space(void) +{ + int space = check_free_buffer_size(); if(space < min_free_space)return 0; return space-min_free_space; } @@ -606,13 +630,7 @@ static int get_space(void) */ static int play(void* data, int len, int flags) { - DWORD play_offset; - int space; - - // make sure we have enough space to write data - IDirectSoundBuffer_GetCurrentPosition(hdsbuf,&play_offset,NULL); - space=buffer_size-(write_offset-play_offset); - if(space > buffer_size)space -= buffer_size; // write_offset < play_offset + int space = check_free_buffer_size(); if(space < len) len = space; if (!(flags & AOPLAY_FINAL_CHUNK)) @@ -626,10 +644,6 @@ static int play(void* data, int len, int flags) */ static float get_delay(void) { - DWORD play_offset; - int space; - IDirectSoundBuffer_GetCurrentPosition(hdsbuf,&play_offset,NULL); - space=play_offset-write_offset; - if(space <= 0)space += buffer_size; + int space = check_free_buffer_size(); return (float)(buffer_size - space) / (float)ao_data.bps; } |