From owner-svn-ports-all@freebsd.org Fri Jul 20 15:09:33 2018 Return-Path: Delivered-To: svn-ports-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id CF8B91048B7B; Fri, 20 Jul 2018 15:09:33 +0000 (UTC) (envelope-from tobik@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 7749B808C0; Fri, 20 Jul 2018 15:09:33 +0000 (UTC) (envelope-from tobik@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 3260C11C8B; Fri, 20 Jul 2018 15:09:33 +0000 (UTC) (envelope-from tobik@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w6KF9XqD024019; Fri, 20 Jul 2018 15:09:33 GMT (envelope-from tobik@FreeBSD.org) Received: (from tobik@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w6KF9WOo024018; Fri, 20 Jul 2018 15:09:32 GMT (envelope-from tobik@FreeBSD.org) Message-Id: <201807201509.w6KF9WOo024018@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: tobik set sender to tobik@FreeBSD.org using -f From: Tobias Kortkamp Date: Fri, 20 Jul 2018 15:09:32 +0000 (UTC) To: ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org Subject: svn commit: r475024 - in head/audio/portaudio: . files X-SVN-Group: ports-head X-SVN-Commit-Author: tobik X-SVN-Commit-Paths: in head/audio/portaudio: . files X-SVN-Commit-Revision: 475024 X-SVN-Commit-Repository: ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-ports-all@freebsd.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: SVN commit messages for the ports tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 20 Jul 2018 15:09:34 -0000 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;