SDL: audio: Prefer Pipewire if at least version 1.0.0

From b1e47704eeaa9cab8933497ef867d902db0cd01b Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Mon, 15 Apr 2024 12:36:01 -0400
Subject: [PATCH] audio: Prefer Pipewire if at least version 1.0.0

Checking for the pipewire-pulse service is unreliable when used in containers such as Flatpak, so simply use a minimum version check instead and prefer it over the Pulseaudio backend if at least version 1.0.0.
---
 src/audio/pipewire/SDL_pipewire.c | 39 +++++++++--------
 src/core/linux/SDL_dbus.c         | 69 -------------------------------
 src/core/linux/SDL_dbus.h         |  2 -
 3 files changed, 19 insertions(+), 91 deletions(-)

diff --git a/src/audio/pipewire/SDL_pipewire.c b/src/audio/pipewire/SDL_pipewire.c
index a699746af001b..499bf6aea9748 100644
--- a/src/audio/pipewire/SDL_pipewire.c
+++ b/src/audio/pipewire/SDL_pipewire.c
@@ -31,15 +31,6 @@
 
 #include "../../core/linux/SDL_dbus.h"
 
-static SDL_bool CheckPipewirePulseService()
-{
-#ifdef SDL_USE_LIBDBUS
-    return SDL_DBus_QuerySystemdUnitRunning("pipewire-pulse.service", SDL_TRUE);
-#else
-    return SDL_FALSE;
-#endif
-}
-
 /*
  * The following keys are defined for compatibility when building against older versions of Pipewire
  * prior to their introduction and can be removed if the minimum required Pipewire build version is
@@ -221,7 +212,7 @@ static SDL_bool pipewire_version_at_least(int major, int minor, int patch)
            (pipewire_version_major > major || pipewire_version_minor > minor || pipewire_version_patch >= patch);
 }
 
-static int init_pipewire_library(void)
+static int init_pipewire_library(int major, int minor, int patch)
 {
     if (!load_pipewire_library()) {
         if (!load_pipewire_syms()) {
@@ -232,8 +223,7 @@ static int init_pipewire_library(void)
                 return -1;
             }
 
-            // SDL can build against 0.3.20, but requires 0.3.24
-            if (pipewire_version_at_least(0, 3, 24)) {
+            if (pipewire_version_at_least(major, minor, patch)) {
                 PIPEWIRE_pw_init(NULL, NULL);
                 return 0;
             }
@@ -1262,10 +1252,23 @@ static void PIPEWIRE_Deinitialize(void)
     }
 }
 
-static SDL_bool PipewireInitialize(SDL_AudioDriverImpl *impl)
+static SDL_bool PipewireInitialize(SDL_AudioDriverImpl *impl, SDL_bool check_preferred_version)
 {
     if (!pipewire_initialized) {
-        if (init_pipewire_library() < 0) {
+        int major, minor, patch;
+
+        // SDL can build against 0.3.20, but requires 0.3.24 at minimum, and 1.0.0 for preferred default status.
+        if (check_preferred_version) {
+            major = 1;
+            minor = 0;
+            patch = 0;
+        } else {
+            major = 0;
+            minor = 3;
+            patch = 24;
+        }
+
+        if (init_pipewire_library(major, minor, patch) < 0) {
             return SDL_FALSE;
         }
 
@@ -1295,16 +1298,12 @@ static SDL_bool PipewireInitialize(SDL_AudioDriverImpl *impl)
 
 static SDL_bool PIPEWIRE_PREFERRED_Init(SDL_AudioDriverImpl *impl)
 {
-    if (CheckPipewirePulseService()) {
-        return PipewireInitialize(impl);
-    }
-
-    return SDL_FALSE;
+    return PipewireInitialize(impl, SDL_TRUE);
 }
 
 static SDL_bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl)
 {
-    return PipewireInitialize(impl);
+    return PipewireInitialize(impl, SDL_FALSE);
 }
 
 AudioBootStrap PIPEWIRE_PREFERRED_bootstrap = {
diff --git a/src/core/linux/SDL_dbus.c b/src/core/linux/SDL_dbus.c
index a0c96a878b71e..9e6a56b65e1d8 100644
--- a/src/core/linux/SDL_dbus.c
+++ b/src/core/linux/SDL_dbus.c
@@ -632,73 +632,4 @@ char **SDL_DBus_DocumentsPortalRetrieveFiles(const char *key, int *path_count)
     return NULL;
 }
 
-/* Check to see if a Systemd unit exists and is currently running. */
-SDL_bool SDL_DBus_QuerySystemdUnitRunning(const char *unit_name, SDL_bool user_unit)
-{
-    const char *path, *prop;
-    DBusError err;
-    SDL_bool running = SDL_FALSE;
-
-    /* Make sure we have a connection to the dbus session bus */
-    if (!SDL_DBus_GetContext() || !dbus.session_conn) {
-        /* We either cannot connect to the session bus or were unable to
-         * load the D-Bus library at all. */
-        return SDL_FALSE;
-    }
-
-    /* Make sure the appropriate bus is available. */
-    if ((user_unit && !dbus.session_conn) || (!user_unit && !dbus.system_conn)) {
-        return SDL_FALSE;
-    }
-
-    dbus.error_init(&err);
-
-    /* Get the object path for the unit. */
-    DBusMessage *method = dbus.message_new_method_call("org.freedesktop.systemd1",
-                                                       "/org/freedesktop/systemd1",
-                                                       "org.freedesktop.systemd1.Manager",
-                                                       "GetUnit");
-    if (!method) {
-        return SDL_FALSE;
-    }
-
-    if (!dbus.message_append_args(method, DBUS_TYPE_STRING, &unit_name, DBUS_TYPE_INVALID)) {
-        SDL_OutOfMemory();
-        dbus.message_unref(method);
-        return SDL_FALSE;
-    }
-
-    DBusMessage *reply = dbus.connection_send_with_reply_and_block(user_unit ? dbus.session_conn : dbus.system_conn, method, DBUS_TIMEOUT_USE_DEFAULT, &err);
-    dbus.message_unref(method);
-    if (!reply) {
-        if (dbus.error_is_set(&err)) {
-            SDL_SetError("%s: %s", err.name, err.message);
-            dbus.error_free(&err);
-        }
-        return SDL_FALSE;
-    }
-
-    DBusMessageIter reply_iter;
-    if (!dbus.message_iter_init(reply, &reply_iter)) {
-        goto done;
-    }
-
-    if (dbus.message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_OBJECT_PATH) {
-        goto done;
-    }
-
-    dbus.message_iter_get_basic(&reply_iter, &path);
-
-    /* We want to know the substate of the unit, which should be the string "running". */
-    if (SDL_DBus_QueryPropertyOnConnection(user_unit ? dbus.session_conn : dbus.system_conn,
-                                           "org.freedesktop.systemd1", path, "org.freedesktop.systemd1.Unit",
-                                           "SubState", DBUS_TYPE_STRING, &prop)) {
-        running = SDL_strcmp(prop, "running") == 0;
-    }
-
-done:
-    dbus.message_unref(reply);
-    return running;
-}
-
 #endif
diff --git a/src/core/linux/SDL_dbus.h b/src/core/linux/SDL_dbus.h
index d6841a6db14a3..0be866b36059d 100644
--- a/src/core/linux/SDL_dbus.h
+++ b/src/core/linux/SDL_dbus.h
@@ -109,8 +109,6 @@ extern char *SDL_DBus_GetLocalMachineId(void);
 
 extern char **SDL_DBus_DocumentsPortalRetrieveFiles(const char *key, int *files_count);
 
-extern SDL_bool SDL_DBus_QuerySystemdUnitRunning(const char *unit_name, SDL_bool user_unit);
-
 #endif /* HAVE_DBUS_DBUS_H */
 
 #endif /* SDL_dbus_h_ */