Telegram voice calls with JACK on FreeBSD 15 and a 24-channel USB interface (Soundcraft Signature 22 MTK)

Environment​

  • OS: FreeBSD 15
  • Audio server: JACK (OSS backend)
  • USB audio interface: Soundcraft Signature 22 MTK
  • The mixer exposes 24 USB capture channels.
The mixer is used as the primary audio interface, and all audio routing on the system is done through JACK.

The USB device therefore appears in JACK as:

Code:
system:capture_1
system:capture_2
...
system:capture_24

Signal path​

Code:
microphone
   ↓
external processing (mic preamp / dbx processor)
   ↓
Soundcraft Signature 22 MTK
   ↓
USB multichannel audio (24 channels)
   ↓
JACK
   ↓
applications (OBS, Telegram, etc.)


Important channel mapping​

In this setup:

  • system:capture_1 = microphone signal
  • system:playback_21 and system:playback_22 = USB return channels to the mixer



Application audio is returned to the mixer through PulseAudio:

Code:
PulseAudio JACK Sink:front-left  → system:playback_21
PulseAudio JACK Sink:front-right → system:playback_22


Observed problems​

1. Telegram binary package​

The Telegram package available for FreeBSD does not work correctly in this setup.

Telegram appears to expect a mono microphone device.

However the audio device exposed to applications has 24 capture channels, and Telegram does not correctly select the microphone channel.

2. PulseAudio JACK bridge​

PulseAudio is currently used as a bridge between some applications and JACK.

The PulseAudio JACK source inherits the full number of channels from JACK:

  • 24-channel input
  • 22-channel output
As a result, Telegram sees a multichannel microphone device, not a mono microphone.

3. Attempt to rebuild Telegram with JACK support​

An attempt was made to rebuild Telegram on FreeBSD so that it could use OpenAL Soft (alsoft) with JACK support, allowing Telegram to talk directly to JACK.

This build attempt failed and Telegram could not be successfully compiled with this configuration.

What I need​

Conceptually I need something like this:

Code:
224-channel USB interface
        ↓
JACK routing
        ↓
virtual mono microphone device
        ↓
Telegram
In other words:

  • the microphone signal is system:capture_1
  • Telegram should receive only that channel as a mono input device



JACK routing​

Output of:


jack_lsp -c


Code:
system:capture_1
   LSP Graphic Equalizer x32 Mono:in
   OBS Studio: mic:in_1
system:capture_2
system:capture_3
system:capture_4
system:capture_5
system:capture_6
system:capture_7
system:capture_8
system:capture_9
system:capture_10
system:capture_11
system:capture_12
system:capture_13
system:capture_14
system:capture_15
   OBS Studio: solo:in_1
system:capture_16
   OBS Studio: solo:in_2
system:capture_17
system:capture_18
system:capture_19
system:capture_20
system:capture_21
system:capture_22
system:capture_23
system:capture_24
system:playback_1
system:playback_2
system:playback_3
system:playback_4
system:playback_5
system:playback_6
system:playback_7
system:playback_8
system:playback_9
system:playback_10
system:playback_11
system:playback_12
system:playback_13
system:playback_14
system:playback_15
system:playback_16
system:playback_17
system:playback_18
system:playback_19
system:playback_20
system:playback_21
   PulseAudio JACK Sink:front-left
system:playback_22
   PulseAudio JACK Sink:front-right
PulseAudio JACK Sink:front-left
   system:playback_21
   OBS Studio: pa:in_1
PulseAudio JACK Sink:front-right
   system:playback_22
   OBS Studio: pa:in_2
PulseAudio JACK Sink:rear-left
PulseAudio JACK Sink:rear-right
PulseAudio JACK Sink:front-center
PulseAudio JACK Sink:lfe
PulseAudio JACK Sink:side-left
PulseAudio JACK Sink:side-right
PulseAudio JACK Sink:aux0
PulseAudio JACK Sink:aux1
PulseAudio JACK Sink:aux2
PulseAudio JACK Sink:aux3
PulseAudio JACK Sink:aux4
PulseAudio JACK Sink:aux5
PulseAudio JACK Sink:aux6
PulseAudio JACK Sink:aux7
PulseAudio JACK Sink:aux8
PulseAudio JACK Sink:aux9
PulseAudio JACK Sink:aux10
PulseAudio JACK Sink:aux11
PulseAudio JACK Sink:aux12
PulseAudio JACK Sink:aux13
PulseAudio JACK Source:front-left
PulseAudio JACK Source:front-right
PulseAudio JACK Source:rear-left
PulseAudio JACK Source:rear-right
PulseAudio JACK Source:front-center
PulseAudio JACK Source:lfe
PulseAudio JACK Source:side-left
PulseAudio JACK Source:side-right
PulseAudio JACK Source:aux0
PulseAudio JACK Source:aux1
PulseAudio JACK Source:aux2
PulseAudio JACK Source:aux3
PulseAudio JACK Source:aux4
PulseAudio JACK Source:aux5
PulseAudio JACK Source:aux6
PulseAudio JACK Source:aux7
PulseAudio JACK Source:aux8
PulseAudio JACK Source:aux9
PulseAudio JACK Source:aux10
PulseAudio JACK Source:aux11
PulseAudio JACK Source:aux12
PulseAudio JACK Source:aux13
PulseAudio JACK Source:aux14
PulseAudio JACK Source:aux15
LSP Graphic Equalizer x32 Mono:in
   system:capture_1
LSP Graphic Equalizer x32 Mono:out
OBS Studio: mic:in_1
   system:capture_1
OBS Studio: solo:in_1
   system:capture_15
OBS Studio: solo:in_2
   system:capture_16
OBS Studio: pa:in_1
   PulseAudio JACK Sink:front-left
OBS Studio: pa:in_2
   PulseAudio JACK Sink:front-right

PulseAudio configuration​


pactl list short sinks


Code:
1  jack_out  module-jack-sink.c  float32le 22ch 48000Hz  IDLE


pactl list short sources


Code:
1 1  jack_out.monitor  module-jack-sink.c  float32le 22ch 48000Hz  IDLE<br>2  jack_in           module-jack-source.c float32le 24ch 48000Hz  IDLE<br>

Detailed PulseAudio sink information​


pacmd list-sinks



Code:
1 sink(s) available.
  * index: 1
    name: <jack_out>
    driver: <module-jack-sink.c>
    flags: DECIBEL_VOLUME LATENCY
    state: IDLE
    suspend cause: (none)
    priority: 10000
    volume: front-left: 65536 / 100% / 0.00 dB,   front-right: 65536 / 100% / 0.00 dB,   rear-left: 65536 / 100% / 0.00 dB,   rear-right: 65536 / 100% / 0.00 dB,   front-center: 65536 / 100% / 0.00 dB,   lfe: 65536 / 100% / 0.00 dB,   side-left: 65536 / 100% / 0.00 dB,   side-right: 65536 / 100% / 0.00 dB,   aux0: 65536 / 100% / 0.00 dB,   aux1: 65536 / 100% / 0.00 dB,   aux2: 65536 / 100% / 0.00 dB,   aux3: 65536 / 100% / 0.00 dB,   aux4: 65536 / 100% / 0.00 dB,   aux5: 65536 / 100% / 0.00 dB,   aux6: 65536 / 100% / 0.00 dB,   aux7: 65536 / 100% / 0.00 dB,   aux8: 65536 / 100% / 0.00 dB,   aux9: 65536 / 100% / 0.00 dB,   aux10: 65536 / 100% / 0.00 dB,   aux11: 65536 / 100% / 0.00 dB,   aux12: 65536 / 100% / 0.00 dB,   aux13: 65536 / 100% / 0.00 dB
            balance 0.00
    base volume: 65536 / 100% / 0.00 dB
    volume steps: 65537
    muted: no
    current latency: 16.71 ms
    max request: 22 KiB
    max rewind: 0 KiB
    monitor source: 1
    sample spec: float32le 22ch 48000Hz
    channel map: front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right,aux0,aux1,aux2,aux3,aux4,aux5,aux6,aux7,aux8,aux9,aux10,aux11,aux12,aux13
    used by: 0
    linked by: 0
    fixed latency: 13.33 ms
    module: 17
    properties:
        device.api = "jack"
        device.description = "JACK sink (PulseAudio JACK Sink)"
        jack.client_name = "PulseAudio JACK Sink"
        device.icon_name = "audio-card"

Detailed PulseAudio source information​

pacmd list-sources


Code:
2 source(s) available.
    index: 1
    name: <jack_out.monitor>
    driver: <module-jack-sink.c>
    flags: DECIBEL_VOLUME LATENCY
    state: IDLE
    suspend cause: (none)
    priority: 1000
    volume: front-left: 65536 / 100% / 0.00 dB,   front-right: 65536 / 100% / 0.00 dB,   rear-left: 65536 / 100% / 0.00 dB,   rear-right: 65536 / 100% / 0.00 dB,   front-center: 65536 / 100% / 0.00 dB,   lfe: 65536 / 100% / 0.00 dB,   side-left: 65536 / 100% / 0.00 dB,   side-right: 65536 / 100% / 0.00 dB,   aux0: 65536 / 100% / 0.00 dB,   aux1: 65536 / 100% / 0.00 dB,   aux2: 65536 / 100% / 0.00 dB,   aux3: 65536 / 100% / 0.00 dB,   aux4: 65536 / 100% / 0.00 dB,   aux5: 65536 / 100% / 0.00 dB,   aux6: 65536 / 100% / 0.00 dB,   aux7: 65536 / 100% / 0.00 dB,   aux8: 65536 / 100% / 0.00 dB,   aux9: 65536 / 100% / 0.00 dB,   aux10: 65536 / 100% / 0.00 dB,   aux11: 65536 / 100% / 0.00 dB,   aux12: 65536 / 100% / 0.00 dB,   aux13: 65536 / 100% / 0.00 dB
            balance 0.00
    base volume: 65536 / 100% / 0.00 dB
    volume steps: 65537
    muted: no
    current latency: 0.00 ms
    max rewind: 0 KiB
    sample spec: float32le 22ch 48000Hz
    channel map: front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right,aux0,aux1,aux2,aux3,aux4,aux5,aux6,aux7,aux8,aux9,aux10,aux11,aux12,aux13
    used by: 0
    linked by: 0
    fixed latency: 13.33 ms
    monitor_of: 1
    module: 17
    properties:
        device.description = "Monitor of JACK sink (PulseAudio JACK Sink)"
        device.class = "monitor"
        device.icon_name = "audio-input-microphone"
  * index: 2
    name: <jack_in>
    driver: <module-jack-source.c>
    flags: DECIBEL_VOLUME LATENCY
    state: IDLE
    suspend cause: (none)
    priority: 10000
    volume: front-left: 65536 / 100% / 0.00 dB,   front-right: 65536 / 100% / 0.00 dB,   rear-left: 65536 / 100% / 0.00 dB,   rear-right: 65536 / 100% / 0.00 dB,   front-center: 65536 / 100% / 0.00 dB,   lfe: 65536 / 100% / 0.00 dB,   side-left: 65536 / 100% / 0.00 dB,   side-right: 65536 / 100% / 0.00 dB,   aux0: 65536 / 100% / 0.00 dB,   aux1: 65536 / 100% / 0.00 dB,   aux2: 65536 / 100% / 0.00 dB,   aux3: 65536 / 100% / 0.00 dB,   aux4: 65536 / 100% / 0.00 dB,   aux5: 65536 / 100% / 0.00 dB,   aux6: 65536 / 100% / 0.00 dB,   aux7: 65536 / 100% / 0.00 dB,   aux8: 65536 / 100% / 0.00 dB,   aux9: 65536 / 100% / 0.00 dB,   aux10: 65536 / 100% / 0.00 dB,   aux11: 65536 / 100% / 0.00 dB,   aux12: 65536 / 100% / 0.00 dB,   aux13: 65536 / 100% / 0.00 dB,   aux14: 65536 / 100% / 0.00 dB,   aux15: 65536 / 100% / 0.00 dB
            balance 0.00
    base volume: 65536 / 100% / 0.00 dB
    volume steps: 65537
    muted: no
    current latency: 4.98 ms
    max rewind: 0 KiB
    sample spec: float32le 24ch 48000Hz
    channel map: front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right,aux0,aux1,aux2,aux3,aux4,aux5,aux6,aux7,aux8,aux9,aux10,aux11,aux12,aux13,aux14,aux15
    used by: 0
    linked by: 0
    fixed latency: 2.67 ms
    module: 18
    properties:
        device.api = "jack"
        device.description = "JACK source (PulseAudio JACK Source)"
        jack.client_name = "PulseAudio JACK Source"
        device.icon_name = "audio-input-microphone"

JACK configuration​

Driver parameters:

jack_control dp



Code:
--- get driver parameters (type:isset:default:value)
                rate: Sample rate (uint:set:48000:48000)
              period: Frames per period (uint:set:1024:256)
            nperiods: Number of periods to prefill output buffer (uint:notset:1:1)
          wordlength: Word length (sint:set:16:32)
          inchannels: Capture channels (uint:notset:2:2)
         outchannels: Playback channels (uint:notset:2:2)
                excl: Exclusive and direct device access (bool:set:False:True)
             capture: Input device (str:notset:/dev/dsp:/dev/dsp)
            playback: Output device (str:notset:/dev/dsp:/dev/dsp)
              device: OSS device name (str:set:/dev/dsp:/dev/dsp4)
         ignorehwbuf: Ignore hardware period size (bool:notset:False:False)
       input-latency: Extra input latency (uint:notset:0:0)
      output-latency: Extra output latency (uint:notset:0:0)



Available drivers:

jack_control dl



Code:
--- drivers list
net
loopback
netone
dummy
proxy
oss


Engine parameters:

jack_control ep



Code:
--- get engine parameters (type:isset:default:value)
              driver: Driver to use (str:set:dummy:oss)
                name: Server name to use. (str:notset:default:default)
            realtime: Whether to use realtime mode. (bool:set:True:True)
   realtime-priority: Scheduler priority when running in realtime mode. (sint:notset:10:10)
           temporary: Exit once all clients have closed their connections. (bool:notset:False:False)
             verbose: Verbose mode. (bool:set:False:False)
      client-timeout: Client timeout limit in milliseconds. (sint:notset:0:0)
        clock-source: Clocksource type : c(ycle) | h(pet) | s(ystem). (uint:notset:0:0)
            port-max: Maximum number of ports. (uint:notset:2048:2048)
    replace-registry: Replace shared memory registry. (bool:notset:False:False)
                sync: Use server synchronous mode. (bool:set:False:False)
   self-connect-mode: Self connect mode. (char:notset: : )
       slave-drivers: Slave drivers to use (str:notset::)



Internal clients:

jack_control il



Code:
--- internals list
profiler
netmanager
netadapter
audioadapter



OSS / system audio configuration​

/etc/sysctl.conf

Code:
hw.snd.default_unit=4

dev.pcm.4.bitperfect=1
dev.pcm.4.play.vchanrate=48000
dev.pcm.4.play.vchanformat=s16le:2.0
dev.pcm.4.play.vchanmode=fixed

hw.usb.uaudio.default_channels=24
hw.usb.uaudio.default_rate=48000
hw.usb.uaudio.default_bits=24

Question​

How do FreeBSD users typically solve this situation when:

  • the audio interface exposes 24 capture channels
  • audio routing is handled by JACK
  • an application such as Telegram expects a mono microphone device
Possible approaches I am considering:

  • creating a virtual mono microphone device
  • JACK channel mixing
  • OSS virtual devices
  • PulseAudio remapped sources
What is the typical approach used in FreeBSD JACK setups for applications that expect a simple mono microphone device?
 
Back
Top