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. http://adi.loris.tv/jackd2-portnames.png alsa_pcm:hw:1,0:out1 system:capture_1 alsa_pcm:hw:1,0:out2 system:capture_2 --- /dev/null +++ b/linux/alsa/port_names.c @@ -0,0 +1,179 @@ +/* -*- mode: c; c-file-style: "linux"; -*- */ +/* + Copyright (C) 2010 Florian Faber, faber@faberman.de + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; iframe_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, faber@faberman.de + + 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 @@ -42,6 +42,7 @@ #include "JackPosixThread.h" #include "JackCompilerDeps.h" #include "JackServerGlobals.h" +#include "port_names.h" namespace Jack { @@ -97,6 +98,8 @@ unsigned long port_flags = (unsigned long)CaptureDriverFlags; char name[REAL_JACK_PORT_NAME_SIZE]; char alias[REAL_JACK_PORT_NAME_SIZE]; + char old_name[REAL_JACK_PORT_NAME_SIZE]; + char **portnames; assert(fCaptureChannels < DRIVER_PORT_NUM); assert(fPlaybackChannels < DRIVER_PORT_NUM); @@ -112,13 +115,17 @@ 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), "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1); - snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, i + 1); + snprintf(old_name, sizeof(old_name), "%s:capture_%d", fClientControl.fName, i + 1); + snprintf(name, sizeof(name), "%s:%s", fClientControl.fName, portnames[i]); if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_index) < 0) { jack_error("driver: cannot register port for %s", name); return -1; } + free(portnames[i]); port = fGraphManager->GetPort(port_index); port->SetAlias(alias); fCapturePortList[i] = port_index; @@ -129,11 +136,13 @@ for (int i = 0; i < fPlaybackChannels; i++) { snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, i + 1); - snprintf(name, sizeof(name), "%s:playback_%d", fClientControl.fName, i + 1); + snprintf(old_name, sizeof(old_name), "%s:playback_%d", fClientControl.fName, i + 1); + snprintf(name, sizeof(name), "%s:%s", fClientControl.fName, portnames[i+fCaptureChannels]); if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_index) < 0) { jack_error("driver: cannot register port for %s", name); return -1; } + free(portnames[i+fCaptureChannels]); port = fGraphManager->GetPort(port_index); port->SetAlias(alias); fPlaybackPortList[i] = port_index; @@ -151,6 +160,8 @@ } } + free(portnames); + UpdateLatencies(); if (alsa_driver->midi) { --- a/linux/wscript +++ b/linux/wscript @@ -55,6 +55,7 @@ 'alsa/hdsp.c', 'alsa/alsa_driver.c', 'alsa/hammerfall.c', + 'alsa/port_names.c', 'alsa/ice1712.c' ] alsa_pcm:hw:1,0:out1 system:capture_1 alsa_pcm:hw:1,0:out2 system:capture_2 alsa_pcm:hw:1,0:out3 system:capture_3 alsa_pcm:hw:1,0:out4 system:capture_4 alsa_pcm:hw:1,0:out5 system:capture_5 alsa_pcm:hw:1,0:out6 system:capture_6 alsa_pcm:hw:1,0:out7 system:capture_7 alsa_pcm:hw:1,0:out8 system:capture_8 alsa_pcm:hw:1,0:out9 system:capture_9 alsa_pcm:hw:1,0:out10 system:capture_10 alsa_pcm:hw:1,0:out11 system:capture_11 alsa_pcm:hw:1,0:out12 system:capture_12 alsa_pcm:hw:1,0:out13 system:capture_13 alsa_pcm:hw:1,0:out14 system:capture_14 alsa_pcm:hw:1,0:out15 system:capture_15 alsa_pcm:hw:1,0:out16 system:capture_16 alsa_pcm:hw:1,0:out17 system:capture_17 alsa_pcm:hw:1,0:out18 system:capture_18 alsa_pcm:hw:1,0:out19 system:capture_19 alsa_pcm:hw:1,0:out20 system:capture_20 alsa_pcm:hw:1,0:out21 system:capture_21 alsa_pcm:hw:1,0:out22 system:capture_22 alsa_pcm:hw:1,0:out23 system:capture_23 alsa_pcm:hw:1,0:out24 system:capture_24 alsa_pcm:hw:1,0:out25 system:capture_25 alsa_pcm:hw:1,0:out26 system:capture_26 alsa_pcm:hw:1,0:out27 system:capture_27 alsa_pcm:hw:1,0:out28 system:capture_28 alsa_pcm:hw:1,0:out29 system:capture_29 alsa_pcm:hw:1,0:out30 system:capture_30 alsa_pcm:hw:1,0:out31 system:capture_31 alsa_pcm:hw:1,0:out32 system:capture_32 alsa_pcm:hw:1,0:out33 system:capture_33 alsa_pcm:hw:1,0:out34 system:capture_34 alsa_pcm:hw:1,0:out35 system:capture_35 alsa_pcm:hw:1,0:out36 system:capture_36 alsa_pcm:hw:1,0:in1 system:playback_1 alsa_pcm:hw:1,0:in2 system:playback_2 alsa_pcm:hw:1,0:in3 system:playback_3 alsa_pcm:hw:1,0:in4 system:playback_4 alsa_pcm:hw:1,0:in5 system:playback_5 alsa_pcm:hw:1,0:in6 system:playback_6 alsa_pcm:hw:1,0:in7 system:playback_7 alsa_pcm:hw:1,0:in8 system:playback_8 alsa_pcm:hw:1,0:in9 system:playback_9 alsa_pcm:hw:1,0:in10 system:playback_10 alsa_pcm:hw:1,0:in11 system:playback_11 alsa_pcm:hw:1,0:in12 system:playback_12 alsa_pcm:hw:1,0:in13 system:playback_13 alsa_pcm:hw:1,0:in14 system:playback_14 alsa_pcm:hw:1,0:in15 system:playback_15 alsa_pcm:hw:1,0:in16 system:playback_16 alsa_pcm:hw:1,0:in17 system:playback_17 alsa_pcm:hw:1,0:in18 system:playback_18 alsa_pcm:hw:1,0:in19 system:playback_19 alsa_pcm:hw:1,0:in20 system:playback_20 alsa_pcm:hw:1,0:in21 system:playback_21 alsa_pcm:hw:1,0:in22 system:playback_22 alsa_pcm:hw:1,0:in23 system:playback_23 alsa_pcm:hw:1,0:in24 system:playback_24 alsa_pcm:hw:1,0:in25 system:playback_25 alsa_pcm:hw:1,0:in26 system:playback_26 alsa_pcm:hw:1,0:in27 system:playback_27 alsa_pcm:hw:1,0:in28 system:playback_28 alsa_pcm:hw:1,0:in29 system:playback_29 alsa_pcm:hw:1,0:in30 system:playback_30 alsa_pcm:hw:1,0:in31 system:playback_31 alsa_pcm:hw:1,0:in32 system:playback_32 alsa_pcm:hw:1,0:in33 system:playback_33 alsa_pcm:hw:1,0:in34 system:playback_34 alsa_pcm:hw:1,0:in35 system:playback_35 alsa_pcm:hw:1,0:in36 system:playback_36