From 9667cccb5a58f8298b9c63a6f78d31a392630947 Mon Sep 17 00:00:00 2001 From: Julian Bouzas Date: Mon, 25 May 2020 12:11:16 -0400 Subject: [PATCH] modules: move monitor device activation logic into a new device-activation module --- modules/meson.build | 21 +- modules/module-device-activation.c | 269 ++++++++++++++++++ .../dbus-device-reservation.c | 0 .../dbus-device-reservation.h | 0 .../org.freedesktop.ReserveDevice1.xml | 0 .../reserve-device.c | 0 .../reserve-device.h | 0 .../reserve-node.c | 0 .../reserve-node.h | 0 modules/module-monitor.c | 99 ------- src/config/wireplumber.conf | 6 +- tests/modules/dbus-device-reservation.c | 2 +- tests/modules/meson.build | 2 +- 13 files changed, 292 insertions(+), 107 deletions(-) create mode 100644 modules/module-device-activation.c rename modules/{module-monitor => module-device-activation}/dbus-device-reservation.c (100%) rename modules/{module-monitor => module-device-activation}/dbus-device-reservation.h (100%) rename modules/{module-monitor => module-device-activation}/org.freedesktop.ReserveDevice1.xml (100%) rename modules/{module-monitor => module-device-activation}/reserve-device.c (100%) rename modules/{module-monitor => module-device-activation}/reserve-device.h (100%) rename modules/{module-monitor => module-device-activation}/reserve-node.c (100%) rename modules/{module-monitor => module-device-activation}/reserve-node.h (100%) diff --git a/modules/meson.build b/modules/meson.build index 31bb587d..ab44aa07 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -15,7 +15,7 @@ shared_library( ) reserve_device_interface_src = gnome.gdbus_codegen('reserve-device-interface', - sources: 'module-monitor/org.freedesktop.ReserveDevice1.xml', + sources: 'module-device-activation/org.freedesktop.ReserveDevice1.xml', interface_prefix : 'org.freedesktop.ReserveDevice1.', namespace : 'Wp' ) @@ -24,14 +24,25 @@ shared_library( 'wireplumber-module-monitor', [ 'module-monitor.c', - 'module-monitor/reserve-node.c', - 'module-monitor/reserve-device.c', - 'module-monitor/dbus-device-reservation.c', - reserve_device_interface_src, ], c_args : [common_c_args, '-DG_LOG_DOMAIN="m-monitor"'], install : true, install_dir : wireplumber_module_dir, + dependencies : [wp_dep, pipewire_dep], +) + +shared_library( + 'wireplumber-module-device-activation', + [ + 'module-device-activation.c', + 'module-device-activation/reserve-node.c', + 'module-device-activation/reserve-device.c', + 'module-device-activation/dbus-device-reservation.c', + reserve_device_interface_src, + ], + c_args : [common_c_args, '-DG_LOG_DOMAIN="m-device-activation"'], + install : true, + install_dir : wireplumber_module_dir, dependencies : [wp_dep, pipewire_dep, giounix_dep], ) diff --git a/modules/module-device-activation.c b/modules/module-device-activation.c new file mode 100644 index 00000000..293ff2c1 --- /dev/null +++ b/modules/module-device-activation.c @@ -0,0 +1,269 @@ +/* WirePlumber + * + * Copyright © 2020 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +#include + +#include +#include + +#include "module-device-activation/reserve-device.h" +#include "module-device-activation/reserve-node.h" + +G_DEFINE_QUARK (wp-module-device-activation-reserve, reserve); + +enum { + PROP_0, + PROP_MODE, +}; + +struct _WpDeviceActivation +{ + WpPlugin parent; + + /* Props */ + gchar *mode; + + WpObjectManager *spa_devices_om; + WpObjectManager *nodes_om; +}; + +G_DECLARE_FINAL_TYPE (WpDeviceActivation, wp_device_activation, WP, + DEVICE_ACTIVATION, WpPlugin) +G_DEFINE_TYPE (WpDeviceActivation, wp_device_activation, WP_TYPE_PLUGIN) + +static void +on_node_state_changed (WpNode * node, WpNodeState old, WpNodeState curr, + WpReserveNode * node_data) +{ + g_return_if_fail (node_data); + + switch (curr) { + case WP_NODE_STATE_IDLE: + /* Release reservation after 3 seconds */ + wp_reserve_node_timeout_release (node_data, 3000); + break; + case WP_NODE_STATE_RUNNING: + /* Clear pending timeout if any and acquire reservation */ + wp_reserve_node_acquire (node_data); + break; + default: + break; + } +} + +static void +add_reserve_node_data (WpDeviceActivation * self, WpProxy *node, + WpProxy *device) +{ + WpReserveDevice *device_data = NULL; + g_autoptr (WpReserveNode) node_data = NULL; + + /* Only add reservation data on nodes whose device has reservation data */ + device_data = g_object_get_qdata (G_OBJECT (device), reserve_quark ()); + if (!device_data) + return; + + /* Create the node reservation data */ + node_data = wp_reserve_node_new (node, device_data); + + /* Set the reserve node data on the node */ + g_object_set_qdata_full (G_OBJECT (node), reserve_quark (), node_data, + g_object_unref); + + /* Handle the info signal */ + g_signal_connect_object (WP_NODE (node), "state-changed", + (GCallback) on_node_state_changed, node_data, 0); +} + +static void +on_node_added (WpObjectManager *om, WpProxy *proxy, gpointer d) +{ + WpDeviceActivation *self = WP_DEVICE_ACTIVATION (d); + const gchar *device_id = NULL; + g_autoptr (WpProxy) device = NULL; + + /* Get the device associated with the node */ + device_id = wp_proxy_get_property (proxy, PW_KEY_DEVICE_ID); + if (!device_id) + return; + device = wp_object_manager_lookup (self->spa_devices_om, WP_TYPE_SPA_DEVICE, + WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=i", atoi (device_id), NULL); + if (!device) { + wp_warning_object (self, "cannot find device for node reservation data"); + return; + } + + /* Add reserve data */ + add_reserve_node_data (self, proxy, device); +} + +static void +add_reserve_device_data (WpDeviceActivation * self, WpProxy *device, + gint card_id) +{ + g_autoptr (WpCore) core = wp_proxy_get_core (WP_PROXY (device)); + g_autoptr (WpProperties) props = wp_proxy_get_properties (device); + const char *app_dev_name = NULL; + g_autoptr (WpDbusDeviceReservation) reservation = NULL; + g_autoptr (WpReserveDevice) device_data = NULL; + + app_dev_name = wp_properties_get (props, SPA_KEY_API_ALSA_PATH); + + /* Create the dbus device reservation */ + reservation = wp_dbus_device_reservation_new (card_id, "PipeWire", 10, + app_dev_name); + + /* Create the reserve device data */ + device_data = wp_reserve_device_new (device, reservation); + + /* Set the reserve device data on the device */ + g_object_set_qdata_full (G_OBJECT (device), reserve_quark (), + g_steal_pointer (&device_data), g_object_unref); +} + +static void +on_device_added (WpObjectManager *om, WpProxy *proxy, gpointer d) +{ + WpDeviceActivation *self = WP_DEVICE_ACTIVATION (d); + const gchar *card_id = NULL; + + /* TODO: for now we only activate devices with the ALSA Card property set. + * However, we eventually need to handle Video and MIDI devices too */ + card_id = wp_proxy_get_property (proxy, SPA_KEY_API_ALSA_CARD); + if (!card_id) + return; + + /* Depending on the mode, activate or let dbus activate the devices */ + if (self->mode && g_strcmp0 (self->mode, "dbus") == 0) { + add_reserve_device_data (self, proxy, atoi (card_id)); + } else { + g_autoptr (WpSpaPod) profile = wp_spa_pod_new_object ( + "Profile", "Profile", + "index", "i", 1, + NULL); + wp_proxy_set_param (proxy, "Profile", profile); + } +} + +static void +wp_device_activation_activate (WpPlugin * plugin) +{ + WpDeviceActivation *self = WP_DEVICE_ACTIVATION (plugin); + g_autoptr (WpCore) core = wp_plugin_get_core (WP_PLUGIN (self)); + + /* Create the devices object manager and handle the device added signal */ + self->spa_devices_om = wp_object_manager_new (); + wp_object_manager_add_interest (self->spa_devices_om, WP_TYPE_SPA_DEVICE, + NULL); + wp_object_manager_request_proxy_features (self->spa_devices_om, + WP_TYPE_SPA_DEVICE, WP_PROXY_FEATURE_BOUND); + g_signal_connect_object (self->spa_devices_om, "object-added", + G_CALLBACK (on_device_added), self, 0); + wp_core_install_object_manager (core, self->spa_devices_om); + + /* Create the nodes object manager and handle the node added signal */ + self->nodes_om = wp_object_manager_new (); + wp_object_manager_add_interest (self->nodes_om, WP_TYPE_NODE, NULL); + wp_object_manager_request_proxy_features (self->nodes_om, WP_TYPE_NODE, + WP_PROXY_FEATURES_STANDARD); + g_signal_connect_object (self->nodes_om, "object-added", + G_CALLBACK (on_node_added), self, 0); + wp_core_install_object_manager (core, self->nodes_om); +} + +static void +wp_device_activation_deactivate (WpPlugin * plugin) +{ + WpDeviceActivation *self = WP_DEVICE_ACTIVATION (plugin); + + g_clear_object (&self->nodes_om); + g_clear_object (&self->spa_devices_om); +} + +static void +wp_monitor_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + WpDeviceActivation *self = WP_DEVICE_ACTIVATION (object); + + switch (property_id) { + case PROP_MODE: + g_clear_pointer (&self->mode, g_free); + self->mode = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +wp_monitor_get_property (GObject * object, guint property_id, GValue * value, + GParamSpec * pspec) +{ + WpDeviceActivation *self = WP_DEVICE_ACTIVATION (object); + + switch (property_id) { + case PROP_MODE: + g_value_set_string (value, self->mode); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +wp_monitor_finalize (GObject * object) +{ + WpDeviceActivation *self = WP_DEVICE_ACTIVATION (object); + + g_clear_pointer (&self->mode, g_free); + + G_OBJECT_CLASS (wp_device_activation_parent_class)->finalize (object); +} + +static void +wp_device_activation_init (WpDeviceActivation * self) +{ +} + +static void +wp_device_activation_class_init (WpDeviceActivationClass * klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + WpPluginClass *plugin_class = (WpPluginClass *) klass; + + object_class->finalize = wp_monitor_finalize; + object_class->set_property = wp_monitor_set_property; + object_class->get_property = wp_monitor_get_property; + + plugin_class->activate = wp_device_activation_activate; + plugin_class->deactivate = wp_device_activation_deactivate; + + /* Properties */ + g_object_class_install_property (object_class, PROP_MODE, + g_param_spec_string ("mode", "mode", + "The mode to activate devices", NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); +} + + +WP_PLUGIN_EXPORT void +wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args) +{ + const gchar *mode = NULL; + + /* Get the mode */ + g_variant_lookup (args, "mode", "s", &mode); + + wp_plugin_register (g_object_new (wp_device_activation_get_type (), + "module", module, + "mode", mode, + NULL)); +} diff --git a/modules/module-monitor/dbus-device-reservation.c b/modules/module-device-activation/dbus-device-reservation.c similarity index 100% rename from modules/module-monitor/dbus-device-reservation.c rename to modules/module-device-activation/dbus-device-reservation.c diff --git a/modules/module-monitor/dbus-device-reservation.h b/modules/module-device-activation/dbus-device-reservation.h similarity index 100% rename from modules/module-monitor/dbus-device-reservation.h rename to modules/module-device-activation/dbus-device-reservation.h diff --git a/modules/module-monitor/org.freedesktop.ReserveDevice1.xml b/modules/module-device-activation/org.freedesktop.ReserveDevice1.xml similarity index 100% rename from modules/module-monitor/org.freedesktop.ReserveDevice1.xml rename to modules/module-device-activation/org.freedesktop.ReserveDevice1.xml diff --git a/modules/module-monitor/reserve-device.c b/modules/module-device-activation/reserve-device.c similarity index 100% rename from modules/module-monitor/reserve-device.c rename to modules/module-device-activation/reserve-device.c diff --git a/modules/module-monitor/reserve-device.h b/modules/module-device-activation/reserve-device.h similarity index 100% rename from modules/module-monitor/reserve-device.h rename to modules/module-device-activation/reserve-device.h diff --git a/modules/module-monitor/reserve-node.c b/modules/module-device-activation/reserve-node.c similarity index 100% rename from modules/module-monitor/reserve-node.c rename to modules/module-device-activation/reserve-node.c diff --git a/modules/module-monitor/reserve-node.h b/modules/module-device-activation/reserve-node.h similarity index 100% rename from modules/module-monitor/reserve-node.h rename to modules/module-device-activation/reserve-node.h diff --git a/modules/module-monitor.c b/modules/module-monitor.c index 96039ce3..3e1efb02 100644 --- a/modules/module-monitor.c +++ b/modules/module-monitor.c @@ -14,18 +14,12 @@ #include #include -#include "module-monitor/reserve-device.h" -#include "module-monitor/reserve-node.h" - G_DEFINE_QUARK (wp-module-monitor-id, id); G_DEFINE_QUARK (wp-module-monitor-children, children); -G_DEFINE_QUARK (wp-module-monitor-data, data); typedef enum { FLAG_LOCAL_NODES = (1 << 0), FLAG_USE_ADAPTER = (1 << 1), - FLAG_ACTIVATE_DEVICES = (1 << 2), - FLAG_DBUS_RESERVATION = (1 << 3), } MonitorFlags; static const struct { @@ -34,8 +28,6 @@ static const struct { } flag_names[] = { { FLAG_LOCAL_NODES, "local-nodes" }, { FLAG_USE_ADAPTER, "use-adapter" }, - { FLAG_ACTIVATE_DEVICES, "activate-devices" }, - { FLAG_DBUS_RESERVATION, "dbus-reservation" } }; enum { @@ -280,54 +272,6 @@ find_child (GObject * parent, guint32 id, GList ** children, GList ** link, } } -static void -on_node_event_info (WpProxy * proxy, GParamSpec *spec, gpointer data) -{ - WpReserveNode *node_data = data; - const struct pw_node_info *info = wp_proxy_get_info (proxy); - - g_return_if_fail (node_data); - - /* handle the different states */ - switch (info->state) { - case PW_NODE_STATE_IDLE: - /* Release reservation after 3 seconds */ - wp_reserve_node_timeout_release (node_data, 3000); - break; - case PW_NODE_STATE_RUNNING: - /* Clear pending timeout if any and acquire reservation */ - wp_reserve_node_acquire (node_data); - break; - case PW_NODE_STATE_SUSPENDED: - break; - default: - break; - } -} - -static void -add_reserve_node_data (WpMonitor * self, WpProxy *node, WpProxy *device) -{ - WpReserveDevice *device_data = NULL; - g_autoptr (WpReserveNode) node_data = NULL; - - /* Only add reservation data on nodes whose device has reservation data */ - device_data = g_object_get_qdata (G_OBJECT (device), data_quark ()); - if (!device_data) - return; - - /* Create the node reservation data */ - node_data = wp_reserve_node_new (node, device_data); - - /* Handle the info signal */ - g_signal_connect_object (WP_NODE (node), "notify::info", - (GCallback) on_node_event_info, node_data, 0); - - /* Set the reserve node data on the node */ - g_object_set_qdata_full (G_OBJECT (node), data_quark (), - g_steal_pointer (&node_data), g_object_unref); -} - static void create_node (WpMonitor * self, WpProxy * parent, GList ** children, guint id, const gchar * spa_factory, WpProperties * props, @@ -366,39 +310,6 @@ create_node (WpMonitor * self, WpProxy * parent, GList ** children, g_object_set_qdata (G_OBJECT (node), id_quark (), GUINT_TO_POINTER (id)); *children = g_list_prepend (*children, node); - - add_reserve_node_data (self, node, parent); -} - -static void -add_reserve_device_data (WpMonitor * self, WpProxy *device) -{ - g_autoptr (WpCore) core = wp_proxy_get_core (WP_PROXY (device)); - g_autoptr (WpProperties) props = wp_proxy_get_properties (device); - const char *card_id = NULL; - const char *app_dev_name = NULL; - g_autoptr (WpDbusDeviceReservation) reservation = NULL; - g_autoptr (WpReserveDevice) device_data = NULL; - - if ((self->flags & FLAG_DBUS_RESERVATION) == 0) - return; - - card_id = wp_properties_get (props, SPA_KEY_API_ALSA_CARD); - if (!card_id) - return; - - app_dev_name = wp_properties_get (props, SPA_KEY_API_ALSA_PATH); - - /* Create the dbus device reservation */ - reservation = wp_dbus_device_reservation_new (atoi(card_id), - "PipeWire", 10, app_dev_name); - - /* Create the reserve device data */ - device_data = wp_reserve_device_new (device, reservation); - - /* Set the reserve device data on the device */ - g_object_set_qdata_full (G_OBJECT (device), data_quark (), - g_steal_pointer (&device_data), g_object_unref); } static void @@ -411,16 +322,6 @@ device_created (GObject * proxy, GAsyncResult * res, gpointer user_data) wp_warning_object (self, "%s", error->message); return; } - - if (self->flags & FLAG_DBUS_RESERVATION) { - add_reserve_device_data (self, WP_PROXY (proxy)); - } else if (self->flags & FLAG_ACTIVATE_DEVICES) { - g_autoptr (WpSpaPod) profile = wp_spa_pod_new_object ( - "Profile", "Profile", - "index", "i", 1, - NULL); - wp_proxy_set_param (WP_PROXY (proxy), "Profile", profile); - } } static void diff --git a/src/config/wireplumber.conf b/src/config/wireplumber.conf index 4876f5b0..d354da00 100644 --- a/src/config/wireplumber.conf +++ b/src/config/wireplumber.conf @@ -21,7 +21,7 @@ load-module C libwireplumber-module-jack-device load-module C libwireplumber-module-monitor { "factory": <"api.alsa.enum.udev">, - "flags": <["use-adapter", "activate-devices", "dbus-reservation"]> + "flags": <["use-adapter"]> } # load-module C libwireplumber-module-monitor { @@ -33,6 +33,10 @@ load-module C libwireplumber-module-monitor { "factory": <"api.v4l2.enum.udev"> } +load-module C libwireplumber-module-device-activation { + "mode": <"dbus"> +} + load-module C libwireplumber-module-node-suspension load-module C libwireplumber-module-session-settings diff --git a/tests/modules/dbus-device-reservation.c b/tests/modules/dbus-device-reservation.c index a75a80a4..db523204 100644 --- a/tests/modules/dbus-device-reservation.c +++ b/tests/modules/dbus-device-reservation.c @@ -9,7 +9,7 @@ #include #include -#include "../../modules/module-monitor/dbus-device-reservation.h" +#include "../../modules/module-device-activation/dbus-device-reservation.h" typedef struct { GTestDBus *dbus_test; diff --git a/tests/modules/meson.build b/tests/modules/meson.build index cfc78b6f..b1360c25 100644 --- a/tests/modules/meson.build +++ b/tests/modules/meson.build @@ -55,7 +55,7 @@ test( executable('test-dbus-device-reservation', [ 'dbus-device-reservation.c', - '../../modules/module-monitor/dbus-device-reservation.c', + '../../modules/module-device-activation/dbus-device-reservation.c', reserve_device_interface_src, ], dependencies: common_deps + [giounix_dep], c_args: common_args),