aboutsummaryrefslogtreecommitdiff
path: root/src/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio.c')
-rw-r--r--src/audio.c169
1 files changed, 104 insertions, 65 deletions
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);