[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