spatialaudio/python-sounddevice

How to include Jack in API list for sounddevice (on Windows)?

Opened this issue · 3 comments

I've added ASIO to portaudio.dll for sounddevice to include ASIO devices as options no problem, but how do we use Jack with sounddevice? All documentation i've read on how to do it seems to think C:\Program Files\JACK2\bin exists but I don't think Jack2 uses it anymore. What Jack includes/preprocessors am I meant to be building portaudio.dll with for sounddevice to list Jack as a client api so I can connect/create to Jack ports?

import sounddevice as sd

# List all available host APIs
hostapis = sd.query_hostapis()
print("Available host APIs:")
for idx, api in enumerate(hostapis):
    print(f"Host API {idx}: {api['name']}")

(venv) python -u "C:\Users\skhoc\Desktop\Test\api_test.py"
Jack: JackClient::SetupDriverSync driver sem in normal mode
Jack: JackWinSemaphore::Connect jack_pipe.default_python
Jack: JackLibClient::Open name = python refnum = 3
Jack: JackClient::Deactivate
Jack: JackClient::Deactivate
Jack: jack_client_close
Jack: JackClient::Close ref = 3
Jack: JackClient::Deactivate
Jack: JackWinNamedPipeClientChannel::Stop
Jack: JackWinThread::Kill
Jack: JackWinNamedPipeServer::Close
Jack: JackLibClient::Open name = python refnum = 3
Jack: JackClient::Deactivate
Jack: JackClient::Deactivate
Jack: jack_client_close
Jack: JackClient::Close ref = 3
Jack: JackClient::Deactivate
Jack: JackWinNamedPipeClientChannel::Stop
Jack: JackWinThread::Kill
Jack: JackWinNamedPipeServer::Close
Jack: JackClient::Deactivate
Jack: JackWinNamedPipeClientChannel::Stop
Jack: JackWinThread::Kill
Jack: JackWinNamedPipeServer::Close
Jack: JackWinNamedPipeServer::Close
Jack: JackWinSemaphore::Disconnect jack_pipe.default_python
Jack: JackLibClient::~JackLibClient
Jack: JackShmReadWritePtr1::~JackShmReadWritePtr1 7
Jack: Succeeded in unlocking 426 byte memory area
Jack: JackLibGlobals Destroy 23af2490
Jack: ~JackLibGlobals
Jack: JackWinSemaphore::Disconnect jack_pipe.default_system
Jack: JackWinSemaphore::Disconnect jack_pipe.default_freewheel
Jack: JackWinSemaphore::Disconnect jack_pipe.default_qjackctl
Jack: no message buffer overruns
Jack: JackWinThread::Stop
Jack: JackWinThread::ThreadHandler : exit
Jack: JackShmReadWritePtr::~JackShmReadWritePtr 5
Jack: Succeeded in unlocking 1196 byte memory area
Jack: JackShmReadWritePtr::~JackShmReadWritePtr 4
Jack: Succeeded in unlocking 107341340 byte memory area
Jack: jack_client_close res = 0
Available host APIs:
Host API 0: MME
Host API 1: Windows DirectSound
Host API 2: ASIO
Host API 3: Windows WASAPI
Host API 4: Windows WDM-KS

In my Visual Studio properties I have setup:

Include Path: C:\Program Files\JACK2\include
Library Path: C:\Program Files\JACK2\lib
Linker Dependencies: libjack64.lib

I have a Preprocessor definition of: PA_USE_JACK=1 same way I have PA_USE_ASIO=1 and which worked.

It seems libjack64.dll is also required and that seems to get installed to C:\Windows by Jack2 installer so would be included automatically in the portaudio.dll build.

I'm not a Windows user, so I don't know for sure, but I think you have to start the JACK daemon (a.k.a. jackd) to be able to see the devices provided by JACK.

Here's an example how jackd can be started on Windows (but of course you'll need to use a more meaningful -d option): https://github.com/spatialaudio/jackclient-python/blob/055fc96e5042dc6e21e22c6077c6ea572d40cf42/.github/workflows/test.yml#L39-L43

OTOH, your log messages already show some output from JACK, so I don't know if that's it.

For compiling the PortAudio DLL with JACK enabled, I guess you'll need to set -D PA_USE_JACK=ON when running cmake but you mentioned that you are already using that (it's not a preprocessor thing though, it's a cmake thing).

The typical way I've worked with Jack in the past on Windows apps is to use the jackclient-python library. Then I just create the app as a Jack client, set the number of ports up I want connect and connect them to Jack. Jack works great on Windows itself, but I was hoping to streamline ASIO, WASAPI and JACK via sounddevice, but don't seem to be able to get sounddevice to set itself up as a Jack client in a similar way. Typical way I start Jack is like this for testing:

./jackd.exe -v -m -S -dportaudio -d"Windows WASAPI::Headphones (Realtek(R) Audio)" -r48000 -p512 -P

I'll try building the .sln via cmake, I'm not convinced PA_USE_JACK=1 actually is doing anything though so don't see why cmake would fix that when it works for ASIO.

Still not having much luck with sounddevice and Jack. I kind of gave up on using Jack direct and would just direct users to use the JackRouter ASIO driver that gets installed with Jack Audio Connection Kit but sounddevice doesn't even find that. e.g.

import os
os.environ["SD_ENABLE_ASIO"] = "1"
import sounddevice as sd

print(sd.query_devices())

0 Microsoft Sound Mapper - Output, MME (0 in, 2 out)
< 1 Speakers (Apogee Groove), MME (0 in, 2 out)
2 Primary Sound Driver, Windows DirectSound (0 in, 2 out)
3 Speakers (Apogee Groove), Windows DirectSound (0 in, 2 out)
4 Apogee USB ASIO Driver, ASIO (0 in, 2 out)
5 NDI Virtual Soundcard, ASIO (64 in, 64 out)
6 Realtek ASIO, ASIO (2 in, 2 out)
7 ReaRoute ASIO (x64), ASIO (16 in, 16 out)
8 Steinberg built-in ASIO Driver, ASIO (0 in, 2 out)
9 VB-Matrix VASIO-128, ASIO (128 in, 128 out)
10 VB-Matrix VASIO-64A, ASIO (64 in, 64 out)
11 VB-Matrix VASIO-64B, ASIO (64 in, 64 out)
12 VB-Matrix VASIO-8, ASIO (8 in, 8 out)
13 Speakers (Apogee Groove), Windows WASAPI (0 in, 2 out)
14 Speakers (Groove Output), Windows WDM-KS (0 in, 2 out)

If I look at the ASIO device list on any ASIO application I see JackRouter ASIO as an option?

image