Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 20 Jul 2018 15:09:32 +0000 (UTC)
From:      Tobias Kortkamp <tobik@FreeBSD.org>
To:        ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org
Subject:   svn commit: r475024 - in head/audio/portaudio: . files
Message-ID:  <201807201509.w6KF9WOo024018@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tobik
Date: Fri Jul 20 15:09:32 2018
New Revision: 475024
URL: https://svnweb.freebsd.org/changeset/ports/475024

Log:
  audio/portaudio: Add support for enumerating multiple sndio devices
  
  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).  This however means that we are stuck with
  only one device at a time for playback/recording and would have to
  restart applications (or the sndiod instance) to switch between
  devices.
  
  This is detrimental to the workflow in applications like Audacity
  and makes them unusable in sndio only setups.
  
  Add a new PA_SNDIO_AUDIODEVICES environment variables with which
  users can specify and expose a list of 16 additional sndio devices
  to applications using PortAudio.
  
  Example:
  PA_SNDIO_AUDIODEVICES=snd/0.monitor:snd@remote/0:rsnd/3

Modified:
  head/audio/portaudio/Makefile
  head/audio/portaudio/files/pa_sndio.c

Modified: head/audio/portaudio/Makefile
==============================================================================
--- head/audio/portaudio/Makefile	Fri Jul 20 14:54:16 2018	(r475023)
+++ head/audio/portaudio/Makefile	Fri Jul 20 15:09:32 2018	(r475024)
@@ -3,7 +3,7 @@
 
 PORTNAME=	portaudio
 DISTVERSION=	19_20140130
-PORTREVISION=	7
+PORTREVISION=	8
 CATEGORIES=	audio
 MASTER_SITES=	http://www.portaudio.com/archives/
 DISTNAME=	pa_stable_v${DISTVERSION}

Modified: head/audio/portaudio/files/pa_sndio.c
==============================================================================
--- head/audio/portaudio/files/pa_sndio.c	Fri Jul 20 14:54:16 2018	(r475023)
+++ head/audio/portaudio/files/pa_sndio.c	Fri Jul 20 15:09:32 2018	(r475024)
@@ -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 *
 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 **hostA
 	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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201807201509.w6KF9WOo024018>