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(a)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