Coder Social home page Coder Social logo

spotlightkid / jack-matchmaker Goto Github PK

View Code? Open in Web Editor NEW
71.0 7.0 6.0 150 KB

Auto-connect new JACK ports matching the patterns given on the command line.

License: GNU General Public License v2.0

Python 95.29% Shell 4.71%
jackaudio connections connection-manager

jack-matchmaker's Introduction

jack-matchmaker

Auto-connect JACK ports as they appear and when they match the port patterns given on the command line or read from a file.

Latest version Date of latest release Project status GNU General Public License 2 Python versions Distribution format

Description

jack-matchmaker is a small command line utility that listens to port registrations by JACK clients and connects these ports when their names match one of the port pattern pairs given on the command line at startup. jack-matchmaker never disconnects any ports.

The port name patterns are specified as pairs of positional arguments or read from a file (see below) and by default are always interpreted as Python regular expressions, where the first pattern of a pair is matched against both output (readable) ports and input (writeable) ports, and the second pattern of a pair is matched only against input ports. As many pattern pairs as needed can be given.

If the first pattern matches an input port, all output ports connected to that input port will be connected to the input ports matching the second pattern.

Patterns are matched against:

  • normal port names
  • port aliases
  • pretty-names set in the port meta data

You can run jack-matchmaker -oian to list all available output and input ports with their aliases and pretty-names.

Installation

Before you install the software, please refer to the section "Requirements".

Then simply do:

$ pip install jack-matchmaker

There is also an AUR package available for Arch Linux users.

Usage

Run jack-matchmaker -h (or --help) to show help on the available command line options.

See also the section "Systemd service" below on how to use jack-matchmaker as a systemd user service.

Examples

Automatically connect the first two ports of Fluidsynth to the audio outs using exact matching mode:

$ jack-matchmaker -e \
    fluidsynth:l_01 system:playback_1 \
    fluidsynth:r_01 system:playback_2

Both the output port and the input port patterns can be regular expressions. If a match is found on an output port, the matching port will be connected to all input ports, which match the corresponding input port pattern:

$ jack-matchmaker \
    'fluidsynth:l_\d+' 'system:playback_[13]' \
    'fluidsynth:r_\d+' 'system:playback_[24]'

You can also use named regular expression groups in the output port pattern and fill the port name sub-strings they match to into placeholders in the input port pattern:

$ jack-matchmaker \
    'system:midi_capture_(?P<num>\d+)$' 'mydaw:midi_in_track_{num}'

Automatically connect all ports going to the system output to an FFmpeg recording instance as well:

$ jack-matchmaker \
    'system:playback_(?P<num>\d+)$' 'ffmpeg:input_{num}'

Regular expression and exact matching

By default port name patterns are always interpreted as Python regular expressions and are matched against port names, aliases and pretty-names using case-sensitive matching. They are anchored to the start of the string they match, i.e. they must match the start of the port name, but they still match, if the port name continues after the part the pattern matches.

E.g. the pattern client:out_\d matches client:out_1, client:out_2 etc. and also client:out_10 (even though the trailing zero is not included in the pattern), but does not match otherclient:out_1.

You can still match port names with arbitrary prefixes by using .* at the start of the pattern, e.g. .*client:out_\d.

To anchor the pattern to the end of the matched string as well, use a $ at the end of the pattern. E.g client:out_[12]$ will match client:out_1 and client:out_2, but not client:out_10, client:out_21 etc.

To use exact string matching instead of regular expression matching, use the -e, --exact-matching command line option. When this option is given, patterns must match port names (or aliases or pretty-names) exactly. You can still use regular expression patterns by enclosing a pattern in forward slashes, e.g. like so:

$ jack-matchmaker -e system:capture_1 '/myclient:in_l_\d+/'

All this applies to patterns given as positional command line arguments and to patterns listed in a pattern file (see below).

Pattern match group substitution

An output port pattern can contain one or more named groups with the syntax (?P<name>...), where the three dots represent a sub regular expression. The part of the port name matched by this sub regex, is available as a substitution value for a placeholder corresponding to the name of group in the input port pattern. Placeholders use the Python string formatting syntax.

Example:

$ jack-matchmaker \
    'mysynth:out_(?P<channel>[lr])_\d+$' 'myfx:in_{channel}$'

This would connect all ports named mysynth:out_l_1, mysynth:out_l_2 and so on to myfx:in_l and all ports named mysynth:out_r_1, mysynth:out_r_2 and so on to myfx:in_r.

Pattern files

In addition to or instead of listing port patterns as as positional arguments on the command line, port patterns can also be put in a textfile.

The -p, --pattern-file option instructs the program to read the patterns from the file path given as the option value. The file must list one port pattern per line, where the first line of every pair of two lines specifies the output port pattern, and the second specifies the input port pattern. Empty lines and lines starting with a hash-sign (#) are ignored and whitespace at the start of the end of each line is stripped.

Example file:

# Left channel
# This will match output ports of any client named
# 'out_1', 'out_l', 'output_1' or 'output_l'
.*:out(put)?_(1|l)$
    system:playback_1

# Right channel
# This will match output ports of any client named
# 'out_2', 'out_r', 'output_2' or 'output_r'
.*:out(put)?_(2|r)$
    system:playback_2

# Another common naming scheme for output ports:
.*:Out L
    system:playback_1

.*:Out R
    system:playback_2

Easy pattern file creation

Set up your JACK connections using GUI tools like QJackCtl or Carla first. Then use jack-matchmaker -c > patterns to save a the current JACK connections in the file patterns in a pattern file compatible format. You may then edit this file and and delete or add pattern pairs as needed.

When using the -c option, you can also optionally give one or more regular expression patterns as positional arguments on the command line. In that case only connections, where any of the given patterns is matching (part of) either the output or input port names, are listed. If the patterns contain any uppercase letters, they will be matched in a case-sensitive fashion, if not, they will be matched case-insensitively. The patterns are matched against the full port name, including the client name. For example:

$ jack-matchmaker -c JACK

This would list connections, where one of the connected ports contains "JACK" in its name, but not if it contained only "jack" or "Jack" (unless matched by another pattern).

Reloading the pattern file

When you send a HUP signal to a running jack-matchmaker process, the file that was specified on the command line when the process was started is re-read and the resulting patterns replace all previously used patterns (including those listed as positional command line arguments!). If there should be an error reading the file, the pattern list will then be empty.

On systemd you can use systemctl --user reload jack-matchmaker to reload the pattern file.

JACK server connection

jack-matchmaker needs a connection to a running JACK server to be notified about new ports. On start-up it tries to connect to JACK until a connection can be established or the maximum number of connection attempts is exceeded. This number can be set with the command line option -m, --max-attempts, which defaults to 0 (i.e. infinite attempts or until interrupted). jack-matchmaker waits for 3 seconds between each connection attempt by default. Change this interval with the option -I, --connect-interval.

When jack-matchmaker is connected and the JACK server is stopped, the shutdown event is signaled to jack-matchmaker, which then enters the connection loop described above again.

To disconnect from the JACK server and stop jack-matchmaker, send an INT signal to the process, usually done by pressing Control-C in the terminal where jack-matchmaker is running.

Systemd service

You can optionally install jack-matchmaker as a systemd user service:

$ install -Dm644 systemd/jack-matchmaker.conf /etc/conf.d/jack-matchmaker
$ install -Dm644 systemd/jack-matchmaker.service -t /usr/lib/systemd/user

To start the service, edit /etc/conf.d/jack-matchmaker according to your needs (see section "Environment file" below) and then start the service with:

$ systemctl --user start jack-matchmaker

To stop it again:

$ systemctl --user stop jack-matchmaker

To reload the pattern file:

$ systemctl --user reload jack-matchmaker

Environment file

The jack-matchmaker systemd user service reads an environment file, which is expected to be located at /etc/conf.d/jack-matchmaker. In this file, you can set the following service startup settings as environment variables:

PATTERN_FILE (default: "/etc/jack-matchmaker/patterns.txt")

A file with port pattern pairs to read at startup as described above in section "Pattern files".

PATTERNS

A space-separated list of port patterns in pairs of two. The default list is empty and it is recommened to use PATTERN_FILE instead when running jack-matchmaker as a systemd service, unless the patterns should remain static and never change.

CLIENT_NAME (default: "jack-matchmaker")

Set the JACK client name used by jack-matchnmaker to the given value.

CONNECT_INTERVAL (default: 3)

Set the interval in seconds between attempts to connect to JACK server to the given numeric value.

EXACT_MATCHING

Enable literal matching mode. Patterns must match port names exactly. To still use regular expressions, surround a port pattern with forward slashes, e.g. "/system:out_\d+/".

Set EXACT_MATCHING to any value to enable it.

MAX_ATTEMPTS (default: 0)

Set the maximum number of attempts to connect to JACK server before giving up. The default value 0 means to keep on trying until interrupted.

VERBOSITY (default: INFO)

Set output verbosity level. Choices are: DEBUG, INFO, WARNING, and ERROR.

Requirements

  • A version of Python 3 with a ctypes module (i.e. PyPy 3 works too)
  • pyjacklib
  • cachetools
  • JACK version 1 or 2
  • Linux, OS X (untested) or Windows (untested, no signal handling)

License

jack-matchmaker is licensed under the GNU Public License Version v2.

Please see the file LICENSE for more information.

Author

jack-matchmaker was written by Christopher Arndt 2016 - 2023.

Acknowledgements

jack-matchmaker is written in Python and depends on the pyjacklib module, which was originally taken from falkTX's Cadence application but now turned into a stand-alone Python package and was heavily modified and extended in the process.

It was inspired by jack-autoconnect, which also auto-connects JACK ports, but doesn't support port aliases or meta data pretty-names. jack-autoconnect is also written in C++, and therefore probably faster and less memory hungry.

The idea to read ports (patterns) from a file and re-read them on the HUP signal was "inspired" by aj-snapshot.

There is also a similar tool called jack-plumbing, part of the jack-tools package on popular Linux distributions.

jack-matchmaker's People

Contributors

bluemax avatar peterfab9845 avatar spotlightkid avatar terencode avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

jack-matchmaker's Issues

Auto reconnect when Jack server is restarted

If the Jack server is restarted while matchmaker is running, stdout is flooded with "JackClientSocket::Read time out" messages. It could try to reconnect to the new Jack server.

Segfault

We run jack-matchmaker as a systemd service. After some time it crashed with a segfault. Other jack clients are not affected.
I don't know how to debug this.

[11557.773032] jack-matchmaker[1155]: segfault at 4 ip 00007f4c0d44b2ce sp 00007f4c0d0f2c50 error 4 in libjack.so.0.1.0[7f4c0d427000+28000]
[11557.773039] Code: ba 03 00 00 00 31 ff be 0c 00 00 00 e8 7b d2 fd ff 48 89 85 08 01 00 00 48 85 c0 0f 84 bb 00 00 00 80 bd 10 01 00 00 00 75 0a <44> 0f b6 60 05 45 84 e4 75 48 41 bc 01 00 00 00 48 83 c4 08 44 89
[12995.735951] jack-matchmaker[3759]: segfault at 4 ip 00007f998a4a92ce sp 00007ffcf9cfb3a0 error 4 in libjack.so.0.1.0[7f998a485000+28000]
[12995.735955] Code: ba 03 00 00 00 31 ff be 0c 00 00 00 e8 7b d2 fd ff 48 89 85 08 01 00 00 48 85 c0 0f 84 bb 00 00 00 80 bd 10 01 00 00 00 75 0a <44> 0f b6 60 05 45 84 e4 75 48 41 bc 01 00 00 00 48 83 c4 08 44 89

Ubuntu 20.04.1 with 5.4.0-62-lowlatency kernel

Reconnecting ports that have been disconnected

Thank you for writing this utility. It is very useful. The use-case I have an issue with is as follows. Suppose I have source "A" that is supposed to be connected to sink "B" by a rule in jack-matchmaker. once source "A" registers, reg_callback() will be called and in turn call _refresh() to connect it. Now suppose I used a graph GUI tool such as Carla to connect "A" to sink "C" and disconnect it from sink "B". Now if any additional port (such as source port "D") will register with jack, matchmaker will again execute _refresh() and will re-connect "A" to "B". my point is that reconnecting should only occur for and when a port on the rules list registers, and not be globally refreshed and re-connected when any registration occurs.

Only makes a connection if none already exists

jack-plumbing works this way - from their docs:

(connect "SuperCollider:out_(.*)" "system:playback_\1")
This connect rule ensures that whenever scsynth(1) is running any output ports it registers are connected to appropriate ALSA playback ports. 
The connect rule only makes a connection if none already exist.

Cheers!

Unable to connect to JACK when starting more than one instance

It is not possible to run more than one instance of jack-matchmaker at the same time unless the -N is used to set distinctive JACK client names. The second instance only connects the moment after the first one closes.

jack-matchmaker erroneously interprets a non-zero return value of jack_client_open which has the JackNameNotUnique bit set as an error and remains in the re-connect loop.

Add documentation for systemd setup

  • How to install systemd service
  • How to configure as user service
  • Environment file settings
  • Pattern file
  • How to configure as system service (untested, so not supported yet)

Detect it only 1 channel

If there is only one channel, can jack connect this one channel to the all(LR) channels of the system playback port? It's a good simple for a single app, but it's a lot more complicated if it's a Firefox browser.
Here is the actual port of Firefox, when there is only one tab and it is playing stereo there,
Firefox Developer Edition:AudioStream_0_out_0 (Tab 1, Youtube)
Firefox Developer Edition:AudioStream_0_out_1 (Tab 1, Youtube)
Google Translate TTS under only one tab,
Firefox Developer Edition:AudioStream_0_out_0 (Only the left channel sound on my speakers)
And, contains two tabs,
Firefox Developer Edition:AudioStream_0_out_0 (Tab 1, Youtube)
Firefox Developer Edition:AudioStream_0_out_1 (Tab 1, Youtube)
Firefox Developer Edition:AudioStream_1_out_0 (Tab 2, Google Translate)

Add disconnect pattern functionality

It would be very useful if we could have the same behavior, but just for disconnecting port, so everything on JACK would be automated.

A flow would be like:
jack-matchmaker listens to new connections / events -> disconnect pattern match -> disconnects the connection between the ports.

Discover, remember and apply connections

Would it be possible to have a different ruleset that would match connections being made and store them so they can be applied again automatically?

I was thinking it could have lower prio than anything explicit from the current ruleset, but a wildcard regex would then mean you will no longer have to write down every thing you need to match, making the setup and testing phase of a new system much quicker.

Might be easier to only have a toggle for "remember connection" if the rules way seem redundant.

If this can be implemented it would probably be good to either store the connections in a human readable format or have a cli option to list and remove parts of the db/list.

Clarify in documentation that patterns are always treated as regular expressions

Add exmples to readme where this could be an issue and how to work around that. E.g.

jack-matchmaker foo:out_1 system:out_1

would connect all of of foo:out_1, foo:out_11, foo:out_12 etc. to all of system:out_1, system:out_11, system:out_12 etc.

To prevent that, anchor the regular expression to the string end by adding a `$':

jack-matchmaker 'foo:out_1$' 'system:out_1$'

Unable to create systemd service using provided instructions

System: Arch/Manjaro-5.17.1-3
Jack-matchmaker version: 0.10.0-1 (from AUR)

Output of provided commands:
image

(same issue when running as sudo)

Issue persists if directory is 'corrected' to /etc/

Issue also persists when files are manually created:
image

install issue on Raspbain Buster

Tired to install jack-matchmaker today on Raspberry Pi 4 with Buster installed. Getting some errors.

Any suggestions on how to troubleshoot this?

10.0.1.20 ~ $ pip install jack-matchmaker
...

Successfully installed jack-matchmaker-0.7.1

10.0.1.20 ~ $ jack-matchmaker --help
Traceback (most recent call last):
  File "/home/we/.local/bin/jack-matchmaker", line 6, in <module>
    from jackmatchmaker import main
  File "/home/we/.local/lib/python2.7/site-packages/jackmatchmaker/__init__.py", line 245
    num_aliases, *aliases = jacklib.port_get_aliases(port)
                 ^
SyntaxError: invalid syntax

10.0.1.20 ~ $ jackd -V
jackdmp version 1.9.12 tmpdir /dev/shm protocol 8

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.