From: Grazvydas Ignotas Date: Sun, 23 Jun 2013 23:42:36 +0000 (+0300) Subject: add preliminary alsa driver too X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=32d23d03ac9f6f105b2fdb3f1ec15db55e313e08;p=libpicofe.git add preliminary alsa driver too --- diff --git a/linux/sndout_alsa.c b/linux/sndout_alsa.c new file mode 100644 index 0000000..c10e39a --- /dev/null +++ b/linux/sndout_alsa.c @@ -0,0 +1,139 @@ +/* + * (C) notaz, 2013 + * + * This work is licensed under the terms of any of these licenses + * (at your option): + * - GNU GPL, version 2 or later. + * - GNU LGPL, version 2.1 or later. + * - MAME license. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include + +#include "sndout_alsa.h" + +static snd_pcm_t *handle; +static snd_pcm_uframes_t buffer_size, period_size; +static unsigned int channels; +static void *silent_period; + +int sndout_alsa_init(void) +{ + int ret; + + ret = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); + if (ret != 0) + return -1; + + return 0; +} + +int sndout_alsa_start(int rate_, int stereo) +{ + snd_pcm_hw_params_t *hwparams = NULL; + unsigned int rate = rate_; + int samples, shift; + int ret; + + samples = rate * 40 / 1000; + for (shift = 8; (1 << shift) < samples; shift++) + ; + period_size = 1 << shift; + buffer_size = 8 * period_size; + + snd_pcm_hw_params_alloca(&hwparams); + + ret = snd_pcm_hw_params_any(handle, hwparams); + ret |= snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); + ret |= snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE); + ret |= snd_pcm_hw_params_set_channels(handle, hwparams, stereo ? 2 : 1); + ret |= snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, 0); + ret |= snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size); + ret |= snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, NULL); + + if (ret != 0) { + fprintf(stderr, "sndout_alsa: failed to set hwparams\n"); + return -1; + } + + ret = snd_pcm_hw_params(handle, hwparams); + if (ret != 0) { + fprintf(stderr, "sndout_alsa: failed to apply hwparams: %d\n", + ret); + return -1; + } + + snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); + snd_pcm_hw_params_get_period_size(hwparams, &period_size, NULL); + snd_pcm_hw_params_get_channels(hwparams, &channels); + + silent_period = realloc(silent_period, period_size * 2 * channels); + if (silent_period != NULL) + memset(silent_period, 0, period_size * 2 * channels); + + ret = snd_pcm_prepare(handle); + ret |= snd_pcm_start(handle); + + if (ret != 0) { + fprintf(stderr, "sndout_alsa: failed to start pcm: %d\n", + ret); + return -1; + } + + return 0; +} + +void sndout_alsa_stop(void) +{ + // nothing? +} + +void sndout_alsa_wait(void) +{ + snd_pcm_sframes_t left; + + while (1) + { + left = snd_pcm_avail(handle); + if (left < 0 || left >= buffer_size / 2) + break; + + usleep(4000); + } +} + +int sndout_alsa_write_nb(const void *samples, int len) +{ + snd_pcm_sframes_t left; + int ret; + + len /= 2; + if (channels == 2) + len /= 2; + + left = snd_pcm_avail(handle); + if (left >= 0 && left < len) + return 0; + + ret = snd_pcm_writei(handle, samples, len); + if (ret < 0) { + ret = snd_pcm_recover(handle, ret, 1); + if (ret != 0) + fprintf(stderr, "sndout_alsa snd_pcm_recover: %d\n", ret); + + if (silent_period) + snd_pcm_writei(handle, silent_period, period_size); + snd_pcm_writei(handle, samples, len); + } + + return len; +} + +void sndout_alsa_exit(void) +{ + snd_pcm_close(handle); + handle = NULL; +} diff --git a/linux/sndout_alsa.h b/linux/sndout_alsa.h new file mode 100644 index 0000000..52e95e3 --- /dev/null +++ b/linux/sndout_alsa.h @@ -0,0 +1,7 @@ + +int sndout_alsa_init(void); +int sndout_alsa_start(int rate, int stereo); +void sndout_alsa_stop(void); +void sndout_alsa_wait(void); +int sndout_alsa_write_nb(const void *samples, int len); +void sndout_alsa_exit(void); diff --git a/sndout.c b/sndout.c index ba34f3c..2750423 100644 --- a/sndout.c +++ b/sndout.c @@ -13,6 +13,7 @@ #include #include "linux/sndout_oss.h" +#include "linux/sndout_alsa.h" #include "sndout_sdl.h" #include "sndout.h" @@ -58,6 +59,9 @@ static struct sndout_driver sndout_avail[] = #ifdef HAVE_SDL SNDOUT_DRIVER(sdl), #endif +#ifdef HAVE_ALSA + SNDOUT_DRIVER(alsa), +#endif #ifdef HAVE_OSS SNDOUT_DRIVER(oss), #endif