Virtual machine audio setup – or how to get pulse audio working

In this post, I compare several options of how to get the sound output from an KVM virtual machine guest, back into the host. I will compare spice server, pulse audio and a hardware solution.

The Host runs an Asus Xonar DGX 5.1 PCIE sound card.

In any case – harmonize sample rates of host and guest system

A common issue with sound passthrough between guest and host is lagging or chopped up sound playback. In order to fix this make sure the host and the guest use the same default playback sample rate.

Setting default sample rate in Linux

open /etc/libvirt/qemu.conf via

sudo nano /etc/libvirt/qemu.conf

and uncomment the line

user = "example"

replace your username with example

open /etc/pulse/daemon.conf

and find/add/uncomment the lines and set these values:

default-sample-rate = 44100
alternate-sample-rate = 48000

afterwards restart the pulse audio service via

pulseaudio -k or reboot.

Setting default sample rate in Windows

Set the frequency of your windows sound to 44100 Hz

Set sample rate for default audio device in windows 10
Set sample rate for default audio device in windows 10

Option 1 – use Spice Server

(+) Easy to set up
(+) Very good for first setup of the VM OS.
(-) Needs VM window open in order to work
(-) a little more delay than direct pulse audio version
(-) Adds an extra display to the VM.

This one is pretty straight forward, open the info page of the VM on virt-manager and add a spice server.

Add spice server via virtmanager GUI
Add spice server via virt-manager GUI

Adding the spice server adds actually several devices to the VM config, one for example is a display.

In order to hear sound, I have to open the VM while it is running (I hope the sentence make sense 🙂 ). Basically it is double clicking on the running VM in the virt-manager list.

Open VM spice server window while VM is running
Open VM spice server window while VM is running

Option 2 – use Pulse Audio

(+) Less sound delay than the spice server version
(+) Less overhead once running
(+) Nicer Integration
(-) Complicated to get it working
(-) Lots of users complain about bad sound quality

Pulse Audio with QEMU 4.2 (and above)

Edit the virtual machine config via
virsh edit <your vm name>

e.g. virsh edit windows10

Make sure the very first line of the file does read:

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>

Instead of

<domain type='kvm'>

Check at the bottom of your config if a line <qemu:commandline> exists. If yes make sure to add these options:

  <qemu:arg value='-device'/>
  <qemu:arg value='ich9-intel-hda,bus=pcie.0,addr=0x1b'/>
  <qemu:arg value='-device'/>
  <qemu:arg value='hda-micro,audiodev=hda'/>
  <qemu:arg value='-audiodev'/>
  <qemu:arg value='pa,id=hda,server=unix:/run/user/1000/pulse/native'/>
</qemu:commandline>

In case <qemu:commandline> is missing, find the line which ends with </devices>
and add the following block afterwards:

<qemu:commandline>
  <qemu:arg value='-device'/>
  <qemu:arg value='ich9-intel-hda,bus=pcie.0,addr=0x1b'/>
  <qemu:arg value='-device'/>
  <qemu:arg value='hda-micro,audiodev=hda'/>
  <qemu:arg value='-audiodev'/>
  <qemu:arg value='pa,id=hda,server=unix:/run/user/1000/pulse/native'/>
</qemu:commandline>

The 1000 in

server=unix:/run/user/1000/pulse/native

represents your user-id, 1000 is the default (one user) Id.

Attention!

Make sure <devices> and <qemu:commandline> have the same indent.

Remark!

The <qemu:commandline> part can hold further options, simply append the sound options if others were already present.

Open the apparmor libvirt abstractions file via

sudo nano /etc/apparmor.d/abstractions/libvirt-qemu

Append the following lines

/etc/pulse/client.conf.d/ r,
/etc/pulse/client.conf.d/* r,
/run/user/1000/pulse/native rw,
/home/your-username/.config/pulse/* r,
/home/your-username/.config/pulse/cookie k,

Replace your-username with your username.

→ reboot your system.

Settings in Virt-manager

Make sure no further audio devices are added by virt-manager – remove all audio devices from the virtual hardware details bar (left side in VM info view).

Troubleshooting

If you have no sound at all, run pax11publish and check if a server with name /run/user/1000/pulse/native is available.

Pulse Audio with QEMU 4.1 (and below)

Edit the virtual machine config via
virsh edit <your vm name>

e.g. virsh edit windows10

Make sure the very first line of the file does read:

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>

instead of

<domain type='kvm'>

Check at the bottom of your config if a line <qemu:commandline> exists. If yes make sure to add these options:

  <qemu:env name='QEMU_AUDIO_DRV' value='pa'/>
  <qemu:env name='QEMU_PA_SAMPLES' value='8192'/>
  <qemu:env name='QEMU_AUDIO_TIMER_PERIOD' value='99'/>
  <qemu:env name='QEMU_PA_SERVER' value='/run/user/1000/pulse/native'/>

In case <qemu:commandline> is missing, find the line which ends with </devices>
and add the following block afterwards:

<qemu:commandline>
  <qemu:env name='QEMU_AUDIO_DRV' value='pa'/>
  <qemu:env name='QEMU_PA_SAMPLES' value='8192'/>
  <qemu:env name='QEMU_AUDIO_TIMER_PERIOD' value='99'/>
  <qemu:env name='QEMU_PA_SERVER' value='/run/user/1000/pulse/native'/>
</qemu:commandline>

The 1000 in /run/user/1000/pulse/native represents your user-id. 1000 is the default (one user) user id.

Attention!

After adding the enlightments, I had no internet on one Windows 10 guest (also not every time).

After some digging, I found a reddit post with the proposed “solution” to change the model type of the network bridge interface in the libvirt config from “virtio” to “virtio-net-pci”.

Remark!

Lorem Ipsum!

Extract from my config file

   </devices>
   <qemu:commandline>
     <qemu:arg value='-cpu'/>
     <qemu:arg value='host,hv_time,kvm=off,hv_vendor_id=null'/>
     <qemu:env name='QEMU_AUDIO_DRV' value='pa'/>
     <qemu:env name='QEMU_PA_SAMPLES' value='8192'/>
     <qemu:env name='QEMU_AUDIO_TIMER_PERIOD' value='99'/>
     <qemu:env name='QEMU_PA_SERVER' value='/run/user/1000/pulse/native'/>
   </qemu:commandline>
</domain>

[collapse]

Settings in Virt-manager

As said before, add a sound “ich6” device to your VM.

Attention!

Do not use 6ch/9ch audio devices in Windows 10 1903 virtual machines. It creates awful stuttering and performance loss. Use ac97 audio devices instead.

Troubleshooting

If the sound distortions occur, make sure host and guest run at the same sample rate. You can also play around with QEMU_PA_SAMPLES and QEMU_AUDIO_TIMER_PERIOD values (see the reddit post(s) from the sources for further information).

Option 3 – use Hardware

(+) Very easy
(-) Costs money
I haven’t tried this, but it should be easily possible to add a USB sound card to the guest and run the output back into your host sound card via a real audio wire (connecting guest line-out with host line-in).

Updates:

  • 2020.06.24 …. added information for QEMU version 4.2
  • 2018.02.17 …. initial creation

Sources:

The glorious arch-wiki

Users spheeniks reddit post

Reddit post for audio problem with QEMU 4.2 and bigger

15 comments on “Virtual machine audio setup – or how to get pulse audio working”

  1. AMD Ryzen based passthrough setup between (X)Ubuntu 16.04 and Windows 10 - www.MathiasHueber.com

    […] After some nights without sleep, I wrote an separate article on that matter. […]

    Reply
  2. Kevinesan Pillay

    Cheers mate, worked like a charm!

    Reply
    1. Mathias Hueber

      glad it helps 🙂

      Reply
  3. dz0rg

    Thank you for this tutorial, I finally understood why sometimes I had the sound of my VM with my headphones.

    Reply
  4. voider1

    I’m having a problem where when I use Discord and play a game, the mic stops working and sometimes the audio too, and I have to rejoin the call. Any idea how to fix this?

    Reply
    1. Mathias Hueber

      Do you use discord on the host, or on the guest?
      I use discord on the host with occasional app crashes, but I don’t think they are VFIO related.

      Reply
  5. Vlad

    Hi Mathias,

    I just wanted to thank you for your tutorial, it helped so much setting up my passthrough setup so I can finally make the switch to Linux full time. That’s it, you rock 🙂

    Reply
    1. Mathias Hueber

      Thank you for the kind words, means a lot. The whole idea is to pave the way for people to switch to Linux.

      Guten Rutsch :)!

      Reply
  6. Jonathan Rubnstein

    Hey! I think you should add in /etc/libvirt/qemu.conf to uncomment nographics_allow_host_audio=1, if the audio still doesn’t work.

    Reply
  7. 上手 Linux 原生的虚拟机工具 QEMU/KVM | 水景一页

    […] 关于声音配置,这里有较为详细的说明。但是实际上,随着 QEMU 4.2 的发布,这个声音的的配置就简单多了。可以参考 Archlinux 上的说明来操作。 […]

    Reply
  8. Carrie

    I was having trouble getting my VM’s audio to work with PulseAudio (following the Arch wiki guide), but this did the trick! Thanks!

    Reply
  9. Andrej Podzimek

    Your pulseaudio method appears to be rather complex. I’ve found a oneliner modification to the XML generated by default by virt-manager (at least for my FreeBSD VM and ArchLinux host) that gets pulseaudio working.

    So, my very first configuration used to be:

    This^^^ was not necessarily for “4.1 and below”; it actually worked until 5.2.x and the legacy support for these environment variables got ultimately dropped in 6.0. Which brought me to your blogpost. 😉

    For the record, your solution worked fine for me. It gave me audio on FreeBSD in KDE:

    However, this^^^ low-level configuration does *not* resemble the audio devices configured by default by virt-manager, which is quite confusing, because it doesn’t appear in the left configuration bar in virt-manager etc.

    So ultimately my solution was to create a “default” ICH9 audio card in virt-manager, which translates into something like this:

    Now this^^^ won’t work by default, presumably, because sound goes to nowhere. But it suffices to replace the element with this:

    There. That makes audio work. One can (presumably) set the ID to something else (instead of the default), say 7, and then set inside . But with just one sound card the default is the shortest option.

    Here’s the trick in /etc/pulse/default.pa:

    load-module module-native-protocol-unix auth-group=kvm socket=/tmp/pulse-socket-for-freebsd-on-kvm

    The last bit of the puzzle is that my qemu runs under the kvm group.

    Reply
    1. Andrej Podzimek

      Gah. Something is wrong with CSS or whatnot on this page. My XML snippets are escaped correctly in thes sources, but hidden from sight.

      Anyway, here’s my response: https://pastebin.com/UUU4XGrr

      Reply
      1. Mathias Hueber

        Thank you Andrej, I will give this a try and update the article.

        Sorry for the code snipped inconvenience, I think that is a WordPress security measure. I have to check it well 🙂

        Well, thank

        Reply

Leave a Reply

Your email address will not be published. Required fields are marked *