add support for enumerating multiple sndio devices

imported from FreeBSD (thanks to tobik@freebsd)
https://svnweb.freebsd.org/ports/head/audio/portaudio/files/pa_sndio.c

use new PA_SNDIO_DEVICES environment variables to specify additional sndio
devices, for example:

PA_SNDIO_AUDIODEVICES=snd/0.monitor:snd@remote/0:rsnd/3

ok ratchov@
This commit is contained in:
uaa 2019-01-12 20:29:34 +00:00
parent 26232b64a2
commit 2d59a73b69
2 changed files with 75 additions and 22 deletions

View File

@ -1,4 +1,4 @@
# $OpenBSD: Makefile,v 1.17 2014/09/13 04:56:28 bentley Exp $
# $OpenBSD: Makefile,v 1.18 2019/01/12 20:29:34 uaa Exp $
COMMENT= portable cross-platform audio API
@ -7,6 +7,7 @@ PKGNAME = portaudio-svn-1919
CATEGORIES= audio
MASTER_SITES = http://www.portaudio.com/archives/
EXTRACT_SUFX = .tgz
REVISION = 0
SHARED_LIBS = portaudio 1.1

View File

@ -61,11 +61,20 @@ typedef struct PaSndioHostApiRepresentation
PaUtilStreamInterface callback;
PaUtilStreamInterface blocking;
/*
* sndio has no device discovery mechanism, so expose only
* the default device, the user will have a chance to change it
* using the environment variable
* sndio has no device discovery mechanism and PortAudio has
* no way of accepting raw device strings from users.
* Normally we just expose the default device, which can be
* changed via the AUDIODEVICE environment variable, but we
* also allow specifying a list of up to 16 devices via the
* PA_SNDIO_AUDIODEVICES environment variable.
*
* Example:
* PA_SNDIO_AUDIODEVICES=default:snd/0.monitor:snd@remote/0
*/
PaDeviceInfo *infos[1], default_info;
#define PA_SNDIO_AUDIODEVICES_MAX 16
PaDeviceInfo device_info[PA_SNDIO_AUDIODEVICES_MAX];
PaDeviceInfo *infos[PA_SNDIO_AUDIODEVICES_MAX];
char *audiodevices;
} PaSndioHostApiRepresentation;
/*
@ -248,6 +257,7 @@ OpenStream(struct PaUtilHostApiRepresentation *hostApi,
unsigned mode;
int inch, onch;
PaSampleFormat ifmt, ofmt, siofmt;
const char *dev;
DPR("OpenStream:\n");
@ -257,7 +267,7 @@ OpenStream(struct PaUtilHostApiRepresentation *hostApi,
sio_initpar(&par);
if (outputPar && outputPar->channelCount > 0) {
if (outputPar->device != 0) {
if (outputPar->device >= sndioHostApi->base.info.deviceCount) {
DPR("OpenStream: %d: bad output device\n", outputPar->device);
return paInvalidDevice;
}
@ -273,7 +283,7 @@ OpenStream(struct PaUtilHostApiRepresentation *hostApi,
mode |= SIO_PLAY;
}
if (inputPar && inputPar->channelCount > 0) {
if (inputPar->device != 0) {
if (inputPar->device >= sndioHostApi->base.info.deviceCount) {
DPR("OpenStream: %d: bad input device\n", inputPar->device);
return paInvalidDevice;
}
@ -294,7 +304,14 @@ OpenStream(struct PaUtilHostApiRepresentation *hostApi,
DPR("OpenStream: mode = %x, trying rate = %u\n", mode, par.rate);
hdl = sio_open(SIO_DEVANY, mode, 0);
if (outputPar) {
dev = sndioHostApi->device_info[outputPar->device].name;
} else if (inputPar) {
dev = sndioHostApi->device_info[inputPar->device].name;
} else {
return paUnanticipatedHostError;
}
hdl = sio_open(dev, mode, 0);
if (hdl == NULL)
return paUnanticipatedHostError;
if (!sio_setpar(hdl, &par)) {
@ -636,16 +653,37 @@ IsFormatSupported(struct PaUtilHostApiRepresentation *hostApi,
static void
Terminate(struct PaUtilHostApiRepresentation *hostApi)
{
PaSndioHostApiRepresentation *sndioHostApi;
sndioHostApi = (PaSndioHostApiRepresentation *)hostApi;
free(sndioHostApi->audiodevices);
PaUtil_FreeMemory(hostApi);
}
static void
InitDeviceInfo(PaDeviceInfo *info, PaHostApiIndex hostApiIndex, const char *name)
{
info->structVersion = 2;
info->name = name;
info->hostApi = hostApiIndex;
info->maxInputChannels = 128;
info->maxOutputChannels = 128;
info->defaultLowInputLatency = 0.01;
info->defaultLowOutputLatency = 0.01;
info->defaultHighInputLatency = 0.5;
info->defaultHighOutputLatency = 0.5;
info->defaultSampleRate = 48000;
}
PaError
PaSndio_Initialize(PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex)
{
PaSndioHostApiRepresentation *sndioHostApi;
PaDeviceInfo *info;
struct sio_hdl *hdl;
char *audiodevices;
char *device;
size_t deviceCount;
DPR("PaSndio_Initialize: initializing...\n");
/* unusable APIs should return paNoError and a NULL hostApi */
@ -655,24 +693,38 @@ PaSndio_Initialize(PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApi
if (sndioHostApi == NULL)
return paNoError;
info = &sndioHostApi->default_info;
info->structVersion = 2;
info->name = "default";
info->hostApi = hostApiIndex;
info->maxInputChannels = 128;
info->maxOutputChannels = 128;
info->defaultLowInputLatency = 0.01;
info->defaultLowOutputLatency = 0.01;
info->defaultHighInputLatency = 0.5;
info->defaultHighOutputLatency = 0.5;
info->defaultSampleRate = 48000;
// Add default device
info = &sndioHostApi->device_info[0];
InitDeviceInfo(info, hostApiIndex, SIO_DEVANY);
sndioHostApi->infos[0] = info;
deviceCount = 1;
// Add additional devices as specified in the PA_SNDIO_AUDIODEVICES
// environment variable as a colon separated list
sndioHostApi->audiodevices = NULL;
audiodevices = getenv("PA_SNDIO_AUDIODEVICES");
if (audiodevices != NULL) {
sndioHostApi->audiodevices = strdup(audiodevices);
if (sndioHostApi->audiodevices == NULL)
return paNoError;
audiodevices = sndioHostApi->audiodevices;
while ((device = strsep(&audiodevices, ":")) != NULL &&
deviceCount < PA_SNDIO_AUDIODEVICES_MAX) {
if (*device == '\0')
continue;
info = &sndioHostApi->device_info[deviceCount];
InitDeviceInfo(info, hostApiIndex, device);
sndioHostApi->infos[deviceCount] = info;
deviceCount++;
}
}
*hostApi = &sndioHostApi->base;
(*hostApi)->info.structVersion = 1;
(*hostApi)->info.type = paSndio;
(*hostApi)->info.name = "sndio";
(*hostApi)->info.deviceCount = 1;
(*hostApi)->info.deviceCount = deviceCount;
(*hostApi)->info.defaultInputDevice = 0;
(*hostApi)->info.defaultOutputDevice = 0;
(*hostApi)->deviceInfos = sndioHostApi->infos;