Sys-audio and (Windows) HVMs

So, after a while of having no audio in HVMs if using sys-audio, I decided to have a look into the issue. Using Using sys-audio for Windows audio - #9 by disp584 as a starting point, I created a patch file that can be applied to init in /usr/libexec/xen/boot/qemu-stubdom-linux-full-rootfs.

--- init	2023-03-30 17:15:27.389013186 +0100
+++ init	2023-03-30 17:17:35.048015003 +0100
@@ -29,6 +29,7 @@
 
 # add audiodev conf to cmdline and run pulseaudio 
 audio_model=$(echo "$dm_args" | sed -n '/^-soundhw/ {n;p}')
+audioid=$(xenstore-read "/global/qvm-hvm-audio-id" || echo "0")
 if [ -n "$audio_model" ] ; then
     model_args=
     if [ "$audio_model" == "ich6" ] ; then
@@ -38,7 +39,7 @@
     pa_args=$'-audiodev\npa,id=qemupa,server=unix:/tmp/pa.sock'$model_args;
     pulseaudio --use-pid-file=no --daemonize=no --exit-idle-time=-1 --disable-shm=yes -n \
 	-L "module-native-protocol-unix auth-anonymous=1 socket=/tmp/pa.sock" \
-	-L "module-vchan-sink domid=0" &
+	-L "module-vchan-sink domid=$audioid" &
 fi
 
 # Extract network parameters and remove them from dm_args

Following @disp584’s instructions, ensuring that commands are run as root…

  1. If patch is not already installed… qubes-dom0-update patch
  2. Make a working directory for the stubdom: mkdir /tmp/stubroot
  3. Copy the stubdom into the directory: cp /usr/libexec/xen/boot/qemu-stubdom-linux-full-rootfs /tmp/stubroot/stubdom.gz
  4. cd into the directory: cd /tmp/stubroot
  5. Decompress: gzip -d stubdom.gz
  6. Extract: cpio -i -d -H newc --no-absolute-filenames < stubdom ; rm stubdom
  7. Patch init: patch < /path/to/downloaded/audioid.patch
  8. Rebuild stubdom: find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../new-stubdom
  9. (Optional) Make a backup of the original stubdom: cp /usr/libexec/xen/boot/qemu-stubdom-linux-full-rootfs /usr/libexec/xen/boot/qemu-stubdom-linux-full-rootfs.BAK
  10. Copy the new stubdom over the old one: mv ../new-stubdom /usr/libexec/xen/boot/qemu-stubdom-linux-full-rootfs
  11. Save the following below to a script and execute said script to update the requisite xen variable:
#!/bin/bash
audiodomain=$(qubes-prefs default_audiovm)
echo "Audio domain is $audiodomain"
ADxid=$(qvm-prefs "$audiodomain" xid)
echo "xid of audio domain is $ADxid"
if [ "$ADxid" -gt -1 ]; then
  xenstore-write /global/qvm-hvm-audio-id "$ADxid"
  xenstore-chmod /global/qvm-hvm-audio-id "r*w0"
else
  echo "Not updating, AudioVM not running!"
fi

echo "Wrote $ADxid to /global/qvm-hvm-audio-id and reset perms to r*w0"

This should now allow audio to work correctly within HVMs. Unfortunately, attempts to make the script above execute automatically as a libvirt hook only caused the system to hang upon reboot or upon starting up any HVM. Even executing the script above in background results in the system hanging. I suspect this is due to QubesDB or whatever qubes-prefs/qvm-prefs uses hanging while a VM starts up. Also, this script assumes that “default_audiovm” is set to something other than dom0 via qubes-prefs default_audiovm.

So, any additions to this solution is welcome!

Deprecated in favor for: Proper guide on how to use sys-audio (AudioVM) must be created - #16 by neowutran

The following patches and script automatically applies the needed steps:
stubdom_libvirtargs.patch

--- init	2023-04-12 17:17:09.718014699 +0100
+++ init	2023-04-12 17:16:44.420014339 +0100
@@ -27,6 +27,14 @@
     mdev -d
 fi
 
+# Get audio params and remove from dm_args
+audio_args=$(echo "$dm_args" | sed -n '/^-qubes-audio:/p')
+dm_args=$(echo "$dm_args" | sed '/^-qubes-audio:/d')
+
+get_audio_arg() {
+    echo "$audio_args" | sed -n 's/^.*[:,]'$1'=\([^,]\+\).*$/\1/p'
+}
+
 # add audiodev conf to cmdline and run pulseaudio 
 audio_model=$(echo "$dm_args" | sed -n '/^-soundhw/ {n;p}')
 if [ -n "$audio_model" ] ; then
@@ -38,7 +46,7 @@
     pa_args=$'-audiodev\npa,id=qemupa,server=unix:/tmp/pa.sock'$model_args;
     pulseaudio --use-pid-file=no --daemonize=no --exit-idle-time=-1 --disable-shm=yes -n \
 	-L "module-native-protocol-unix auth-anonymous=1 socket=/tmp/pa.sock" \
-	-L "module-vchan-sink domid=0" &
+	-L "module-vchan-sink domid=$(get_audio_arg 'audiovm_xid')" &
 fi
 
 # Extract network parameters and remove them from dm_args

xenxml.patch

--- xen.xml	2023-04-12 17:24:15.359020758 +0100
+++ xen.xml	2023-04-12 17:24:44.456021172 +0100
@@ -160,6 +160,11 @@
             {% endfor %}
 
 
+            {% if vm.audiovm %}
+              {% set audiovm_xid = vm.audiovm.xid %}
+            {% else %}
+              {% set audiovm_xid = 0 %}
+            {% endif %}
             {% if vm.virt_mode == 'hvm' %}
                 <!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
                 <emulator
@@ -174,13 +179,15 @@
                             ,dns_0={{ vm.dns[0] -}}
                             ,dns_1={{ vm.dns[1] -}}
                             ,gw={{ vm.netvm.gateway -}}
-                            ,netmask={{ vm.netmask }}"
+                            ,netmask={{ vm.netmask }}
+                            -qubes-audio:audiovm_xid={{ audiovm_xid }}"
                       {% else %}
                         cmdline="-net lwip,client_ip={{ vm.ip -}}
                             ,server_ip={{ vm.dns[1] -}}
                             ,dns={{ vm.dns[0] -}}
                             ,gw={{ vm.netvm.gateway -}}
-                            ,netmask={{ vm.netmask }}"
+                            ,netmask={{ vm.netmask }}
+                            -qubes-audio:audiovm_xid={{ audiovm_xid }}"
                       {% endif %}
                     {% endif %}
                     {% if vm.stubdom_mem %}

script.sh

#!/bin/bash
qubes-dom0-update patch

ORIGLOC=`pwd`
# Apply patch to xen.xml
cd /usr/share/qubes/templates/libvirt
patch -N < $ORIGLOC/xemxml.patch
rm xen.xml.rej || true

# Patch stubdom
mkdir /tmp/stubroot
cp /usr/libexec/xen/boot/qemu-stubdom-linux-full-rootfs /tmp/stubroot/stubdom.gz
cd /tmp/stubroot
gzip -d stubdom.gz
cpio -i -d -H newc --no-absolute-filenames < stubdom ; rm stubdom
patch -N < $ORIGLOC/stubdom_libvirtargs.patch
rm init.rej || true
cp /usr/libexec/xen/boot/qemu-stubdom-linux-full-rootfs /usr/libexec/xen/boot/stubdom-full-rootfs.BAK
find . -print0 | cpio --null -ov --format=newc | gzip -9 > /usr/libexec/xen/boot/qemu-stubdom-linux-full-rootfs
rm -fR /tmp/stubroot
# Return to starting location
cd $ORIGLOC

Could easily be adapted into a salt script.

2 Likes