lib: implement proxy & impl for PW_TYPE_INTERFACE_EndpointLink
This commit is contained in:
610
lib/wp/endpoint-link.c
Normal file
610
lib/wp/endpoint-link.c
Normal file
@@ -0,0 +1,610 @@
|
|||||||
|
/* WirePlumber
|
||||||
|
*
|
||||||
|
* Copyright © 2020 Collabora Ltd.
|
||||||
|
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION: WpEndpointLink
|
||||||
|
*
|
||||||
|
* The #WpEndpointLink class allows accessing the properties and methods of a
|
||||||
|
* PipeWire endpoint link object (`struct pw_endpoint_link` from the
|
||||||
|
* session-manager extension).
|
||||||
|
*
|
||||||
|
* A #WpEndpointLink is constructed internally when a new endpoint link appears
|
||||||
|
* on the PipeWire registry and it is made available through the
|
||||||
|
* #WpObjectManager API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "endpoint-link.h"
|
||||||
|
#include "private.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "wpenums.h"
|
||||||
|
|
||||||
|
#include <pipewire/pipewire.h>
|
||||||
|
#include <pipewire/extensions/session-manager.h>
|
||||||
|
#include <pipewire/extensions/session-manager/introspect-funcs.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SIGNAL_STATE_CHANGED,
|
||||||
|
N_SIGNALS,
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint32 signals[N_SIGNALS] = {0};
|
||||||
|
|
||||||
|
/* WpEndpointLink */
|
||||||
|
|
||||||
|
typedef struct _WpEndpointLinkPrivate WpEndpointLinkPrivate;
|
||||||
|
struct _WpEndpointLinkPrivate
|
||||||
|
{
|
||||||
|
WpProperties *properties;
|
||||||
|
struct pw_endpoint_link_info *info;
|
||||||
|
struct pw_endpoint_link *iface;
|
||||||
|
struct spa_hook listener;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_WITH_PRIVATE (WpEndpointLink, wp_endpoint_link, WP_TYPE_PROXY)
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_endpoint_link_init (WpEndpointLink * self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_endpoint_link_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
WpEndpointLink *self = WP_ENDPOINT_LINK (object);
|
||||||
|
WpEndpointLinkPrivate *priv = wp_endpoint_link_get_instance_private (self);
|
||||||
|
|
||||||
|
g_clear_pointer (&priv->properties, wp_properties_unref);
|
||||||
|
g_clear_pointer (&priv->info, pw_endpoint_link_info_free);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (wp_endpoint_link_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gconstpointer
|
||||||
|
wp_endpoint_link_get_info (WpProxy * proxy)
|
||||||
|
{
|
||||||
|
WpEndpointLink *self = WP_ENDPOINT_LINK (proxy);
|
||||||
|
WpEndpointLinkPrivate *priv = wp_endpoint_link_get_instance_private (self);
|
||||||
|
|
||||||
|
return priv->info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WpProperties *
|
||||||
|
wp_endpoint_link_get_properties (WpProxy * proxy)
|
||||||
|
{
|
||||||
|
WpEndpointLink *self = WP_ENDPOINT_LINK (proxy);
|
||||||
|
WpEndpointLinkPrivate *priv = wp_endpoint_link_get_instance_private (self);
|
||||||
|
|
||||||
|
return wp_properties_ref (priv->properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
wp_endpoint_link_enum_params (WpProxy * self, guint32 id, guint32 start,
|
||||||
|
guint32 num, const struct spa_pod *filter)
|
||||||
|
{
|
||||||
|
WpEndpointLinkPrivate *priv =
|
||||||
|
wp_endpoint_link_get_instance_private (WP_ENDPOINT_LINK (self));
|
||||||
|
int endpoint_link_enum_params_result;
|
||||||
|
|
||||||
|
endpoint_link_enum_params_result =
|
||||||
|
pw_endpoint_link_enum_params (priv->iface, 0, id, start, num, filter);
|
||||||
|
g_warn_if_fail (endpoint_link_enum_params_result >= 0);
|
||||||
|
|
||||||
|
return endpoint_link_enum_params_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
wp_endpoint_link_subscribe_params (WpProxy * self, guint32 n_ids, guint32 *ids)
|
||||||
|
{
|
||||||
|
WpEndpointLinkPrivate *priv =
|
||||||
|
wp_endpoint_link_get_instance_private (WP_ENDPOINT_LINK (self));
|
||||||
|
int endpoint_link_subscribe_params_result;
|
||||||
|
|
||||||
|
endpoint_link_subscribe_params_result =
|
||||||
|
pw_endpoint_link_subscribe_params (priv->iface, ids, n_ids);
|
||||||
|
g_warn_if_fail (endpoint_link_subscribe_params_result >= 0);
|
||||||
|
|
||||||
|
return endpoint_link_subscribe_params_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
wp_endpoint_link_set_param (WpProxy * self, guint32 id, guint32 flags,
|
||||||
|
const struct spa_pod *param)
|
||||||
|
{
|
||||||
|
WpEndpointLinkPrivate *priv =
|
||||||
|
wp_endpoint_link_get_instance_private (WP_ENDPOINT_LINK (self));
|
||||||
|
int endpoint_link_set_param_result;
|
||||||
|
|
||||||
|
endpoint_link_set_param_result =
|
||||||
|
pw_endpoint_link_set_param (priv->iface, id, flags, param);
|
||||||
|
g_warn_if_fail (endpoint_link_set_param_result >= 0);
|
||||||
|
|
||||||
|
return endpoint_link_set_param_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
endpoint_link_event_info (void *data, const struct pw_endpoint_link_info *info)
|
||||||
|
{
|
||||||
|
WpEndpointLink *self = WP_ENDPOINT_LINK (data);
|
||||||
|
WpEndpointLinkPrivate *priv = wp_endpoint_link_get_instance_private (self);
|
||||||
|
WpEndpointLinkState old_state =
|
||||||
|
priv->info ? priv->info->state : PW_ENDPOINT_LINK_STATE_ERROR;
|
||||||
|
|
||||||
|
priv->info = pw_endpoint_link_info_update (priv->info, info);
|
||||||
|
|
||||||
|
if (info->change_mask & PW_ENDPOINT_LINK_CHANGE_MASK_PROPS) {
|
||||||
|
g_clear_pointer (&priv->properties, wp_properties_unref);
|
||||||
|
priv->properties = wp_properties_new_wrap_dict (priv->info->props);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_proxy_set_feature_ready (WP_PROXY (self), WP_PROXY_FEATURE_INFO);
|
||||||
|
g_object_notify (G_OBJECT (self), "info");
|
||||||
|
|
||||||
|
if (info->change_mask & PW_ENDPOINT_LINK_CHANGE_MASK_PROPS)
|
||||||
|
g_object_notify (G_OBJECT (self), "properties");
|
||||||
|
|
||||||
|
if (info->change_mask & PW_ENDPOINT_LINK_CHANGE_MASK_STATE) {
|
||||||
|
g_signal_emit (self, signals[SIGNAL_STATE_CHANGED], 0,
|
||||||
|
old_state, info->state, info->error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_endpoint_link_events endpoint_link_events = {
|
||||||
|
PW_VERSION_ENDPOINT_LINK_EVENTS,
|
||||||
|
.info = endpoint_link_event_info,
|
||||||
|
.param = wp_proxy_handle_event_param,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_endpoint_link_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
|
||||||
|
{
|
||||||
|
WpEndpointLink *self = WP_ENDPOINT_LINK (proxy);
|
||||||
|
WpEndpointLinkPrivate *priv = wp_endpoint_link_get_instance_private (self);
|
||||||
|
|
||||||
|
priv->iface = (struct pw_endpoint_link *) pw_proxy;
|
||||||
|
pw_endpoint_link_add_listener (priv->iface, &priv->listener,
|
||||||
|
&endpoint_link_events, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_endpoint_link_class_init (WpEndpointLinkClass * klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = (GObjectClass *) klass;
|
||||||
|
WpProxyClass *proxy_class = (WpProxyClass *) klass;
|
||||||
|
|
||||||
|
object_class->finalize = wp_endpoint_link_finalize;
|
||||||
|
|
||||||
|
proxy_class->pw_iface_type = PW_TYPE_INTERFACE_EndpointLink;
|
||||||
|
proxy_class->pw_iface_version = PW_VERSION_ENDPOINT_LINK;
|
||||||
|
|
||||||
|
proxy_class->get_info = wp_endpoint_link_get_info;
|
||||||
|
proxy_class->get_properties = wp_endpoint_link_get_properties;
|
||||||
|
proxy_class->enum_params = wp_endpoint_link_enum_params;
|
||||||
|
proxy_class->subscribe_params = wp_endpoint_link_subscribe_params;
|
||||||
|
proxy_class->set_param = wp_endpoint_link_set_param;
|
||||||
|
proxy_class->pw_proxy_created = wp_endpoint_link_pw_proxy_created;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WpEndpointLink::state-changed:
|
||||||
|
* @self: the endpoint link
|
||||||
|
* @old_state: the old state of the link
|
||||||
|
* @new_state: the new state of the link
|
||||||
|
* @error: (nullable): the error string if the new state is
|
||||||
|
* %WP_ENDPOINT_LINK_STATE_ERROR
|
||||||
|
*
|
||||||
|
* Emitted when an endpoint link changes state
|
||||||
|
*/
|
||||||
|
signals[SIGNAL_STATE_CHANGED] = g_signal_new (
|
||||||
|
"state-changed", G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 3,
|
||||||
|
WP_TYPE_ENDPOINT_LINK_STATE, WP_TYPE_ENDPOINT_LINK_STATE, G_TYPE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wp_endpoint_link_get_linked_object_ids:
|
||||||
|
* @self: the endpoint link
|
||||||
|
* @output_endpoint: (out) (optional): the bound id of the output (source)
|
||||||
|
* endpoint
|
||||||
|
* @output_stream: (out) (optional): the bound id of the output (source)
|
||||||
|
* endpoint's stream
|
||||||
|
* @input_endpoint: (out) (optional): the bound id of the input (sink)
|
||||||
|
* endpoint
|
||||||
|
* @input_stream: (out) (optional): the bound id of the input (sink)
|
||||||
|
* endpoint's stream
|
||||||
|
*
|
||||||
|
* Retrieves the ids of the objects that are linked by this endpoint link
|
||||||
|
*
|
||||||
|
* Note: Using this method requires %WP_PROXY_FEATURE_INFO
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
wp_endpoint_link_get_linked_object_ids (WpEndpointLink * self,
|
||||||
|
guint32 * output_endpoint, guint32 * output_stream,
|
||||||
|
guint32 * input_endpoint, guint32 * input_stream)
|
||||||
|
{
|
||||||
|
g_return_if_fail (WP_IS_ENDPOINT_LINK (self));
|
||||||
|
|
||||||
|
WpEndpointLinkPrivate *priv = wp_endpoint_link_get_instance_private (self);
|
||||||
|
g_return_if_fail (priv->info);
|
||||||
|
|
||||||
|
if (output_endpoint)
|
||||||
|
*output_endpoint = priv->info->output_endpoint_id;
|
||||||
|
if (output_stream)
|
||||||
|
*output_stream = priv->info->output_stream_id;
|
||||||
|
if (input_endpoint)
|
||||||
|
*input_endpoint = priv->info->input_endpoint_id;
|
||||||
|
if (input_stream)
|
||||||
|
*input_stream = priv->info->input_stream_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wp_endpoint_link_get_state:
|
||||||
|
* @self: the endpoint link
|
||||||
|
* @error: (out) (optional) (transfer none): the error string if the state is
|
||||||
|
* %WP_ENDPOINT_LINK_STATE_ERROR
|
||||||
|
*
|
||||||
|
* Retrieves the current state of the link
|
||||||
|
*
|
||||||
|
* Note: Using this method requires %WP_PROXY_FEATURE_INFO
|
||||||
|
* Returns: the current state of the link
|
||||||
|
*/
|
||||||
|
WpEndpointLinkState
|
||||||
|
wp_endpoint_link_get_state (WpEndpointLink * self, const gchar ** error)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (WP_IS_ENDPOINT_LINK (self), WP_ENDPOINT_LINK_STATE_ERROR);
|
||||||
|
|
||||||
|
WpEndpointLinkPrivate *priv = wp_endpoint_link_get_instance_private (self);
|
||||||
|
g_return_val_if_fail (priv->info, WP_ENDPOINT_LINK_STATE_ERROR);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
*error = priv->info->error;
|
||||||
|
return priv->info->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wp_endpoint_link_request_state:
|
||||||
|
* @self: the endpoint link
|
||||||
|
* @target: the desired target state of the link
|
||||||
|
*
|
||||||
|
* Requests a state change on the link
|
||||||
|
*
|
||||||
|
* Note: Using this method requires %WP_PROXY_FEATURE_PW_PROXY
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
wp_endpoint_link_request_state (WpEndpointLink * self,
|
||||||
|
WpEndpointLinkState target)
|
||||||
|
{
|
||||||
|
g_return_if_fail (WP_IS_ENDPOINT_LINK (self));
|
||||||
|
|
||||||
|
WpEndpointLinkPrivate *priv = wp_endpoint_link_get_instance_private (self);
|
||||||
|
g_return_if_fail (priv->iface);
|
||||||
|
|
||||||
|
pw_endpoint_link_request_state (priv->iface,
|
||||||
|
(enum pw_endpoint_link_state) target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WpImplEndpointLink */
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IMPL_PROP_0,
|
||||||
|
IMPL_PROP_ITEM,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _WpImplEndpointLink
|
||||||
|
{
|
||||||
|
WpEndpointLink parent;
|
||||||
|
|
||||||
|
struct spa_interface iface;
|
||||||
|
struct spa_hook_list hooks;
|
||||||
|
struct pw_endpoint_link_info info;
|
||||||
|
|
||||||
|
WpSiLink *item;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (WpImplEndpointLink, wp_impl_endpoint_link, WP_TYPE_ENDPOINT_LINK)
|
||||||
|
|
||||||
|
#define pw_endpoint_link_emit(hooks,method,version,...) \
|
||||||
|
spa_hook_list_call_simple(hooks, struct pw_endpoint_link_events, \
|
||||||
|
method, version, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define pw_endpoint_link_emit_info(hooks,...) \
|
||||||
|
pw_endpoint_link_emit(hooks, info, 0, ##__VA_ARGS__)
|
||||||
|
#define pw_endpoint_link_emit_param(hooks,...) \
|
||||||
|
pw_endpoint_link_emit(hooks, param, 0, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
static int
|
||||||
|
impl_add_listener(void *object,
|
||||||
|
struct spa_hook *listener,
|
||||||
|
const struct pw_endpoint_link_events *events,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
WpImplEndpointLink *self = WP_IMPL_ENDPOINT_LINK (object);
|
||||||
|
struct spa_hook_list save;
|
||||||
|
|
||||||
|
spa_hook_list_isolate (&self->hooks, &save, listener, events, data);
|
||||||
|
|
||||||
|
self->info.change_mask = PW_ENDPOINT_LINK_CHANGE_MASK_ALL;
|
||||||
|
pw_endpoint_link_emit_info (&self->hooks, &self->info);
|
||||||
|
self->info.change_mask = 0;
|
||||||
|
|
||||||
|
spa_hook_list_join (&self->hooks, &save);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
impl_enum_params (void *object, int seq,
|
||||||
|
uint32_t id, uint32_t start, uint32_t num,
|
||||||
|
const struct spa_pod *filter)
|
||||||
|
{
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
impl_subscribe_params (void *object, uint32_t *ids, uint32_t n_ids)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
impl_set_param (void *object, uint32_t id, uint32_t flags,
|
||||||
|
const struct spa_pod *param)
|
||||||
|
{
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
impl_request_state (void *object, enum pw_endpoint_link_state state)
|
||||||
|
{
|
||||||
|
WpImplEndpointLink *self = WP_IMPL_ENDPOINT_LINK (object);
|
||||||
|
wp_si_link_request_state (self->item, (WpEndpointLinkState) state);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_endpoint_link_methods impl_endpoint_link = {
|
||||||
|
PW_VERSION_ENDPOINT_LINK_METHODS,
|
||||||
|
.add_listener = impl_add_listener,
|
||||||
|
.subscribe_params = impl_subscribe_params,
|
||||||
|
.enum_params = impl_enum_params,
|
||||||
|
.set_param = impl_set_param,
|
||||||
|
.request_state = impl_request_state,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
populate_properties (WpImplEndpointLink * self, WpProperties *global_props)
|
||||||
|
{
|
||||||
|
WpEndpointLinkPrivate *priv =
|
||||||
|
wp_endpoint_link_get_instance_private (WP_ENDPOINT_LINK (self));
|
||||||
|
|
||||||
|
g_clear_pointer (&priv->properties, wp_properties_unref);
|
||||||
|
priv->properties = wp_si_link_get_properties (self->item);
|
||||||
|
priv->properties = wp_properties_ensure_unique_owner (priv->properties);
|
||||||
|
wp_properties_update (priv->properties, global_props);
|
||||||
|
|
||||||
|
self->info.props = priv->properties ?
|
||||||
|
(struct spa_dict *) wp_properties_peek_dict (priv->properties) : NULL;
|
||||||
|
|
||||||
|
g_object_notify (G_OBJECT (self), "properties");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_si_link_properties_changed (WpSiLink * item, WpImplEndpointLink * self)
|
||||||
|
{
|
||||||
|
populate_properties (self, wp_proxy_get_global_properties (WP_PROXY (self)));
|
||||||
|
|
||||||
|
self->info.change_mask = PW_ENDPOINT_LINK_CHANGE_MASK_PROPS;
|
||||||
|
pw_endpoint_link_emit_info (&self->hooks, &self->info);
|
||||||
|
self->info.change_mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_si_link_state_changed (WpSiLink * item, WpEndpointLinkState state,
|
||||||
|
const gchar * error, WpImplEndpointLink * self)
|
||||||
|
{
|
||||||
|
WpEndpointLinkState old_state = self->info.state;
|
||||||
|
|
||||||
|
self->info.state = state;
|
||||||
|
self->info.error = g_strdup (error);
|
||||||
|
|
||||||
|
self->info.change_mask = PW_ENDPOINT_LINK_CHANGE_MASK_STATE;
|
||||||
|
pw_endpoint_link_emit_info (&self->hooks, &self->info);
|
||||||
|
self->info.change_mask = 0;
|
||||||
|
|
||||||
|
g_signal_emit (self, signals[SIGNAL_STATE_CHANGED], 0, old_state, state, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_impl_endpoint_link_init (WpImplEndpointLink * self)
|
||||||
|
{
|
||||||
|
/* reuse the parent's private to optimize memory usage and to be able
|
||||||
|
to re-use some of the parent's methods without reimplementing them */
|
||||||
|
WpEndpointLinkPrivate *priv =
|
||||||
|
wp_endpoint_link_get_instance_private (WP_ENDPOINT_LINK (self));
|
||||||
|
|
||||||
|
self->iface = SPA_INTERFACE_INIT (
|
||||||
|
PW_TYPE_INTERFACE_EndpointLink,
|
||||||
|
PW_VERSION_ENDPOINT_LINK,
|
||||||
|
&impl_endpoint_link, self);
|
||||||
|
spa_hook_list_init (&self->hooks);
|
||||||
|
|
||||||
|
priv->iface = (struct pw_endpoint_link *) &self->iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_impl_endpoint_link_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
WpImplEndpointLink *self = WP_IMPL_ENDPOINT_LINK (object);
|
||||||
|
WpEndpointLinkPrivate *priv =
|
||||||
|
wp_endpoint_link_get_instance_private (WP_ENDPOINT_LINK (self));
|
||||||
|
|
||||||
|
g_free (self->info.error);
|
||||||
|
priv->info = NULL;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (wp_impl_endpoint_link_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_impl_endpoint_link_set_property (GObject * object, guint property_id,
|
||||||
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
WpImplEndpointLink *self = WP_IMPL_ENDPOINT_LINK (object);
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case IMPL_PROP_ITEM:
|
||||||
|
self->item = g_value_get_object (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_impl_endpoint_link_get_property (GObject * object, guint property_id,
|
||||||
|
GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
WpImplEndpointLink *self = WP_IMPL_ENDPOINT_LINK (object);
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case IMPL_PROP_ITEM:
|
||||||
|
g_value_set_object (value, self->item);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_impl_endpoint_link_augment (WpProxy * proxy, WpProxyFeatures features)
|
||||||
|
{
|
||||||
|
WpImplEndpointLink *self = WP_IMPL_ENDPOINT_LINK (proxy);
|
||||||
|
WpEndpointLinkPrivate *priv =
|
||||||
|
wp_endpoint_link_get_instance_private (WP_ENDPOINT_LINK (self));
|
||||||
|
g_autoptr (GVariant) info = NULL;
|
||||||
|
g_autoptr (GVariantIter) immutable_props = NULL;
|
||||||
|
g_autoptr (WpProperties) props = NULL;
|
||||||
|
|
||||||
|
/* PW_PROXY depends on BOUND */
|
||||||
|
if (features & WP_PROXY_FEATURE_PW_PROXY)
|
||||||
|
features |= WP_PROXY_FEATURE_BOUND;
|
||||||
|
|
||||||
|
/* BOUND depends on INFO */
|
||||||
|
if (features & WP_PROXY_FEATURE_BOUND)
|
||||||
|
features |= WP_PROXY_FEATURE_INFO;
|
||||||
|
|
||||||
|
if (features & WP_PROXY_FEATURE_INFO) {
|
||||||
|
guchar state;
|
||||||
|
const gchar *key, *value;
|
||||||
|
WpSiStream *stream;
|
||||||
|
|
||||||
|
/* get info from the interface */
|
||||||
|
info = wp_si_link_get_registration_info (self->item);
|
||||||
|
g_variant_get (info, "(ya{ss})", &state, &immutable_props);
|
||||||
|
|
||||||
|
/* associate with the session, the endpoints and the streams */
|
||||||
|
self->info.session_id = wp_session_item_get_associated_proxy_id (
|
||||||
|
WP_SESSION_ITEM (self->item), WP_TYPE_SESSION);
|
||||||
|
|
||||||
|
stream = wp_si_link_get_out_stream (self->item);
|
||||||
|
self->info.output_endpoint_id = wp_session_item_get_associated_proxy_id (
|
||||||
|
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT);
|
||||||
|
self->info.output_stream_id = wp_session_item_get_associated_proxy_id (
|
||||||
|
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT_STREAM);
|
||||||
|
|
||||||
|
stream = wp_si_link_get_in_stream (self->item);
|
||||||
|
self->info.input_endpoint_id = wp_session_item_get_associated_proxy_id (
|
||||||
|
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT);
|
||||||
|
self->info.input_stream_id = wp_session_item_get_associated_proxy_id (
|
||||||
|
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT_STREAM);
|
||||||
|
|
||||||
|
/* construct export properties (these will come back through
|
||||||
|
the registry and appear in wp_proxy_get_global_properties) */
|
||||||
|
props = wp_properties_new_empty ();
|
||||||
|
wp_properties_setf (props, PW_KEY_SESSION_ID, "%d", self->info.session_id);
|
||||||
|
wp_properties_setf (props, PW_KEY_ENDPOINT_LINK_OUTPUT_ENDPOINT, "%d",
|
||||||
|
self->info.output_endpoint_id);
|
||||||
|
wp_properties_setf (props, PW_KEY_ENDPOINT_LINK_OUTPUT_STREAM, "%d",
|
||||||
|
self->info.output_stream_id);
|
||||||
|
wp_properties_setf (props, PW_KEY_ENDPOINT_LINK_INPUT_ENDPOINT, "%d",
|
||||||
|
self->info.input_endpoint_id);
|
||||||
|
wp_properties_setf (props, PW_KEY_ENDPOINT_LINK_INPUT_STREAM, "%d",
|
||||||
|
self->info.input_stream_id);
|
||||||
|
|
||||||
|
/* populate immutable (global) properties */
|
||||||
|
while (g_variant_iter_next (immutable_props, "{&s&s}", &key, &value))
|
||||||
|
wp_properties_set (props, key, value);
|
||||||
|
|
||||||
|
/* populate standard properties */
|
||||||
|
populate_properties (self, props);
|
||||||
|
|
||||||
|
/* subscribe to changes */
|
||||||
|
g_signal_connect_object (self->item, "link-properties-changed",
|
||||||
|
G_CALLBACK (on_si_link_properties_changed), self, 0);
|
||||||
|
g_signal_connect_object (self->item, "link-state-changed",
|
||||||
|
G_CALLBACK (on_si_link_state_changed), self, 0);
|
||||||
|
|
||||||
|
/* finalize info struct */
|
||||||
|
self->info.version = PW_VERSION_ENDPOINT_LINK_INFO;
|
||||||
|
self->info.state = state;
|
||||||
|
self->info.error = NULL;
|
||||||
|
self->info.params = NULL;
|
||||||
|
self->info.n_params = 0;
|
||||||
|
priv->info = &self->info;
|
||||||
|
g_object_notify (G_OBJECT (self), "info");
|
||||||
|
|
||||||
|
wp_proxy_set_feature_ready (WP_PROXY (self), WP_PROXY_FEATURE_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (features & WP_PROXY_FEATURE_BOUND) {
|
||||||
|
g_autoptr (WpCore) core = wp_proxy_get_core (proxy);
|
||||||
|
struct pw_core *pw_core = wp_core_get_pw_core (core);
|
||||||
|
|
||||||
|
/* no pw_core -> we are not connected */
|
||||||
|
if (!pw_core) {
|
||||||
|
wp_proxy_augment_error (proxy, g_error_new (WP_DOMAIN_LIBRARY,
|
||||||
|
WP_LIBRARY_ERROR_OPERATION_FAILED,
|
||||||
|
"The WirePlumber core is not connected; "
|
||||||
|
"object cannot be exported to PipeWire"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_proxy_set_pw_proxy (proxy, pw_core_export (pw_core,
|
||||||
|
PW_TYPE_INTERFACE_EndpointLink,
|
||||||
|
wp_properties_peek_dict (props),
|
||||||
|
priv->iface, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_impl_endpoint_link_class_init (WpImplEndpointLinkClass * klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = (GObjectClass *) klass;
|
||||||
|
WpProxyClass *proxy_class = (WpProxyClass *) klass;
|
||||||
|
|
||||||
|
object_class->finalize = wp_impl_endpoint_link_finalize;
|
||||||
|
object_class->set_property = wp_impl_endpoint_link_set_property;
|
||||||
|
object_class->get_property = wp_impl_endpoint_link_get_property;
|
||||||
|
|
||||||
|
proxy_class->augment = wp_impl_endpoint_link_augment;
|
||||||
|
|
||||||
|
proxy_class->pw_proxy_created = NULL;
|
||||||
|
proxy_class->param = NULL;
|
||||||
|
|
||||||
|
g_object_class_install_property (object_class, IMPL_PROP_ITEM,
|
||||||
|
g_param_spec_object ("item", "item", "item", WP_TYPE_SI_LINK,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||||
|
}
|
||||||
|
|
||||||
|
WpImplEndpointLink *
|
||||||
|
wp_impl_endpoint_link_new (WpCore * core, WpSiLink * item)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (WP_IS_CORE (core), NULL);
|
||||||
|
|
||||||
|
return g_object_new (WP_TYPE_IMPL_ENDPOINT_LINK,
|
||||||
|
"core", core,
|
||||||
|
"item", item,
|
||||||
|
NULL);
|
||||||
|
}
|
60
lib/wp/endpoint-link.h
Normal file
60
lib/wp/endpoint-link.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/* WirePlumber
|
||||||
|
*
|
||||||
|
* Copyright © 2020 Collabora Ltd.
|
||||||
|
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WIREPLUMBER_ENDPOINT_LINK_H__
|
||||||
|
#define __WIREPLUMBER_ENDPOINT_LINK_H__
|
||||||
|
|
||||||
|
#include "proxy.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WpEndpointLinkState:
|
||||||
|
* @WP_ENDPOINT_LINK_STATE_ERROR:
|
||||||
|
* @WP_ENDPOINT_LINK_STATE_PREPARING:
|
||||||
|
* @WP_ENDPOINT_LINK_STATE_INACTIVE:
|
||||||
|
* @WP_ENDPOINT_LINK_STATE_ACTIVE:
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
WP_ENDPOINT_LINK_STATE_ERROR = -1,
|
||||||
|
WP_ENDPOINT_LINK_STATE_PREPARING,
|
||||||
|
WP_ENDPOINT_LINK_STATE_INACTIVE,
|
||||||
|
WP_ENDPOINT_LINK_STATE_ACTIVE,
|
||||||
|
} WpEndpointLinkState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WP_TYPE_ENDPOINT_LINK:
|
||||||
|
*
|
||||||
|
* The #WpEndpointLink #GType
|
||||||
|
*/
|
||||||
|
#define WP_TYPE_ENDPOINT_LINK (wp_endpoint_link_get_type ())
|
||||||
|
WP_API
|
||||||
|
G_DECLARE_DERIVABLE_TYPE (WpEndpointLink, wp_endpoint_link,
|
||||||
|
WP, ENDPOINT_LINK, WpProxy)
|
||||||
|
|
||||||
|
struct _WpEndpointLinkClass
|
||||||
|
{
|
||||||
|
WpProxyClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
WP_API
|
||||||
|
void wp_endpoint_link_get_linked_object_ids (WpEndpointLink * self,
|
||||||
|
guint32 * output_endpoint, guint32 * output_stream,
|
||||||
|
guint32 * input_endpoint, guint32 * input_stream);
|
||||||
|
|
||||||
|
WP_API
|
||||||
|
WpEndpointLinkState wp_endpoint_link_get_state (WpEndpointLink * self,
|
||||||
|
const gchar ** error);
|
||||||
|
|
||||||
|
WP_API
|
||||||
|
void wp_endpoint_link_request_state (WpEndpointLink * self,
|
||||||
|
WpEndpointLinkState target);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
@@ -5,6 +5,7 @@ wp_lib_sources = files(
|
|||||||
'core.c',
|
'core.c',
|
||||||
'device.c',
|
'device.c',
|
||||||
'endpoint.c',
|
'endpoint.c',
|
||||||
|
'endpoint-link.c',
|
||||||
'endpoint-stream.c',
|
'endpoint-stream.c',
|
||||||
'error.c',
|
'error.c',
|
||||||
'factory.c',
|
'factory.c',
|
||||||
@@ -32,6 +33,7 @@ wp_lib_headers = files(
|
|||||||
'defs.h',
|
'defs.h',
|
||||||
'device.h',
|
'device.h',
|
||||||
'endpoint.h',
|
'endpoint.h',
|
||||||
|
'endpoint-link.h',
|
||||||
'endpoint-stream.h',
|
'endpoint-stream.h',
|
||||||
'error.h',
|
'error.h',
|
||||||
'factory.h',
|
'factory.h',
|
||||||
|
@@ -192,6 +192,14 @@ G_DECLARE_FINAL_TYPE (WpImplEndpointStream, wp_impl_endpoint_stream,
|
|||||||
WpImplEndpointStream * wp_impl_endpoint_stream_new (WpCore * core,
|
WpImplEndpointStream * wp_impl_endpoint_stream_new (WpCore * core,
|
||||||
WpSiStream * item);
|
WpSiStream * item);
|
||||||
|
|
||||||
|
/* impl endpoint link */
|
||||||
|
|
||||||
|
#define WP_TYPE_IMPL_ENDPOINT_LINK (wp_impl_endpoint_link_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (WpImplEndpointLink, wp_impl_endpoint_link,
|
||||||
|
WP, IMPL_ENDPOINT_LINK, WpEndpointLink)
|
||||||
|
|
||||||
|
WpImplEndpointLink * wp_impl_endpoint_link_new (WpCore * core, WpSiLink * item);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "si-interfaces.h"
|
#include "si-interfaces.h"
|
||||||
|
#include "wpenums.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WpSiEndpoint:
|
* WpSiEndpoint:
|
||||||
@@ -228,6 +229,46 @@ G_DEFINE_INTERFACE (WpSiLink, wp_si_link, WP_TYPE_SESSION_ITEM)
|
|||||||
static void
|
static void
|
||||||
wp_si_link_default_init (WpSiLinkInterface * iface)
|
wp_si_link_default_init (WpSiLinkInterface * iface)
|
||||||
{
|
{
|
||||||
|
g_signal_new ("link-properties-changed", G_TYPE_FROM_INTERFACE (iface),
|
||||||
|
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||||
|
g_signal_new ("link-state-changed", G_TYPE_FROM_INTERFACE (iface),
|
||||||
|
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2,
|
||||||
|
WP_TYPE_ENDPOINT_LINK_STATE, G_TYPE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wp_si_link_get_registration_info: (virtual get_registration_info)
|
||||||
|
* @self: the session item
|
||||||
|
*
|
||||||
|
* This should return information that is used for registering the link,
|
||||||
|
* as a GVariant tuple of type (ya{ss}) that contains, in order:
|
||||||
|
* - y: the link's initial state (#WpEndpointLinkState)
|
||||||
|
* - a{ss}: additional properties to be added to the list of global properties
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): registration info for the link
|
||||||
|
*/
|
||||||
|
GVariant *
|
||||||
|
wp_si_link_get_registration_info (WpSiLink * self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (WP_IS_SI_LINK (self), NULL);
|
||||||
|
g_return_val_if_fail (WP_SI_LINK_GET_IFACE (self)->get_registration_info, NULL);
|
||||||
|
|
||||||
|
return WP_SI_LINK_GET_IFACE (self)->get_registration_info (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wp_si_link_get_properties: (virtual get_properties)
|
||||||
|
* @self: the session item
|
||||||
|
*
|
||||||
|
* Returns: (transfer full) (nullable): the properties of the link
|
||||||
|
*/
|
||||||
|
WpProperties *
|
||||||
|
wp_si_link_get_properties (WpSiLink * self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (WP_IS_SI_LINK (self), NULL);
|
||||||
|
g_return_val_if_fail (WP_SI_LINK_GET_IFACE (self)->get_properties, NULL);
|
||||||
|
|
||||||
|
return WP_SI_LINK_GET_IFACE (self)->get_properties (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -259,3 +300,19 @@ wp_si_link_get_in_stream (WpSiLink * self)
|
|||||||
|
|
||||||
return WP_SI_LINK_GET_IFACE (self)->get_in_stream (self);
|
return WP_SI_LINK_GET_IFACE (self)->get_in_stream (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wp_si_link_request_state: (virtual request_state)
|
||||||
|
* @self: the session item
|
||||||
|
* @target: the desired target state of the link
|
||||||
|
*
|
||||||
|
* Requests a state change on the link
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
wp_si_link_request_state (WpSiLink * self, WpEndpointLinkState target)
|
||||||
|
{
|
||||||
|
g_return_if_fail (WP_IS_SI_LINK (self));
|
||||||
|
g_return_if_fail (WP_SI_LINK_GET_IFACE (self)->request_state);
|
||||||
|
|
||||||
|
WP_SI_LINK_GET_IFACE (self)->request_state (self, target);
|
||||||
|
}
|
||||||
|
@@ -12,13 +12,12 @@
|
|||||||
#include "session-item.h"
|
#include "session-item.h"
|
||||||
#include "properties.h"
|
#include "properties.h"
|
||||||
#include "endpoint.h"
|
#include "endpoint.h"
|
||||||
|
#include "endpoint-link.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
typedef struct _WpSiStream WpSiStream;
|
typedef struct _WpSiStream WpSiStream;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WP_TYPE_SI_ENDPOINT:
|
* WP_TYPE_SI_ENDPOINT:
|
||||||
*
|
*
|
||||||
@@ -120,16 +119,30 @@ struct _WpSiLinkInterface
|
|||||||
{
|
{
|
||||||
GTypeInterface interface;
|
GTypeInterface interface;
|
||||||
|
|
||||||
|
GVariant * (*get_registration_info) (WpSiLink * self);
|
||||||
|
WpProperties * (*get_properties) (WpSiLink * self);
|
||||||
|
|
||||||
WpSiStream * (*get_out_stream) (WpSiLink * self);
|
WpSiStream * (*get_out_stream) (WpSiLink * self);
|
||||||
WpSiStream * (*get_in_stream) (WpSiLink * self);
|
WpSiStream * (*get_in_stream) (WpSiLink * self);
|
||||||
|
|
||||||
|
void (*request_state) (WpSiLink * self, WpEndpointLinkState target);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
WP_API
|
||||||
|
GVariant * wp_si_link_get_registration_info (WpSiLink * self);
|
||||||
|
|
||||||
|
WP_API
|
||||||
|
WpProperties * wp_si_link_get_properties (WpSiLink * self);
|
||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
WpSiStream * wp_si_link_get_out_stream (WpSiLink * self);
|
WpSiStream * wp_si_link_get_out_stream (WpSiLink * self);
|
||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
WpSiStream * wp_si_link_get_in_stream (WpSiLink * self);
|
WpSiStream * wp_si_link_get_in_stream (WpSiLink * self);
|
||||||
|
|
||||||
|
WP_API
|
||||||
|
void wp_si_link_request_state (WpSiLink * self, WpEndpointLinkState target);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "endpoint.h"
|
#include "endpoint.h"
|
||||||
|
#include "endpoint-link.h"
|
||||||
#include "endpoint-stream.h"
|
#include "endpoint-stream.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "factory.h"
|
#include "factory.h"
|
||||||
|
Reference in New Issue
Block a user