mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-08 17:28:38 +02:00
modules: move monitor device activation logic into a new device-activation module
This commit is contained in:
parent
5a9cb7688a
commit
9667cccb5a
13 changed files with 292 additions and 107 deletions
|
|
@ -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],
|
||||
)
|
||||
|
||||
|
|
|
|||
269
modules/module-device-activation.c
Normal file
269
modules/module-device-activation.c
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2020 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <spa/utils/keys.h>
|
||||
|
||||
#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));
|
||||
}
|
||||
|
|
@ -14,18 +14,12 @@
|
|||
#include <spa/monitor/device.h>
|
||||
#include <spa/pod/builder.h>
|
||||
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#include <wp/wp.h>
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
#include "../../modules/module-monitor/dbus-device-reservation.h"
|
||||
#include "../../modules/module-device-activation/dbus-device-reservation.h"
|
||||
|
||||
typedef struct {
|
||||
GTestDBus *dbus_test;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue