diff options
Diffstat (limited to 'libao2')
-rw-r--r-- | libao2/ao_dsound.c | 70 | ||||
-rw-r--r-- | libao2/ao_openal.c | 30 |
2 files changed, 69 insertions, 31 deletions
diff --git a/libao2/ao_dsound.c b/libao2/ao_dsound.c index b33f2949fd..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; } } @@ -421,6 +425,7 @@ static int init(int rate, int channels, int format, int flags) if (!InitDirectSound()) return 0; global_ao->no_persistent_volume = true; + audio_volume = 100; // ok, now create the buffers WAVEFORMATEXTENSIBLE wformat; @@ -544,6 +549,7 @@ static void reset(void) // reset directsound buffer IDirectSoundBuffer_SetCurrentPosition(hdsbuf, 0); write_offset=0; + underrun_check=0; } /** @@ -568,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; @@ -595,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; } @@ -608,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)) @@ -628,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; } diff --git a/libao2/ao_openal.c b/libao2/ao_openal.c index 490aac0eb8..0e04f2cc81 100644 --- a/libao2/ao_openal.c +++ b/libao2/ao_openal.c @@ -28,9 +28,11 @@ #ifdef OPENAL_AL_H #include <OpenAL/alc.h> #include <OpenAL/al.h> +#include <OpenAL/alext.h> #else #include <AL/alc.h> #include <AL/al.h> +#include <AL/alext.h> #endif #include "mp_msg.h" @@ -86,11 +88,27 @@ static int control(int cmd, void *arg) { static void print_help(void) { mp_msg(MSGT_AO, MSGL_FATAL, "\n-ao openal commandline help:\n" - "Example: mplayer -ao openal\n" + "Example: mplayer -ao openal:device=subdevice\n" "\nOptions:\n" + " device=subdevice\n" + " Audio device OpenAL should use. Devices can be listed\n" + " with -ao openal:device=help\n" ); } +static void list_devices(void) { + if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_TRUE) { + mp_msg(MSGT_AO, MSGL_FATAL, "Device listing not supported.\n"); + return; + } + const char *list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); + mp_msg(MSGT_AO, MSGL_FATAL, "OpenAL devices:\n"); + while (list && *list) { + mp_msg(MSGT_AO, MSGL_FATAL, " '%s'\n", list); + list = list + strlen(list) + 1; + } +} + static int init(int rate, int channels, int format, int flags) { float position[3] = {0, 0, 0}; float direction[6] = {0, 0, 1, 0, -1, 0}; @@ -105,7 +123,9 @@ static int init(int rate, int channels, int format, int flags) { ALCint freq = 0; ALCint attribs[] = {ALC_FREQUENCY, rate, 0, 0}; int i; + char *device = NULL; const opt_t subopts[] = { + {"device", OPT_ARG_MSTRZ, &device, NULL}, {NULL} }; global_ao->no_persistent_volume = true; @@ -113,11 +133,15 @@ static int init(int rate, int channels, int format, int flags) { print_help(); return 0; } + if (device && strcmp(device, "help") == 0) { + list_devices(); + goto err_out; + } if (channels > MAX_CHANS) { mp_msg(MSGT_AO, MSGL_FATAL, "[OpenAL] Invalid number of channels: %i\n", channels); goto err_out; } - dev = alcOpenDevice(NULL); + dev = alcOpenDevice(device); if (!dev) { mp_msg(MSGT_AO, MSGL_FATAL, "[OpenAL] could not open device\n"); goto err_out; @@ -146,9 +170,11 @@ static int init(int rate, int channels, int format, int flags) { ao_data.buffersize = CHUNK_SIZE * NUM_BUF; ao_data.outburst = channels * CHUNK_SIZE; tmpbuf = malloc(CHUNK_SIZE); + free(device); return 1; err_out: + free(device); return 0; } |