Re: [Jack-Devel] RFC: jackd portnames

PrevNext  Index
DateThu, 03 Nov 2011 09:08:43 -0500
From David Nielson <[hidden] at comcast dot net>
To[hidden] at lists dot jackaudio dot org
In-Reply-ToAdrian Knoth [Jack-Devel] RFC: jackd portnames
  ***APPLAUSE***

David Nielson
(Naptastic)

On 11/03/2011 05:53 AM, Adrian Knoth wrote:
> Hi!
>
> I've forward-ported faberman's portname patch from jackd2-1.9.4 to
> 1.9.7.
>
> It is supposed to provide stable port names across cards, no matter of
> the underlying physical connection.
>
> I see mainly two use cases:
>
>     1.) Human-readable portnames on larger cards where "playback_56" is
>         simply to cumbersome to figure out what's actually connected
>
>     2.) People who travel with ADAT-ADCs/DACs, but connect them via
>         different interfaces in different locations, e.g. a Multiface
>         when on the road and a RayDat when in the studio. Despite the
>         different cards, the port names and hence any ardour session
>         would remain intact.
>
> We would probably want a generic approach including firewire, either by
> duplicating the code (bad) or somewhere higher in the higher layers, but
> let's get started, first.
>
> Here is how it looks like:
>
>     http://adi.loris.tv/jackd2-portnames.png
>
> Right now, I've added a bit of verbosity to point the user to the
> correct file location:
>
> Using port names patch v0.1 (07.04.2010)
> Trying to load portnames from /home/racl/adi/.config/jack/cards/RME
> RayDAT_f1cd85.ss.ports.in
> Trying to load portnames from /home/racl/adi/.config/jack/cards/RME
> RayDAT_f1cd85.ports.in
> Trying to load portnames from /etc/jack/cards/RME RayDAT_f1cd85.ss.ports.in
> Trying to load portnames from /etc/jack/cards/RME RayDAT_f1cd85.ports.in
> Trying to load portnames from /home/racl/adi/.config/jack/cards/RME
> RayDAT_f1cd85.ss.ports.out
> Trying to load portnames from /home/racl/adi/.config/jack/cards/RME
> RayDAT_f1cd85.ports.out
> Trying to load portnames from /etc/jack/cards/RME RayDAT_f1cd85.ss.ports.out
> Trying to load portnames from /etc/jack/cards/RME RayDAT_f1cd85.ports.out
>
>
> The beginning of my ports.in file:
>
> # generated by hdspm
> 1=Korg-L
> 2=Korg-R
> 3=IN-ADAT1.3
> 4=IN-ADAT1.4
> 5=IN-ADAT1.5
> 6=IN-ADAT1.6
> 7=Guitar
> 8=Sindy
>
> While the generic portnames were defined by the driver, I had to prepend
> an "IN-" to have different portnames for input and output.
>
> How do you feel about system:in:portname? This is easier for the user,
> but a little less freedom.
>
> OTOH, I can also image cardname:portname in case users have multiple
> cards.
>
> That's the main purpose of this RFC: what's a useful naming convention?
> Any requirements from the pro-audio/broadcasting camp?
>
> Note that all the previous names are still available:
>
> $ jack_lsp -A
> system:Korg-L
>     alsa_pcm:hw:1,0:out1
>     system:capture_1
> system:Korg-R
>     alsa_pcm:hw:1,0:out2
>     system:capture_2
> [...]
>
> This hopefully remains backward compatibility with existing sessions.
>
> Of course, if we agree on something, I'd forward-port faberman's jackd
> version, too, but since jackd2 was installed on my workstation, I
> started with jackd2.
>
>
> Note that nobody has to use portnames. If the user does nothing, he'd
> end up with his ordinary channel names. The patch hence targets more
> advanced users.
>
>
>
> Cheers
>
> And here's the patch:
>
>
> --- /dev/null
> +++ b/linux/alsa/port_names.c
> @@ -0,0 +1,179 @@
> +/* -*- mode: c; c-file-style: "linux"; -*- */
> +/*
> +    Copyright (C) 2010 Florian Faber, [hidden]
> +
> +    This program is free software; you can redistribute it and/or modify
> +    it under the terms of the GNU General Public License as published by
> +    the Free Software Foundation; either version 2 of the License, or
> +    (at your option) any later version.
> +
> +    This program 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 General Public License for more details.
> +
> +    You should have received a copy of the GNU General Public License
> +    along with this program; if not, write to the Free Software
> +    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> +
> +*/
> +
> +
> +#include<math.h>
> +#include<stdio.h>
> +#include<memory.h>
> +#include<unistd.h>
> +#include<stdlib.h>
> +#include<errno.h>
> +#include<stdarg.h>
> +#include<signal.h>
> +#include<sys/types.h>
> +#include<regex.h>
> +#include<string.h>
> +
> +#include "alsa_driver.h"
> +
> +
> +static int port_names_load_portfile(alsa_driver_t *driver, const char
> *filename, char **buf, const unsigned int offset, const unsigned int num) {
> +	int fh, i, ret, lineno, id, res=0;
> +	char line[256];
> +
> +	printf("Trying to load portnames from %s\n", filename);
> +	fh = open(filename, O_RDONLY);
> +	if (-1!=fh) {
> +		res = 1;
> +		i = 0;
> +		lineno = 1;
> +		for (;;) {
> +			ret = read(fh,&line[i], 1);
> +			if (0==ret) {
> +				break;
> +			} else if (-1==ret) {
> +				sprintf(stderr, "Error while reading \"%s\": %s", filename,
> strerror(errno));
> +				break;
> +			}
> +			if (0x0A==line[i]) {
> +				/* new line, parse input */
> +				line[i] = 0;
> +
> +				if ('#' != line[0]) {
> +					i=0;
> +					while ((i<255)&&  (line[i]!='=')) i++;
> +					if (255==i) {
> +						sprintf(stderr, "Error while reading \"%s\": Line %d has no
> key=value syntax!", filename, lineno);
> +					} else {
> +						line[i] = 0;
> +						id = atoi(line);
> +						if ((id>=1)&&  (id<=num)) {
> +							if (NULL==buf[id-1+offset]) {
> +								/* don't overwrite existing names */
> +								buf[id-1+offset] = strdup(&line[i+1]);
> +							}
> +						} else {
> +							sprintf(stderr, "Error while reading \"%s\": Key %d out of range
> in line %d (1..%d)", filename, id, lineno, num);
> +						}
> +					}
> +				}
> +
> +				i = 0;
> +				lineno++;
> +			} else {
> +				i++;
> +				if (i==255) {
> +					sprintf(stderr, "Error while reading \"%s\": Line %d is too long",
> filename, lineno);
> +					break;
> +				}
> +			}
> +		}
> +
> +		(void) close(fh);
> +	}
> +
> +	return res;
> +}
> +
> +
> +static void port_names_default_portnames(char **buf, const unsigned int
> offset, const unsigned int num, const char *defaultname) {
> +	unsigned int i;
> +	char line[256];
> +
> +	/* Fill in default names */
> +	for (i=0; i<num; i++) {
> +		if (NULL==buf[i+offset]) {
> +			snprintf(line, 255, defaultname, i+1);
> +			buf[i+offset] = strdup(line);
> +		}
> +	}
> +}
> +
> +
> +char** port_names_get_portnames(alsa_driver_t *driver) {
> +	snd_ctl_card_info_t *card_info;
> +	int err;
> +	const char *card_name = NULL;
> +	char filename[256], *speed;
> +	char **buf;
> +
> +	printf("Using port names patch v0.1 (07.04.2010)\n");
> +
> +	if (driver->frame_rate>  96000) {
> +		speed="qs";
> +	} else if (driver->frame_rate>  48000) {
> +		speed="ds";
> +	} else {
> +		speed="ss";
> +	}
> +
> +	snd_ctl_card_info_alloca(&card_info);
> +	err = snd_ctl_card_info(driver->ctl_handle, card_info);
> +	if (err>= 0) {
> +		card_name = snd_ctl_card_info_get_name(card_info);
> +	} else {
> +		card_name = "noname";
> +	}
> +
> +	buf = malloc(sizeof(char *)*(driver->capture_nchannels +
> driver->playback_nchannels));
> +	if (NULL==buf) {
> +		sprintf(stderr, "ALSA: Not enough memory for %d port names",
> driver->capture_nchannels + driver->playback_nchannels);
> +		return NULL;
> +	}
> +	bzero(buf, sizeof(char *)*(driver->capture_nchannels +
> driver->playback_nchannels));
> +
> +	/* Read port names from special to general:
> +	 * Begin with user and speed specific port names */
> +	snprintf(filename, 255, "%s/.config/jack/cards/%s.%s.ports.in",
> getenv("HOME"), card_name, speed);
> +	(void) port_names_load_portfile(driver, filename, buf, 0,
> driver->capture_nchannels);
> +
> +	/* Now user general */
> +	snprintf(filename, 255, "%s/.config/jack/cards/%s.ports.in",
> getenv("HOME"), card_name);
> +	(void) port_names_load_portfile(driver, filename, buf, 0,
> driver->capture_nchannels);
> +
> +	/* System speed specific */
> +	snprintf(filename, 255, "/etc/jack/cards/%s.%s.ports.in", card_name,
> speed);
> +	(void) port_names_load_portfile(driver, filename, buf, 0,
> driver->capture_nchannels);
> +
> +	/* System general */
> +	snprintf(filename, 255, "/etc/jack/cards/%s.ports.in", card_name);
> +	(void) port_names_load_portfile(driver, filename, buf, 0,
> driver->capture_nchannels);
> +
> +	/* Fill all still unnamed ports with default names */
> +	port_names_default_portnames(buf, 0, driver->capture_nchannels,
> "capture_%lu");
> +
> +
> +	/* Same procedure for the playback channels */
> +	snprintf(filename, 255, "%s/.config/jack/cards/%s.%s.ports.out",
> getenv("HOME"), card_name, speed);
> +	(void) port_names_load_portfile(driver, filename, buf,
> driver->capture_nchannels, driver->playback_nchannels);
> +
> +	snprintf(filename, 255, "%s/.config/jack/cards/%s.ports.out",
> getenv("HOME"), card_name);
> +	(void) port_names_load_portfile(driver, filename, buf,
> driver->capture_nchannels, driver->playback_nchannels);
> +
> +	snprintf(filename, 255, "/etc/jack/cards/%s.%s.ports.out", card_name,
> speed);
> +	(void) port_names_load_portfile(driver, filename, buf,
> driver->capture_nchannels, driver->playback_nchannels);
> +
> +	snprintf(filename, 255, "/etc/jack/cards/%s.ports.out", card_name);
> +	(void) port_names_load_portfile(driver, filename, buf,
> driver->capture_nchannels, driver->playback_nchannels);
> +
> +	port_names_default_portnames(buf, driver->capture_nchannels,
> driver->playback_nchannels, "playback_%lu");
> +
> +	return buf;
> +}
> --- /dev/null
> +++ b/linux/alsa/port_names.h
> @@ -0,0 +1,34 @@
> +/*
> +    Copyright (C) 2010 Florian Faber, [hidden]
> +
> +    This program is free software; you can redistribute it and/or modify
> +    it under the terms of the GNU General Public License as published by
> +    the Free Software Foundation; either version 2 of the License, or
> +    (at your option) any later version.
> +
> +    This program 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 General Public License for more details.
> +
> +    You should have received a copy of the GNU General Public License
> +    along with this program; if not, write to the Free Software
> +    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> +
> +*/
> +
> +#ifndef __jack_port_names_h__
> +#define __jack_port_names_h__
> +
> +#ifdef __cplusplus
> +extern "C"
> +{
> +#endif
> +
> +char** port_names_get_portnames(alsa_driver_t *driver);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* __jack_port_names_h__ */
> --- a/linux/alsa/JackAlsaDriver.cpp
> +++ b/linux/alsa/JackAlsaDriver.cpp
> @@ -43,6 +43,7 @@
>   #include "JackPosixThread.h"
>   #include "JackCompilerDeps.h"
>   #include "JackServerGlobals.h"
> +#include "port_names.h"
>
>   namespace Jack
>   {
> @@ -72,6 +73,8 @@
>       unsigned long port_flags = (unsigned long)CaptureDriverFlags;
>       char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
>       char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
> +    char old_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
> +    char **portnames;
>       jack_latency_range_t range;
>
>       assert(fCaptureChannels<  DRIVER_PORT_NUM);
> @@ -88,15 +91,20 @@
>
>       jack_log("JackAlsaDriver::Attach fBufferSize %ld fSampleRate %ld",
> fEngineControl->fBufferSize, fEngineControl->fSampleRate);
>
> +    portnames = port_names_get_portnames(alsa_driver);
> +
>       for (int i = 0; i<  fCaptureChannels; i++) {
>           snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName,
> fCaptureDriverName, i + 1);
> -        snprintf(name, sizeof(name) - 1, "%s:capture_%d",
> fClientControl.fName, i + 1);
> +        snprintf(old_name, sizeof(old_name) - 1, "%s:capture_%d",
> fClientControl.fName, i + 1);
> +        snprintf(name, sizeof(name) - 1, "%s:%s", fClientControl.fName,
> portnames[i]);
>           if ((port_index =
> fGraphManager->AllocatePort(fClientControl.fRefNum, name,
> JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags,
> fEngineControl->fBufferSize)) == NO_PORT) {
>               jack_error("driver: cannot register port for %s", name);
>               return -1;
>           }
> +        free(portnames[i]);
>           port = fGraphManager->GetPort(port_index);
>           port->SetAlias(alias);
> +        port->SetAlias(old_name);
>           range.min = range.max = alsa_driver->frames_per_cycle +
> alsa_driver->capture_frame_latency;
>           port->SetLatencyRange(JackCaptureLatency,&range);
>           fCapturePortList[i] = port_index;
> @@ -107,13 +115,16 @@
>
>       for (int i = 0; i<  fPlaybackChannels; i++) {
>           snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName,
> fPlaybackDriverName, i + 1);
> -        snprintf(name, sizeof(name) - 1, "%s:playback_%d",
> fClientControl.fName, i + 1);
> +        snprintf(old_name, sizeof(old_name) - 1, "%s:playback_%d",
> fClientControl.fName, i + 1);
> +        snprintf(name, sizeof(name) - 1, "%s:%s", fClientControl.fName,
> portnames[i+fCaptureChannels]);
>           if ((port_index =
> fGraphManager->AllocatePort(fClientControl.fRefNum, name,
> JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags,
> fEngineControl->fBufferSize)) == NO_PORT) {
>               jack_error("driver: cannot register port for %s", name);
>               return -1;
>           }
> +        free(portnames[i+fCaptureChannels]);
>           port = fGraphManager->GetPort(port_index);
>           port->SetAlias(alias);
> +        port->SetAlias(old_name);
>           // Add one buffer more latency if "async" mode is used...
>           range.min = range.max = (alsa_driver->frames_per_cycle *
> (alsa_driver->user_nperiods - 1)) +
>                            ((fEngineControl->fSyncMode) ? 0 :
> fEngineControl->fBufferSize) + alsa_driver->playback_frame_latency;
> @@ -137,6 +148,8 @@
>           }
>       }
>
> +    free(portnames);
> +
>       if (alsa_driver->midi) {
>           int err = (alsa_driver->midi->attach)(alsa_driver->midi);
>           if (err)
> --- a/linux/wscript
> +++ b/linux/wscript
> @@ -54,6 +54,7 @@
>                          'alsa/hdsp.c',
>   		       'alsa/alsa_driver.c',
>                          'alsa/hammerfall.c',
> +                       'alsa/port_names.c',
>                          'alsa/ice1712.c'
>                          ]
>
>
>
> 
> Jack-Devel mailing list
> [hidden]
> http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org
PrevNext  Index

1320329375.32612_0.ltw:2,a <4EB2A06B.4080900 at comcast dot net>