Skip to content
Permalink
Browse files

Added OpenBSD "sndio" audio target.

Thanks to Brad Smith and the OpenBSD team for the patch!
  • Loading branch information
icculus committed Jul 8, 2012
1 parent c3be661 commit 240fa9286f4d265127d60adc3d7bb9b8e161f57f
@@ -486,6 +486,34 @@ AC_HELP_STRING([--enable-esd-shared], [dynamically load ESD audio support [[defa
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 @@ case "$host" in
CheckALSA
CheckARTSC
CheckESD
CheckSndio
CheckPulseAudio
CheckNAS
CheckX11
@@ -2390,7 +2419,7 @@ case "$host" in
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
@@ -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
@@ -42,6 +42,9 @@ static AudioBootStrap *bootstrap[] = {
#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
@@ -102,6 +102,9 @@ typedef struct AudioBootStrap {
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
@@ -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);
}

0 comments on commit 240fa92

Please sign in to comment.