From a253aa4c4948cdd87ba222670ee17db849af85dd Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Mon, 27 Sep 2021 18:01:11 +0300 Subject: [PATCH] modules: implement logind module and integrate with bluez monitor This copies the logic of media-session's logind module and allows the bluez monitor to be active in only one user session at a time. This is especially useful to avoid interference between the gdm session and the actual user session, which momentarily both have wireplumber running when logging in/out. Fixes #54 --- meson.build | 5 + meson_options.txt | 2 +- modules/meson.build | 13 ++ modules/module-logind.c | 142 ++++++++++++++++++ .../bluetooth.lua.d/30-bluez-monitor.lua | 2 + src/scripts/monitors/bluez.lua | 40 ++++- src/systemd/meson.build | 3 - 7 files changed, 196 insertions(+), 11 deletions(-) create mode 100644 modules/module-logind.c diff --git a/meson.build b/meson.build index 5f87ade6..b119c74b 100644 --- a/meson.build +++ b/meson.build @@ -79,6 +79,11 @@ else endif summary({'Lua version': lua_dep.version() + (system_lua ? ' (system)' : ' (built-in)')}) +systemd = dependency('systemd', required: get_option('systemd')) +libsystemd_dep = dependency('libsystemd',required: get_option('systemd')) +summary({'systemd conf data': systemd.found(), + 'libsystemd': libsystemd_dep.found()}, bool_yn: true) + gnome = import('gnome') pkgconfig = import('pkgconfig') fs = import('fs') diff --git a/meson_options.txt b/meson_options.txt index 4008864e..4c86bd12 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -9,7 +9,7 @@ option('system-lua-version', description: 'The system lua version to use or "auto" for auto-detection') option('systemd', type: 'feature', value: 'auto', - description: 'Enable installing systemd units') + description: 'Enable installing systemd units & logind integration') option('systemd-system-service', type : 'boolean', value : false, description: 'Install systemd system service file') diff --git a/modules/meson.build b/modules/meson.build index d55b9a1f..d58c3f70 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -176,3 +176,16 @@ shared_library( install_dir : wireplumber_module_dir, dependencies : [wp_dep, pipewire_dep], ) + +if libsystemd_dep.found() + shared_library( + 'wireplumber-module-logind', + [ + 'module-logind.c', + ], + c_args : [common_c_args, '-DG_LOG_DOMAIN="m-logind"'], + install : true, + install_dir : wireplumber_module_dir, + dependencies : [wp_dep, pipewire_dep, libsystemd_dep], + ) +endif diff --git a/modules/module-logind.c b/modules/module-logind.c new file mode 100644 index 00000000..57e0c236 --- /dev/null +++ b/modules/module-logind.c @@ -0,0 +1,142 @@ +/* WirePlumber + * + * Copyright © 2021 Collabora Ltd. + * @author George Kiagiadakis + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include + +#include +#include + +#define NAME "logind" + +struct _WpLogind +{ + WpPlugin parent; + sd_login_monitor *monitor; + GSource *source; + char *state; +}; + +enum { + ACTION_GET_STATE, + SIGNAL_STATE_CHANGED, + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = {0}; + +G_DECLARE_FINAL_TYPE (WpLogind, wp_logind, WP, LOGIND, WpPlugin) +G_DEFINE_TYPE (WpLogind, wp_logind, WP_TYPE_PLUGIN) + +static void +wp_logind_init (WpLogind * self) +{ +} + +static gchar * +wp_logind_get_state (WpLogind *self) +{ + return g_strdup (self->state); +} + +static gboolean +wp_logind_source_ready (gint fd, GIOCondition condition, gpointer user_data) +{ + WpLogind *self = WP_LOGIND (user_data); + sd_login_monitor_flush (self->monitor); + { + char *state = NULL; + sd_uid_get_state (getuid(), &state); + if (g_strcmp0 (state, self->state) != 0) { + char *tmp = state; + state = self->state; + self->state = tmp; + g_signal_emit (self, signals[SIGNAL_STATE_CHANGED], 0, self->state); + } + free (state); + } + return G_SOURCE_CONTINUE; +} + +static void +wp_logind_enable (WpPlugin * plugin, WpTransition * transition) +{ + WpLogind *self = WP_LOGIND (plugin); + int res = 0; + + if ((res = sd_login_monitor_new (NULL, &self->monitor)) < 0) { + wp_transition_return_error (transition, g_error_new (G_IO_ERROR, + g_io_error_from_errno (-res), + "failed to start systemd logind monitor: %d (%s)", + res, spa_strerror(res))); + return; + } + + if ((res = sd_uid_get_state (getuid(), &self->state)) < 0) { + wp_transition_return_error (transition, g_error_new (G_IO_ERROR, + g_io_error_from_errno (-res), + "failed to get systemd login state: %d (%s)", + res, spa_strerror(res))); + g_clear_pointer (&self->monitor, sd_login_monitor_unref); + return; + } + + self->source = g_unix_fd_source_new ( + sd_login_monitor_get_fd (self->monitor), + sd_login_monitor_get_events (self->monitor)); + g_source_set_callback (self->source, G_SOURCE_FUNC (wp_logind_source_ready), + self, NULL); + + g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin)); + GMainContext *context = wp_core_get_g_main_context (core); + g_source_attach (self->source, context); + + wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0); +} + +static void +wp_logind_disable (WpPlugin * plugin) +{ + WpLogind *self = WP_LOGIND (plugin); + + g_clear_pointer (&self->state, free); + g_source_destroy (self->source); + g_clear_pointer (&self->source, g_source_unref); + g_clear_pointer (&self->monitor, sd_login_monitor_unref); +} + +static void +wp_logind_class_init (WpLogindClass * klass) +{ + WpPluginClass *plugin_class = (WpPluginClass *) klass; + + plugin_class->enable = wp_logind_enable; + plugin_class->disable = wp_logind_disable; + + signals[ACTION_GET_STATE] = g_signal_new_class_handler ( + "get-state", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + (GCallback) wp_logind_get_state, + NULL, NULL, NULL, G_TYPE_STRING, 0); + + signals[SIGNAL_STATE_CHANGED] = g_signal_new ( + "state-changed", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING); +} + +WP_PLUGIN_EXPORT gboolean +wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) +{ + wp_plugin_register (g_object_new (wp_logind_get_type (), + "name", NAME, + "core", core, + NULL)); + return TRUE; +} diff --git a/src/config/bluetooth.lua.d/30-bluez-monitor.lua b/src/config/bluetooth.lua.d/30-bluez-monitor.lua index 83027c4e..2240f57a 100644 --- a/src/config/bluetooth.lua.d/30-bluez-monitor.lua +++ b/src/config/bluetooth.lua.d/30-bluez-monitor.lua @@ -7,4 +7,6 @@ function bluez_monitor.enable() properties = bluez_monitor.properties, rules = bluez_monitor.rules, }) + + load_module("logind") end diff --git a/src/scripts/monitors/bluez.lua b/src/scripts/monitors/bluez.lua index 4066536b..172e013d 100644 --- a/src/scripts/monitors/bluez.lua +++ b/src/scripts/monitors/bluez.lua @@ -125,13 +125,39 @@ function createDevice(parent, id, type, factory, properties) end end -local monitor_props = config.properties or {} -monitor_props["api.bluez5.connection-info"] = true +function createMonitor() + local monitor_props = config.properties or {} + monitor_props["api.bluez5.connection-info"] = true -monitor = SpaDevice("api.bluez5.enum.dbus", monitor_props) -if monitor then - monitor:connect("create-object", createDevice) + local monitor = SpaDevice("api.bluez5.enum.dbus", monitor_props) + if monitor then + monitor:connect("create-object", createDevice) + else + Log.message("PipeWire's BlueZ SPA missing or broken. Bluetooth not supported.") + return nil + end monitor:activate(Feature.SpaDevice.ENABLED) -else - Log.message("PipeWire's BlueZ SPA missing or broken. Bluetooth not supported.") + + return monitor +end + +logind_plugin = Plugin.find("logind") +if logind_plugin then + -- if logind support is enabled, activate + -- the monitor only when the seat is active + function startStopMonitor(seat_state) + Log.info(logind_plugin, "Seat state changed: " .. seat_state) + + if seat_state == "active" then + monitor = createMonitor() + elseif monitor then + monitor:deactivate(Feature.SpaDevice.ENABLED) + monitor = nil + end + end + + logind_plugin:connect("state-changed", function(p, s) startStopMonitor(s) end) + startStopMonitor(logind_plugin:call("get-state")) +else + monitor = createMonitor() end diff --git a/src/systemd/meson.build b/src/systemd/meson.build index 27a11ab7..9f8bcb58 100644 --- a/src/systemd/meson.build +++ b/src/systemd/meson.build @@ -1,6 +1,3 @@ -systemd = dependency('systemd', required: get_option('systemd')) -summary({'systemd conf data': systemd.found()}, bool_yn: true) - if systemd.found() systemd_config = configuration_data() systemd_config.set('WP_BINARY', wireplumber_bin_dir / 'wireplumber')