From 180e1b8f9fb90ac428e365236961cf18cbd6aaca Mon Sep 17 00:00:00 2001 From: Christian Kellermann Date: Mon, 9 Dec 2019 08:18:57 +0100 Subject: [PATCH] Add sndio sound support for OpenBSD This commit introduces a new plugin "vm-sound-sndio" which uses the native OpenBSD sound system as backend. This commit is meant as an initial introduction of the plugin, as sound output currently blocks the whole VM. The plugin is not loaded by default and should only get built when running on OpenBSD. --- platforms/unix/vm-sound-sndio/Makefile.inc | 2 + platforms/unix/vm-sound-sndio/acinclude.m4 | 23 ++ .../unix/vm-sound-sndio/sqUnixSndioSound.c | 203 ++++++++++++++++++ platforms/unix/vm/sqUnixMain.c | 3 +- 4 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 platforms/unix/vm-sound-sndio/Makefile.inc create mode 100644 platforms/unix/vm-sound-sndio/acinclude.m4 create mode 100644 platforms/unix/vm-sound-sndio/sqUnixSndioSound.c diff --git a/platforms/unix/vm-sound-sndio/Makefile.inc b/platforms/unix/vm-sound-sndio/Makefile.inc new file mode 100644 index 0000000000..1c42fd3869 --- /dev/null +++ b/platforms/unix/vm-sound-sndio/Makefile.inc @@ -0,0 +1,2 @@ +PLIBS = -lsndio + diff --git a/platforms/unix/vm-sound-sndio/acinclude.m4 b/platforms/unix/vm-sound-sndio/acinclude.m4 new file mode 100644 index 0000000000..e642678ae0 --- /dev/null +++ b/platforms/unix/vm-sound-sndio/acinclude.m4 @@ -0,0 +1,23 @@ +# -*- sh -*- + +AC_MSG_CHECKING([for sndio sound support]) + +AC_ARG_WITH(sndio-sound, +[ --with-sndio-sound enable sndio sound support [default=disabled]], + [have_snd_sndio="$withval"], + [have_snd_sndio="no"]) + +if test "$have_snd_sndio" = "yes"; then + # check for libraries, headers, etc., here... + AC_MSG_CHECKING([for OpenBSD sndio Sound System]) + sio_h_found="no" + AC_CHECK_HEADERS([sndio.h],[sndio_h_found="yes"; break]) + if test "$sndio_h_found" = "no"; then + AC_PLUGIN_DISABLE + else + AC_CHECK_LIB([sndio],[sio_open],[AC_PLUGIN_USE_LIB([sndio])]) + fi +else + AC_MSG_RESULT([no]) + AC_PLUGIN_DISABLE +fi diff --git a/platforms/unix/vm-sound-sndio/sqUnixSndioSound.c b/platforms/unix/vm-sound-sndio/sqUnixSndioSound.c new file mode 100644 index 0000000000..25c92b4042 --- /dev/null +++ b/platforms/unix/vm-sound-sndio/sqUnixSndioSound.c @@ -0,0 +1,203 @@ +/* sqUnixSndioSound.c -- sound module for sndio sound system + * + * Last edited: + * 2019-12-11 by Christian Kellermann + * + * This is a driver for the OpenBSD sndio sound drivers for Squeak. + * + */ + +#include "sq.h" +#include "sqaio.h" + +#include +#include + +#if defined (DEBUG) +#define trace() fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__) +#else +#define trace() while(0){}; +#endif + +struct sio_hdl *snd; +struct sio_par par; +int opened = false; + +/*** sound output ***/ + + +static sqInt sound_AvailableSpace(void) +{ + trace(); + return par.bufsz * par.bps * par.pchan; +} + +static sqInt sound_InsertSamplesFromLeadTime(sqInt frameCount, sqInt srcBufPtr, sqInt samplesOfLeadTime) +{ + trace(); + return success(false); +} + +static sqInt sound_PlaySamplesFromAtLength(sqInt frameCount, sqInt arrayIndex, sqInt startIndex) +{ + size_t bytes_played; + trace(); + bytes_played = sio_write(snd, pointerForOop(arrayIndex) + startIndex * (par.bps * par.pchan), frameCount * par.bps * par.pchan); + if (bytes_played < 0) + return 0; + return bytes_played / (par.bps * par.pchan); +} + +static sqInt sound_PlaySilence(void) +{ + trace(); + return 8192; +} + +static int semaphore = 0; + +static sqInt sound_Start(sqInt frameCount, sqInt samplesPerSec, sqInt stereo, sqInt semaIndex) +{ + int channels = stereo + 1; + + trace(); + fprintf(stderr, "%ld frames, %ld samplesPerSec, %ld stereo, %ld semaIndex\n", + frameCount, + samplesPerSec, + stereo, + semaIndex); + + if (opened && snd){ + sio_close(snd); + snd = NULL; + } + snd = sio_open(SIO_DEVANY, SIO_PLAY, 0); /* blocking */ + if (! snd) { + fprintf(stderr, "Unable to open sound device!\n"); + return false; + } + opened = true; + + sio_initpar(&par); + + par.bps = 2; /* Always 2 bytes per sample */ + par.sig = 1; + par.pchan = channels; + par.le = 1; + par.rate = samplesPerSec; /* that should be the same as frames per second(!?) */ + par.appbufsz = frameCount * 2 * channels; + par.rchan = 0; + par.xrun = SIO_SYNC; + + if (! sio_setpar(snd, &par)){ + fprintf(stderr, "Unable to set snd dev parameters\n"); + return false; + } + + if (! sio_getpar(snd, &par)){ + fprintf(stderr, "Unable to set snd dev parameters\n"); + return false; + } + + if (!sio_start(snd)) { + fprintf(stderr, "Unable to set device into start mode\n"); + return false; + } + + semaphore = semaIndex; + + return true; +} + +sqInt sound_Stop(void){ + trace(); + if (opened) { + if (!sio_stop(snd)){ + fprintf(stderr, "Unable to stop device\n"); + return false; + } + sio_close(snd); snd = NULL; + opened = false; + } + + return true; +} + + +/*** sound input ***/ + + +sqInt sound_StartRecording(sqInt desiredSamplesPerSec, sqInt stereo, sqInt semaIndex) +{ + trace(); + return 0; +} + +sqInt sound_StopRecording(void) +{ + trace(); + return 0; +} + +double sound_GetRecordingSampleRate(void) +{ + trace(); + return 8192; +} + +sqInt sound_RecordSamplesIntoAtLength(sqInt buf, sqInt startSliceIndex, sqInt bufferSizeInBytes) +{ + trace(); + return 8192; +} + +/*** sound mixer ***/ + +void sound_Volume(double *left, double *right) +{ + trace(); + *left= 1.0; + *right= 1.0; +} + +void sound_SetVolume(double left, double right) +{ + trace(); +} + +sqInt sound_SetRecordLevel(sqInt level) +{ + trace(); + return level; +} + +sqInt sound_GetSwitch(sqInt id, sqInt captureFlag, sqInt channel) { return success(true); } + +sqInt sound_SetSwitch(sqInt id, sqInt captureFlag, sqInt parameter) { return success(true); } + +sqInt sound_SetDevice(sqInt id, char *name) { return success(true); } + + +#include "SqSound.h" + +SqSoundDefine(sndio); /* must match name in makeInterface() below */ + +#include "SqModule.h" + +static void sound_parseEnvironment(void) {} + +static int sound_parseArgument(int argc, char **argv) +{ + if (!strcmp(argv[0], "-nosound")) return 1; + return 0; +} + +static void sound_printUsage(void) {} +static void sound_printUsageNotes(void) {} + +static void *sound_makeInterface(void) +{ + return &sound_sndio_itf; /* must match name in SqSoundDefine() above */ +} + +SqModuleDefine(sound, sndio); /* must match name in sqUnixMain.c's moduleDescriptions */ diff --git a/platforms/unix/vm/sqUnixMain.c b/platforms/unix/vm/sqUnixMain.c index ed5f5e3ab1..ad75f858f1 100644 --- a/platforms/unix/vm/sqUnixMain.c +++ b/platforms/unix/vm/sqUnixMain.c @@ -1166,6 +1166,7 @@ static struct moduleDescription moduleDescriptions[]= { &displayModule, "display", "custom" }, /*** NO DEFAULT ***/ { &soundModule, "sound", "NAS" }, /*** NO DEFAULT ***/ { &soundModule, "sound", "custom" }, /*** NO DEFAULT ***/ + { &soundModule, "sound", "sndio" }, /*** NO DEFAULT ***/ /* when adding an entry above be sure to change the defaultModules offset below */ { &displayModule, "display", "Quartz" }, /* defaults... */ { &soundModule, "sound", "OSS" }, @@ -1177,7 +1178,7 @@ static struct moduleDescription moduleDescriptions[]= { 0, 0, 0 } }; -static struct moduleDescription *defaultModules= moduleDescriptions + 6; +static struct moduleDescription *defaultModules= moduleDescriptions + 7; struct SqModule *queryLoadModule(char *type, char *name, int query)