[PATCH 2/3] qemu: Generate cmd line for pipewire audio backend

Michal Prívozník mprivozn at redhat.com
Tue May 16 10:49:02 UTC 2023


On 5/16/23 11:52, Martin Kletzander wrote:
> On Thu, May 11, 2023 at 02:14:51PM +0200, Michal Privoznik wrote:
>> This is mostly straightforward, except for a teensy-weensy
>> detail: usually, there's no system wide daemon running, no system
>> wide available socket that anybody could connect to. PipeWire
>> uses a per user daemon approach instead. But this in turn means,
> 
> I spent some time thinking about this even after I said "just give it
> runtime dir" and now I'm wondering, is this not similar to the dbus
> daemon?  When we launch it with a constructed config file for graphics
> type='dbus' we could also launch pipewire deamon with our config file
> and let qemu connect to that daemon.  I'm not sure what the audio
> permissions would look like, but it seems like a less messy approach.

And how would then this per-domain pipewire daemon talk to the user
session daemon that's actually doing all the mixing? I mean, how would
sound from a domain get to speakers/headphones?

For dbus it's fairly easy to use, because the socket (and config file)
is located under configurable location (cfg->dbusStateDir) and with
predictable name (domain short name) AND (more importantly) we have
virDomainOpenGraphics() API which then handles virt-viewer connection
requests.

> 
>> that the socket location floats between various locations and is
>> derived from various environment variables (just like the actual
>> socket name) and thus we must pass the variables to QEMU.
>>
>> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
>> ---
>> src/qemu/qemu_command.c                       | 61 +++++++++++++++++++
>> .../audio-many-backends.x86_64-latest.args    |  2 +
>> .../qemuxml2argvdata/audio-many-backends.xml  |  1 +
>> .../audio-pipewire-best.x86_64-latest.args    | 36 +++++++++++
>> .../audio-pipewire-full.x86_64-latest.args    | 36 +++++++++++
>> .../audio-pipewire-minimal.x86_64-latest.args | 36 +++++++++++
>> tests/qemuxml2argvtest.c                      | 12 ++++
>> 7 files changed, 184 insertions(+)
>> create mode 100644
>> tests/qemuxml2argvdata/audio-pipewire-best.x86_64-latest.args
>> create mode 100644
>> tests/qemuxml2argvdata/audio-pipewire-full.x86_64-latest.args
>> create mode 100644
>> tests/qemuxml2argvdata/audio-pipewire-minimal.x86_64-latest.args
>>
>> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
>> index 3a08cac870..b31f4db6b1 100644
>> --- a/src/qemu/qemu_command.c
>> +++ b/src/qemu/qemu_command.c
>> @@ -7783,6 +7783,60 @@ qemuBuildAudioSDLProps(virDomainAudioIOSDL *def,
>> }
>>
>>
>> +static int
>> +qemuBuildAudioPipewireAudioProps(virDomainAudioIOPipewireAudio *def,
>> +                                 virJSONValue **props)
>> +{
>> +    return virJSONValueObjectAdd(props,
>> +                                 "S:name", def->name,
>> +                                 "S:stream-name", def->streamName,
>> +                                 "p:latency", def->latency,
>> +                                 NULL);
>> +}
>> +
>> +
>> +static void
>> +qemuBuildAudioPipewireAudioEnv(virCommand *cmd)
>> +{
>> +    const char *envVars[] = { "PIPEWIRE_RUNTIME_DIR", "XDG_RUNTIME_DIR",
>> +                              "USERPROFILE" };
>> +    size_t i;
>> +
>> +    /* PipeWire needs access to its daemon socket. The socket name is
>> +     * configurable (core.name in pipewire.conf, or PIPEWIRE_CORE and
>> +     * PIPEWIRE_REMOTE env vars). If the socket name is not an absolute
>> +     * path, then the socket is looked for in the following directories
>> +     * (in order):
>> +     *
>> +     * - PIPEWIRE_RUNTIME_DIR
>> +     * - XDG_RUNTIME_DIR
>> +     * - USERPROFILE
>> +     *
>> +     * This order is defined in get_runtime_dir() from
>> +     * src/modules/module-protocol-native/local-socket.c from PipeWire's
>> +     * codebase.
>> +     *
>> +     * Now, PIPEWIRE_CORE and/or PIPEWIRE_REMOTE should be passed
>> +     * whenever present in the environment. But for the other three
>> +     * (socket location dirs), we can add just the first existing one
>> +     * (basically mimic get_runtime_dir() logic).
>> +     */
>> +
>> +    virCommandAddEnvPass(cmd, "PIPEWIRE_CORE");
>> +    virCommandAddEnvPass(cmd, "PIPEWIRE_REMOTE");
>> +
>> +    for (i = 0; i < G_N_ELEMENTS(envVars); i++) {
>> +        const char *value = getenv(envVars[i]);
>> +
>> +        if (!value)
>> +            continue;
>> +
>> +        virCommandAddEnvPair(cmd, envVars[i], value);
>> +        break;
>> +    }
>> +}
>> +
>> +
>> static int
>> qemuBuildAudioCommandLineArg(virCommand *cmd,
>>                              virDomainAudioDef *def)
>> @@ -7889,6 +7943,13 @@ qemuBuildAudioCommandLineArg(virCommand *cmd,
>>         break;
>>
>>     case VIR_DOMAIN_AUDIO_TYPE_PIPEWIRE:
>> +        if
>> (qemuBuildAudioPipewireAudioProps(&def->backend.pipewire.input, &in) <
>> 0 ||
>> +           
>> qemuBuildAudioPipewireAudioProps(&def->backend.pipewire.output, &out)
>> < 0)
>> +            return -1;
>> +
>> +        qemuBuildAudioPipewireAudioEnv(cmd);
>> +        break;
>> +
>>     case VIR_DOMAIN_AUDIO_TYPE_LAST:
>>     default:
>>         virReportEnumRangeError(virDomainAudioType, def->type);
>> diff --git
>> a/tests/qemuxml2argvdata/audio-many-backends.x86_64-latest.args
>> b/tests/qemuxml2argvdata/audio-many-backends.x86_64-latest.args
>> index 9caf591daf..13dd55054e 100644
>> --- a/tests/qemuxml2argvdata/audio-many-backends.x86_64-latest.args
>> +++ b/tests/qemuxml2argvdata/audio-many-backends.x86_64-latest.args
>> @@ -6,6 +6,7 @@ LOGNAME=test \
>> XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.local/share \
>> XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.cache \
>> XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
>> +XDG_RUNTIME_DIR=/bad-test-used-env-xdg-runtime-dir \
> 
> This should fail the test suite IIRC.

I'm failing to see why. The poisoning was done so that things like:

  virDirCreate("${XGD_RUNTIME_DIR}/something/something");

fail. It's okay if it's in environment. But for everybody's peace of
mind, I can squash this in:

diff --git i/tests/qemuxml2argvtest.c w/tests/qemuxml2argvtest.c
index f29597a19f..37c2ab0826 100644
--- i/tests/qemuxml2argvtest.c
+++ w/tests/qemuxml2argvtest.c
@@ -1002,7 +1002,9 @@ mymain(void)
     DO_TEST_CAPS_LATEST("audio-spice-full");
     DO_TEST_CAPS_LATEST("audio-file-full");

+    g_setenv("PIPEWIRE_RUNTIME_DIR", "/run/user/1000", TRUE);
     DO_TEST_CAPS_LATEST("audio-many-backends");
+    g_unsetenv("PIPEWIRE_RUNTIME_DIR");

     /* Validate auto-creation of <audio> for legacy compat */
     g_setenv("QEMU_AUDIO_DRV", "sdl", TRUE);


Michal



More information about the libvir-list mailing list