Added OpenBSD "sndio" audio target. SDL-1.2
authorRyan C. Gordon <icculus@icculus.org>
Sun, 08 Jul 2012 07:20:50 -0400
branchSDL-1.2
changeset 6353 dfcbd0d9209c
parent 6347 fdde82eb1ce3
child 6361 173deb250f75
Added OpenBSD "sndio" audio target. Thanks to Brad Smith and the OpenBSD team for the patch!
configure.in
include/SDL_config.h.in
src/audio/SDL_audio.c
src/audio/SDL_sysaudio.h
src/audio/sndio/SDL_sndioaudio.c
src/audio/sndio/SDL_sndioaudio.h
--- a/configure.in	Mon Jul 02 08:29:57 2012 -0400
+++ b/configure.in	Sun Jul 08 07:20:50 2012 -0400
@@ -486,6 +486,34 @@
     fi
 }
 
+dnl Find Sndio
+CheckSndio()
+{
+    AC_ARG_ENABLE(sndio,
+AC_HELP_STRING([--enable-sndio], [support the sndio audio API [[default=yes]]]),
+                  , enable_sndioaudio=yes)
+    if test x$enable_audio = xyes -a x$enable_sndioaudio = xyes; then
+        AC_CHECK_HEADER(sndio.h, have_sndio_hdr=yes)
+        AC_CHECK_LIB(sndio, sio_open, have_sndio_lib=yes)
+
+        AC_MSG_CHECKING(for sndio support)
+        have_sndio=no
+
+        if test x$have_sndio_hdr = xyes -a x$have_sndio_lib = xyes; then
+            have_sndio=yes
+            SNDIO_LIBS="-lsndio"
+        fi
+
+        AC_MSG_RESULT($have_nas)
+
+        if test x$have_sndio = xyes; then
+            AC_DEFINE(SDL_AUDIO_DRIVER_SNDIO)
+            SOURCES="$SOURCES $srcdir/src/audio/sndio/*.c"
+            EXTRA_LDFLAGS="$EXTRA_LDFLAGS $SNDIO_LIBS"
+            have_audio=yes
+        fi
+}
+
 dnl Find PulseAudio
 CheckPulseAudio()
 {
@@ -2358,6 +2386,7 @@
         CheckALSA
         CheckARTSC
         CheckESD
+        CheckSndio
         CheckPulseAudio
         CheckNAS
         CheckX11
@@ -2390,7 +2419,7 @@
                 SOURCES="$SOURCES $srcdir/src/audio/sun/*.c"
                 have_audio=yes
             ;;
-            netbsd|openbsd)
+            netbsd)
                 AC_DEFINE(SDL_AUDIO_DRIVER_BSD)
                 SOURCES="$SOURCES $srcdir/src/audio/bsd/*.c"
                 have_audio=yes
--- a/include/SDL_config.h.in	Mon Jul 02 08:29:57 2012 -0400
+++ b/include/SDL_config.h.in	Sun Jul 08 07:20:50 2012 -0400
@@ -182,6 +182,7 @@
 #undef SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
 #undef SDL_AUDIO_DRIVER_PAUD
 #undef SDL_AUDIO_DRIVER_QNXNTO
+#undef SDL_AUDIO_DRIVER_SNDIO
 #undef SDL_AUDIO_DRIVER_SNDMGR
 #undef SDL_AUDIO_DRIVER_SUNAUDIO
 #undef SDL_AUDIO_DRIVER_WAVEOUT
--- a/src/audio/SDL_audio.c	Mon Jul 02 08:29:57 2012 -0400
+++ b/src/audio/SDL_audio.c	Sun Jul 08 07:20:50 2012 -0400
@@ -42,6 +42,9 @@
 #if SDL_AUDIO_DRIVER_ALSA
 	&ALSA_bootstrap,
 #endif
+#if SDL_AUDIO_DRIVER_SNDIO
+	&SNDIO_bootstrap,
+#endif
 #if SDL_AUDIO_DRIVER_BSD
 	&BSD_AUDIO_bootstrap,
 #endif
--- a/src/audio/SDL_sysaudio.h	Mon Jul 02 08:29:57 2012 -0400
+++ b/src/audio/SDL_sysaudio.h	Sun Jul 08 07:20:50 2012 -0400
@@ -102,6 +102,9 @@
 	SDL_AudioDevice *(*create)(int devindex);
 } AudioBootStrap;
 
+#if SDL_AUDIO_DRIVER_SNDIO
+extern AudioBootStrap SNDIO_bootstrap;
+#endif
 #if SDL_AUDIO_DRIVER_BSD
 extern AudioBootStrap BSD_AUDIO_bootstrap;
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audio/sndio/SDL_sndioaudio.c	Sun Jul 08 07:20:50 2012 -0400
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2008 Jacob Meuser <jakemsr@sdf.lonestar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#include <unistd.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_sndioaudio.h"
+
+/* The tag name used by sndio audio */
+#define SNDIO_DRIVER_NAME         "sndio"
+
+/* Audio driver functions */
+static int SNDIO_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void SNDIO_WaitAudio(_THIS);
+static void SNDIO_PlayAudio(_THIS);
+static Uint8 *SNDIO_GetAudioBuf(_THIS);
+static void SNDIO_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+	struct sio_hdl *this_hdl;
+	int available = 0;
+
+	if ( (this_hdl = sio_open(NULL, SIO_PLAY, 0)) != NULL ) {
+		sio_close(this_hdl);
+		available = 1;
+	}
+
+	return available;
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+	SDL_free(device->hidden);
+	SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+	SDL_AudioDevice *this;
+
+	/* Initialize all variables that we clean on shutdown */
+	this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+	if ( this ) {
+		SDL_memset(this, 0, (sizeof *this));
+		this->hidden = (struct SDL_PrivateAudioData *)
+				SDL_malloc((sizeof *this->hidden));
+	}
+	if ( (this == NULL) || (this->hidden == NULL) ) {
+		SDL_OutOfMemory();
+		if ( this ) {
+			SDL_free(this);
+		}
+		return(0);
+	}
+	SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+	/* Set the function pointers */
+	this->OpenAudio = SNDIO_OpenAudio;
+	this->WaitAudio = SNDIO_WaitAudio;
+	this->PlayAudio = SNDIO_PlayAudio;
+	this->GetAudioBuf = SNDIO_GetAudioBuf;
+	this->CloseAudio = SNDIO_CloseAudio;
+
+	this->free = Audio_DeleteDevice;
+
+	hdl = NULL;
+
+	return this;
+}
+
+AudioBootStrap SNDIO_bootstrap = {
+	SNDIO_DRIVER_NAME, "sndio",
+	Audio_Available, Audio_CreateDevice
+};
+
+
+
+/* This function waits until it is possible to write a full sound buffer */
+static void SNDIO_WaitAudio(_THIS)
+{
+	/* Check to see if the thread-parent process is still alive */
+	{ static int cnt = 0;
+		/* Note that this only works with thread implementations 
+		   that use a different process id for each thread.
+		*/
+		if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
+			if ( kill(parent, 0) < 0 ) {
+				this->enabled = 0;
+			}
+		}
+	}
+}
+
+static void SNDIO_PlayAudio(_THIS)
+{
+	int written;
+
+	/* Write the audio data */
+	written = sio_write(hdl, mixbuf, mixlen);
+	
+	/* If we couldn't write, assume fatal error for now */
+	if ( written == 0 ) {
+		this->enabled = 0;
+	}
+#ifdef DEBUG_AUDIO
+	fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+#endif
+}
+
+static Uint8 *SNDIO_GetAudioBuf(_THIS)
+{
+	return(mixbuf);
+}
+
+static void SNDIO_CloseAudio(_THIS)
+{
+	if ( mixbuf != NULL ) {
+		SDL_FreeAudioMem(mixbuf);
+		mixbuf = NULL;
+	}
+	if ( hdl != NULL ) {
+		sio_close(hdl);
+		hdl = NULL;
+	}
+}
+
+static int SNDIO_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+	struct sio_par par, reqpar;
+	int newrate;
+
+	mixbuf = NULL;
+
+	if ((hdl = sio_open(NULL, SIO_PLAY, 0)) == NULL) {
+		SDL_SetError("sio_open() failed");
+		return(-1);
+	}
+
+	sio_initpar(&par);
+
+	switch (spec->format) {
+	case AUDIO_S16LSB:
+		par.bits = 16;
+		par.sig = 1;
+		par.le = 1;
+		break;
+	case AUDIO_S16MSB:
+		par.bits = 16;
+		par.sig = 1;
+		par.le = 0;
+		break;
+	case AUDIO_S8:
+		par.bits = 8;
+		par.sig = 1;
+		break;
+	case AUDIO_U16LSB:
+		par.bits = 16;
+		par.sig = 0;
+		par.le = 1;
+		break;
+	case AUDIO_U16MSB:
+		par.bits = 16;
+		par.sig = 0;
+		par.le = 0;
+		break;
+	case AUDIO_U8:
+		par.bits = 8;
+		par.sig = 0;
+		break;
+	default:
+		SDL_SetError("SNDIO unknown format");
+		return(-1);
+	}
+
+	par.rate = spec->freq;
+	par.pchan = spec->channels;
+	par.round = spec->samples;
+	par.appbufsz = par.round * 2;
+
+	reqpar = par;
+
+	if (sio_setpar(hdl, &par) == 0) {
+		SDL_SetError("sio_setpar() failed");
+		return(-1);
+	}
+
+	if (sio_getpar(hdl, &par) == 0) {
+		SDL_SetError("sio_getpar() failed");
+		return(-1);
+	}
+
+	/* if wanted rate not found, find a multiple/factor */
+	if (par.rate != spec->freq) {
+		newrate = par.rate;
+		if ((newrate > spec->freq && newrate % spec->freq != 0) ||
+		     (newrate < spec->freq && spec->freq % newrate != 0)) {
+			if ((spec->freq < 44100 && 44100 % spec->freq == 0) ||
+			     (spec->freq > 44100 && spec->freq % 44100 == 0)) {
+				newrate = 44100;
+			}
+		}
+		/* only change sample rate */
+		par = reqpar;
+		par.rate = newrate;
+		/* keep same latency */
+		par.round = spec->samples * par.rate / reqpar.rate;
+		par.appbufsz = par.round * 2;
+		if (sio_setpar(hdl, &par) == 0) {
+			SDL_SetError("sio_setpar() failed");
+			return(-1);
+		}
+	}
+
+	if (sio_getpar(hdl, &par) == 0) {
+		SDL_SetError("sio_getpar() failed");
+		return(-1);
+	}
+
+	if (par.bits == 16) {
+		if (par.sig && par.le) {
+			spec->format = AUDIO_S16LSB;
+		} else if (par.sig && !par.le) {
+			spec->format = AUDIO_S16MSB;
+		} else if (!par.sig && par.le) {
+			spec->format = AUDIO_U16LSB;
+		} else 
+			spec->format = AUDIO_U16MSB;
+	} else if (par.bits == 8) {
+		spec->format = par.sig ? AUDIO_S8 : AUDIO_U8;
+	} else {
+		SDL_SetError("SNDIO couldn't configure a suitable format");
+		return(-1);
+	}
+
+	spec->freq = par.rate;
+	spec->channels = par.pchan;
+	spec->samples = par.round;
+
+	SDL_CalculateAudioSpec(spec);
+
+	/* Allocate mixing buffer */
+	mixlen = spec->size;
+	mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
+	if ( mixbuf == NULL ) {
+		return(-1);
+	}
+	SDL_memset(mixbuf, spec->silence, spec->size);
+
+	/* Get the parent process id (we're the parent of the audio thread) */
+	parent = getpid();
+
+	if ( sio_start(hdl) == 0 ) {
+		SDL_SetError("sio_start() failed");
+		return(-1);
+	}
+
+	/* We're ready to rock and roll. :-) */
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audio/sndio/SDL_sndioaudio.h	Sun Jul 08 07:20:50 2012 -0400
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2008 Jacob Meuser <jakemsr@sdf.lonestar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "SDL_config.h"
+
+#ifndef _SDL_sndioaudio_h
+#define _SDL_sndioaudio_h
+
+#include <sndio.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS	SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+	/* The stream descriptor for the audio device */
+	struct sio_hdl *hdl;
+
+	/* The parent process id, to detect when application quits */
+	pid_t parent;
+
+	/* Raw mixing buffer */
+	Uint8 *mixbuf;
+	int    mixlen;
+
+};
+
+/* Old variable names */
+#define stream			(this->hidden->stream)
+#define parent			(this->hidden->parent)
+#define mixbuf			(this->hidden->mixbuf)
+#define mixlen			(this->hidden->mixlen)
+#define hdl			(this->hidden->hdl)
+
+#endif /* _SDL_sndioaudio_h */
+