mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-04-17 15:10:38 +02:00
modules: implement a new reserve-device module
This one offers API to interract on a lower level with the D-Bus reservation API and uses GDBus high level bindings only. Also, this one implements the full Acquire procedure, calling RequestRelease() on the peer and requesting the name again with REPLACE_EXISTING
This commit is contained in:
parent
bf71b73ae2
commit
ef908439c4
11 changed files with 1588 additions and 20 deletions
|
|
@ -14,12 +14,6 @@ shared_library(
|
|||
dependencies : [wp_dep, pipewire_dep],
|
||||
)
|
||||
|
||||
reserve_device_interface_src = gnome.gdbus_codegen('reserve-device-interface',
|
||||
sources: 'module-dbus-reservation/org.freedesktop.ReserveDevice1.xml',
|
||||
interface_prefix : 'org.freedesktop.ReserveDevice1.',
|
||||
namespace : 'Wp'
|
||||
)
|
||||
|
||||
shared_library(
|
||||
'wireplumber-module-metadata',
|
||||
[
|
||||
|
|
@ -42,20 +36,6 @@ shared_library(
|
|||
dependencies : [wp_dep, pipewire_dep],
|
||||
)
|
||||
|
||||
shared_library(
|
||||
'wireplumber-module-dbus-reservation',
|
||||
[
|
||||
'module-dbus-reservation.c',
|
||||
'module-dbus-reservation/reserve-device.c',
|
||||
'module-dbus-reservation/dbus-device-reservation.c',
|
||||
reserve_device_interface_src,
|
||||
],
|
||||
c_args : [common_c_args, '-DG_LOG_DOMAIN="m-dbus-reservation"'],
|
||||
install : true,
|
||||
install_dir : wireplumber_module_dir,
|
||||
dependencies : [wp_dep, pipewire_dep, giounix_dep],
|
||||
)
|
||||
|
||||
shared_library(
|
||||
'wireplumber-module-default-profile',
|
||||
[
|
||||
|
|
@ -143,6 +123,23 @@ shared_library(
|
|||
dependencies : [wp_dep, wptoml_dep, pipewire_dep],
|
||||
)
|
||||
|
||||
subdir('module-reserve-device')
|
||||
shared_library(
|
||||
'wireplumber-module-reserve-device',
|
||||
[
|
||||
'module-reserve-device/plugin.c',
|
||||
'module-reserve-device/reserve-device.c',
|
||||
'module-reserve-device/transitions.c',
|
||||
reserve_device_interface_src,
|
||||
reserve_device_enums,
|
||||
],
|
||||
c_args : [common_c_args, '-DG_LOG_DOMAIN="m-reserve-device"'],
|
||||
include_directories: reserve_device_includes,
|
||||
install : true,
|
||||
install_dir : wireplumber_module_dir,
|
||||
dependencies : [wp_dep, giounix_dep],
|
||||
)
|
||||
|
||||
shared_library(
|
||||
'wireplumber-module-si-adapter',
|
||||
[
|
||||
|
|
|
|||
11
modules/module-reserve-device/meson.build
Normal file
11
modules/module-reserve-device/meson.build
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
reserve_device_interface_src = gnome.gdbus_codegen('reserve-device-interface',
|
||||
sources: 'org.freedesktop.ReserveDevice1.xml',
|
||||
interface_prefix : 'org.freedesktop.ReserveDevice1.',
|
||||
namespace : 'Wp'
|
||||
)
|
||||
|
||||
reserve_device_enums = gnome.mkenums_simple('reserve-device-enums',
|
||||
sources: [ 'plugin.h', 'reserve-device.h' ],
|
||||
)
|
||||
|
||||
reserve_device_includes = include_directories('.')
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<node>
|
||||
<interface name="org.freedesktop.ReserveDevice1">
|
||||
<method name="RequestRelease">
|
||||
<arg name="priority" type="i" direction="in"/>
|
||||
<arg name="result" type="b" direction="out"/>
|
||||
</method>
|
||||
<property name="Priority" type="i" access="read"/>
|
||||
<property name="ApplicationName" type="s" access="read"/>
|
||||
<property name="ApplicationDeviceName" type="s" access="read"/>
|
||||
</interface>
|
||||
</node>
|
||||
277
modules/module-reserve-device/plugin.c
Normal file
277
modules/module-reserve-device/plugin.c
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2021 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "reserve-device.h"
|
||||
#include "reserve-device-enums.h"
|
||||
|
||||
G_DEFINE_TYPE (WpReserveDevicePlugin, wp_reserve_device_plugin, WP_TYPE_PLUGIN)
|
||||
|
||||
enum
|
||||
{
|
||||
ACTION_CREATE_RESERVATION,
|
||||
ACTION_DESTROY_RESERVATION,
|
||||
ACTION_GET_RESERVATION,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_STATE,
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
rd_unref (gpointer data)
|
||||
{
|
||||
WpReserveDevice *rd = data;
|
||||
g_signal_emit_by_name (rd, "release");
|
||||
g_object_unref (rd);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_plugin_init (WpReserveDevicePlugin * self)
|
||||
{
|
||||
self->cancellable = g_cancellable_new ();
|
||||
self->reserve_devices = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL, rd_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_plugin_finalize (GObject * object)
|
||||
{
|
||||
WpReserveDevicePlugin *self = WP_RESERVE_DEVICE_PLUGIN (object);
|
||||
|
||||
g_clear_pointer (&self->reserve_devices, g_hash_table_unref);
|
||||
g_clear_object (&self->cancellable);
|
||||
|
||||
G_OBJECT_CLASS (wp_reserve_device_plugin_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_plugin_disable (WpReserveDevicePlugin *self)
|
||||
{
|
||||
g_hash_table_remove_all (self->reserve_devices);
|
||||
g_clear_object (&self->manager);
|
||||
g_clear_object (&self->connection);
|
||||
|
||||
if (self->state != WP_DBUS_CONNECTION_STATE_CLOSED) {
|
||||
self->state = WP_DBUS_CONNECTION_STATE_CLOSED;
|
||||
g_object_notify (G_OBJECT (self), "state");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_connection_closed (GDBusConnection *connection,
|
||||
gboolean remote_peer_vanished, GError *error, gpointer data)
|
||||
{
|
||||
WpReserveDevicePlugin *self = WP_RESERVE_DEVICE_PLUGIN (data);
|
||||
wp_info_object (self, "D-Bus connection closed: %s", error->message);
|
||||
wp_reserve_device_plugin_disable (self);
|
||||
}
|
||||
|
||||
static void
|
||||
got_bus (GObject * obj, GAsyncResult * res, gpointer data)
|
||||
{
|
||||
WpReserveDevicePlugin *self = WP_RESERVE_DEVICE_PLUGIN (data);
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
self->connection = g_dbus_connection_new_for_address_finish (res, &error);
|
||||
if (!self->connection) {
|
||||
wp_message_object (self, "Failed to connect to session bus: %s",
|
||||
error->message);
|
||||
wp_reserve_device_plugin_disable (self);
|
||||
return;
|
||||
}
|
||||
|
||||
wp_debug_object (self, "Connected to bus");
|
||||
|
||||
g_signal_connect_object (self->connection, "closed",
|
||||
G_CALLBACK (on_connection_closed), self, 0);
|
||||
g_dbus_connection_set_exit_on_close (self->connection, FALSE);
|
||||
|
||||
self->manager = g_dbus_object_manager_server_new (FDO_RESERVE_DEVICE1_PATH);
|
||||
g_dbus_object_manager_server_set_connection (self->manager, self->connection);
|
||||
|
||||
self->state = WP_DBUS_CONNECTION_STATE_CONNECTED;
|
||||
g_object_notify (G_OBJECT (self), "state");
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_plugin_activate (WpPlugin * plugin)
|
||||
{
|
||||
WpReserveDevicePlugin *self = WP_RESERVE_DEVICE_PLUGIN (plugin);
|
||||
g_autoptr (GError) error = NULL;
|
||||
g_autofree gchar *address = NULL;
|
||||
|
||||
g_return_if_fail (self->state == WP_DBUS_CONNECTION_STATE_CLOSED);
|
||||
|
||||
address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
||||
if (!address) {
|
||||
wp_message_object (self, "Error acquiring session bus address: %s",
|
||||
error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
wp_debug_object (self, "Connecting to bus: %s", address);
|
||||
|
||||
self->state = WP_DBUS_CONNECTION_STATE_CONNECTING;
|
||||
g_object_notify (G_OBJECT (self), "state");
|
||||
|
||||
g_dbus_connection_new_for_address (address,
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
|
||||
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
|
||||
NULL, self->cancellable, got_bus, self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_plugin_deactivate (WpPlugin * plugin)
|
||||
{
|
||||
WpReserveDevicePlugin *self = WP_RESERVE_DEVICE_PLUGIN (plugin);
|
||||
|
||||
g_cancellable_cancel (self->cancellable);
|
||||
wp_reserve_device_plugin_disable (self);
|
||||
|
||||
g_clear_object (&self->cancellable);
|
||||
self->cancellable = g_cancellable_new ();
|
||||
}
|
||||
|
||||
static gpointer
|
||||
wp_reserve_device_plugin_create_reservation (WpReserveDevicePlugin *self,
|
||||
const gchar *name, const gchar *app_name, const gchar *app_dev_name,
|
||||
gint priority)
|
||||
{
|
||||
if (self->state != WP_DBUS_CONNECTION_STATE_CONNECTED) {
|
||||
wp_message_object (self, "not connected to D-Bus");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WpReserveDevice *rd = g_object_new (wp_reserve_device_get_type (),
|
||||
"plugin", self,
|
||||
"name", name,
|
||||
"application-name", app_name,
|
||||
"application-device-name", app_dev_name,
|
||||
"priority", priority,
|
||||
NULL);
|
||||
|
||||
/* use rd->name to avoid copying @name again */
|
||||
g_hash_table_insert (self->reserve_devices, rd->name, rd);
|
||||
|
||||
return g_object_ref (rd);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_plugin_destroy_reservation (WpReserveDevicePlugin *self,
|
||||
const gchar *name)
|
||||
{
|
||||
if (self->state != WP_DBUS_CONNECTION_STATE_CONNECTED) {
|
||||
wp_message_object (self, "not connected to D-Bus");
|
||||
return;
|
||||
}
|
||||
g_hash_table_remove (self->reserve_devices, name);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
wp_reserve_device_plugin_get_reservation (WpReserveDevicePlugin *self,
|
||||
const gchar *name)
|
||||
{
|
||||
if (self->state != WP_DBUS_CONNECTION_STATE_CONNECTED) {
|
||||
wp_message_object (self, "not connected to D-Bus");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WpReserveDevice *rd = g_hash_table_lookup (self->reserve_devices, name);
|
||||
return rd ? g_object_ref (rd) : NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_plugin_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpReserveDevicePlugin *self = WP_RESERVE_DEVICE_PLUGIN (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_STATE:
|
||||
g_value_set_enum (value, self->state);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_plugin_class_init (WpReserveDevicePluginClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
WpPluginClass *plugin_class = (WpPluginClass *) klass;
|
||||
|
||||
object_class->finalize = wp_reserve_device_plugin_finalize;
|
||||
object_class->get_property = wp_reserve_device_plugin_get_property;
|
||||
|
||||
plugin_class->activate = wp_reserve_device_plugin_activate;
|
||||
plugin_class->deactivate = wp_reserve_device_plugin_deactivate;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_STATE,
|
||||
g_param_spec_enum ("state", "state", "The state",
|
||||
WP_TYPE_DBUS_CONNECTION_STATE, WP_DBUS_CONNECTION_STATE_CLOSED,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* WpReserveDevicePlugin::create-reservation:
|
||||
* @name:
|
||||
* @app_name:
|
||||
* @app_dev_name:
|
||||
* @priority:
|
||||
*
|
||||
* Returns: (transfer full): the reservation object
|
||||
*/
|
||||
signals[ACTION_CREATE_RESERVATION] = g_signal_new_class_handler (
|
||||
"create-reservation", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
(GCallback) wp_reserve_device_plugin_create_reservation,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_OBJECT, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
|
||||
|
||||
/**
|
||||
* WpReserveDevicePlugin::destroy-reservation:
|
||||
* @name:
|
||||
*
|
||||
*/
|
||||
signals[ACTION_DESTROY_RESERVATION] = g_signal_new_class_handler (
|
||||
"destroy-reservation", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
(GCallback) wp_reserve_device_plugin_destroy_reservation,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, G_TYPE_STRING);
|
||||
|
||||
/**
|
||||
* WpReserveDevicePlugin::get-reservation:
|
||||
* @name:
|
||||
*
|
||||
* Returns: (transfer full): the reservation object
|
||||
*/
|
||||
signals[ACTION_GET_RESERVATION] = g_signal_new_class_handler (
|
||||
"get-reservation", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
(GCallback) wp_reserve_device_plugin_get_reservation,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_OBJECT, 1, G_TYPE_STRING);
|
||||
|
||||
}
|
||||
|
||||
WP_PLUGIN_EXPORT void
|
||||
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
||||
{
|
||||
wp_plugin_register (g_object_new (wp_reserve_device_plugin_get_type (),
|
||||
"name", "reserve-device",
|
||||
"module", module,
|
||||
NULL));
|
||||
}
|
||||
42
modules/module-reserve-device/plugin.h
Normal file
42
modules/module-reserve-device/plugin.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2021 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __WIREPLUMBER_RESERVE_DEVICE_PLUGIN_H__
|
||||
#define __WIREPLUMBER_RESERVE_DEVICE_PLUGIN_H__
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FDO_RESERVE_DEVICE1_SERVICE "org.freedesktop.ReserveDevice1"
|
||||
#define FDO_RESERVE_DEVICE1_PATH "/org/freedesktop/ReserveDevice1"
|
||||
|
||||
typedef enum {
|
||||
WP_DBUS_CONNECTION_STATE_CLOSED = 0,
|
||||
WP_DBUS_CONNECTION_STATE_CONNECTING,
|
||||
WP_DBUS_CONNECTION_STATE_CONNECTED,
|
||||
} WpDBusConnectionState;
|
||||
|
||||
G_DECLARE_FINAL_TYPE (WpReserveDevicePlugin, wp_reserve_device_plugin,
|
||||
WP, RESERVE_DEVICE_PLUGIN, WpPlugin)
|
||||
|
||||
struct _WpReserveDevicePlugin
|
||||
{
|
||||
WpPlugin parent;
|
||||
|
||||
WpDBusConnectionState state;
|
||||
GHashTable *reserve_devices;
|
||||
|
||||
GCancellable *cancellable;
|
||||
GDBusConnection *connection;
|
||||
GDBusObjectManagerServer *manager;
|
||||
};
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
499
modules/module-reserve-device/reserve-device.c
Normal file
499
modules/module-reserve-device/reserve-device.c
Normal file
|
|
@ -0,0 +1,499 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2021 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "reserve-device.h"
|
||||
#include "plugin.h"
|
||||
#include "transitions.h"
|
||||
#include "reserve-device-interface.h"
|
||||
#include "reserve-device-enums.h"
|
||||
|
||||
G_DEFINE_TYPE (WpReserveDevice, wp_reserve_device, G_TYPE_OBJECT)
|
||||
|
||||
enum
|
||||
{
|
||||
ACTION_ACQUIRE,
|
||||
ACTION_RELEASE,
|
||||
ACTION_DENY_RELEASE,
|
||||
SIGNAL_RELEASE_REQUESTED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PLUGIN,
|
||||
PROP_NAME,
|
||||
PROP_APP_NAME,
|
||||
PROP_APP_DEV_NAME,
|
||||
PROP_PRIORITY,
|
||||
PROP_STATE,
|
||||
PROP_OWNER_APP_NAME,
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
wp_reserve_device_init (WpReserveDevice * self)
|
||||
{
|
||||
g_weak_ref_init (&self->plugin, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
on_got_proxy (GObject * src, GAsyncResult * res, WpReserveDevice *self)
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
g_autoptr (WpOrgFreedesktopReserveDevice1) proxy =
|
||||
wp_org_freedesktop_reserve_device1_proxy_new_finish (res, &error);
|
||||
if (!proxy) {
|
||||
wp_info_object (self, "%s: Could not get proxy of remote reservation: %s",
|
||||
self->name, error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
wp_debug_object (self, "%s owned by: %s", self->name,
|
||||
wp_org_freedesktop_reserve_device1_get_application_name (proxy));
|
||||
|
||||
/* ensure that we are still busy and there is no owner_app_name */
|
||||
if (self->state == WP_RESERVE_DEVICE_STATE_BUSY && !self->owner_app_name) {
|
||||
self->owner_app_name =
|
||||
wp_org_freedesktop_reserve_device1_dup_application_name (proxy);
|
||||
g_object_notify (G_OBJECT (self), "owner-application-name");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_owner_app_name (WpReserveDevice *self)
|
||||
{
|
||||
if (self->state == WP_RESERVE_DEVICE_STATE_BUSY && !self->owner_app_name) {
|
||||
/* create proxy */
|
||||
g_autoptr (WpReserveDevicePlugin) plugin = g_weak_ref_get (&self->plugin);
|
||||
wp_org_freedesktop_reserve_device1_proxy_new (plugin->connection,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
self->service_name, self->object_path, NULL,
|
||||
(GAsyncReadyCallback) on_got_proxy, self);
|
||||
}
|
||||
else if (self->state != WP_RESERVE_DEVICE_STATE_BUSY && self->owner_app_name) {
|
||||
g_clear_pointer (&self->owner_app_name, g_free);
|
||||
g_object_notify (G_OBJECT (self), "owner-application-name");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_appeared (GDBusConnection *connection, const gchar *name,
|
||||
const gchar *owner, gpointer user_data)
|
||||
{
|
||||
WpReserveDevice *self = WP_RESERVE_DEVICE (user_data);
|
||||
|
||||
if (!self->transition) {
|
||||
self->state = WP_RESERVE_DEVICE_STATE_BUSY;
|
||||
wp_info_object (self, "%s busy (by %s)", name, owner);
|
||||
g_object_notify (G_OBJECT (self), "state");
|
||||
update_owner_app_name (self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_vanished (GDBusConnection *connection, const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
WpReserveDevice *self = WP_RESERVE_DEVICE (user_data);
|
||||
|
||||
if (!self->transition) {
|
||||
self->state = WP_RESERVE_DEVICE_STATE_AVAILABLE;
|
||||
wp_info_object (self, "%s released", name);
|
||||
g_object_notify (G_OBJECT (self), "state");
|
||||
update_owner_app_name (self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_constructed (GObject * object)
|
||||
{
|
||||
WpReserveDevice *self = WP_RESERVE_DEVICE (object);
|
||||
g_autoptr (WpReserveDevicePlugin) plugin = g_weak_ref_get (&self->plugin);
|
||||
|
||||
self->service_name =
|
||||
g_strdup_printf (FDO_RESERVE_DEVICE1_SERVICE ".%s", self->name);
|
||||
self->object_path =
|
||||
g_strdup_printf (FDO_RESERVE_DEVICE1_PATH "/%s", self->name);
|
||||
|
||||
/* Watch for the name */
|
||||
self->watcher_id = g_bus_watch_name_on_connection (plugin->connection,
|
||||
self->service_name, G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
on_name_appeared, on_name_vanished, self, NULL);
|
||||
|
||||
G_OBJECT_CLASS (wp_reserve_device_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_finalize (GObject * object)
|
||||
{
|
||||
WpReserveDevice *self = WP_RESERVE_DEVICE (object);
|
||||
|
||||
if (self->watcher_id > 0)
|
||||
g_bus_unwatch_name (self->watcher_id);
|
||||
if (self->owner_id > 0)
|
||||
g_bus_unown_name (self->owner_id);
|
||||
|
||||
g_weak_ref_clear (&self->plugin);
|
||||
g_clear_pointer (&self->name, g_free);
|
||||
g_clear_pointer (&self->app_name, g_free);
|
||||
g_clear_pointer (&self->app_dev_name, g_free);
|
||||
g_clear_pointer (&self->service_name, g_free);
|
||||
g_clear_pointer (&self->object_path, g_free);
|
||||
|
||||
G_OBJECT_CLASS (wp_reserve_device_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
on_acquire_transition_done (GObject *rd, GAsyncResult *res, gpointer data)
|
||||
{
|
||||
WpReserveDevice *self = WP_RESERVE_DEVICE (data);
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
gboolean acquired = wp_reserve_device_acquire_transition_finish (res, &error);
|
||||
if (error) {
|
||||
wp_message_object (self, "%s: Acquire error: %s", self->name,
|
||||
error->message);
|
||||
}
|
||||
|
||||
self->state = acquired ?
|
||||
WP_RESERVE_DEVICE_STATE_ACQUIRED : WP_RESERVE_DEVICE_STATE_BUSY;
|
||||
self->transition = NULL;
|
||||
g_object_notify (G_OBJECT (self), "state");
|
||||
update_owner_app_name (self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_acquire (WpReserveDevice * self)
|
||||
{
|
||||
if (self->state == WP_RESERVE_DEVICE_STATE_ACQUIRED ||
|
||||
self->transition != NULL) {
|
||||
wp_debug_object (self, "%s: already acquired or operation in progress",
|
||||
self->name);
|
||||
return;
|
||||
}
|
||||
|
||||
g_autoptr (WpReserveDevicePlugin) plugin = g_weak_ref_get (&self->plugin);
|
||||
self->transition = wp_reserve_device_acquire_transition_new (self,
|
||||
plugin->cancellable, on_acquire_transition_done, self);
|
||||
wp_transition_advance (self->transition);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_release (WpReserveDevice * self)
|
||||
{
|
||||
if (self->state != WP_RESERVE_DEVICE_STATE_ACQUIRED) {
|
||||
wp_debug_object (self, "%s: not acquired", self->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* set state to AVAILABLE to ensure that on_name_lost()
|
||||
does not emit SIGNAL_REQUEST_RELEASE */
|
||||
/* on_name_vanished() will emit the state change */
|
||||
self->state = WP_RESERVE_DEVICE_STATE_AVAILABLE;
|
||||
wp_reserve_device_unown_name (self);
|
||||
|
||||
if (self->req_rel_invocation) {
|
||||
wp_org_freedesktop_reserve_device1_complete_request_release (NULL,
|
||||
self->req_rel_invocation, TRUE);
|
||||
self->req_rel_invocation = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_deny_release (WpReserveDevice * self, gboolean success)
|
||||
{
|
||||
if (self->req_rel_invocation) {
|
||||
wp_org_freedesktop_reserve_device1_complete_request_release (NULL,
|
||||
self->req_rel_invocation, FALSE);
|
||||
self->req_rel_invocation = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wp_reserve_device_handle_request_release (WpOrgFreedesktopReserveDevice1 *iface,
|
||||
GDBusMethodInvocation *invocation, gint priority, gpointer user_data)
|
||||
{
|
||||
WpReserveDevice *self = WP_RESERVE_DEVICE (user_data);
|
||||
|
||||
/* deny release if the priority is lower than ours */
|
||||
if (priority < self->priority) {
|
||||
wp_org_freedesktop_reserve_device1_complete_request_release (iface,
|
||||
g_object_ref (invocation), FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* else, request the release of the device from the implementation;
|
||||
if signal handlers are connected, assume the functionality is implemented,
|
||||
otherwise return FALSE to let the iface return UnknownMethod */
|
||||
if (g_signal_has_handler_pending (self,
|
||||
signals[SIGNAL_RELEASE_REQUESTED], 0, FALSE)) {
|
||||
self->req_rel_invocation = g_object_ref (invocation);
|
||||
g_signal_emit (self, signals[SIGNAL_RELEASE_REQUESTED], 0, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpReserveDevice *self = WP_RESERVE_DEVICE (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, self->name);
|
||||
break;
|
||||
case PROP_APP_NAME:
|
||||
g_value_set_string (value, self->app_name);
|
||||
break;
|
||||
case PROP_APP_DEV_NAME:
|
||||
g_value_set_string (value, self->app_dev_name);
|
||||
break;
|
||||
case PROP_PRIORITY:
|
||||
g_value_set_int (value, self->priority);
|
||||
break;
|
||||
case PROP_STATE:
|
||||
g_value_set_enum (value, self->state);
|
||||
break;
|
||||
case PROP_OWNER_APP_NAME:
|
||||
switch (self->state) {
|
||||
case WP_RESERVE_DEVICE_STATE_ACQUIRED:
|
||||
g_value_set_string (value, self->app_name);
|
||||
break;
|
||||
default:
|
||||
g_value_set_string (value, self->owner_app_name);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_set_property (GObject * object,
|
||||
guint property_id, const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpReserveDevice *self = WP_RESERVE_DEVICE (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_PLUGIN:
|
||||
g_weak_ref_set (&self->plugin, g_value_get_object (value));
|
||||
break;
|
||||
case PROP_NAME:
|
||||
g_clear_pointer (&self->name, g_free);
|
||||
self->name = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_APP_NAME:
|
||||
g_clear_pointer (&self->app_name, g_free);
|
||||
self->app_name = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_APP_DEV_NAME:
|
||||
g_clear_pointer (&self->app_dev_name, g_free);
|
||||
self->app_dev_name = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_PRIORITY:
|
||||
self->priority = g_value_get_int(value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_class_init (WpReserveDeviceClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
|
||||
object_class->constructed = wp_reserve_device_constructed;
|
||||
object_class->finalize = wp_reserve_device_finalize;
|
||||
object_class->get_property = wp_reserve_device_get_property;
|
||||
object_class->set_property = wp_reserve_device_set_property;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PLUGIN,
|
||||
g_param_spec_object ("plugin", "plugin",
|
||||
"The parent plugin instance", wp_reserve_device_plugin_get_type (),
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_NAME,
|
||||
g_param_spec_string ("name", "name",
|
||||
"The reservation name", NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_APP_NAME,
|
||||
g_param_spec_string ("application-name", "application-name",
|
||||
"The application name", NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_APP_DEV_NAME,
|
||||
g_param_spec_string ("application-device-name", "application-device-name",
|
||||
"The application device name", NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PRIORITY,
|
||||
g_param_spec_int ("priority", "priority",
|
||||
"The priority", G_MININT, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_STATE,
|
||||
g_param_spec_enum ("state", "state", "The state",
|
||||
WP_TYPE_RESERVE_DEVICE_STATE, WP_RESERVE_DEVICE_STATE_UNKNOWN,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_OWNER_APP_NAME,
|
||||
g_param_spec_string ("owner-application-name", "owner-application-name",
|
||||
"The owner application name", NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* WpReserveDevice::acquire:
|
||||
*
|
||||
*/
|
||||
signals[ACTION_ACQUIRE] = g_signal_new_class_handler (
|
||||
"acquire", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
(GCallback) wp_reserve_device_acquire,
|
||||
NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
|
||||
/**
|
||||
* WpReserveDevice::release:
|
||||
*
|
||||
*/
|
||||
signals[ACTION_RELEASE] = g_signal_new_class_handler (
|
||||
"release", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
(GCallback) wp_reserve_device_release,
|
||||
NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
|
||||
/**
|
||||
* WpReserveDevice::deny-release:
|
||||
*
|
||||
*/
|
||||
signals[ACTION_DENY_RELEASE] = g_signal_new_class_handler (
|
||||
"deny-release", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
(GCallback) wp_reserve_device_deny_release,
|
||||
NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
|
||||
/**
|
||||
* WpReserveDevice::release-requested:
|
||||
* @forced: %TRUE if the name was forcibly taken from us,
|
||||
* %FALSE if the `RequestRelease()` d-bus method was called
|
||||
*
|
||||
* Signaled when the device needs to be released. If @forced is %FALSE,
|
||||
* call #WpReserveDevice::release to release or #WpReserveDevice::deny-release
|
||||
* to refuse and return %FALSE from the `RequestRelease()` d-bus method
|
||||
*/
|
||||
signals[SIGNAL_RELEASE_REQUESTED] = g_signal_new (
|
||||
"release-requested", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
|
||||
}
|
||||
|
||||
void
|
||||
wp_reserve_device_export_object (WpReserveDevice *self)
|
||||
{
|
||||
g_autoptr (WpReserveDevicePlugin) plugin = g_weak_ref_get (&self->plugin);
|
||||
if (plugin) {
|
||||
g_autoptr (GDBusObjectSkeleton) skeleton =
|
||||
g_dbus_object_skeleton_new (self->object_path);
|
||||
g_autoptr (WpOrgFreedesktopReserveDevice1) iface =
|
||||
wp_org_freedesktop_reserve_device1_skeleton_new ();
|
||||
g_object_set (iface,
|
||||
"priority", self->priority,
|
||||
"application-name", self->app_name,
|
||||
"application-device-name", self->app_dev_name,
|
||||
NULL);
|
||||
g_signal_connect_object (iface, "handle-request-release",
|
||||
(GCallback) wp_reserve_device_handle_request_release, self, 0);
|
||||
g_dbus_object_skeleton_add_interface (skeleton,
|
||||
G_DBUS_INTERFACE_SKELETON (iface));
|
||||
g_dbus_object_manager_server_export (plugin->manager, skeleton);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wp_reserve_device_unexport_object (WpReserveDevice *self)
|
||||
{
|
||||
g_autoptr (WpReserveDevicePlugin) plugin = g_weak_ref_get (&self->plugin);
|
||||
if (plugin) {
|
||||
wp_debug_object (self, "unexport %s", self->object_path);
|
||||
g_dbus_object_manager_server_unexport (plugin->manager, self->object_path);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection, const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
WpReserveDevice *self = WP_RESERVE_DEVICE (user_data);
|
||||
|
||||
wp_debug_object (self, "%s acquired", name);
|
||||
|
||||
if (WP_IS_RESERVE_DEVICE_ACQUIRE_TRANSITION (self->transition)) {
|
||||
wp_reserve_device_acquire_transition_name_acquired (self->transition);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection, const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
WpReserveDevice *self = WP_RESERVE_DEVICE (user_data);
|
||||
|
||||
wp_debug_object (self, "%s lost", name);
|
||||
|
||||
if (WP_IS_RESERVE_DEVICE_ACQUIRE_TRANSITION (self->transition)) {
|
||||
wp_reserve_device_acquire_transition_name_lost (self->transition);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->state == WP_RESERVE_DEVICE_STATE_ACQUIRED) {
|
||||
/* Emit release signal with forced set to TRUE */
|
||||
g_signal_emit (self, signals[SIGNAL_RELEASE_REQUESTED], 0, TRUE);
|
||||
wp_reserve_device_unown_name (self);
|
||||
}
|
||||
|
||||
wp_reserve_device_unexport_object (self);
|
||||
}
|
||||
|
||||
void
|
||||
wp_reserve_device_own_name (WpReserveDevice * self, gboolean force)
|
||||
{
|
||||
g_return_if_fail (self->owner_id == 0);
|
||||
|
||||
g_autoptr (WpReserveDevicePlugin) plugin = g_weak_ref_get (&self->plugin);
|
||||
if (plugin) {
|
||||
GBusNameOwnerFlags flags = G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE;
|
||||
if (self->priority != G_MAXINT32)
|
||||
flags |= G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT;
|
||||
if (force)
|
||||
flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE;
|
||||
|
||||
wp_debug_object (self, "request ownership of %s", self->service_name);
|
||||
|
||||
self->owner_id = g_bus_own_name_on_connection (plugin->connection,
|
||||
self->service_name, flags, on_name_acquired, on_name_lost, self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wp_reserve_device_unown_name (WpReserveDevice * self)
|
||||
{
|
||||
if (self->owner_id) {
|
||||
wp_debug_object (self, "drop ownership of %s", self->service_name);
|
||||
g_bus_unown_name (self->owner_id);
|
||||
self->owner_id = 0;
|
||||
}
|
||||
}
|
||||
55
modules/module-reserve-device/reserve-device.h
Normal file
55
modules/module-reserve-device/reserve-device.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2021 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __WIREPLUMBER_RESERVE_DEVICE_H__
|
||||
#define __WIREPLUMBER_RESERVE_DEVICE_H__
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
WP_RESERVE_DEVICE_STATE_UNKNOWN = 0,
|
||||
WP_RESERVE_DEVICE_STATE_BUSY,
|
||||
WP_RESERVE_DEVICE_STATE_AVAILABLE,
|
||||
WP_RESERVE_DEVICE_STATE_ACQUIRED,
|
||||
} WpReserveDeviceState;
|
||||
|
||||
G_DECLARE_FINAL_TYPE (WpReserveDevice, wp_reserve_device,
|
||||
WP, RESERVE_DEVICE, GObject)
|
||||
|
||||
struct _WpReserveDevice
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
GWeakRef plugin;
|
||||
gchar *name;
|
||||
gchar *app_name;
|
||||
gchar *app_dev_name;
|
||||
gint priority;
|
||||
gchar *owner_app_name;
|
||||
|
||||
gchar *service_name;
|
||||
gchar *object_path;
|
||||
|
||||
WpTransition *transition;
|
||||
GDBusMethodInvocation *req_rel_invocation;
|
||||
WpReserveDeviceState state;
|
||||
guint watcher_id;
|
||||
guint owner_id;
|
||||
};
|
||||
|
||||
void wp_reserve_device_export_object (WpReserveDevice *self);
|
||||
void wp_reserve_device_unexport_object (WpReserveDevice *self);
|
||||
|
||||
void wp_reserve_device_own_name (WpReserveDevice * self, gboolean force);
|
||||
void wp_reserve_device_unown_name (WpReserveDevice * self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
266
modules/module-reserve-device/transitions.c
Normal file
266
modules/module-reserve-device/transitions.c
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2021 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "transitions.h"
|
||||
#include "plugin.h"
|
||||
#include "reserve-device.h"
|
||||
#include "reserve-device-interface.h"
|
||||
|
||||
struct _WpReserveDeviceAcquireTransition
|
||||
{
|
||||
WpTransition parent;
|
||||
gint owner_state;
|
||||
WpOrgFreedesktopReserveDevice1 *proxy;
|
||||
};
|
||||
|
||||
enum {
|
||||
OWNER_STATE_NONE = 0,
|
||||
OWNER_STATE_ACQUIRED,
|
||||
OWNER_STATE_LOST,
|
||||
};
|
||||
|
||||
enum {
|
||||
STEP_EXPORT_OBJECT = WP_TRANSITION_STEP_CUSTOM_START,
|
||||
STEP_ACQUIRE_NO_FORCE,
|
||||
STEP_GET_PROXY,
|
||||
STEP_REQUEST_RELEASE,
|
||||
STEP_ACQUIRE_WITH_FORCE,
|
||||
STEP_UNEXPORT_OBJECT,
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (WpReserveDeviceAcquireTransition,
|
||||
wp_reserve_device_acquire_transition, WP_TYPE_TRANSITION)
|
||||
|
||||
static void
|
||||
wp_reserve_device_acquire_transition_init (
|
||||
WpReserveDeviceAcquireTransition * self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_acquire_transition_finalize (GObject * object)
|
||||
{
|
||||
WpReserveDeviceAcquireTransition *self =
|
||||
WP_RESERVE_DEVICE_ACQUIRE_TRANSITION (object);
|
||||
|
||||
g_clear_object (&self->proxy);
|
||||
|
||||
G_OBJECT_CLASS (wp_reserve_device_acquire_transition_parent_class)->
|
||||
finalize (object);
|
||||
}
|
||||
|
||||
static guint
|
||||
wp_reserve_device_acquire_transition_get_next_step (
|
||||
WpTransition * transition, guint step)
|
||||
{
|
||||
WpReserveDeviceAcquireTransition *self =
|
||||
WP_RESERVE_DEVICE_ACQUIRE_TRANSITION (transition);
|
||||
|
||||
switch (step) {
|
||||
case WP_TRANSITION_STEP_NONE:
|
||||
return STEP_EXPORT_OBJECT;
|
||||
|
||||
case STEP_EXPORT_OBJECT:
|
||||
return STEP_ACQUIRE_NO_FORCE;
|
||||
|
||||
case STEP_ACQUIRE_NO_FORCE:
|
||||
switch (self->owner_state) {
|
||||
case OWNER_STATE_ACQUIRED:
|
||||
return WP_TRANSITION_STEP_NONE;
|
||||
|
||||
case OWNER_STATE_LOST:
|
||||
return STEP_GET_PROXY;
|
||||
|
||||
default:
|
||||
return WP_TRANSITION_STEP_ERROR;
|
||||
}
|
||||
|
||||
case STEP_GET_PROXY:
|
||||
if (self->proxy)
|
||||
return STEP_REQUEST_RELEASE;
|
||||
else
|
||||
return STEP_ACQUIRE_WITH_FORCE;
|
||||
|
||||
case STEP_REQUEST_RELEASE:
|
||||
switch (self->owner_state) {
|
||||
case OWNER_STATE_ACQUIRED:
|
||||
return STEP_ACQUIRE_WITH_FORCE;
|
||||
|
||||
case OWNER_STATE_LOST:
|
||||
return STEP_UNEXPORT_OBJECT;
|
||||
|
||||
default:
|
||||
return WP_TRANSITION_STEP_ERROR;
|
||||
}
|
||||
|
||||
case STEP_ACQUIRE_WITH_FORCE:
|
||||
return WP_TRANSITION_STEP_NONE;
|
||||
|
||||
case STEP_UNEXPORT_OBJECT:
|
||||
return WP_TRANSITION_STEP_NONE;
|
||||
|
||||
default:
|
||||
return WP_TRANSITION_STEP_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_got_proxy (GObject * src, GAsyncResult * res, WpTransition * transition)
|
||||
{
|
||||
WpReserveDeviceAcquireTransition *self =
|
||||
WP_RESERVE_DEVICE_ACQUIRE_TRANSITION (transition);
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
self->proxy =
|
||||
wp_org_freedesktop_reserve_device1_proxy_new_finish (res, &error);
|
||||
if (!self->proxy) {
|
||||
WpReserveDevice *rd = wp_transition_get_source_object (transition);
|
||||
wp_info_object (rd, "%s: Could not get proxy of remote reservation: %s",
|
||||
rd->name, error->message);
|
||||
}
|
||||
|
||||
wp_transition_advance (transition);
|
||||
}
|
||||
|
||||
static void
|
||||
on_request_release_done (GObject * src, GAsyncResult * res,
|
||||
WpTransition * transition)
|
||||
{
|
||||
WpReserveDeviceAcquireTransition *self =
|
||||
WP_RESERVE_DEVICE_ACQUIRE_TRANSITION (transition);
|
||||
g_autoptr (GError) error = NULL;
|
||||
gboolean released = FALSE;
|
||||
|
||||
if (!wp_org_freedesktop_reserve_device1_call_request_release_finish (
|
||||
self->proxy, &released, res, &error)) {
|
||||
WpReserveDevice *rd = wp_transition_get_source_object (transition);
|
||||
wp_info_object (rd, "%s: Could not call RequestRelease: %s",
|
||||
rd->name, error->message);
|
||||
}
|
||||
|
||||
self->owner_state = released ? OWNER_STATE_ACQUIRED : OWNER_STATE_LOST;
|
||||
wp_transition_advance (transition);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_acquire_transition_execute_step (
|
||||
WpTransition * transition, guint step)
|
||||
{
|
||||
WpReserveDeviceAcquireTransition *self =
|
||||
WP_RESERVE_DEVICE_ACQUIRE_TRANSITION (transition);
|
||||
WpReserveDevice *rd = wp_transition_get_source_object (transition);
|
||||
g_autoptr (WpReserveDevicePlugin) plugin = g_weak_ref_get (&rd->plugin);
|
||||
|
||||
if (G_UNLIKELY (!plugin && step != WP_TRANSITION_STEP_ERROR)) {
|
||||
wp_transition_return_error (transition, g_error_new (
|
||||
WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
|
||||
"plugin destroyed while Acquire was in progress"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (step) {
|
||||
case STEP_EXPORT_OBJECT:
|
||||
wp_reserve_device_export_object (rd);
|
||||
wp_transition_advance (transition);
|
||||
break;
|
||||
|
||||
case STEP_ACQUIRE_NO_FORCE:
|
||||
wp_reserve_device_own_name (rd, FALSE);
|
||||
break;
|
||||
|
||||
case STEP_GET_PROXY:
|
||||
wp_org_freedesktop_reserve_device1_proxy_new (plugin->connection,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
rd->service_name, rd->object_path, NULL,
|
||||
(GAsyncReadyCallback) on_got_proxy, self);
|
||||
break;
|
||||
|
||||
case STEP_REQUEST_RELEASE:
|
||||
self->owner_state = OWNER_STATE_NONE;
|
||||
wp_org_freedesktop_reserve_device1_call_request_release (
|
||||
self->proxy, rd->priority, NULL,
|
||||
(GAsyncReadyCallback) on_request_release_done, self);
|
||||
break;
|
||||
|
||||
case STEP_ACQUIRE_WITH_FORCE:
|
||||
wp_reserve_device_unown_name (rd);
|
||||
self->owner_state = OWNER_STATE_NONE;
|
||||
wp_reserve_device_own_name (rd, TRUE);
|
||||
break;
|
||||
|
||||
case STEP_UNEXPORT_OBJECT:
|
||||
wp_reserve_device_unown_name (rd);
|
||||
wp_reserve_device_unexport_object (rd);
|
||||
wp_transition_advance (transition);
|
||||
break;
|
||||
|
||||
case WP_TRANSITION_STEP_ERROR:
|
||||
wp_reserve_device_unown_name (rd);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_return_if_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_reserve_device_acquire_transition_class_init (
|
||||
WpReserveDeviceAcquireTransitionClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
WpTransitionClass *transition_class = (WpTransitionClass *) klass;
|
||||
|
||||
object_class->finalize =
|
||||
wp_reserve_device_acquire_transition_finalize;
|
||||
|
||||
transition_class->get_next_step =
|
||||
wp_reserve_device_acquire_transition_get_next_step;
|
||||
transition_class->execute_step =
|
||||
wp_reserve_device_acquire_transition_execute_step;
|
||||
}
|
||||
|
||||
WpTransition *
|
||||
wp_reserve_device_acquire_transition_new (WpReserveDevice *rd,
|
||||
GCancellable * cancellable, GAsyncReadyCallback callback,
|
||||
gpointer callback_data)
|
||||
{
|
||||
return wp_transition_new (wp_reserve_device_acquire_transition_get_type (),
|
||||
rd, cancellable, callback, callback_data);
|
||||
}
|
||||
|
||||
void
|
||||
wp_reserve_device_acquire_transition_name_acquired (WpTransition * tr)
|
||||
{
|
||||
WpReserveDeviceAcquireTransition *self =
|
||||
WP_RESERVE_DEVICE_ACQUIRE_TRANSITION (tr);
|
||||
self->owner_state = OWNER_STATE_ACQUIRED;
|
||||
wp_transition_advance (tr);
|
||||
}
|
||||
|
||||
void
|
||||
wp_reserve_device_acquire_transition_name_lost (WpTransition * tr)
|
||||
{
|
||||
WpReserveDeviceAcquireTransition *self =
|
||||
WP_RESERVE_DEVICE_ACQUIRE_TRANSITION (tr);
|
||||
self->owner_state = OWNER_STATE_LOST;
|
||||
wp_transition_advance (tr);
|
||||
}
|
||||
|
||||
gboolean
|
||||
wp_reserve_device_acquire_transition_finish (GAsyncResult * res,
|
||||
GError ** error)
|
||||
{
|
||||
if (!wp_transition_finish (res, error))
|
||||
return FALSE;
|
||||
|
||||
WpReserveDeviceAcquireTransition *self =
|
||||
WP_RESERVE_DEVICE_ACQUIRE_TRANSITION (res);
|
||||
return (self->owner_state == OWNER_STATE_ACQUIRED) ? TRUE : FALSE;
|
||||
}
|
||||
32
modules/module-reserve-device/transitions.h
Normal file
32
modules/module-reserve-device/transitions.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2021 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __WIREPLUMBER_RESERVE_DEVICE_TRANSITIONS_H__
|
||||
#define __WIREPLUMBER_RESERVE_DEVICE_TRANSITIONS_H__
|
||||
|
||||
#include "reserve-device.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_DECLARE_FINAL_TYPE (WpReserveDeviceAcquireTransition,
|
||||
wp_reserve_device_acquire_transition,
|
||||
WP, RESERVE_DEVICE_ACQUIRE_TRANSITION, WpTransition)
|
||||
|
||||
WpTransition * wp_reserve_device_acquire_transition_new (WpReserveDevice *rd,
|
||||
GCancellable * cancellable, GAsyncReadyCallback callback,
|
||||
gpointer callback_data);
|
||||
|
||||
void wp_reserve_device_acquire_transition_name_acquired (WpTransition * tr);
|
||||
void wp_reserve_device_acquire_transition_name_lost (WpTransition * tr);
|
||||
|
||||
gboolean wp_reserve_device_acquire_transition_finish (GAsyncResult * res,
|
||||
GError ** error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
@ -63,6 +63,13 @@ test(
|
|||
workdir : meson.current_source_dir(),
|
||||
)
|
||||
|
||||
test(
|
||||
'test-reserve-device',
|
||||
executable('test-reserve-device', 'reserve-device.c',
|
||||
dependencies: common_deps, c_args: common_args),
|
||||
env: common_env,
|
||||
)
|
||||
|
||||
test(
|
||||
'test-si-simple-node-endpoint',
|
||||
executable('test-si-simple-node-endpoint', 'si-simple-node-endpoint.c',
|
||||
|
|
|
|||
371
tests/modules/reserve-device.c
Normal file
371
tests/modules/reserve-device.c
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2021 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "../common/base-test-fixture.h"
|
||||
|
||||
typedef struct {
|
||||
WpBaseTestFixture base;
|
||||
GTestDBus *test_dbus;
|
||||
WpPlugin *rd_plugin_1;
|
||||
WpPlugin *rd_plugin_2;
|
||||
gint expected_rd1_state;
|
||||
gint expected_rd2_state;
|
||||
} RdTestFixture;
|
||||
|
||||
static void
|
||||
test_rd_setup (RdTestFixture *f, gconstpointer data)
|
||||
{
|
||||
wp_base_test_fixture_setup (&f->base,
|
||||
WP_BASE_TEST_FLAG_CLIENT_CORE | WP_BASE_TEST_FLAG_DONT_CONNECT);
|
||||
|
||||
f->test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
|
||||
g_test_dbus_up (f->test_dbus);
|
||||
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
WpModule *module = wp_module_load (f->base.core, "C",
|
||||
"libwireplumber-module-reserve-device", NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (module);
|
||||
}
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
WpModule *module = wp_module_load (f->base.client_core, "C",
|
||||
"libwireplumber-module-reserve-device", NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (module);
|
||||
}
|
||||
|
||||
f->rd_plugin_1 = wp_plugin_find (f->base.core, "reserve-device");
|
||||
g_assert_nonnull (f->rd_plugin_1);
|
||||
|
||||
f->rd_plugin_2 = wp_plugin_find (f->base.client_core, "reserve-device");
|
||||
g_assert_nonnull (f->rd_plugin_2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_rd_teardown (RdTestFixture *f, gconstpointer data)
|
||||
{
|
||||
g_clear_object (&f->rd_plugin_1);
|
||||
g_clear_object (&f->rd_plugin_2);
|
||||
g_test_dbus_down (f->test_dbus);
|
||||
g_clear_object (&f->test_dbus);
|
||||
wp_base_test_fixture_teardown (&f->base);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_plugins_stable_state (GObject * obj, GParamSpec * spec, RdTestFixture *f)
|
||||
{
|
||||
gint state1 = 0, state2 = 0;
|
||||
g_object_get (f->rd_plugin_1, "state", &state1, NULL);
|
||||
g_object_get (f->rd_plugin_2, "state", &state2, NULL);
|
||||
if (state1 != 1 && state2 != 1 && state1 == state2)
|
||||
g_main_loop_quit (f->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_rd_plugin (RdTestFixture *f, gconstpointer data)
|
||||
{
|
||||
GObject *rd1 = NULL, *rd2 = NULL, *rd_video = NULL, *tmp = NULL;
|
||||
gint state = 0xffff;
|
||||
gchar *str;
|
||||
|
||||
g_object_get (f->rd_plugin_1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 0);
|
||||
g_object_get (f->rd_plugin_2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 0);
|
||||
|
||||
wp_plugin_activate (f->rd_plugin_1);
|
||||
wp_plugin_activate (f->rd_plugin_2);
|
||||
|
||||
g_object_get (f->rd_plugin_1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 1);
|
||||
g_object_get (f->rd_plugin_2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 1);
|
||||
|
||||
g_signal_connect (f->rd_plugin_1, "notify::state",
|
||||
G_CALLBACK (ensure_plugins_stable_state), f);
|
||||
g_signal_connect (f->rd_plugin_2, "notify::state",
|
||||
G_CALLBACK (ensure_plugins_stable_state), f);
|
||||
g_main_loop_run (f->base.loop);
|
||||
|
||||
g_object_get (f->rd_plugin_1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 2);
|
||||
g_object_get (f->rd_plugin_2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 2);
|
||||
|
||||
g_signal_emit_by_name (f->rd_plugin_1, "create-reservation",
|
||||
"Audio0", "WirePlumber", "hw:0,0", 10, &rd1);
|
||||
g_assert_nonnull (rd1);
|
||||
g_signal_emit_by_name (f->rd_plugin_2, "create-reservation",
|
||||
"Audio0", "Other Server", "hw:0,0", 15, &rd2);
|
||||
g_assert_nonnull (rd2);
|
||||
g_signal_emit_by_name (f->rd_plugin_1, "create-reservation",
|
||||
"Video0", "WirePlumber", "/dev/video0", 10, &rd_video);
|
||||
g_assert_nonnull (rd_video);
|
||||
|
||||
g_signal_emit_by_name (f->rd_plugin_1, "get-reservation", "Video1", &tmp);
|
||||
g_assert_null (tmp);
|
||||
g_signal_emit_by_name (f->rd_plugin_2, "get-reservation", "Video0", &tmp);
|
||||
g_assert_null (tmp);
|
||||
|
||||
g_signal_emit_by_name (f->rd_plugin_1, "get-reservation", "Audio0", &tmp);
|
||||
g_assert_nonnull (tmp);
|
||||
g_assert_true (tmp == rd1);
|
||||
g_clear_object (&tmp);
|
||||
|
||||
g_object_get (rd1, "name", &str, NULL);
|
||||
g_assert_cmpstr (str, ==, "Audio0");
|
||||
g_free (str);
|
||||
g_object_get (rd2, "name", &str, NULL);
|
||||
g_assert_cmpstr (str, ==, "Audio0");
|
||||
g_free (str);
|
||||
g_object_get (rd_video, "name", &str, NULL);
|
||||
g_assert_cmpstr (str, ==, "Video0");
|
||||
g_free (str);
|
||||
g_object_get (rd1, "application-name", &str, NULL);
|
||||
g_assert_cmpstr (str, ==, "WirePlumber");
|
||||
g_free (str);
|
||||
g_object_get (rd1, "application-device-name", &str, NULL);
|
||||
g_assert_cmpstr (str, ==, "hw:0,0");
|
||||
g_free (str);
|
||||
g_object_get (rd1, "priority", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 10);
|
||||
g_object_get (rd2, "priority", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 15);
|
||||
|
||||
g_signal_emit_by_name (f->rd_plugin_1, "destroy-reservation", "Audio0");
|
||||
g_signal_emit_by_name (f->rd_plugin_1, "get-reservation", "Audio0", &tmp);
|
||||
g_assert_null (tmp);
|
||||
g_signal_emit_by_name (f->rd_plugin_2, "get-reservation", "Audio0", &tmp);
|
||||
g_assert_nonnull (tmp);
|
||||
g_assert_true (tmp == rd2);
|
||||
g_clear_object (&tmp);
|
||||
g_clear_object (&rd2);
|
||||
g_clear_object (&rd1);
|
||||
g_clear_object (&rd_video);
|
||||
|
||||
wp_plugin_deactivate (f->rd_plugin_1);
|
||||
wp_plugin_deactivate (f->rd_plugin_2);
|
||||
|
||||
g_object_get (f->rd_plugin_1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 0);
|
||||
g_object_get (f->rd_plugin_2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_rd_conn_closed (RdTestFixture *f, gconstpointer data)
|
||||
{
|
||||
GObject *rd1 = NULL;
|
||||
gint state = 0xffff;
|
||||
|
||||
g_object_get (f->rd_plugin_1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 0);
|
||||
g_object_get (f->rd_plugin_2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 0);
|
||||
|
||||
wp_plugin_activate (f->rd_plugin_1);
|
||||
wp_plugin_activate (f->rd_plugin_2);
|
||||
|
||||
g_object_get (f->rd_plugin_1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 1);
|
||||
g_object_get (f->rd_plugin_2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 1);
|
||||
|
||||
g_signal_connect (f->rd_plugin_1, "notify::state",
|
||||
G_CALLBACK (ensure_plugins_stable_state), f);
|
||||
g_signal_connect (f->rd_plugin_2, "notify::state",
|
||||
G_CALLBACK (ensure_plugins_stable_state), f);
|
||||
g_main_loop_run (f->base.loop);
|
||||
|
||||
g_object_get (f->rd_plugin_1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 2);
|
||||
g_object_get (f->rd_plugin_2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 2);
|
||||
|
||||
g_signal_emit_by_name (f->rd_plugin_1, "create-reservation",
|
||||
"Audio0", "WirePlumber", "hw:0,0", 10, &rd1);
|
||||
g_assert_nonnull (rd1);
|
||||
g_clear_object (&rd1);
|
||||
|
||||
/* stop the bus, expect the connections to close
|
||||
and state to go back to CLOSED */
|
||||
g_test_dbus_stop (f->test_dbus);
|
||||
g_main_loop_run (f->base.loop);
|
||||
|
||||
g_object_get (f->rd_plugin_1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 0);
|
||||
g_object_get (f->rd_plugin_2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 0);
|
||||
|
||||
g_signal_emit_by_name (f->rd_plugin_1, "get-reservation", "Audio0", &rd1);
|
||||
g_assert_null (rd1);
|
||||
}
|
||||
|
||||
static void
|
||||
expect_rd1_state (GObject * rd, GParamSpec * spec, RdTestFixture *f)
|
||||
{
|
||||
gint state;
|
||||
g_object_get (rd, "state", &state, NULL);
|
||||
if (state == f->expected_rd1_state)
|
||||
g_main_loop_quit (f->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
expect_rd2_state (GObject * rd, GParamSpec * spec, RdTestFixture *f)
|
||||
{
|
||||
gint state;
|
||||
g_object_get (rd, "state", &state, NULL);
|
||||
if (state == f->expected_rd2_state)
|
||||
g_main_loop_quit (f->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_release_requested (GObject * rd, gboolean forced, RdTestFixture *f)
|
||||
{
|
||||
gint state = 0xffff;
|
||||
g_signal_emit_by_name (rd, "release");
|
||||
g_object_get (rd, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 2);
|
||||
g_main_loop_quit (f->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_rd_acquire_release (RdTestFixture *f, gconstpointer data)
|
||||
{
|
||||
GObject *rd1 = NULL, *rd2 = NULL;
|
||||
gint state = 0xffff;
|
||||
gchar *str = NULL;
|
||||
|
||||
g_object_get (f->rd_plugin_1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 0);
|
||||
g_object_get (f->rd_plugin_2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 0);
|
||||
|
||||
wp_plugin_activate (f->rd_plugin_1);
|
||||
wp_plugin_activate (f->rd_plugin_2);
|
||||
|
||||
g_object_get (f->rd_plugin_1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 1);
|
||||
g_object_get (f->rd_plugin_2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 1);
|
||||
|
||||
g_signal_connect (f->rd_plugin_1, "notify::state",
|
||||
G_CALLBACK (ensure_plugins_stable_state), f);
|
||||
g_signal_connect (f->rd_plugin_2, "notify::state",
|
||||
G_CALLBACK (ensure_plugins_stable_state), f);
|
||||
g_main_loop_run (f->base.loop);
|
||||
|
||||
g_object_get (f->rd_plugin_1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 2);
|
||||
g_object_get (f->rd_plugin_2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 2);
|
||||
|
||||
g_signal_emit_by_name (f->rd_plugin_1, "create-reservation",
|
||||
"Audio0", "WirePlumber", "hw:0,0", 10, &rd1);
|
||||
g_assert_nonnull (rd1);
|
||||
g_signal_emit_by_name (f->rd_plugin_2, "create-reservation",
|
||||
"Audio0", "Other Server", "hw:0,0", 15, &rd2);
|
||||
g_assert_nonnull (rd2);
|
||||
|
||||
g_signal_connect (rd1, "notify::state", G_CALLBACK (expect_rd1_state), f);
|
||||
g_signal_connect (rd2, "notify::state", G_CALLBACK (expect_rd2_state), f);
|
||||
|
||||
/* acquire */
|
||||
wp_info ("rd1 acquire");
|
||||
|
||||
f->expected_rd1_state = 3;
|
||||
g_signal_emit_by_name (rd1, "acquire");
|
||||
g_main_loop_run (f->base.loop);
|
||||
g_object_get (rd1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 3);
|
||||
g_object_get (rd1, "owner-application-name", &str, NULL);
|
||||
g_assert_cmpstr (str, ==, "WirePlumber");
|
||||
g_free (str);
|
||||
|
||||
g_signal_connect (rd1, "release-requested",
|
||||
G_CALLBACK (handle_release_requested), f);
|
||||
|
||||
/* acquire with higher priority */
|
||||
wp_info ("rd2 acquire, higher prio");
|
||||
g_signal_emit_by_name (rd2, "acquire");
|
||||
|
||||
/* rd1 is now released */
|
||||
g_main_loop_run (f->base.loop);
|
||||
g_object_get (rd1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 2);
|
||||
|
||||
/* rd2 acquired */
|
||||
f->expected_rd2_state = 3;
|
||||
g_main_loop_run (f->base.loop);
|
||||
g_object_get (rd2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 3);
|
||||
|
||||
/* rd1 busy */
|
||||
g_signal_connect_swapped (rd1, "notify::owner-application-name",
|
||||
G_CALLBACK (g_main_loop_quit), f->base.loop);
|
||||
g_main_loop_run (f->base.loop);
|
||||
g_object_get (rd1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 1);
|
||||
g_object_get (rd1, "owner-application-name", &str, NULL);
|
||||
g_assert_cmpstr (str, ==, "Other Server");
|
||||
g_free (str);
|
||||
g_signal_handlers_disconnect_by_func (rd1, G_CALLBACK (g_main_loop_quit),
|
||||
f->base.loop);
|
||||
|
||||
/* try to acquire back with lower priority */
|
||||
wp_info ("rd1 acquire, lower prio");
|
||||
g_signal_emit_by_name (rd1, "acquire");
|
||||
|
||||
/* ... expect this to fail */
|
||||
f->expected_rd1_state = 1;
|
||||
g_main_loop_run (f->base.loop);
|
||||
g_object_get (rd1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 1);
|
||||
|
||||
g_object_get (rd1, "owner-application-name", &str, NULL);
|
||||
g_assert_cmpstr (str, ==, "Other Server");
|
||||
g_free (str);
|
||||
|
||||
/* release */
|
||||
wp_info ("rd2 release");
|
||||
g_signal_emit_by_name (rd2, "release");
|
||||
g_object_get (rd2, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 2);
|
||||
|
||||
f->expected_rd1_state = 2;
|
||||
g_main_loop_run (f->base.loop);
|
||||
g_object_get (rd1, "state", &state, NULL);
|
||||
g_assert_cmpint (state, ==, 2);
|
||||
|
||||
g_object_get (rd1, "owner-application-name", &str, NULL);
|
||||
g_assert_null (str);
|
||||
|
||||
g_clear_object (&rd1);
|
||||
g_clear_object (&rd2);
|
||||
|
||||
wp_plugin_deactivate (f->rd_plugin_1);
|
||||
wp_plugin_deactivate (f->rd_plugin_2);
|
||||
}
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
wp_init (WP_INIT_ALL);
|
||||
|
||||
g_test_add ("/modules/rd/plugin", RdTestFixture, NULL,
|
||||
test_rd_setup, test_rd_plugin, test_rd_teardown);
|
||||
g_test_add ("/modules/rd/conn_closed", RdTestFixture, NULL,
|
||||
test_rd_setup, test_rd_conn_closed, test_rd_teardown);
|
||||
g_test_add ("/modules/rd/acquire_release", RdTestFixture, NULL,
|
||||
test_rd_setup, test_rd_acquire_release, test_rd_teardown);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue