Skip to content

Instantly share code, notes, and snippets.

@lehnerpat
Last active June 1, 2020 06:23
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lehnerpat/10915619 to your computer and use it in GitHub Desktop.
Save lehnerpat/10915619 to your computer and use it in GitHub Desktop.
Simultaneous output to Analog and HDMI with Jack on Ubuntu 13.10

How to get simultaneous / dual output to both Analog out and HDMI out with Jack Audio on Ubuntu 13.10

Configuration used:

  • OS: Xubuntu (Ubuntu) 13.10 (saucy)
  • Audio: HDA Intel PCH (ALC269VB Analog) on an Intel Core i5 2557M (Sandy Bridge microarch)

Install below packages and set user group, then reboot

Packages you will need (and the versions I had when I did this):

  • jackd2, 1.9.9.5+20130622git7de15e7a-1
  • pulseaudio (preinstalled), 4.0-ubuntu6
  • pulseaudio-module-jack, 4.0-ubuntu6
  • qjackctl, 0.3.10-2
  • Alsa audio support, which should be required by Pulseaudio and/or Jack, and pre-installed by Ubuntu anyway

Allowing your user to run processes with realtime priority

By default, your user account is not allowed to run processes with realtime priority. Jack audio, however, is intended to run on realtime so as to minimize latency.

The Jack article on realtime privileges mentions that Ubuntu does some special magic. Looking around, I found this Ubuntu article on preparing for running Ubuntu Studio, which explains that the appropriate privileges are granted to the audio group (to which your user account is not automatically added).

However, the indicated file /etc/security/limits.d/audio.conf did not exist for me -- it was named /etc/security/limits.d/audio.conf.disabled instead, and apparently the OS honors the .disabled suffix. Renaming the file to audio.conf enabled realtime privileges for me, and seems to have no adverse effects.

Make sure to add your user account to the audio group as explained in the latter article.

Now, Reboot

After installing the necessary packages and setting up your user group, you should reboot.

Details: You would need to restart Pulseaudio anyway to apply the new module, and you need to log out and back in to apply your changed user group. You can do all that, but a catch-all is to just reboot.

Setting up dual output

Once you've logged back it, it's time to try and set up the simultaneous output to both sinks. For this, you will need to have speakers connected to both outputs, of course.

  • Have some audio player handy to test the output (some audio with audible, isolated beats will help you minimize the delay between the outputs). You do not need to set it up to use Jack directly. Pulseaudio can pipe its output to Jack.

Find out your Alsa device identifiers

  • Open a terminal, and run aplay -l to get a list of your Alsa cards and devices. For me this returned:
$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: ALC269VB Analog [ALC269VB Analog]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 3: HDMI 0 [HDMI 0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

i.e. I have one Alsa card (index 0) with two devices on it: analog output (device 0) and HDMI output (device 3). (Note: I have not tested whether the HDMI device also shows up if no HDMI cable/device is connected.)

To select these devices later on, we will use the identifiers hw:0,0 for the analog output and hw:0,3 for the HDMI output. (Note: If your identifiers are different, use those of course. The pattern is hw:<card id>,<device id>.)

Set up Jackd with QJackCtl

  • Open QJackCtl
  • Click "Setup..." on the right
  • In the "Driver" field (top-right), select "alsa"
  • In the "Interface" field (top-right), select or enter "hw:0" (card identifier only)
  • In the "Output Device" field (center-right), select or enter "hw:0,0" (Note: I think it should not matter which of the two devices you select here, but I've only tested it with selecting Analog Out here.)
  • Close the Setup dialog by clicking "OK" in the bottom right
  • Click "Messages" on the left to display the message log
  • Click "Connect" on the left to display the connections panel
  • Move and resize the three QJackCtl windows so you can easily see all of them
  • In the main window, click "Start" on the left to start the Jack Audio daemon.
    The message log should reflect it starting successfully, and after a wait time of 2 seconds, the Connections panel should show "PulseAudio JACK Sink" and "system" on the left, and "PulseAudio JACK Source" and "system" on the right. The former of each is used for interaction with Pulseaudio (duh), and the latter are the hardware inputs/outputs of the selected Alsa device. The Pulseaudio devices of each side should have a line connecting them to the system device of the opposite side.
    Note: if you get errors in the message log or no ports show up in the connections window, then you should start troubleshooting and fix this before continuing with these instructions.
  • Open a terminal and run alsa_out -j "HDMI out" -d hw:0,3 (the -j "HDMI out" part is just a label used in Jack, you can use anything you want)
    This should also start without errors, possibly printing selected sample format: 32bit and then just sit there. Leave this terminal window open.
  • In your QJackCtl connections window, you should now have a new Writable port "HDMI out" (or whatever you called it) in the right-hand list
  • In your QJackCtl connections window, select the "PulseAudio JACK Sink" on the left and the "HDMI out" on the right, then click "Connect" on the bottom left. Another line should appear connecting the selected ports.
  • Open pavucontrol ("Pulseaudio Volume Control"; or click sound indicator icon, then "Sound Settings")
  • On the "Output Devices" tab, make "Jack sink" the default output (click the green tick icon on the right of it)
  • Test your audio by playing something. Audio should now be output to both analog and HDMI outputs, but there may be an audible delay. If audio does not work on both outputs:
    • Be sure that you've applied the changes by logging out and back in, and restarting the related services (or having rebooted)
    • If HDMI is not working (and you've made sure it's not muted on the receiver etc), quit the alsa_out pipe (Ctrl-C in its terminal window) and restart it (it only worked on the second launch for me sometimes)
    • Otherwise, try stopping and restarting Jack (if you get an error on the second try that the audio resource is already in use, killall -9 jackdbus -- it sometimes doesn't seem to quit properly.)
    • Try magic?

Minimizing audio delay between outputs

After getting the actual dual output working, I had the problem that there was an audible delay between both outputs (in the order of a few hundred milliseconds, giving the audio a kind of hall effect).

To work with this, play with the following:

  • In QJackCtl, open the "Setup..." dialog
  • Notice the "Latency" info field on the very bottom right. It should read a value of a few tens to hundreds of msec. This value is determined by the Sample Rate used, the Frames/Period and the Periods/Buffer (all three are values in the center column of the Setup dialog)
  • For me, the latency value initially read 46.4 msec (44100Hz/1024/2 selected). Using a lower Frames/Period setting to lower the latency actually made the delay worse.
  • So my advice: a slightly higher latency seems to make the delay less (or at least less noticable), I am currently using 44100Hz/2048/2
  • Note: When you change the settings, you need to restart Jack to make them take effect (stopping Jack also stops the alsa_out pipe, you need to re-start it after Jack is running again)
  • However, when I increased Frames/Period to 2048, the alsa_out pipe had syncing problems (shown by it dumping a load of delay = <num> lines in the terminal all the time. To fix this, you have to tell alsa_out to also use more frames per period, by invoking it like alsa_out -j "HDMI out" -d hw:0,3 -p 2048 (see also the alsa_in man page)

The above setting was good enough for me, as it reduced the delay to pretty much unnoticable. Feel free to play around some more and post about your experiences in the comments below.

Using the Patch Bay to make QJackCtl remember your connections

The connections setup seems to be quite transient by default. However, the "Patchbay" allows you to save and switch between configurations.

Here's how I've set it up. Open the "Patchbay" dialog of QJackCtl (while your ports are set up correctly, most importantly while alsa_out is running for your second output):

  • On the left, click "Add..." to create a new output socket (something where audio is coming from)
  • Enter a name if you wish, as "Client" select "PulseAudio JACK Sink", add both Plugs to the list, save with "OK"
  • On the right, click "Add..." to create a new input socket (something where audio is going to)
  • Enter a name if you wish, as "Client" select one of your outputs (system or HDMI), add both Plugs to the list, save with "OK"
  • Select the output and the input socket in the two lists, click "Connect" on the bottom left
  • On the right, click "Add..." to add another input socket; name it if you wish, select the other of your outputs, add both plugs to the list; at the bottom, select the first input socket in the "Forward" dropdown; save with "OK".
  • Save the profile with the "Save..." button on the top, give it some name you like.
  • From now on, you can "Activate" this profile with the button on the top right of the patch bay. Once activated, it will stay active even if you restart Jack (and alsa_out), and reconnect your ports as configured.

Random notes

  • I did not use a lowlatency kernel for this, but the delay was pretty much unnoticable in the end, so I didn't bother trying it out. Feel free to give it a shot and comment below on whether it gives you any improvement or not.
@budimanjojo
Copy link

Nice tutorial. How did you make it start automatically? Are you using the qjackctl start script or using your DE autostart function? Thanks :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment