I’ve got a notebook with some fancy HD Audio sound card (stereo!), and a single output jack — not a sane way to get surround sound (sure, cool kids use HDMI these days). Even worse, connecting an external amplifier to the jack results in catching a lot of electrical interference. Since I also have a PC which has surround speakers connected, I figured it would be a good idea to stream the audio over the network.
On non-Windows, the streaming would be trivial to setup. Likely PulseAudio on both machines, few setup bits and done. If you are looking for a guide on how to do such a thing in Windows, you’re likely end up setting up an icecast server listening to the stereo mix. Bad twice. Firstly, stereo-only. Secondly, poor latency. Now imagine playing a game or watching a movie with sound noticeably delayed after picture (well, in the movie player you could at least play with A/V delay to work-around that). But there must be another way…
In order to get a working surround sound system, you need to have:
- two JACK2 servers — one on each computer,
- and an ASIO-friendly virtual sound device such as VB-Audio Hi-Fi Cable.
Install the JACK server on the computer with speakers, and all the tools on the other machine.
Setting up the JACK slave (on speaker-PC)
I’m going to start with setting up the speaker-PC since it’s simpler. It can run basically any operating system, though I’m using Gentoo Linux for this guide. JACK is set up pretty much the same everywhere, with the only difference in used audio driver.
The choice of master vs. slave is pretty much arbitrary. The slave needs to either combine a regular audio driver with netadapter, or the net driver with audioadapter. I’ve used the former.
First, install JACK2. In Gentoo, it can be found in the pro-audio project overlay. A good idea is to disable D-Bus support (
USE=-dbus) since I wasn’t able to get JACK running with it and the ebuild doesn’t build regular jackd when D-Bus support is enabled.
Afterwards, start JACK with the desired sound driver and a surround-capable device. You will want to specify a sample rate and bit depth too. Best fit it with the application you’re planning to use. For example:
$ jackd -R -d alsa -P surround40 -r 48000 -S
This starts the JACK daemon with real-time priority support (important for low latency), using ALSA playback device surround40 (4-speaker surround), 48 kHz sample rate and 16-bit samples.
Afterwards, load netadapter with matching number of capture channels, and connect them to the output channels:
$ jack_load netadapter -i '-C 4' $ jack_connect netadapter:capture_1 system:playback_1 $ jack_connect netadapter:capture_2 system:playback_2 $ jack_connect netadapter:capture_3 system:playback_3 $ jack_connect netadapter:capture_4 system:playback_4
At this point, slave is ready. JACK will wait for a master to start, and will forward any audio received from the master to the local sound card surround output. Since JACK2 supports zero-configuration networking, you don’t need to specify any IP addresses.
Setting up the virtual device
After getting the slave up, it’s time to set the sound source. After installing all the components, the first goal is to set up the virtual audio device. Once the Hi-Fi Cable package is insalled (no need to reboot), the system should start seeing two new devices — playback device called ‘Hi-Fi Cable Input’ and recording device called ‘Hi-Fi Cable Output’. Now open the sound control panel applet and:
- select ‘Hi-Fi Cable Input’ as the default output device.
- Right-click it and configure speakers. Select whatever configuration is appropriate for your real speaker set (e.g. quad speakers).
- (Optionally) right-click it and open properties. On the advanced tab select sample rate and bit depth. Afterwards, open properties of the ‘Hi-Fi Cable Output’ recording device and set the same parameters.
As you may notice, even after setting the input to multiple speakers, the output will still be stereo. That’s a bug (limitation?) we’re going to work-around soon…
Setting up the JACK master
Now that device is ready, we need to start setting up JACK. On Windows, the ‘Jack Control’ GUI is probably the easiest way. Start with ‘Setup’. Ensure that the ‘portaudio’ driver is selected, and choose ‘ASIO::ASIO4ALL v2’ both as input and output device. The right-arrow button right of the text inputs should provide a list of devices to select. Additionally select the sample rate matching the one set for the virtual device and the JACk slave.
Now, we need to load the netmanager module. Similarly to the slave setup, this is done using jack_load. To get this fully automated, you can use the ‘Execute script after startup’ option from the ‘Options’ (right-arrow button is not helpful this time). Create a new .bat file somewhere, and put the following command inside:
Save the file and select is as post-startup script. Now the module will be automatically loaded every time you start JACK via Jack Control. You may also fine-tune some of the ‘Misc’ settings to fit your preferences. Then confirm ‘Ok’ and click ‘Start’. If everything went well so far, after clicking ‘Connect’ you should see both ‘System’ and the slave’s hostname (assuming it is up and running). Do not connect anything yet, just verify that JACK sees the slave.
Connecting the virtual sound card to JACK
Now that the JACK is ready, it’s time to connect the virtual sound card to the remote host. The traditional way of doing that would be through connecting the local recording device (stereo mix or Virtual Cable Output) to the respective remote pins. However, that would mean just stereo. Instead, we have to cheat a little.
One of the fancy features of VB-Audio’s Virtual Hi-Fi Cable is that it supports using ASIO-compatible sound processors. In other words, the sound from virtual cable input is directed into ASIO output port for processing. Good news is that the stereo stripping occurs directly in virtual cable output, so ASIO still gets all the channels. All we have to do is to capture sound there…
Find VB-Cable’s ‘ASIO Bridge’ and start it. If the button in the middle states ‘ASIO OFF’, switch it to enable ASIO. Then click on the ‘Select A.S.I.O. Device’ text below it and select ‘JackRouter’. If everything went well, ‘VBCABLE_AsioBridge’ should appear in the JACK connection panel.
The final touches
Now that everything’s in place, it’s just a matter of connecting the right pins. To avoid having to connect them manually every time, use the ‘Patchbay’ panel. First, use ‘Add’ on left-hand side to add an output socket, select ‘VBCABLE_AsioBridge’ client and keep clicking ‘Add plug’ for all the input channels. Then, ‘Add’ on right-hand side, your remote host as client and add all the output channels. Now select both new sockets and ‘Connect’.
Save your new patchbay definition somewhere, and ‘Activate’ it. If you did well, the connections window should now show connections between respective local and remote pins and you should be able to hear sound from the remote speakers.
Now you can open ‘Setup’ again, and on the ‘Options’ tab activate patchbay persistence. Select your newly created patchbay definition file and from now on, starting JACK should enable the patchbay, and the patchbay should ensure that the pins are connected every time they reappear.
First of all, you usually don’t need to set an explicit connection between your virtual device and real system audio device. On my system that connection is established automatically, so that the sounds reach both remote host and local speakers. If that’s unrequested, just mute the sound card…
Secondly, note that now the virtual sound card is the default device, so applications will control its volume (both for remote and local speakers). If you want to mute the local speakers, you need to open the mixer and select your local sound card from device drop-down.
Thirdly, VBCABLE_AsioBridge likes to disappear occasionally when restarting JACK. If you don’t see it in the connections, just turn it off and on again (the ‘ASIO ON’ button) and it should reappear.
Fourthly, if you hear skipping, you can try playing with ‘Frames/Period’ in JACK’s setup. Or reduce the sample rate.