En bref:
Il est connu que la cohabitation de pulseaudio et jack n'est pas la meilleure des choses à faire sur une station de travail dédiée à la mao. Mais il existe un moyen de bénéficier de cette fonction sans avoir à installer
PulseAudio 
. Pour cela vos applications devront être routées vers alsa et/ou loopback. Je dis bien "et/ou" car dans certains cas de figure le choix vers alsa doit être défini vers une autre carte et loopback est une carte son virtuelle qui sera apte à remplir ce rôle.
Pré-requis
AvertissementSi vous utilisez Cadence, ce tutoriel ne vous sera d'aucune aide
Cadence inclue directement cette fonction...
- Un kernel compilé avec le module snd-aloop
- jackd2
- python 3
Script python
à placer et
chmoder +x dans /usr/local/bin
[+]jack-aloop-daemon
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Imports (Global)
from ctypes import *
from os import system
from sys import version_info
from signal import signal, SIGINT, SIGTERM
from time import sleep
# --------------------------------------------------
# Test for python 3.x
if (version_info >= (3,0)):
PYTHON3 = True
else:
PYTHON3 = False
# --------------------------------------------------
# Global loop check
global doLoop, doRunNow
doLoop = True
doRunNow = True
# --------------------------------------------------
# Global JACK variables
global sample_rate, buffer_size
sample_rate = 44100
buffer_size = 1024
# --------------------------------------------------
# JACK ctypes implementation
jacklib = cdll.LoadLibrary("libjack.so.0")
class jack_client_t(Structure):
_fields_ = []
jack_nframes_t = c_uint32
JackBufferSizeCallback = CFUNCTYPE(c_int, jack_nframes_t, c_void_p)
JackShutdownCallback = CFUNCTYPE(None, c_void_p)
def jack_client_open(client_name, options, status):
if (PYTHON3): client_name = client_name.encode("ascii")
jacklib.jack_client_open.argtypes = [c_char_p, c_int, POINTER(c_int)]
jacklib.jack_client_open.restype = POINTER(jack_client_t)
return jacklib.jack_client_open(client_name, options, status)
def jack_client_close(client):
jacklib.jack_client_close.argtypes = [POINTER(jack_client_t)]
jacklib.jack_client_close.restype = c_int
return jacklib.jack_client_close(client)
def jack_activate(client):
jacklib.jack_activate.argtypes = [POINTER(jack_client_t)]
jacklib.jack_activate.restype = c_int
return jacklib.jack_activate(client)
def jack_deactivate(client):
jacklib.jack_deactivate.argtypes = [POINTER(jack_client_t)]
jacklib.jack_deactivate.restype = c_int
return jacklib.jack_deactivate(client)
def jack_connect(client, source_port, destination_port):
if (PYTHON3): source_port = source_port.encode("ascii")
if (PYTHON3): destination_port = destination_port.encode("ascii")
jacklib.jack_connect.argtypes = [POINTER(jack_client_t), c_char_p, c_char_p]
jacklib.jack_connect.restype = c_int
return jacklib.jack_connect(client, source_port, destination_port)
def jack_get_sample_rate(client):
jacklib.jack_get_sample_rate.argtypes = [POINTER(jack_client_t)]
jacklib.jack_get_sample_rate.restype = jack_nframes_t
return jacklib.jack_get_sample_rate(client)
def jack_get_buffer_size(client):
jacklib.jack_get_buffer_size.argtypes = [POINTER(jack_client_t)]
jacklib.jack_get_buffer_size.restype = jack_nframes_t
return jacklib.jack_get_buffer_size(client)
def jack_on_shutdown(client, shutdown_callback, arg):
global _shutdown_callback
_shutdown_callback = JackShutdownCallback(shutdown_callback)
jacklib.jack_on_shutdown.argtypes = [POINTER(jack_client_t), JackShutdownCallback, c_void_p]
jacklib.jack_on_shutdown.restype = None
jacklib.jack_on_shutdown(client, _shutdown_callback, arg)
def jack_set_buffer_size_callback(client, bufsize_callback, arg):
global _bufsize_callback
_bufsize_callback = JackBufferSizeCallback(bufsize_callback)
jacklib.jack_set_buffer_size_callback.argtypes = [POINTER(jack_client_t), JackBufferSizeCallback, c_void_p]
jacklib.jack_set_buffer_size_callback.restype = c_int
return jacklib.jack_set_buffer_size_callback(client, _bufsize_callback, arg)
# --------------------------------------------------
# quit on SIGINT or SIGTERM
def signal_handler(sig, frame=0):
global doLoop
doLoop = False
# --------------------------------------------------
# listen to jack shutdown
def shutdown_callback(arg):
global doLoop
doLoop = False
# --------------------------------------------------
# listen to jack buffer size changes
def buffer_size_callback(new_buffer_size, arg):
global doRunNow, buffer_size
buffer_size = new_buffer_size
doRunNow = True
return 0
# --------------------------------------------------
# run alsa_in and alsa_out
def run_alsa_bridge():
global sample_rate, buffer_size
system("killall alsa_in alsa_out pulseaudio")
system("env JACK_SAMPLE_RATE=%i JACK_PERIOD_SIZE=%i alsa_in -j alsa_in -dcloop -q 1 2>&1 1> /dev/null &" % (sample_rate, buffer_size))
system("env JACK_SAMPLE_RATE=%i JACK_PERIOD_SIZE=%i alsa_out -j alsa_out -dploop -q 1 2>&1 1> /dev/null &" % (sample_rate, buffer_size))
# Pause it for a bit, and connect to the proper system ports
sleep(1)
jack_connect(client, "alsa_in:capture_1", "system:playback_1")
jack_connect(client, "alsa_in:capture_2", "system:playback_2")
jack_connect(client, "system:capture_1", "alsa_out:playback_1")
jack_connect(client, "system:capture_2", "alsa_out:playback_2")
#--------------- main ------------------
if __name__ == '__main__':
# Init JACK client
client = jack_client_open("jack-aloop-daemon", 0, None)
if (not client):
quit()
jack_on_shutdown(client, shutdown_callback, None)
jack_set_buffer_size_callback(client, buffer_size_callback, None)
jack_activate(client)
# Quit when requested
signal(SIGINT, signal_handler)
signal(SIGTERM, signal_handler)
# Get initial values
sample_rate = jack_get_sample_rate(client)
buffer_size = jack_get_buffer_size(client)
# Keep running until told otherwise
while (doLoop):
if (doRunNow):
run_alsa_bridge()
doRunNow = False
sleep(1)
# Close JACK client
jack_deactivate(client)
jack_client_close(client)
.asoundrc
J'ai repiqué le ~/.asoundrc généré par cadence lors du choix du bridge
ALSA -> LOOP -> JACK et je l'ai essayé sur une machine qui n'a pas cadence ;).
[+].asoundrc
# ------------------------------------------------------
# Custom asoundrc file for use with snd-aloop and JACK
#
# use it like this:
# env JACK_SAMPLE_RATE=44100 JACK_PERIOD_SIZE=1024 alsa_in (...)
#
# ------------------------------------------------------
# playback device
pcm.aloopPlayback {
type dmix
ipc_key 1
ipc_key_add_uid true
slave {
pcm "hw:Loopback,0,0"
format S32_LE
rate {
@func igetenv
vars [ JACK_SAMPLE_RATE ]
default 44100
}
period_size {
@func igetenv
vars [ JACK_PERIOD_SIZE ]
default 1024
}
buffer_size 4096
}
}
# capture device
pcm.aloopCapture {
type dsnoop
ipc_key 2
ipc_key_add_uid true
slave {
pcm "hw:Loopback,0,1"
format S32_LE
rate {
@func igetenv
vars [ JACK_SAMPLE_RATE ]
default 44100
}
period_size {
@func igetenv
vars [ JACK_PERIOD_SIZE ]
default 1024
}
buffer_size 4096
}
}
# duplex device
pcm.aloopDuplex {
type asym
playback.pcm "aloopPlayback"
capture.pcm "aloopCapture"
}
# ------------------------------------------------------
# default device
pcm.!default {
type plug
slave.pcm "aloopDuplex"
}
# ------------------------------------------------------
# alsa_in -j alsa_in -dcloop -q 1
pcm.cloop {
type dsnoop
ipc_key 3
ipc_key_add_uid true
slave {
pcm "hw:Loopback,1,0"
channels 2
format S32_LE
rate {
@func igetenv
vars [ JACK_SAMPLE_RATE ]
default 44100
}
period_size {
@func igetenv
vars [ JACK_PERIOD_SIZE ]
default 1024
}
buffer_size 32768
}
}
# ------------------------------------------------------
# alsa_out -j alsa_out -dploop -q 1
pcm.ploop {
type plug
slave.pcm "hw:Loopback,1,1"
}
Action !
Ladish
Lancer jack puis la commande
jack-aloop-daemon désormais toutes les applications définies sur alsa sont routées vers le loopback. Dans les connexions de jack, la carte son virtuelle
loopback apparait sous les nom suivants:
alsa_in et
alsa_out.
Audacious (exemple)
Préférences de
Audacious pour
snd-loopback.
Ici
Audacious étant lancé le flux audio est routé vers
alsa_in qu'il suffit de rebrancher sur vos sorties d'écoute habituelles.
Merci à falktx pour ses trouvailles
[+]