aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.org.uk>2009-07-19 23:25:26 +0100
committerThomas White <taw@bitwiz.org.uk>2009-07-19 23:25:26 +0100
commit1f734762998ff92dff6173e877ece014a288b7b5 (patch)
tree342a418c593e3dd634af0b3ecf88b9b538488064
parentc324c1f0bc2974d154a2dd2ff1472d652f3f45c2 (diff)
Use ALSA directly for audio
I'm really bored of hearing about problems with the audio in OpenMooCow, when these problems are due to SDL's audio subsystem. Problems have arised from configuration problems somewhere in the OE configuration for Openmoko, or from a strange kernel interaction seen in Debian and Fedora. With this commit, the audio module of OpenMooCow will use ALSA directly, circumventing all these problems. There should no longer be any need for fallbacks.
-rw-r--r--configure.ac15
-rw-r--r--src/audio.c169
-rw-r--r--src/types.h15
3 files changed, 126 insertions, 73 deletions
diff --git a/configure.ac b/configure.ac
index 712ddcd..a1898a1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -30,7 +30,7 @@ AM_PATH_GTK_2_0(2.0.0,,AC_MSG_ERROR([
*** Please make sure you have the GTK+ development files installed. The
*** latest version of GTK+ is always available at http://www.gtk.org/.]))
-AC_MSG_CHECKING([SDL])
+AC_MSG_CHECKING([for SDL])
if $PKG_CONFIG sdl ; then
LIBSDL_CFLAGS=`$PKG_CONFIG --cflags sdl`
LIBSDL_LIBS=`$PKG_CONFIG --libs sdl`
@@ -40,7 +40,16 @@ else
AC_MSG_ERROR([*** SDL not found. Do you have 'libsdl-dev' or similar installed?])
fi
-CFLAGS="$CFLAGS $GTK_CFLAGS $LIBSDL_CFLAGS"
-LIBS="$LIBS $GTK_LIBS $LIBSDL_LIBS -lgthread-2.0"
+AC_MSG_CHECKING([for ALSA])
+if $PKG_CONFIG sdl ; then
+ ALSA_CFLAGS=`$PKG_CONFIG --cflags alsa`
+ ALSA_LIBS=`$PKG_CONFIG --libs alsa`
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([not found])
+fi
+
+CFLAGS="$CFLAGS $GTK_CFLAGS $LIBSDL_CFLAGS $ALSA_CFLAGS"
+LIBS="$LIBS $GTK_LIBS $LIBSDL_LIBS $ALSA_LIBS -lgthread-2.0"
AC_OUTPUT(Makefile src/Makefile data/Makefile)
diff --git a/src/audio.c b/src/audio.c
index 1ec8108..5120f5b 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -32,6 +32,7 @@
#include <stdio.h>
#include <SDL.h>
#include <SDL_audio.h>
+#include <alsa/asoundlib.h>
#include <math.h>
#include <sys/types.h>
#include <unistd.h>
@@ -43,30 +44,6 @@
static AudioContext *audio_context = NULL;
-static void audio_mix(void *data, Uint8 *stream8, int len)
-{
- AudioContext *a = data;
- int j;
- Sint16 *stream = (Sint16 *)stream8;
- Sint16 samp;
-
- len /= 2; /* Number of samples to write */
-
- for ( j=0; j<len; j++ ) {
-
- stream[j] = 0;
-
- if ( a->moo_pos < a->moo_len ) {
- samp = a->moo_buf[a->moo_pos++];
- stream[j] += samp;
- } else {
- a->mootex = 0;
- }
-
- }
-
- a->aplay_fallback = 0;
-}
void audio_trigger_moo()
{
@@ -84,43 +61,116 @@ void audio_trigger_moo()
a = audio_context;
if ( a == NULL ) return;
}
+
printf("Moo!\n");
+ snd_pcm_prepare(a->alsa_handle);
a->mootex = 1;
+ a->moo_pos = 0;
+}
+
+
+static void *audio_alsa_work(void *data)
+{
+ AudioContext *a = data;
+
+ while ( !a->finished ) {
+
+ int ret;
+
+ if ( a->moo_pos >= a->moo_len ) {
+ usleep(1000);
+ continue;
+ }
+
+ ret = snd_pcm_writei(a->alsa_handle, a->moo_buf+a->moo_pos,
+ a->alsa_frames);
+
+ if (ret == -EPIPE) {
+ fprintf(stderr, "ALSA buffer underrun\n");
+ snd_pcm_prepare(a->alsa_handle);
+ } else if (ret < 0) {
+ fprintf(stderr, "ALSA write error: %s\n",
+ snd_strerror(ret));
+ } else if (ret != (int)a->alsa_frames) {
+ fprintf(stderr, "ALSA short write, %d frames\n",
+ ret);
+ } else {
- if ( a->aplay_fallback ) {
-
- pid_t pid;
- int status;
-
- printf("Using aplay fallback\n");
- pid = fork();
- if ( !( (pid != 0) && (pid != -1) ) ) {
- if ( pid == -1 ) {
- fprintf(stderr, "fork() failed.\n");
- return;
- } else {
- /* Forked successfully, child process */
- execlp("aplay", "aplay",
- DATADIR"/openmoocow/moo.wav", NULL);
+ /* Successful write */
+ a->moo_pos += ret;
+
+ if ( a->moo_pos > a->moo_len ) {
+ while ( snd_pcm_avail(a->alsa_handle) >= 0 ) {
+ usleep(1000);
+ }
+ a->mootex = 0;
+ printf("Done.\n");
}
- } /* else forked successfully, parent process */
- waitpid(pid, &status, 0);
- a->mootex = 0;
- } else if ( a->moo_pos == a->moo_len ) {
- a->moo_pos = 0;
+ }
+
}
+
+ snd_pcm_drain(a->alsa_handle);
+ snd_pcm_close(a->alsa_handle);
+
+ return NULL;
}
-/* SDL audio initial setup */
+static int audio_open_alsa(AudioContext *a)
+{
+ int ret;
+ snd_pcm_t *handle;
+ snd_pcm_hw_params_t *params;
+ unsigned int val;
+ snd_pcm_uframes_t frames;
+ int dir;
+
+ ret = snd_pcm_open(&handle, "default",
+ SND_PCM_STREAM_PLAYBACK, 0);
+ if ( ret < 0 ) {
+ fprintf(stderr, "Couldn't open audio: %s\n", snd_strerror(ret));
+ return FALSE;
+ }
+
+ snd_pcm_hw_params_alloca(&params);
+ snd_pcm_hw_params_any(handle, params);
+ snd_pcm_hw_params_set_access(handle, params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
+ snd_pcm_hw_params_set_channels(handle, params, 1); /* One channel */
+ val = 44100; /* 44.1 kHz */
+ snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
+ frames = 32;
+ snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
+ ret = snd_pcm_hw_params(handle, params);
+ if ( ret < 0 ) {
+ fprintf(stderr, "Couldn't set parameters: %s\n",
+ snd_strerror(ret));
+ return FALSE;
+ }
+
+ /* Get the actual period size */
+ snd_pcm_hw_params_get_period_size(params, &frames, &dir);
+ a->alsa_frames = frames;
+ printf("%i frames per period\n", frames);
+
+ a->alsa_handle = handle;
+ a->finished = 0;
+ a->alsa_thread = g_thread_create(audio_alsa_work, a, TRUE, NULL);
+
+ return TRUE;
+}
+
+
+/* Audio initial setup */
void audio_setup()
{
- AudioContext *a;
- SDL_AudioSpec fmt;
SDL_AudioSpec wave;
Uint8 *data;
Uint32 dlen;
SDL_AudioCVT cvt;
+ AudioContext *a;
/* Create audio context */
a = malloc(sizeof(AudioContext));
@@ -128,32 +178,24 @@ void audio_setup()
a->mootex = 1; /* Not ready yet */
audio_context = a;
- /* 16-bit mono audio at 44.1 kHz */
- fmt.freq = 44100;
- fmt.format = AUDIO_S16;
- fmt.channels = 1;
- fmt.samples = 512;
- fmt.callback = audio_mix;
- fmt.userdata = a;
- fmt.silence = 0;
-
- if ( SDL_OpenAudio(&fmt, NULL) < 0 ) {
- fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
- goto out; /* and use fallback */
+ if ( audio_open_alsa(a) ) {
+ printf("Using ALSA for audio.\n");
+ } else {
+ exit(1);
}
if ( SDL_LoadWAV(DATADIR"/openmoocow/moo.wav", &wave, &data, &dlen)
== NULL ) {
fprintf(stderr, "Couldn't load moo sound: %s\n",
SDL_GetError());
- goto out; /* and use fallback */
+ goto out;
}
SDL_BuildAudioCVT(&cvt, wave.format, wave.channels, wave.freq,
AUDIO_S16, 1, 44100);
cvt.buf = malloc(dlen*cvt.len_mult);
if ( cvt.buf == NULL ) {
fprintf(stderr, "Not enough memory to convert audio \n");
- goto out; /* and use fallback */
+ goto out;
}
memcpy(cvt.buf, data, dlen);
cvt.len = dlen;
@@ -163,9 +205,6 @@ void audio_setup()
a->moo_len = cvt.len_cvt/2 - 2; /* Convert bytes to samples */
a->moo_pos = a->moo_len; /* Play nothing to start with */
a->moo_buf = (Sint16 *)cvt.buf;
- a->aplay_fallback = 1;
-
- SDL_PauseAudio(0);
out:
a->mootex = 0; /* Ready now */
@@ -177,7 +216,7 @@ void audio_shutdown()
if ( a == NULL ) return;
- SDL_CloseAudio();
+ a->finished = 1;
/* Now this can be freed */
free(a);
diff --git a/src/types.h b/src/types.h
index b59c933..c23d4b5 100644
--- a/src/types.h
+++ b/src/types.h
@@ -30,6 +30,7 @@
#include <stdio.h>
#include <stdint.h>
#include <SDL.h>
+#include <alsa/asoundlib.h>
typedef enum {
ACCEL_UNKNOWN,
@@ -60,12 +61,16 @@ typedef struct {
typedef struct {
- long moo_len;
- long moo_pos;
- Sint16 *moo_buf;
- int aplay_fallback;
+ long moo_len;
+ long moo_pos;
+ Sint16 *moo_buf;
- unsigned int mootex;
+ int finished;
+ snd_pcm_t *alsa_handle;
+ snd_pcm_uframes_t alsa_frames;
+ GThread *alsa_thread;
+
+ unsigned int mootex;
} AudioContext;