mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2025-12-31 03:50:06 +01:00
242 lines
6.3 KiB
C
242 lines
6.3 KiB
C
/* WirePlumber
|
|
*
|
|
* Copyright © 2019 Collabora Ltd.
|
|
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
/**
|
|
* SECTION: Exported
|
|
*
|
|
* An exported object is an object that is implemented in the local
|
|
* wireplumber process but is exported to pipewire so that it is
|
|
* visible to other clients through the registry.
|
|
*
|
|
* In PipeWire, an object is normally exported with pw_remote_export() or
|
|
* by instantiating a "client-something" object on the server and using
|
|
* the interface of that "client" object to control the exported global
|
|
* object. In both cases, a proxy is created, which is in total control
|
|
* of the object. If the proxy is destroyed, all associated objects
|
|
* - the local exported object, the "client" object and the remote global
|
|
* object - are destroyed.
|
|
*/
|
|
|
|
#include "exported.h"
|
|
#include "error.h"
|
|
#include "private.h"
|
|
|
|
typedef struct _WpExportedPrivate WpExportedPrivate;
|
|
struct _WpExportedPrivate
|
|
{
|
|
GWeakRef core;
|
|
GTask *task;
|
|
};
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_CORE,
|
|
PROP_PROXY,
|
|
};
|
|
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpExported, wp_exported, G_TYPE_OBJECT)
|
|
|
|
static void
|
|
wp_exported_init (WpExported * self)
|
|
{
|
|
WpExportedPrivate *priv = wp_exported_get_instance_private (self);
|
|
|
|
g_weak_ref_init (&priv->core, NULL);
|
|
}
|
|
|
|
static void
|
|
wp_exported_finalize (GObject * object)
|
|
{
|
|
WpExportedPrivate *priv =
|
|
wp_exported_get_instance_private (WP_EXPORTED (object));
|
|
|
|
g_debug ("%s:%p destroyed", G_OBJECT_TYPE_NAME (object), object);
|
|
|
|
g_weak_ref_clear (&priv->core);
|
|
|
|
G_OBJECT_CLASS (wp_exported_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
wp_exported_set_property (GObject * object, guint property_id,
|
|
const GValue * value, GParamSpec * pspec)
|
|
{
|
|
WpExportedPrivate *priv =
|
|
wp_exported_get_instance_private (WP_EXPORTED (object));
|
|
|
|
switch (property_id) {
|
|
case PROP_CORE:
|
|
g_weak_ref_set (&priv->core, g_value_get_object (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
wp_exported_get_property (GObject * object, guint property_id, GValue * value,
|
|
GParamSpec * pspec)
|
|
{
|
|
WpExportedPrivate *priv =
|
|
wp_exported_get_instance_private (WP_EXPORTED (object));
|
|
|
|
switch (property_id) {
|
|
case PROP_CORE:
|
|
g_value_take_object (value, g_weak_ref_get (&priv->core));
|
|
break;
|
|
case PROP_PROXY:
|
|
g_value_take_object (value, wp_exported_get_proxy (WP_EXPORTED (object)));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
wp_exported_class_init (WpExportedClass * klass)
|
|
{
|
|
GObjectClass *object_class = (GObjectClass *) klass;
|
|
|
|
object_class->finalize = wp_exported_finalize;
|
|
object_class->get_property = wp_exported_get_property;
|
|
object_class->set_property = wp_exported_set_property;
|
|
|
|
/* Install the properties */
|
|
|
|
g_object_class_install_property (object_class, PROP_CORE,
|
|
g_param_spec_object ("core", "core", "The WpCore", WP_TYPE_CORE,
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (object_class, PROP_PROXY,
|
|
g_param_spec_pointer ("proxy", "proxy", "The controlling proxy object",
|
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
|
}
|
|
|
|
/**
|
|
* wp_exported_get_core:
|
|
* @self: the exported object
|
|
*
|
|
* Returns: (transfer full): the core that owns this exported object
|
|
*/
|
|
WpCore *
|
|
wp_exported_get_core (WpExported * self)
|
|
{
|
|
WpExportedPrivate *priv;
|
|
|
|
g_return_val_if_fail (WP_IS_EXPORTED (self), NULL);
|
|
|
|
priv = wp_exported_get_instance_private (self);
|
|
return g_weak_ref_get (&priv->core);
|
|
}
|
|
|
|
static void
|
|
on_core_connected (WpCore * core, WpExported * self)
|
|
{
|
|
WpExportedPrivate *priv = wp_exported_get_instance_private (self);
|
|
|
|
if (g_task_return_error_if_cancelled (priv->task))
|
|
g_clear_object (&priv->task);
|
|
else
|
|
WP_EXPORTED_GET_CLASS (self)->export (self);
|
|
|
|
g_signal_handlers_disconnect_by_func (core, on_core_connected, self);
|
|
}
|
|
|
|
void
|
|
wp_exported_export (WpExported * self, GCancellable * cancellable,
|
|
GAsyncReadyCallback callback, gpointer user_data)
|
|
{
|
|
WpExportedPrivate *priv;
|
|
g_autoptr (WpCore) core = NULL;
|
|
|
|
g_return_if_fail (WP_IS_EXPORTED (self));
|
|
g_return_if_fail (WP_EXPORTED_GET_CLASS (self)->export);
|
|
|
|
priv = wp_exported_get_instance_private (self);
|
|
priv->task = g_task_new (self, cancellable, callback, user_data);
|
|
|
|
core = g_weak_ref_get (&priv->core);
|
|
if (!core) {
|
|
g_task_return_new_error (priv->task, WP_DOMAIN_LIBRARY,
|
|
WP_LIBRARY_ERROR_OPERATION_FAILED, "WirePlumber core not available");
|
|
g_clear_object (&priv->task);
|
|
return;
|
|
}
|
|
|
|
/* Export when connected */
|
|
if (wp_core_is_connected (core))
|
|
WP_EXPORTED_GET_CLASS (self)->export (self);
|
|
else
|
|
g_signal_connect_object (core, "connected", (GCallback) on_core_connected,
|
|
self, 0);
|
|
}
|
|
|
|
gboolean
|
|
wp_exported_export_finish (WpExported * self,
|
|
GAsyncResult * res, GError ** error)
|
|
{
|
|
g_return_val_if_fail (WP_IS_EXPORTED (self), FALSE);
|
|
g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
|
|
|
|
return g_task_propagate_boolean (G_TASK (res), error);
|
|
}
|
|
|
|
void
|
|
wp_exported_notify_export_done (WpExported * self, GError * error)
|
|
{
|
|
WpExportedPrivate *priv;
|
|
g_autoptr (WpCore) core = NULL;
|
|
|
|
g_return_if_fail (WP_IS_EXPORTED (self));
|
|
|
|
priv = wp_exported_get_instance_private (self);
|
|
g_return_if_fail (priv->task);
|
|
|
|
g_task_return_boolean (priv->task, TRUE);
|
|
g_clear_object (&priv->task);
|
|
|
|
core = g_weak_ref_get (&priv->core);
|
|
if (core)
|
|
wp_core_register_object (core, g_object_ref (self));
|
|
}
|
|
|
|
void
|
|
wp_exported_unexport (WpExported * self)
|
|
{
|
|
WpExportedPrivate *priv;
|
|
g_autoptr (WpCore) core = NULL;
|
|
|
|
g_return_if_fail (WP_IS_EXPORTED (self));
|
|
|
|
priv = wp_exported_get_instance_private (self);
|
|
g_return_if_fail (!priv->task);
|
|
|
|
if (WP_EXPORTED_GET_CLASS (self)->unexport)
|
|
WP_EXPORTED_GET_CLASS (self)->unexport (self);
|
|
|
|
core = g_weak_ref_get (&priv->core);
|
|
if (core)
|
|
wp_core_remove_object (core, self);
|
|
}
|
|
|
|
/**
|
|
* wp_exported_get_proxy:
|
|
* @self: the exported object
|
|
*
|
|
* Returns: (transfer full): the proxy that controls the export to pipewire
|
|
*/
|
|
WpProxy *
|
|
wp_exported_get_proxy (WpExported * self)
|
|
{
|
|
g_return_val_if_fail (WP_IS_EXPORTED (self), NULL);
|
|
g_return_val_if_fail (WP_EXPORTED_GET_CLASS (self)->get_proxy, NULL);
|
|
|
|
return WP_EXPORTED_GET_CLASS (self)->get_proxy (self);
|
|
}
|