Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

audio: Prefer Pipewire over Pulseaudio (take 2) #9473

Merged
merged 1 commit into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions src/audio/SDL_audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
// Available audio drivers
static const AudioBootStrap *const bootstrap[] = {
#ifdef SDL_AUDIO_DRIVER_PULSEAUDIO
#ifdef SDL_AUDIO_DRIVER_PIPEWIRE
&PIPEWIRE_PREFERRED_bootstrap,
#endif
&PULSEAUDIO_bootstrap,
#endif
#ifdef SDL_AUDIO_DRIVER_PIPEWIRE
Expand Down Expand Up @@ -98,15 +101,41 @@ static const AudioBootStrap *const bootstrap[] = {

static SDL_AudioDriver current_audio;

// Deduplicated list of audio bootstrap drivers.
static const AudioBootStrap *deduped_bootstrap[SDL_arraysize(bootstrap) - 1];

int SDL_GetNumAudioDrivers(void)
{
return SDL_arraysize(bootstrap) - 1;
static int num_drivers = -1;

if (num_drivers >= 0) {
return num_drivers;
}

num_drivers = 0;

// Build a list of unique audio drivers.
for (int i = 0; bootstrap[i] != NULL; ++i) {
SDL_bool duplicate = SDL_FALSE;
for (int j = 0; j < i; ++j) {
if (SDL_strcmp(bootstrap[i]->name, bootstrap[j]->name) == 0) {
duplicate = SDL_TRUE;
break;
}
}

if (!duplicate) {
deduped_bootstrap[num_drivers++] = bootstrap[i];
}
}

return num_drivers;
}

const char *SDL_GetAudioDriver(int index)
{
if (index >= 0 && index < SDL_GetNumAudioDrivers()) {
return bootstrap[index]->name;
return deduped_bootstrap[index]->name;
}
return NULL;
}
Expand Down Expand Up @@ -884,8 +913,8 @@ int SDL_InitAudio(const char *driver_name)
current_audio.name = bootstrap[i]->name;
current_audio.desc = bootstrap[i]->desc;
initialized = SDL_TRUE;
break;
}
break;
}
}

Expand Down
1 change: 1 addition & 0 deletions src/audio/SDL_sysaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ typedef struct AudioBootStrap
} AudioBootStrap;

// Not all of these are available in a given build. Use #ifdefs, etc.
extern AudioBootStrap PIPEWIRE_PREFERRED_bootstrap;
extern AudioBootStrap PIPEWIRE_bootstrap;
extern AudioBootStrap PULSEAUDIO_bootstrap;
extern AudioBootStrap ALSA_bootstrap;
Expand Down
34 changes: 32 additions & 2 deletions src/audio/pipewire/SDL_pipewire.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@
#include <spa/param/audio/format-utils.h>
#include <spa/utils/json.h>

#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
Expand Down Expand Up @@ -1251,7 +1262,7 @@ static void PIPEWIRE_Deinitialize(void)
}
}

static SDL_bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl)
static SDL_bool PipewireInitialize(SDL_AudioDriverImpl *impl)
{
if (!pipewire_initialized) {
if (init_pipewire_library() < 0) {
Expand Down Expand Up @@ -1282,6 +1293,25 @@ static SDL_bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl)
return SDL_TRUE;
}

AudioBootStrap PIPEWIRE_bootstrap = { "pipewire", "Pipewire", PIPEWIRE_Init, SDL_FALSE };
static SDL_bool PIPEWIRE_PREFERRED_Init(SDL_AudioDriverImpl *impl)
{
if (CheckPipewirePulseService()) {
return PipewireInitialize(impl);
}

return SDL_FALSE;
}

static SDL_bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl)
{
return PipewireInitialize(impl);
}

AudioBootStrap PIPEWIRE_PREFERRED_bootstrap = {
"pipewire", "Pipewire", PIPEWIRE_PREFERRED_Init, SDL_FALSE
};
AudioBootStrap PIPEWIRE_bootstrap = {
"pipewire", "Pipewire", PIPEWIRE_Init, SDL_FALSE
};

#endif // SDL_AUDIO_DRIVER_PIPEWIRE
69 changes: 69 additions & 0 deletions src/core/linux/SDL_dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,4 +632,73 @@ 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
2 changes: 2 additions & 0 deletions src/core/linux/SDL_dbus.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ 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_ */