diff --git a/modules/module-monitor.c b/modules/module-monitor.c index 0a7010e3d394b916a529afe64e63cbab4d2ef56a..a8da7e4b4e5bc2d66de35e7e914a6702f73fb81c 100644 --- a/modules/module-monitor.c +++ b/modules/module-monitor.c @@ -14,13 +14,17 @@ #include <spa/monitor/device.h> #include <spa/pod/builder.h> +#include "module-monitor/reservation-data.h" + G_DEFINE_QUARK (wp-module-monitor-id, id); G_DEFINE_QUARK (wp-module-monitor-children, children); +G_DEFINE_QUARK (wp-module-monitor-reservation, reservation); 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 { @@ -29,7 +33,8 @@ static const struct { } flag_names[] = { { FLAG_LOCAL_NODES, "local-nodes" }, { FLAG_USE_ADAPTER, "use-adapter" }, - { FLAG_ACTIVATE_DEVICES, "activate-devices" } + { FLAG_ACTIVATE_DEVICES, "activate-devices" }, + { FLAG_DBUS_RESERVATION, "dbus-reservation" } }; struct module_data @@ -259,6 +264,55 @@ find_child (GObject * parent, guint32 id, GList ** children, GList ** link, } } +static void +on_node_event_info (WpProxy * proxy, GParamSpec *spec, gpointer data) +{ + WpMonitorNodeReservationData *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_monitor_node_reservation_data_timeout_release (node_data, 3000); + break; + case PW_NODE_STATE_RUNNING: + /* Clear pending timeout if any and acquire reservation */ + wp_monitor_node_reservation_data_acquire (node_data); + break; + case PW_NODE_STATE_SUSPENDED: + break; + default: + break; + } +} + +static void +add_node_reservation_data (struct module_data * data, WpProxy *node, + WpProxy *device) +{ + WpMonitorDeviceReservationData *device_data = NULL; + g_autoptr (WpMonitorNodeReservationData) node_data = NULL; + + /* Only add reservation data on nodes whose device has reservation data */ + device_data = g_object_get_qdata (G_OBJECT (device), reservation_quark ()); + if (!device_data) + return; + + /* Create the node reservation data */ + node_data = wp_monitor_node_reservation_data_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 node reservation data on the node */ + g_object_set_qdata_full (G_OBJECT (node), reservation_quark (), + g_steal_pointer (&node_data), g_object_unref); +} + static void create_node (struct module_data * data, WpProxy * parent, GList ** children, guint id, const gchar * spa_factory, WpProperties * props, @@ -291,6 +345,8 @@ create_node (struct module_data * data, WpProxy * parent, GList ** children, g_object_set_qdata (G_OBJECT (node), id_quark (), GUINT_TO_POINTER (id)); *children = g_list_prepend (*children, node); + + add_node_reservation_data (data, node, parent); } static void @@ -304,7 +360,8 @@ device_created (GObject * proxy, GAsyncResult * res, gpointer user_data) return; } - if (data->flags & FLAG_ACTIVATE_DEVICES) { + if (data->flags & FLAG_ACTIVATE_DEVICES && + !(data->flags & FLAG_DBUS_RESERVATION)) { char buf[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); @@ -316,6 +373,38 @@ device_created (GObject * proxy, GAsyncResult * res, gpointer user_data) } } +static void +add_device_reservation_data (struct module_data * data, WpSpaDevice *device, + WpProperties *props) +{ + g_autoptr (WpCore) core = wp_proxy_get_core (WP_PROXY (device)); + const char *card_id = NULL; + const char *app_dev_name = NULL; + g_autoptr (WpMonitorDbusDeviceReservation) reservation = NULL; + g_autoptr (WpMonitorDeviceReservationData) device_data = NULL; + + if ((data->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_monitor_dbus_device_reservation_new (atoi(card_id), + "PipeWire", 10, app_dev_name); + + /* Create the device reservation data */ + device_data = wp_monitor_device_reservation_data_new (WP_PROXY (device), + reservation); + + /* Set the dbus device reservation data on the device */ + g_object_set_qdata_full (G_OBJECT (device), reservation_quark (), + g_steal_pointer (&device_data), g_object_unref); +} + static void create_device (struct module_data * data, WpProxy * parent, GList ** children, guint id, const gchar * spa_factory, WpProperties * props) @@ -338,6 +427,8 @@ create_device (struct module_data * data, WpProxy * parent, GList ** children, g_object_set_qdata (G_OBJECT (device), id_quark (), GUINT_TO_POINTER (id)); *children = g_list_prepend (*children, device); + + add_device_reservation_data (data, device, props); } static void diff --git a/src/config/wireplumber.conf b/src/config/wireplumber.conf index 7a9bd22ff54048ebdb910c44d8d46e7f5ee27aa6..3bb5a655799878fe7ddafa56356cf4734d76914a 100644 --- a/src/config/wireplumber.conf +++ b/src/config/wireplumber.conf @@ -22,7 +22,7 @@ load-module C libwireplumber-module-jack-device load-module C libwireplumber-module-monitor { "factory": <"api.alsa.enum.udev">, - "flags": <["use-adapter", "activate-devices"]> + "flags": <["use-adapter", "activate-devices", "dbus-reservation"]> } # load-module C libwireplumber-module-monitor {