mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-27 07:58:16 -04:00
jack-tunnel: support passing port names to link
Add jack.connect-audio and jack.connect-midi to specify an array of port names to link to instead of the default phyisical ports. Also actually fixes linking the midi ports correctly.
This commit is contained in:
parent
74035f0a34
commit
a241495eaf
2 changed files with 70 additions and 35 deletions
|
|
@ -49,7 +49,7 @@ context.properties = {
|
||||||
minimal.use-pulse = true
|
minimal.use-pulse = true
|
||||||
|
|
||||||
# Load the jack-tunnel as a backend
|
# Load the jack-tunnel as a backend
|
||||||
minimal.use-jack-tunnel = false
|
minimal.use-jack-tunnel = true
|
||||||
}
|
}
|
||||||
|
|
||||||
context.properties.rules = [
|
context.properties.rules = [
|
||||||
|
|
@ -163,12 +163,16 @@ context.modules = [
|
||||||
#jack.server = null
|
#jack.server = null
|
||||||
#jack.client-name = PipeWire
|
#jack.client-name = PipeWire
|
||||||
#jack.connect = true
|
#jack.connect = true
|
||||||
|
#jack.connect-audio = [ ]
|
||||||
|
#jack.connect-midi = [ ]
|
||||||
#tunnel.mode = duplex
|
#tunnel.mode = duplex
|
||||||
#midi.ports = 0
|
#midi.ports = 1
|
||||||
#audio.channels = 2
|
#audio.channels = 2
|
||||||
#audio.position = [ FL FR ]
|
#audio.position = [ FL FR ]
|
||||||
source.props = {
|
source.props = {
|
||||||
# extra sink properties
|
# extra sink properties
|
||||||
|
#jack.connect-audio = [ "system:capture_1" ]
|
||||||
|
#jack.connect-midi = [ "system:midi_capture_2" ]
|
||||||
# jack-tunnel needs a PortConfig from the
|
# jack-tunnel needs a PortConfig from the
|
||||||
# session manager so do this here.
|
# session manager so do this here.
|
||||||
node.param.PortConfig = {
|
node.param.PortConfig = {
|
||||||
|
|
@ -178,6 +182,8 @@ context.modules = [
|
||||||
}
|
}
|
||||||
sink.props = {
|
sink.props = {
|
||||||
# extra sink properties
|
# extra sink properties
|
||||||
|
#jack.connect-audio = [ "system:playback_1" ]
|
||||||
|
#jack.connect-midi = [ "system:midi_playback_2" ]
|
||||||
node.param.PortConfig = {
|
node.param.PortConfig = {
|
||||||
direction = Input
|
direction = Input
|
||||||
mode = dsp
|
mode = dsp
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,12 @@
|
||||||
* - `jack.client-name`: the name of the JACK client.
|
* - `jack.client-name`: the name of the JACK client.
|
||||||
* - `jack.connect`: if jack ports should be connected automatically. Can also be
|
* - `jack.connect`: if jack ports should be connected automatically. Can also be
|
||||||
* placed per stream.
|
* placed per stream.
|
||||||
|
* - `jack.connect-audio`: An array of audio ports to connect to. Can also be placed per
|
||||||
|
* stream. An empty array will not connect anything, even when
|
||||||
|
* jack.connect is true.
|
||||||
|
* - `jack.connect-midi`: An array of midi ports to connect to. Can also be placed per
|
||||||
|
* stream. An empty array will not connect anything, even when
|
||||||
|
* jack.connect is true.
|
||||||
* - `tunnel.mode`: the tunnel mode, sink|source|duplex, default duplex
|
* - `tunnel.mode`: the tunnel mode, sink|source|duplex, default duplex
|
||||||
* - `midi.ports`: the number of midi ports. Can also be added to the stream props.
|
* - `midi.ports`: the number of midi ports. Can also be added to the stream props.
|
||||||
* - `source.props`: Extra properties for the source filter.
|
* - `source.props`: Extra properties for the source filter.
|
||||||
|
|
@ -86,6 +92,8 @@
|
||||||
* #jack.server = null
|
* #jack.server = null
|
||||||
* #jack.client-name = PipeWire
|
* #jack.client-name = PipeWire
|
||||||
* #jack.connect = true
|
* #jack.connect = true
|
||||||
|
* #jack.connect-audio = [ playback_1 playback_2 ]
|
||||||
|
* #jack.connect-midi = [ midi_playback_1 ]
|
||||||
* #tunnel.mode = duplex
|
* #tunnel.mode = duplex
|
||||||
* #midi.ports = 0
|
* #midi.ports = 0
|
||||||
* #audio.channels = 2
|
* #audio.channels = 2
|
||||||
|
|
@ -118,6 +126,8 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
||||||
"( jack.server=<server name> ) " \
|
"( jack.server=<server name> ) " \
|
||||||
"( jack.client-name=<name of the JACK client> ] " \
|
"( jack.client-name=<name of the JACK client> ] " \
|
||||||
"( jack.connect=<bool, autoconnect ports> ] " \
|
"( jack.connect=<bool, autoconnect ports> ] " \
|
||||||
|
"( jack.connect-audio=<array, port names to connect> ] "\
|
||||||
|
"( jack.connect-midi=<array, port names to connect> ] " \
|
||||||
"( tunnel.mode=<sink|source|duplex> ] " \
|
"( tunnel.mode=<sink|source|duplex> ] " \
|
||||||
"( midi.ports=<number of midi ports> ] " \
|
"( midi.ports=<number of midi ports> ] " \
|
||||||
"( audio.channels=<number of channels> ] " \
|
"( audio.channels=<number of channels> ] " \
|
||||||
|
|
@ -164,7 +174,6 @@ struct stream {
|
||||||
struct volume volume;
|
struct volume volume;
|
||||||
|
|
||||||
unsigned int running:1;
|
unsigned int running:1;
|
||||||
unsigned int connect:1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct impl {
|
struct impl {
|
||||||
|
|
@ -450,10 +459,10 @@ static void make_stream_ports(struct stream *s)
|
||||||
struct pw_properties *props;
|
struct pw_properties *props;
|
||||||
const char *str, *prefix, *type;
|
const char *str, *prefix, *type;
|
||||||
char name[256];
|
char name[256];
|
||||||
const char **audio_ports = NULL, **link_ports = NULL;
|
char **audio_ports = NULL, **midi_ports = NULL;
|
||||||
const char **midi_ports = NULL;
|
|
||||||
unsigned long jack_peer, jack_flags;
|
unsigned long jack_peer, jack_flags;
|
||||||
bool is_midi;
|
bool do_connect, is_midi, strv_audio = false, strv_midi = false;
|
||||||
|
int res, n_audio_ports = 0, n_midi_ports = 0;
|
||||||
|
|
||||||
if (s->direction == PW_DIRECTION_INPUT) {
|
if (s->direction == PW_DIRECTION_INPUT) {
|
||||||
/* sink */
|
/* sink */
|
||||||
|
|
@ -467,14 +476,28 @@ static void make_stream_ports(struct stream *s)
|
||||||
prefix = "capture";
|
prefix = "capture";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->connect) {
|
do_connect = pw_properties_get_bool(s->props, "jack.connect", true);
|
||||||
audio_ports = jack.get_ports(impl->client, NULL, JACK_DEFAULT_AUDIO_TYPE,
|
|
||||||
|
str = pw_properties_get(s->props, "jack.connect-audio");
|
||||||
|
if (str != NULL) {
|
||||||
|
audio_ports = pw_strv_parse(str, strlen(str), INT_MAX, NULL);
|
||||||
|
strv_audio = true;
|
||||||
|
} else if (do_connect) {
|
||||||
|
audio_ports = (char**)jack.get_ports(impl->client, NULL, JACK_DEFAULT_AUDIO_TYPE,
|
||||||
JackPortIsPhysical|jack_peer);
|
JackPortIsPhysical|jack_peer);
|
||||||
midi_ports = jack.get_ports(impl->client, NULL, JACK_DEFAULT_MIDI_TYPE,
|
}
|
||||||
|
str = pw_properties_get(s->props, "jack.connect-midi");
|
||||||
|
if (str != NULL) {
|
||||||
|
midi_ports = pw_strv_parse(str, strlen(str), INT_MAX, NULL);
|
||||||
|
strv_midi = true;
|
||||||
|
} else if (do_connect) {
|
||||||
|
midi_ports = (char**)jack.get_ports(impl->client, NULL, JACK_DEFAULT_MIDI_TYPE,
|
||||||
JackPortIsPhysical|jack_peer);
|
JackPortIsPhysical|jack_peer);
|
||||||
}
|
}
|
||||||
for (i = 0; i < s->n_ports; i++) {
|
for (i = 0; i < s->n_ports; i++) {
|
||||||
struct port *port = s->ports[i];
|
struct port *port = s->ports[i];
|
||||||
|
char *link_port = NULL;
|
||||||
|
|
||||||
if (port != NULL) {
|
if (port != NULL) {
|
||||||
s->ports[i] = NULL;
|
s->ports[i] = NULL;
|
||||||
if (port->jack_port)
|
if (port->jack_port)
|
||||||
|
|
@ -498,7 +521,9 @@ static void make_stream_ports(struct stream *s)
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
type = JACK_DEFAULT_AUDIO_TYPE;
|
type = JACK_DEFAULT_AUDIO_TYPE;
|
||||||
link_ports = audio_ports;
|
if (audio_ports && audio_ports[n_audio_ports])
|
||||||
|
link_port = audio_ports[n_audio_ports++];
|
||||||
|
|
||||||
is_midi = false;
|
is_midi = false;
|
||||||
} else {
|
} else {
|
||||||
snprintf(name, sizeof(name), "%s_%d", prefix, i - s->info.channels);
|
snprintf(name, sizeof(name), "%s_%d", prefix, i - s->info.channels);
|
||||||
|
|
@ -509,7 +534,8 @@ static void make_stream_ports(struct stream *s)
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
type = JACK_DEFAULT_MIDI_TYPE;
|
type = JACK_DEFAULT_MIDI_TYPE;
|
||||||
link_ports = midi_ports;
|
if (midi_ports && midi_ports[n_midi_ports])
|
||||||
|
link_port = midi_ports[n_midi_ports++];
|
||||||
is_midi = true;
|
is_midi = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -522,21 +548,35 @@ static void make_stream_ports(struct stream *s)
|
||||||
port->is_midi = is_midi;
|
port->is_midi = is_midi;
|
||||||
port->jack_port = jack.port_register (impl->client, name, type, jack_flags, 0);
|
port->jack_port = jack.port_register (impl->client, name, type, jack_flags, 0);
|
||||||
|
|
||||||
if (link_ports != NULL && link_ports[i] != NULL) {
|
if (link_port != NULL) {
|
||||||
if (jack_flags & JackPortIsOutput) {
|
if (jack_flags & JackPortIsOutput) {
|
||||||
if (jack.connect(impl->client, jack.port_name(port->jack_port), link_ports[i]))
|
pw_log_info("connecting ports '%s' to '%s'",
|
||||||
pw_log_warn("cannot connect ports");
|
jack.port_name(port->jack_port), link_port);
|
||||||
|
if ((res = jack.connect(impl->client, jack.port_name(port->jack_port), link_port)))
|
||||||
|
pw_log_warn("cannot connect ports '%s' to '%s': %s",
|
||||||
|
jack.port_name(port->jack_port), link_port, strerror(res));
|
||||||
} else {
|
} else {
|
||||||
if (jack.connect(impl->client, link_ports[i], jack.port_name(port->jack_port)))
|
pw_log_info("connecting ports '%s' to '%s'",
|
||||||
pw_log_warn("cannot connect ports");
|
link_port, jack.port_name(port->jack_port));
|
||||||
|
if ((res = jack.connect(impl->client, link_port, jack.port_name(port->jack_port))))
|
||||||
|
pw_log_warn("cannot connect ports '%s' to '%s': %s",
|
||||||
|
link_port, jack.port_name(port->jack_port), strerror(res));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s->ports[i] = port;
|
s->ports[i] = port;
|
||||||
}
|
}
|
||||||
if (audio_ports)
|
if (audio_ports) {
|
||||||
jack.free(audio_ports);
|
if (strv_audio)
|
||||||
if (midi_ports)
|
pw_free_strv(audio_ports);
|
||||||
jack.free(midi_ports);
|
else
|
||||||
|
jack.free(audio_ports);
|
||||||
|
}
|
||||||
|
if (midi_ports) {
|
||||||
|
if (strv_midi)
|
||||||
|
pw_free_strv(midi_ports);
|
||||||
|
else
|
||||||
|
jack.free(midi_ports);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct spa_pod *make_props_param(struct spa_pod_builder *b,
|
static struct spa_pod *make_props_param(struct spa_pod_builder *b,
|
||||||
|
|
@ -640,8 +680,7 @@ static int make_stream(struct stream *s, const char *name)
|
||||||
n_params = 0;
|
n_params = 0;
|
||||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||||
|
|
||||||
s->filter = pw_filter_new(impl->core, name, s->props);
|
s->filter = pw_filter_new(impl->core, name, pw_properties_copy(s->props));
|
||||||
s->props = NULL;
|
|
||||||
if (s->filter == NULL)
|
if (s->filter == NULL)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
|
@ -930,12 +969,8 @@ static int create_jack_client(struct impl *impl)
|
||||||
impl->source.info.rate = impl->samplerate;
|
impl->source.info.rate = impl->samplerate;
|
||||||
impl->sink.info.rate = impl->samplerate;
|
impl->sink.info.rate = impl->samplerate;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int start_jack_clients(struct impl *impl)
|
|
||||||
{
|
|
||||||
jack.activate(impl->client);
|
jack.activate(impl->client);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1121,6 +1156,8 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
||||||
copy_props(impl, props, PW_KEY_NODE_GROUP);
|
copy_props(impl, props, PW_KEY_NODE_GROUP);
|
||||||
copy_props(impl, props, PW_KEY_NODE_VIRTUAL);
|
copy_props(impl, props, PW_KEY_NODE_VIRTUAL);
|
||||||
copy_props(impl, props, "jack.connect");
|
copy_props(impl, props, "jack.connect");
|
||||||
|
copy_props(impl, props, "jack.connect-audio");
|
||||||
|
copy_props(impl, props, "jack.connect-midi");
|
||||||
|
|
||||||
parse_audio_info(impl->source.props, &impl->source.info);
|
parse_audio_info(impl->source.props, &impl->source.info);
|
||||||
parse_audio_info(impl->sink.props, &impl->sink.info);
|
parse_audio_info(impl->sink.props, &impl->sink.info);
|
||||||
|
|
@ -1138,11 +1175,6 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl->source.connect = pw_properties_get_bool(impl->source.props,
|
|
||||||
"jack.connect", true);
|
|
||||||
impl->sink.connect = pw_properties_get_bool(impl->sink.props,
|
|
||||||
"jack.connect", true);
|
|
||||||
|
|
||||||
impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core);
|
impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core);
|
||||||
if (impl->core == NULL) {
|
if (impl->core == NULL) {
|
||||||
str = pw_properties_get(props, PW_KEY_REMOTE_NAME);
|
str = pw_properties_get(props, PW_KEY_REMOTE_NAME);
|
||||||
|
|
@ -1172,9 +1204,6 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
||||||
if ((res = create_filters(impl)) < 0)
|
if ((res = create_filters(impl)) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if ((res = start_jack_clients(impl)) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
|
pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
|
||||||
|
|
||||||
pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
|
pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue