QEMU Native JACK Audio Support

Even with jack, when I use the VM instance to play music, I can still hear the terrible ticking sound.

Did you set the sample rate in jack and in the guest to 48KHz? and have you tried increasing the period size jackd is using?

@gnif, did you manage to find a workaround to the 65kHz sample rate limitation in versions beyond v6? I have a Steinberg UR22C (192kHz/32-bit) that I want to work with, and I’d like to not hold it back if I can…

P.S. Your patchbay screencap is so busy, I love it!

My understanding is that the patch was upstreamed so me being on qemu 5.2 on arch shouldn’t change much. However I was having a strange issue with audio. it is somewhat spedup while clipping and popping like I have a sample rate mismatch. however jack is set to 48khz and my windows vm is set to 48khz.

When I set my windows vm to around 16khz is when the audio starts to sound closer to normal. Unsure what I should try doing differently.

There is no workaround, the QEMU resampler needs to be replaced/rewritten to support it.

1 Like

Popping/clicking can be caused by too small/short of a period, not enough periods, etc. Lack of CPU pinning, or starving jack of CPU time. Also make sure that jack is running with RT priority, and QEMU can also start it’s jack client with RT priority also.

I am using csets at the moment for pinning and my host only had a couple of terminals cadence and carla open so I am not too sure that it was getting starved for cpu however it is possible I guess.

I tried changing the periods. setting the buffer size in cadence to 2048 and 4096 with no real change in result. I set the periods up from 2 to 4 to 16 then 32 without any change.

When I checked to see if jack is running with realtime priority just to verify cadence was doing its job it was. one of jackdbus’s processes was set to

pid 38860’s current scheduling policy: SCHED_FIFO
pid 38860’s current scheduling priority: 90

2 of qemu’s processes were set the same except the scheduling priority was 85 instead of 90.

Its very possible one of those things is still the issue I am just not sure what my next move should be.

Should I try to run jack without cadence at all?

Edit:

I decided to try without cadence running at all. That seemed to solve it.
I will try more in the morning. However this seems promising. Thank you for the advice.

All i did that time was configure the period and nperiods with jack_control instead of letting cadence start jack.
Wish me luck.

Please note that csets is no replacement for isolcpus, and jack is very timing sensitive as such being serviced late by the kernel will cause clicks/pops. You may not be starved of CPU cycles, but rather the scheduler is working too hard and can’t service the jack thread again within a decent timeframe.

Hello and thank you for creating this qemu “extension”.

I have managed to make it work, sort of:

Despite following all available tutorials and wiki pages, the jack client created by Qemu is not able to run with real time privileges. The libvirtd guest log shows the following;

jack: E: Cannot use real-time scheduling (RR/68) (1: Operation not permitted)
jack: E: JackClient::AcquireSelfRealTime error
jack: JACK output configured for 48000Hz (512 samples)
jack: E: Cannot use real-time scheduling (RR/68) (1: Operation not permitted)
jack: E: JackClient::AcquireSelfRealTime error

I am running Qemu as a normal user, have edited qemu.conf accordingly, my user is added to real time group, and jack is started by qjackctrl under the same user.

Have you guys checked whether the jack client started by the VM can run in realtime?

Thank you.

PS: the following test seems to indicate that the basics are all available:

perl ./realTimeConfigQuickScan.pl
== GUI-enabled checks ==
Checking if you are root... no - good
Checking filesystem 'noatime' parameter... 5.10.2 kernel - good
(relatime is default since 2.6.30)
Checking CPU Governors... CPU 0: 'performance' CPU 1: 'performance' CPU 10: 'performance' CPU 11: 'performance' CPU 2: 'performance' CPU 3: 'performance' CPU 4: 'performance' CPU 5: 'performance' CPU 6: 'performance' CPU 7: 'performance' CPU 8: 'performance' CPU 9: 'performance'  - good
Checking swappiness... 10 - good
Checking for resource-intensive background processes... none found - good
Checking checking sysctl inotify max_user_watches... >= 524288 - good
Checking whether you're in the 'audio' group... yes - good
Checking for multiple 'audio' groups... no - good
Checking the ability to prioritize processes with chrt... yes - good
Checking kernel support for high resolution timers... found - good
Kernel with Real-Time Preemption... 'threadirqs' kernel parameter - good
Checking if kernel system timer is high-resolution... found - good
Checking kernel support for tickless timer... found - good
   For more information, see http://wiki.linuxaudio.org/wiki/system_configuration#filesystems
Checking for devices at IRQ 153... did not find multiple. ok.

It certainly can, but permissions can be a pita.
You do know that even root applications can’t use realtime unless it’s configured in /etc/security/limits.conf?

Hello @gnif

Thanks for taking the time to answer.
I do understand that realtime users have to be configured yes.

However I did nothing to configure realtime permissions for root.
Do you suggest I should even though jack and qemu are running under non-root username?
I am not sure if this is what you mean.

Thank you.

PS:

At this point I created the following files:

bat /etc/security/limits.d/*

       │ File: /etc/security/limits.d/10-audio.conf

   1   │ @audio           -       rtprio          95
   2   │ @audio           -       memlock         unlimited
   3   │ @audio           -       nice            -19

       │ File: /etc/security/limits.d/10-gamemode.conf

   1   │ @gamemode - nice -10

       │ File: /etc/security/limits.d/10-gcr.conf

   1   │ @users - memlock 1024

       │ File: /etc/security/limits.d/99-realtime-privileges.conf

   1   │ @realtime - rtprio 99
   2   │ @realtime - memlock unlimited
   3   │ @realtime - nice -19

username is member of both realtime and audio groups:

❯ grep real /etc/group
realtime:x:962:username
❯ grep audio /etc/group
audio:x:995:username

Limits are as follow for my user:

ulimit -a
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         unlimited
-m: resident set size (kbytes)      unlimited
-u: processes                       126065
-n: file descriptors                1024
-l: locked-in-memory size (kbytes)  unlimited
-v: address space (kbytes)          unlimited
-x: file locks                      unlimited
-i: pending signals                 126065
-q: bytes in POSIX msg queues       819200
-e: max nice                        36
-r: max rt priority                 95
-N 15:                              unlimited

Both pulseaudio and jackdbus are running under my username:

ps axHo user,lwp,pid,rtprio,ni,command | grep -e pulsea
username      3100    3100      - -16 /usr/bin/pulseaudio --daemonize=no --log-target=journal
username      3101    3100     84   - /usr/bin/pulseaudio --daemonize=no --log-target=journal
username      3102    3100     84   - /usr/bin/pulseaudio --daemonize=no --log-target=journal
username      3103    3100     80   - /usr/bin/pulseaudio --daemonize=no --log-target=journal
username      3104    3100     68   - /usr/bin/pulseaudio --daemonize=no --log-target=journal
username      3105    3100     84   - /usr/bin/pulseaudio --daemonize=no --log-target=journal
username      3106    3100     80   - /usr/bin/pulseaudio --daemonize=no --log-target=journal
username      3107    3100     68   - /usr/bin/pulseaudio --daemonize=no --log-target=journal

ps axHo user,lwp,pid,rtprio,ni,command | grep -e jack
username      2762    2762      -   0 /usr/bin/jackdbus auto
username      3092    2762      -   0 /usr/bin/jackdbus auto
username      3093    2762     73   - /usr/bin/jackdbus auto
username      3094    2762      -   0 /usr/bin/jackdbus auto
username      3028    3028      -   0 qjackctl
username      3029    3028      -   0 qjackctl
username      3030    3028      -   0 qjackctl
username      3031    3028      -   0 qjackctl
username      3032    3028      -   0 qjackctl
username      3033    3028      -   0 qjackctl
username      3035    3028      -   0 qjackctl
username      3095    3028      -   0 qjackctl
username      3096    3028      -   0 qjackctl
username     52132    3028      0  19 qjackctl
username     52133    3028      0  19 qjackctl
username     52134    3028      0  19 qjackctl
username     52135    3028      0  19 qjackctl

Reading through some online resources, I found indication that jackdbus is run as a dbus service and therefore systemd --user services need to be able to raise priority:

systemctl --user edit dbus.service
LimitNICE=-16
LimitRTPRIO=95

Here is the libvirt/qemu config:

batgrep username /etc/libvirt/qemu.conf

     File: /etc/libvirt/qemu.conf
    user = "username"
 
 batgrep seccomp /etc/libvirt/qemu.conf

     File: /etc/libvirt/qemu.conf
   seccomp_sandbox = 0      

Here are the limits applied to jackdbus:

 cat /proc/`pidof jackdbus`/limits
 
 Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     
Max core file size        unlimited            unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             126065               126065               processes 
Max open files            1024                 524288               files     
Max locked memory         unlimited            unlimited            bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       126065               126065               signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         36                   36                   
Max realtime priority     95                   95                   
Max realtime timeout      unlimited            unlimited            us  

Also the pulseaudio jack client is started as follows:

Jan 02 17:25:20 mycomputer pulseaudio[3100]: JACK thread starting up.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: SCHED_RR|SCHED_RESET_ON_FORK worked.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: Successfully enabled SCHED_RR scheduling for thread, with priority 84.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: Thread starting up
Jan 02 17:25:20 mycomputer pulseaudio[3100]: SCHED_RR|SCHED_RESET_ON_FORK worked.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: Successfully enabled SCHED_RR scheduling for thread, with priority 80.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: JACK buffer size changed.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: JACK thread starting up.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: SCHED_RR|SCHED_RESET_ON_FORK worked.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: Successfully enabled SCHED_RR scheduling for thread, with priority 84.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: JACK thread starting up.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: SCHED_RR|SCHED_RESET_ON_FORK worked.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: Successfully enabled SCHED_RR scheduling for thread, with priority 84.
Jan 02 17:25:20 mycomputer pulseaudio[3100]: Connecting PulseAudio JACK Sink:front-left to system:playback_1
Jan 02 17:25:20 mycomputer pulseaudio[3100]: Connecting PulseAudio JACK Sink:front-right to system:playback_2
Jan 02 17:25:20 mycomputer pulseaudio[3100]: jack_out: state: INIT -> IDLE

However all the libvirt guests show that their respective jack client does not start with real time privileges:

jack: E: Cannot use real-time scheduling (RR/68) (1: Operation not permitted)
jack: E: JackClient::AcquireSelfRealTime error
jack: JACK output configured for 48000Hz (512 samples)
jack: E: Cannot use real-time scheduling (RR/68) (1: Operation not permitted)
jack: E: JackClient::AcquireSelfRealTime error

My guests are configured as follows:

  <qemu:commandline>
    <qemu:arg value="-audiodev"/>
    <qemu:arg value="jack,id=ad0,in.client-name=guestvm,out.client-name=guestvm,out.start-server=on,in.start-server=on"/>
    <qemu:arg value="-device"/>
    <qemu:arg value="ich9-intel-hda"/>
    <qemu:arg value="-device"/>
    <qemu:arg value="hda-duplex,audiodev=ad0"/>
  </qemu:commandline>

Any suggestion would be most welcome and appreciated :slight_smile:

1 Like

Sorry but I do not use libvirt for my Jack system. I do know however that things libvirt does such as sandboxing and runas mess with things. QEMU creates the audio threads before it drops privs IIRC as such you must allow the user that spawns QEMU RT access.

In short you will need to experiment I am sorry. If you figure it out please be sure to post the method here for others.

Sorry for being so late for replying. the holidays got slightly busy. I think I found my problem which was likely some configuration issue because when I stopped using cadence and just used jack_control the issues with jack and qemu disappeared. Thanks for spending the time try and help me. I will try isolcpus in a day or two and see how it feels audiowise but right now I think I am happy.

Have a great day.

Hello @gnif

Thank you for your answer.
I have tried starting a VM with QEMU only and it does not display the same error.

Therefore it is indeed a libvirt issue.

After spending many more hours experimenting and investigating this issue, I have determined that the correct way to resolve this problem is indeed to edit systemd services to allow them to acquire real time priority.

The reason is systemd services ignore the contents of /etc/security/limits and PAM.

This is something I had tried before however I had made a syntax error.
I was unable to edit my previous post to correct that. Here is the appropriate syntax so that other people trying the same are not misinformed:


So in order to allow realtime priorities of a systemd service XXX, one has to add the following lines:

systemctl --edit XXX

[Service]
LimitRTPRIO=95
LimitNICE=-16
LimitMEMLOCK=infinity

Source: www freedesktop org/software systemd/man/systemd.exec.html#Process%20Properties


I am running pulseaudio and jack as a user, so I used the following commands:

systemctl --user edit pulseaudio.service #for pulse
systemctl --user edit dbus.service #for jackdbus
systemctl edit libvirtd.service # for libvirt

and added the above lines.
Everything works now.

1 Like

@Al_Jazz
I can confirm that this was required to get it working on my end as well, not to mention adjustments needed to be made to AppArmor’s profile for libvirt so that it was able to access the /dev/shm devices required for JACK.
Also the default settings for jackd (technically launched via jackdbus) had the buffer size set at 1024 with 2 periods which still caused some clipping from the VM’s output, setting that lower (to 128 buffer size) still at 44100Hz rate has fixed that entirely. I still get a few XRUN events here and there, but they are almost non-noticeable now and relatively low in frequency (approx 20 every 2hr or so, slightly more when the system is under heavier load).

I would also echo what others have said, thank you @gnif, not only for this patch but for looking-glass as well. It’s been working fantastically so far, especially once I got the issues ironed out through use of your vendor reset module.

2 Likes

Is anyone able to get JACK output working on Pipewire?

Switching from a working JACK to Pipewire gives me the following in the logs:

2021-04-21 08:13:46.868+0000: Domain id=1 is tainted: custom-argv
char device redirected to /dev/pts/5 (label charserial0)
audio: Device hda: audiodev default parameter is deprecated, please specify audiodev=sound0
jack: jack_client_open failed: status = 0x11
jack: unable to connect to JACK server
jack: jack_client_open failed: status = 0x11
jack: unable to connect to JACK server
audio: Failed to create voice `dac'

I added the following to libvirt-qemu AppArmor profile to silence the obvious access control issue:

  /etc/pipewire/* r,
  capability bpf,
  capability perfmon,

Also tried with AppArmor disabled, but same result.

Yes, when I used pipewire instead of pulseaudio and jack, I found that the jack output of QEMU didn’t seem to work for me.

@gnif Are there any plans to develop “qemu-native-pipewire-audio-support”? :smile:

I’m using pipewire with qemu jack backend few months now :wink:
It’s amazing, almost zero delay even over network.
I’m using libvirt so I can provide you only my XML, no cmdline.

<domain>
  [...]
  <devices>
    <sound model='ich9'>
      <codec type='micro'/>
      <audio id='1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/>
    </sound>
    <audio id='1' type='jack'>
      <input mixingEngine='yes' fixedSettings='yes' clientName='vm-win'>
        <settings frequency='48000' channels='1' format='f32'/>
      </input>
      <output mixingEngine='yes' fixedSettings='yes' clientName='vm-win'>
        <settings frequency='48000' channels='2' format='f32'/>
      </output>
    </audio>
    [...]
  </devices>
  [...]
  <qemu:commandline>
    [...]
    <qemu:env name='PIPEWIRE_RUNTIME_DIR' value='/run/user/0'/>
  </qemu:commandline>
</domain>

You also need symlinks to make pipewire default jack lib provider or in case of Arch Linux pipewire-jack-dropin package from AUR.

1 Like

Debian doesn’t use symlinks for pipewire-jack client libs, but uses ld-config to assign a higher priority for them.

The environment variable is interesting though, will try when I test pipewire again when I have time.