Commit 6a24b323 authored by Sam Lantinga's avatar Sam Lantinga

Added native OpenBSD audio driver (thanks vedge!)

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%4038
parent a95fb100
=============================================================
Using the Simple DirectMedia Layer with OpenBSD 2.9 and later
=============================================================
Author:
Peter Valchev <pvalchev@openbsd.org>
=======
Install
=======
There is an OpenBSD port for SDL and various other tools. Using
this port is recommended, since it contains all the needed patches
and configure arguments nicely organized in several FLAVORS you
can pick from. If you're unfamiliar with the OpenBSD ports system
please visit:
http://www.openbsd.org/ports.html
http://www.openbsd.org/anoncvs.html
You should have a precompiled binary package on your OpenBSD 2.9
or later CD-ROM, which you can easily add with pkg_add(1).
If for whatever reason you're unable to take the advantage of the
created port, or you want to stick with the newest fresh SDL from
the current CVS repository, here are some hints of what has left
unresolved and needs to be disabled/changed.
To build SDL with OSS + esound:
1. ./configure --disable-joystick \
--disable-pthread-sem \
--disable-nasm \
--enable-esd \
--enable-oss \
--disable-arts \
--disable-video-opengl
OR
To build SDL with native audio + esound (remove --disable-esd otherwise):
1. ./configure --disable-joystick \
--disable-pthread-sem \
--disable-nasm \
--enable-openbsdaudio \
--enable-esd \
--disable-arts \
--disable-video-opengl
If you need arts or GL, omit the responding --disable lines. In the
port, they're disabled by default, you need to specify flavors to
make use of them.
2. gmake # Yeah, GNU make is required, install the package
3. sudo gmake install
=========
Todo List
=========
Feedback is always welcome with anything you may find useful and
you can suggest.
For now, the following things have to be worked on:
1. The native audio should be widely tested and will eventually
become the default. At that moment I have not received any
feedback which should explain its current condition.
2. There are occurences of dynamic loading of drivers in the OpenGL
code section, and our a.out architectures need an underscore prefixed
to symbol names. Some solution to that may be a good thing. I can
fix it theoretically, but unfortunately I do not have the needed
hardware/configuration to test it. If you bump into that, email me.
===================
Contact Information
===================
Everybody is welcome to give me any suggestions and to report bugs
(as well as fixing them ;-) You can contact me by email:
Peter Valchev <pvalchev@openbsd.org>
$Id$
......@@ -278,6 +278,19 @@ CheckALSA()
fi
}
dnl Check whether we want to use OpenBSD native audio or not
CheckOPENBSDAUDIO()
{
AC_ARG_ENABLE(openbsdaudio,
[ --enable-openbsdaudio OpenBSD native audio support [default=no]],
, enable_openbsdaudio=no)
if test x$enable_audio = xyes -a x$enable_openbsdaudio = xyes; then
SYSTEM_LIBS="$SYSTEM_LIBS $ESD_LIBS"
AUDIO_SUBDIRS="$AUDIO_SUBDIRS openbsd"
AUDIO_DRIVERS="$AUDIO_DRIVERS openbsd/libaudio_openbsd.la"
fi
}
dnl Find the ESD includes and libraries
CheckESD()
{
......@@ -1275,7 +1288,6 @@ case "$target" in
;;
*-*-openbsd*)
ARCH=openbsd
CFLAGS="$CFLAGS -Dunix"
CheckDummyVideo
CheckNASM
CheckOSS
......@@ -1289,10 +1301,7 @@ case "$target" in
# Set up files for the main() stub
COPY_ARCH_SRC(src/main, linux, SDL_main.c)
# Set up files for the audio library
if test x$enable_audio = xyes; then
AUDIO_SUBDIRS="$AUDIO_SUBDIRS sun"
AUDIO_DRIVERS="$AUDIO_DRIVERS sun/libaudio_sun.la"
fi
CheckOPENBSDAUDIO
# Set up files for the joystick library
# (No joystick support yet)
if test x$enable_joystick = xyes; then
......@@ -1322,6 +1331,8 @@ case "$target" in
if test x$enable_timers = xyes; then
COPY_ARCH_SRC(src/timer, linux, SDL_systimer.c)
fi
# OpenBSD does not define "unix"
CFLAGS="$CFLAGS -Dunix"
;;
*-*-sysv5*)
ARCH=sysv5
......@@ -1882,7 +1893,7 @@ if test $ARCH = solaris; then
fi
if test $ARCH = openbsd; then
SDL_RLD_FLAGS="-Wl,-R\${exec_prefix}/lib -Wl,-R\${X11BASE}/lib"
SDL_RLD_FLAGS="-L${X11BASE}/lib -Wl,-rpath,\${exec_prefix}/lib -Wl,-rpath,${X11BASE}/lib"
fi
dnl Output the video drivers we use
......@@ -1947,6 +1958,7 @@ src/audio/esd/Makefile
src/audio/macrom/Makefile
src/audio/nas/Makefile
src/audio/nto/Makefile
src/audio/openbsd/Makefile
src/audio/paudio/Makefile
src/audio/sun/Makefile
src/audio/ums/Makefile
......
......@@ -16,6 +16,7 @@ be found at the <A HREF="http://www.libsdl.org/"> main SDL page</A>.
Major changes since SDL 1.0.0:
</H2>
<UL>
<LI> 1.2.1: Added native OpenBSD audio driver (thanks vedge!)
<LI> 1.2.1: Added detection of Open Sound System on Solaris x86
<LI> 1.2.1: Added initial support for Nano-X (thanks Hsieh-Fu!)
<LI> 1.2.1: Fixed endian detection on IA64 architectures (thanks Bill!)
......
......@@ -6,7 +6,7 @@ noinst_LTLIBRARIES = libaudio.la
# Define which subdirectories need to be built
SUBDIRS = @AUDIO_SUBDIRS@
DIST_SUBDIRS = alsa arts baudio dma dmedia dsp esd macrom nas nto \
paudio sun ums windib windx5
openbsd paudio sun ums windib windx5
DRIVERS = @AUDIO_DRIVERS@
......
......@@ -47,6 +47,9 @@ static AudioBootStrap *bootstrap[] = {
#ifdef ALSA_SUPPORT
&ALSA_bootstrap,
#endif
#ifdef __OpenBSD__
&OBSD_bootstrap;
#endif
#if (defined(unix) && !defined(__CYGWIN32__)) && \
!defined(OSS_SUPPORT) && !defined(ALSA_SUPPORT)
&AUDIO_bootstrap,
......
......@@ -106,6 +106,9 @@ extern AudioBootStrap DMA_bootstrap;
#ifdef ALSA_SUPPORT
extern AudioBootStrap ALSA_bootstrap;
#endif
#ifdef __OpenBSD__
extern AudioBootStrap OBSD_bootstrap;
#endif
#if (defined(unix) && !defined(__CYGWIN32__)) && \
!defined(OSS_SUPPORT) && !defined(ALSA_SUPPORT)
extern AudioBootStrap AUDIO_bootstrap;
......
## Makefile.am for SDL using the native OpenBSD sound driver
noinst_LTLIBRARIES = libaudio_openbsd.la
libaudio_openbsd_la_SOURCES = $(SRCS)
# The SDL audio driver sources
SRCS = SDL_openbsdaudio.c \
SDL_openbsdaudio.h
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
* Driver for native OpenBSD audio(4).
* vedge@vedge.com.ar.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/audioio.h>
#include "SDL_audio.h"
#include "SDL_error.h"
#include "SDL_audiomem.h"
#include "SDL_audio_c.h"
#include "SDL_timer.h"
#include "SDL_audiodev_c.h"
#include "SDL_openbsdaudio.h"
/* The tag name used by OpenBSD audio */
#define OBSD_DRIVER_NAME "openbsd"
/* Open the audio device for playback, and don't block if busy */
/* #define USE_BLOCKING_WRITES */
/* Use timer for synchronization */
/* #define USE_TIMER_SYNC */
/* #define DEBUG_AUDIO */
/* #define DEBUG_AUDIO_STREAM */
#ifdef USE_BLOCKING_WRITES
#define OPEN_FLAGS O_WRONLY
#else
#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
#endif
/* Audio driver functions */
static void OBSD_WaitAudio(_THIS);
static int OBSD_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void OBSD_PlayAudio(_THIS);
static Uint8 *OBSD_GetAudioBuf(_THIS);
static void OBSD_CloseAudio(_THIS);
#ifdef DEBUG_AUDIO
static void OBSD_Status(_THIS);
#endif
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
{
int fd;
int available;
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if(fd >= 0) {
available = 1;
close(fd);
}
return(available);
}
static void
Audio_DeleteDevice(SDL_AudioDevice *device)
{
free(device->hidden);
free(device);
}
static SDL_AudioDevice
*Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice*)malloc(sizeof(SDL_AudioDevice));
if(this) {
memset(this, 0, (sizeof *this));
this->hidden =
(struct SDL_PrivateAudioData*)malloc((sizeof *this->hidden));
}
if((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if(this) free(this);
return(0);
}
memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = OBSD_OpenAudio;
this->WaitAudio = OBSD_WaitAudio;
this->PlayAudio = OBSD_PlayAudio;
this->GetAudioBuf = OBSD_GetAudioBuf;
this->CloseAudio = OBSD_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap OBSD_bootstrap = {
OBSD_DRIVER_NAME, "Native OpenBSD audio",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
OBSD_WaitAudio(_THIS)
{
#ifndef USE_BLOCKING_WRITES
fd_set fdset;
/* 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;
}
}
#ifdef USE_TIMER_SYNC
/* See if we need to use timed audio synchronization */
if(frame_ticks)
{
/* Use timer for general audio synchronization */
Sint32 ticks;
ticks = ((Sint32)(next_frame - SDL_GetTicks())) - FUDGE_TICKS;
if(ticks > 0)
SDL_Delay(ticks);
}
else
#endif /* USE_TIMER_SYNC */
{
/* Use select() for audio synchronization */
struct timeval timeout;
FD_ZERO(&fdset);
FD_SET(audio_fd, &fdset);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
#if defined(DEBUG_AUDIO_STREAM) && defined(DEBUG_AUDIO_STREAM)
OBSD_Status(this);
#endif
if(select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0)
{
const char *message =
"Audio timeout - buggy audio driver? (disabled)";
fprintf(stderr, "SDL: %s\n", message);
this->enabled = 0;
audio_fd = -1;
}
}
#endif /* !USE_BLOCKING_WRITES */
}
static void
OBSD_PlayAudio(_THIS)
{
int written;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do
{
written = write(audio_fd, mixbuf, mixlen);
if((written < 0) && ((errno == 0) || (errno == EAGAIN)))
SDL_Delay(1);
}
while((written < 0) &&
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
#ifdef USE_TIMER_SYNC
if(frame_ticks)
next_frame += frame_ticks;
#endif
/* If we couldn't write, assume fatal error for now */
if(written < 0)
this->enabled = 0;
#ifdef DEBUG_AUDIO_STREAM
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static Uint8
*OBSD_GetAudioBuf(_THIS)
{
return(mixbuf);
}
static void
OBSD_CloseAudio(_THIS)
{
if(mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if(audio_fd >= 0) {
close(audio_fd);
audio_fd = -1;
}
}
#ifdef DEBUG_AUDIO
void
OBSD_Status(_THIS)
{
audio_info_t info;
if(ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr,"AUDIO_GETINFO failed.\n");
return;
}
fprintf(stderr,"
[play/record info]
buffer size : %d bytes
sample rate : %i Hz
channels : %i
precision : %i-bit
encoding : 0x%x
seek : %i
sample count : %i
EOF count : %i
paused : %s
error occured : %s
waiting : %s
active : %s
",
info.play.buffer_size,
info.play.sample_rate,
info.play.channels,
info.play.precision,
info.play.encoding,
info.play.seek,
info.play.samples,
info.play.eof,
info.play.pause ? "yes" : "no",
info.play.error ? "yes" : "no",
info.play.waiting ? "yes" : "no",
info.play.active ? "yes": "no");
fprintf(stderr,"
[audio info]
monitor_gain : %i
hw block size : %d bytes
hi watermark : %i
lo watermark : %i
audio mode : %s
",
info.monitor_gain,
info.blocksize,
info.hiwat, info.lowat,
(info.mode == AUMODE_PLAY) ? "PLAY"
: (info.mode = AUMODE_RECORD) ? "RECORD"
: (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL"
: "???"));
}
#endif /* DEBUG_AUDIO */
static int
OBSD_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
char audiodev[64];
Uint16 setenc;
audio_encoding_t enc;
audio_info_t info;
AUDIO_INITINFO(&info);
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
#ifdef USE_TIMER_SYNC
frame_ticks = 0.0;
#endif
/* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
if(audio_fd < 0) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return(-1);
}
/* Set to play mode */
info.mode = AUMODE_PLAY;
if(ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
SDL_SetError("Couldn't put device into play mode");
return(-1);
}
mixbuf = NULL;
setenc = 0;
for(enc.index = 0; (ioctl(audio_fd, AUDIO_GETENC, &enc)>=0)
&& (enc.encoding != setenc); enc.index++)
{
switch(spec->format)
{
case AUDIO_U8: /* 8-bit unsigned linear */
setenc = AUDIO_ENCODING_PCM8;
break;
case AUDIO_S8: /* 8-bit signed linear */
setenc = AUDIO_ENCODING_SLINEAR;
break;
case AUDIO_U16LSB: /* 16-bit unsigned linear, LSB */
setenc = AUDIO_ENCODING_ULINEAR_LE;
break;
case AUDIO_U16MSB: /* 16-bit unsigned linear, MSB */
setenc = AUDIO_ENCODING_ULINEAR_BE;
break;
case AUDIO_S16LSB: /* 16-bit signed linear, LSB */
setenc = AUDIO_ENCODING_SLINEAR_LE;
break;
case AUDIO_S16MSB: /* 16-bit signed linear, MSB */
setenc = AUDIO_ENCODING_SLINEAR_BE;
break;
}
#ifdef DEBUG_AUDIO
fprintf(stderr,"encoding #%i: \"%s\" %i-bit (0x%x) flags=%i...\n",
enc.index, enc.name, enc.precision, enc.encoding, enc.flags);
#endif
}
if(!setenc) {
SDL_SetError("No supported encoding for 0x%x", spec->format);
return(-1);
}
/* Set audio encoding */
info.play.encoding = enc.encoding;
info.play.precision = enc.precision;
if((ioctl(audio_fd, AUDIO_SETINFO, &info) < 0)) {
SDL_SetError("Couldn't set encoding to 0x%x %i-bit",
enc.encoding, enc.precision);
return(-1);
}
/* Set audio channels */
info.play.channels = spec->channels;
if(ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
info.play.channels = (spec->channels > 1);
ioctl(audio_fd, AUDIO_SETINFO, &info);
}
/* Set the sample rate */
info.play.sample_rate = spec->freq;
if(ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
SDL_SetError("Couldn't set sample rate to %i Hz", spec->freq);
return(-1);
}
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8*)SDL_AllocAudioMem(mixlen);
if(mixbuf == NULL) {
return(-1);
}
memset(mixbuf, spec->silence, spec->size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
#ifdef DEBUG_AUDIO
OBSD_Status(this);
#endif
/* We're ready to rock and roll. :-) */
return(0);
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
#ifndef _SDL_openbsdaudio_h
#define _SDL_openbsdaudio_h
#include "SDL_sysaudio.h"
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
/* Support for audio timing using a timer, in addition to select() */
float frame_ticks;
float next_frame;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_openbsdaudio_h */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment