diff --git a/audio/alsa.c b/audio/alsa.c index a32154e46f..ec9f0173ba 100644 --- a/audio/alsa.c +++ b/audio/alsa.c @@ -30,6 +30,8 @@ typedef struct alsa snd_pcm_t *pcm; bool nonblock; bool has_float; + + size_t buffer_size; } alsa_t; static bool alsa_use_float(void *data) @@ -62,8 +64,8 @@ static void *alsa_init(const char *device, unsigned rate, unsigned latency) if (device) alsa_dev = device; - unsigned int latency_usec = latency * 1000; - unsigned int channels = 2; + unsigned latency_usec = latency * 1000; + unsigned channels = 2; unsigned periods = 4; snd_pcm_uframes_t buffer_size; snd_pcm_format_t format; @@ -89,6 +91,7 @@ static void *alsa_init(const char *device, unsigned rate, unsigned latency) SSNES_LOG("ALSA: Period size: %d frames\n", (int)buffer_size); snd_pcm_hw_params_get_buffer_size(params, &buffer_size); SSNES_LOG("ALSA: Buffer size: %d frames\n", (int)buffer_size); + alsa->buffer_size = snd_pcm_frames_to_bytes(alsa->pcm, buffer_size); TRY_ALSA(snd_pcm_sw_params_malloc(&sw_params)); TRY_ALSA(snd_pcm_sw_params_current(alsa->pcm, sw_params)); @@ -190,6 +193,18 @@ static void alsa_free(void *data) } } +static size_t alsa_write_avail(void *data) +{ + alsa_t *alsa = (alsa_t*)data; + return snd_pcm_frames_to_bytes(alsa->pcm, snd_pcm_avail_update(alsa->pcm)); +} + +static size_t alsa_buffer_size(void *data) +{ + alsa_t *alsa = (alsa_t*)data; + return alsa->buffer_size; +} + const audio_driver_t audio_alsa = { alsa_init, alsa_write, @@ -198,6 +213,8 @@ const audio_driver_t audio_alsa = { alsa_set_nonblock_state, alsa_free, alsa_use_float, - "alsa" + "alsa", + alsa_write_avail, + alsa_buffer_size, }; diff --git a/audio/dsound.c b/audio/dsound.c index ce7b03d219..976843b7cf 100644 --- a/audio/dsound.c +++ b/audio/dsound.c @@ -373,6 +373,21 @@ static ssize_t dsound_write(void *data, const void *buf_, size_t size) return written; } +static size_t dsound_write_avail(void *data) +{ + dsound_t *ds = (dsound_t*)data; + EnterCriticalSection(&ds->crit); + size_t avail = fifo_write_avail(ds->buffer); + LeaveCriticalSection(&ds->crit); + return avail; +} + +static size_t dsound_buffer_size(void *data) +{ + dsound_t *ds = (dsound_t*)data; + return 4 * 1024; +} + const audio_driver_t audio_dsound = { dsound_init, dsound_write, @@ -381,6 +396,8 @@ const audio_driver_t audio_dsound = { dsound_set_nonblock_state, dsound_free, NULL, - "dsound" + "dsound", + dsound_write_avail, + dsound_buffer_size, }; diff --git a/audio/oss.c b/audio/oss.c index 4d01778a12..e147a64f82 100644 --- a/audio/oss.c +++ b/audio/oss.c @@ -135,7 +135,7 @@ static void oss_set_nonblock_state(void *data, bool state) else rc = fcntl(*fd, F_SETFL, fcntl(*fd, F_GETFL) & (~O_NONBLOCK)); if (rc != 0) - fprintf(stderr, "SSNES [ERROR]: Could not set nonblocking on OSS file descriptor. Will not be able to fast-forward.\n"); + SSNES_WARN("Could not set nonblocking on OSS file descriptor. Will not be able to fast-forward.\n"); } static void oss_free(void *data) @@ -147,6 +147,34 @@ static void oss_free(void *data) free(fd); } +static size_t oss_write_avail(void *data) +{ + int *fd = (int*)data; + + audio_buf_info info; + if (ioctl(*fd, SNDCTL_DSP_GETOSPACE, &info) < 0) + { + SSNES_ERR("SNDCTL_DSP_GETOSPACE failed ...\n"); + return 0; + } + + return info.bytes; +} + +static size_t oss_buffer_size(void *data) +{ + int *fd = (int*)data; + + audio_buf_info info; + if (ioctl(*fd, SNDCTL_DSP_GETOSPACE, &info) < 0) + { + SSNES_ERR("SNDCTL_DSP_GETOSPACE failed ...\n"); + return 1; // Return something non-zero to avoid SIGFPE. + } + + return info.fragsize * info.fragstotal; +} + const audio_driver_t audio_oss = { oss_init, oss_write, @@ -155,6 +183,8 @@ const audio_driver_t audio_oss = { oss_set_nonblock_state, oss_free, NULL, - "oss" + "oss", + oss_write_avail, + oss_buffer_size, }; diff --git a/audio/rsound.c b/audio/rsound.c index bdf965106a..4ac89fcba3 100644 --- a/audio/rsound.c +++ b/audio/rsound.c @@ -183,7 +183,7 @@ static void rs_free(void *data) static size_t rs_write_avail(void *data) { - rsd_t *rsd = data; + rsd_t *rsd = (rsd_t*)data; if (rsd->has_error) return 0;