mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2025-12-21 15:10:04 +01:00
599 lines
18 KiB
C
599 lines
18 KiB
C
/* WirePlumber
|
|
*
|
|
* Copyright © 2020 Collabora Ltd.
|
|
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
/**
|
|
* SECTION: endpoint-link
|
|
* @title: PipeWire Endpoint Link
|
|
*/
|
|
|
|
#define G_LOG_DOMAIN "wp-endpoint-link"
|
|
|
|
#include "endpoint-link.h"
|
|
#include "session.h"
|
|
#include "debug.h"
|
|
#include "error.h"
|
|
#include "wpenums.h"
|
|
#include "private/pipewire-object-mixin.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};
|
|
|
|
static void wp_endpoint_link_pw_object_mixin_priv_interface_init (
|
|
WpPwObjectMixinPrivInterface * iface);
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
G_DEFINE_TYPE_WITH_CODE (WpEndpointLink, wp_endpoint_link, WP_TYPE_GLOBAL_PROXY,
|
|
G_IMPLEMENT_INTERFACE (WP_TYPE_PIPEWIRE_OBJECT,
|
|
wp_pw_object_mixin_object_interface_init)
|
|
G_IMPLEMENT_INTERFACE (WP_TYPE_PW_OBJECT_MIXIN_PRIV,
|
|
wp_endpoint_link_pw_object_mixin_priv_interface_init));
|
|
|
|
static void
|
|
wp_endpoint_link_init (WpEndpointLink * self)
|
|
{
|
|
}
|
|
|
|
static void
|
|
wp_endpoint_link_activate_execute_step (WpObject * object,
|
|
WpFeatureActivationTransition * transition, guint step,
|
|
WpObjectFeatures missing)
|
|
{
|
|
switch (step) {
|
|
case WP_PW_OBJECT_MIXIN_STEP_BIND:
|
|
case WP_TRANSITION_STEP_ERROR:
|
|
/* base class can handle BIND and ERROR */
|
|
WP_OBJECT_CLASS (wp_endpoint_link_parent_class)->
|
|
activate_execute_step (object, transition, step, missing);
|
|
break;
|
|
case WP_PW_OBJECT_MIXIN_STEP_WAIT_INFO:
|
|
/* just wait, info will be emitted anyway after binding */
|
|
break;
|
|
case WP_PW_OBJECT_MIXIN_STEP_CACHE_PARAMS:
|
|
wp_pw_object_mixin_cache_params (object, missing);
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
}
|
|
|
|
static void
|
|
wp_endpoint_link_deactivate (WpObject * object, WpObjectFeatures features)
|
|
{
|
|
wp_pw_object_mixin_deactivate (object, features);
|
|
WP_OBJECT_CLASS (wp_endpoint_link_parent_class)->deactivate (object, features);
|
|
}
|
|
|
|
static const struct pw_endpoint_link_events endpoint_link_events = {
|
|
PW_VERSION_ENDPOINT_LINK_EVENTS,
|
|
.info = (HandleEventInfoFunc(endpoint_link)) wp_pw_object_mixin_handle_event_info,
|
|
.param = wp_pw_object_mixin_handle_event_param,
|
|
};
|
|
|
|
static void
|
|
wp_endpoint_link_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
|
|
{
|
|
wp_pw_object_mixin_handle_pw_proxy_created (proxy, pw_proxy,
|
|
endpoint_link, &endpoint_link_events);
|
|
}
|
|
|
|
static void
|
|
wp_endpoint_link_class_init (WpEndpointLinkClass * klass)
|
|
{
|
|
GObjectClass *object_class = (GObjectClass *) klass;
|
|
WpObjectClass *wpobject_class = (WpObjectClass *) klass;
|
|
WpProxyClass *proxy_class = (WpProxyClass *) klass;
|
|
|
|
object_class->get_property = wp_pw_object_mixin_get_property;
|
|
|
|
wpobject_class->get_supported_features =
|
|
wp_pw_object_mixin_get_supported_features;
|
|
wpobject_class->activate_get_next_step =
|
|
wp_pw_object_mixin_activate_get_next_step;
|
|
wpobject_class->activate_execute_step =
|
|
wp_endpoint_link_activate_execute_step;
|
|
wpobject_class->deactivate = wp_endpoint_link_deactivate;
|
|
|
|
proxy_class->pw_iface_type = PW_TYPE_INTERFACE_EndpointLink;
|
|
proxy_class->pw_iface_version = PW_VERSION_ENDPOINT_LINK;
|
|
proxy_class->pw_proxy_created = wp_endpoint_link_pw_proxy_created;
|
|
proxy_class->pw_proxy_destroyed =
|
|
wp_pw_object_mixin_handle_pw_proxy_destroyed;
|
|
|
|
wp_pw_object_mixin_class_override_properties (object_class);
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
static void
|
|
wp_endpoint_link_process_info (gpointer instance, gpointer old_info, gpointer i)
|
|
{
|
|
const struct pw_endpoint_link_info *info = i;
|
|
|
|
if (info->change_mask & PW_ENDPOINT_LINK_CHANGE_MASK_STATE) {
|
|
WpEndpointLinkState old_state = old_info ?
|
|
(WpEndpointLinkState) ((struct pw_endpoint_link_info *) old_info)->state
|
|
: WP_ENDPOINT_LINK_STATE_ERROR;
|
|
g_signal_emit (instance, signals[SIGNAL_STATE_CHANGED], 0,
|
|
old_state, info->state, info->error);
|
|
}
|
|
}
|
|
|
|
static gint
|
|
wp_endpoint_link_enum_params (gpointer instance, guint32 id,
|
|
guint32 start, guint32 num, WpSpaPod *filter)
|
|
{
|
|
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (instance);
|
|
return pw_endpoint_link_enum_params (d->iface, 0, id, start, num,
|
|
filter ? wp_spa_pod_get_spa_pod (filter) : NULL);
|
|
}
|
|
|
|
static gint
|
|
wp_endpoint_link_set_param (gpointer instance, guint32 id, guint32 flags,
|
|
WpSpaPod * param)
|
|
{
|
|
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (instance);
|
|
return pw_endpoint_link_set_param (d->iface, id, flags,
|
|
wp_spa_pod_get_spa_pod (param));
|
|
}
|
|
|
|
static void
|
|
wp_endpoint_link_pw_object_mixin_priv_interface_init (
|
|
WpPwObjectMixinPrivInterface * iface)
|
|
{
|
|
wp_pw_object_mixin_priv_interface_info_init (iface,
|
|
endpoint_link, ENDPOINT_LINK);
|
|
iface->process_info = wp_endpoint_link_process_info;
|
|
iface->enum_params = wp_endpoint_link_enum_params;
|
|
iface->set_param = wp_endpoint_link_set_param;
|
|
}
|
|
|
|
/**
|
|
* wp_endpoint_link_get_linked_object_ids:
|
|
* @self: the endpoint link
|
|
* @output_endpoint: (out) (optional): the bound id of the output (source)
|
|
* endpoint
|
|
* @input_endpoint: (out) (optional): the bound id of the input (sink)
|
|
* endpoint
|
|
*
|
|
* Retrieves the ids of the objects that are linked by this endpoint link
|
|
*
|
|
* Note: Using this method requires %WP_PIPEWIRE_OBJECT_FEATURE_INFO
|
|
*/
|
|
void
|
|
wp_endpoint_link_get_linked_object_ids (WpEndpointLink * self,
|
|
guint32 * output_endpoint, guint32 * input_endpoint)
|
|
{
|
|
g_return_if_fail (WP_IS_ENDPOINT_LINK (self));
|
|
|
|
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
|
|
struct pw_endpoint_link_info *info = d->info;
|
|
g_return_if_fail (info);
|
|
|
|
if (output_endpoint)
|
|
*output_endpoint = info->output_endpoint_id;
|
|
if (input_endpoint)
|
|
*input_endpoint = info->input_endpoint_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_PIPEWIRE_OBJECT_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);
|
|
|
|
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
|
|
struct pw_endpoint_link_info *info = d->info;
|
|
g_return_val_if_fail (info, WP_ENDPOINT_LINK_STATE_ERROR);
|
|
|
|
if (error)
|
|
*error = info->error;
|
|
return (WpEndpointLinkState) 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_BOUND
|
|
*/
|
|
void
|
|
wp_endpoint_link_request_state (WpEndpointLink * self,
|
|
WpEndpointLinkState target)
|
|
{
|
|
g_return_if_fail (WP_IS_ENDPOINT_LINK (self));
|
|
|
|
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
|
|
g_return_if_fail (d->iface);
|
|
|
|
pw_endpoint_link_request_state (d->iface,
|
|
(enum pw_endpoint_link_state) target);
|
|
}
|
|
|
|
/* WpImplEndpointLink */
|
|
|
|
enum {
|
|
IMPL_PROP_0,
|
|
IMPL_PROP_ITEM,
|
|
};
|
|
|
|
struct _WpImplEndpointLink
|
|
{
|
|
WpEndpointLink parent;
|
|
|
|
struct spa_interface iface;
|
|
struct pw_endpoint_link_info info;
|
|
WpProperties *immutable_props;
|
|
|
|
WpSiLink *item;
|
|
};
|
|
|
|
static void wp_endpoint_link_impl_pw_object_mixin_priv_interface_init (
|
|
WpPwObjectMixinPrivInterface * iface);
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (WpImplEndpointLink, wp_impl_endpoint_link, WP_TYPE_ENDPOINT_LINK,
|
|
G_IMPLEMENT_INTERFACE (WP_TYPE_PW_OBJECT_MIXIN_PRIV,
|
|
wp_endpoint_link_impl_pw_object_mixin_priv_interface_init))
|
|
|
|
static void
|
|
on_item_activated (WpSessionItem * item, GAsyncResult * res, gpointer data)
|
|
{
|
|
WpImplEndpointLink *self = WP_IMPL_ENDPOINT_LINK (data);
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
if (!wp_object_activate_finish (WP_OBJECT (item), res, &error)) {
|
|
wp_message_object (self, "failed to activate link: %s", error->message);
|
|
self->info.error = g_strdup (error->message);
|
|
/* on_si_link_flags_changed() will be called right after we return,
|
|
taking care of the rest... */
|
|
}
|
|
}
|
|
|
|
static int
|
|
impl_request_state (void *object, enum pw_endpoint_link_state state)
|
|
{
|
|
WpImplEndpointLink *self = WP_IMPL_ENDPOINT_LINK (object);
|
|
int ret = 0;
|
|
|
|
if (state == self->info.state)
|
|
return ret;
|
|
|
|
switch (state) {
|
|
case PW_ENDPOINT_LINK_STATE_ACTIVE:
|
|
wp_object_activate (WP_OBJECT (self->item),
|
|
WP_SESSION_ITEM_FEATURE_ACTIVE, NULL,
|
|
(GAsyncReadyCallback) on_item_activated, self);
|
|
break;
|
|
case PW_ENDPOINT_LINK_STATE_INACTIVE:
|
|
wp_object_deactivate (WP_OBJECT (self->item),
|
|
WP_SESSION_ITEM_FEATURE_ACTIVE);
|
|
break;
|
|
default:
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const struct pw_endpoint_link_methods impl_endpoint_link = {
|
|
PW_VERSION_ENDPOINT_LINK_METHODS,
|
|
.add_listener =
|
|
(ImplAddListenerFunc(endpoint_link)) wp_pw_object_mixin_impl_add_listener,
|
|
.subscribe_params = wp_pw_object_mixin_impl_subscribe_params,
|
|
.enum_params = wp_pw_object_mixin_impl_enum_params,
|
|
.set_param = wp_pw_object_mixin_impl_set_param,
|
|
.request_state = impl_request_state,
|
|
};
|
|
|
|
static void
|
|
wp_impl_endpoint_link_init (WpImplEndpointLink * self)
|
|
{
|
|
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
|
|
|
|
self->iface = SPA_INTERFACE_INIT (
|
|
PW_TYPE_INTERFACE_EndpointLink,
|
|
PW_VERSION_ENDPOINT_LINK,
|
|
&impl_endpoint_link, self);
|
|
|
|
d->info = &self->info;
|
|
d->iface = &self->iface;
|
|
}
|
|
|
|
static void
|
|
populate_properties (WpImplEndpointLink * self)
|
|
{
|
|
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
|
|
|
|
g_clear_pointer (&d->properties, wp_properties_unref);
|
|
d->properties = wp_si_link_get_properties (self->item);
|
|
if (!d->properties)
|
|
d->properties = wp_properties_new_empty ();
|
|
d->properties = wp_properties_ensure_unique_owner (d->properties);
|
|
wp_properties_update (d->properties, self->immutable_props);
|
|
|
|
self->info.props = (struct spa_dict *) wp_properties_peek_dict (d->properties);
|
|
}
|
|
|
|
static void
|
|
on_si_link_properties_changed (WpSiLink * item, WpImplEndpointLink * self)
|
|
{
|
|
populate_properties (self);
|
|
wp_pw_object_mixin_notify_info (self, PW_ENDPOINT_LINK_CHANGE_MASK_PROPS);
|
|
}
|
|
|
|
static void
|
|
on_si_link_features_changed (WpSiLink * item, GParamSpec * param,
|
|
WpImplEndpointLink * self)
|
|
{
|
|
enum pw_endpoint_link_state old_state = self->info.state;
|
|
guint features = wp_object_get_active_features (WP_OBJECT (item));
|
|
|
|
if (features & WP_SESSION_ITEM_FEATURE_ACTIVE)
|
|
self->info.state = PW_ENDPOINT_LINK_STATE_ACTIVE;
|
|
else
|
|
self->info.state = PW_ENDPOINT_LINK_STATE_INACTIVE;
|
|
|
|
if (old_state != self->info.state) {
|
|
wp_pw_object_mixin_notify_info (self, PW_ENDPOINT_LINK_CHANGE_MASK_STATE);
|
|
g_signal_emit (self, signals[SIGNAL_STATE_CHANGED], 0,
|
|
old_state, self->info.state, self->info.error);
|
|
}
|
|
}
|
|
|
|
static void
|
|
wp_impl_endpoint_link_constructed (GObject * object)
|
|
{
|
|
WpImplEndpointLink *self = WP_IMPL_ENDPOINT_LINK (object);
|
|
g_autoptr (GVariant) info = NULL;
|
|
g_autoptr (GVariantIter) immutable_props = NULL;
|
|
const gchar *key, *value;
|
|
g_autoptr (WpSiPortInfo) si_out = NULL;
|
|
g_autoptr (WpSiPortInfo) si_in = NULL;
|
|
|
|
self->info.version = PW_VERSION_ENDPOINT_LINK_INFO;
|
|
self->info.error = NULL;
|
|
self->info.params = NULL;
|
|
self->info.n_params = 0;
|
|
|
|
/* get info from the interface */
|
|
info = wp_si_link_get_registration_info (self->item);
|
|
g_variant_get (info, "a{ss}", &immutable_props);
|
|
|
|
/* get the current state */
|
|
self->info.state =
|
|
(wp_object_get_active_features (WP_OBJECT (self->item))
|
|
& WP_SESSION_ITEM_FEATURE_ACTIVE)
|
|
? PW_ENDPOINT_LINK_STATE_ACTIVE
|
|
: PW_ENDPOINT_LINK_STATE_INACTIVE;
|
|
|
|
/* associate with the session and the endpoints */
|
|
self->info.session_id = wp_session_item_get_associated_proxy_id (
|
|
WP_SESSION_ITEM (self->item), WP_TYPE_SESSION);
|
|
|
|
si_out = wp_si_link_get_out_item (self->item);
|
|
self->info.output_endpoint_id = wp_session_item_get_associated_proxy_id (
|
|
WP_SESSION_ITEM (si_out), WP_TYPE_ENDPOINT);
|
|
|
|
si_in = wp_si_link_get_in_item (self->item);
|
|
self->info.input_endpoint_id = wp_session_item_get_associated_proxy_id (
|
|
WP_SESSION_ITEM (si_in), WP_TYPE_ENDPOINT);
|
|
|
|
/* construct export properties (these will come back through
|
|
the registry and appear in wp_proxy_get_global_properties) */
|
|
self->immutable_props = wp_properties_new_empty ();
|
|
wp_properties_setf (self->immutable_props,
|
|
PW_KEY_SESSION_ID, "%d", self->info.session_id);
|
|
wp_properties_setf (self->immutable_props,
|
|
PW_KEY_ENDPOINT_LINK_OUTPUT_ENDPOINT, "%d", self->info.output_endpoint_id);
|
|
wp_properties_setf (self->immutable_props,
|
|
PW_KEY_ENDPOINT_LINK_INPUT_ENDPOINT, "%d", self->info.input_endpoint_id);
|
|
|
|
/* populate immutable (global) properties */
|
|
while (g_variant_iter_next (immutable_props, "{&s&s}", &key, &value))
|
|
wp_properties_set (self->immutable_props, key, value);
|
|
|
|
/* populate standard properties */
|
|
populate_properties (self);
|
|
|
|
/* 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, "notify::active-features",
|
|
G_CALLBACK (on_si_link_features_changed), self, 0);
|
|
|
|
wp_object_update_features (WP_OBJECT (self),
|
|
WP_PIPEWIRE_OBJECT_FEATURE_INFO, 0);
|
|
|
|
G_OBJECT_CLASS (wp_impl_endpoint_link_parent_class)->constructed (object);
|
|
}
|
|
|
|
static void
|
|
wp_impl_endpoint_link_dispose (GObject * object)
|
|
{
|
|
WpImplEndpointLink *self = WP_IMPL_ENDPOINT_LINK (object);
|
|
|
|
g_clear_pointer (&self->immutable_props, wp_properties_unref);
|
|
g_clear_pointer (&self->info.error, g_free);
|
|
|
|
wp_object_update_features (WP_OBJECT (self), 0,
|
|
WP_PIPEWIRE_OBJECT_FEATURE_INFO);
|
|
|
|
G_OBJECT_CLASS (wp_impl_endpoint_link_parent_class)->dispose (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_activate_execute_step (WpObject * object,
|
|
WpFeatureActivationTransition * transition, guint step,
|
|
WpObjectFeatures missing)
|
|
{
|
|
WpImplEndpointLink *self = WP_IMPL_ENDPOINT_LINK (object);
|
|
|
|
switch (step) {
|
|
case WP_PW_OBJECT_MIXIN_STEP_BIND: {
|
|
g_autoptr (WpCore) core = wp_object_get_core (object);
|
|
struct pw_core *pw_core = wp_core_get_pw_core (core);
|
|
|
|
/* no pw_core -> we are not connected */
|
|
if (!pw_core) {
|
|
wp_transition_return_error (WP_TRANSITION (transition), g_error_new (
|
|
WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
|
|
"The WirePlumber core is not connected; "
|
|
"object cannot be exported to PipeWire"));
|
|
return;
|
|
}
|
|
|
|
/* bind */
|
|
wp_proxy_set_pw_proxy (WP_PROXY (self), pw_core_export (pw_core,
|
|
PW_TYPE_INTERFACE_EndpointLink,
|
|
wp_properties_peek_dict (self->immutable_props),
|
|
&self->iface, 0));
|
|
break;
|
|
}
|
|
default:
|
|
WP_OBJECT_CLASS (wp_impl_endpoint_link_parent_class)->
|
|
activate_execute_step (object, transition, step, missing);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
wp_impl_endpoint_link_class_init (WpImplEndpointLinkClass * klass)
|
|
{
|
|
GObjectClass *object_class = (GObjectClass *) klass;
|
|
WpObjectClass *wpobject_class = (WpObjectClass *) klass;
|
|
WpProxyClass *proxy_class = (WpProxyClass *) klass;
|
|
|
|
object_class->constructed = wp_impl_endpoint_link_constructed;
|
|
object_class->dispose = wp_impl_endpoint_link_dispose;
|
|
object_class->set_property = wp_impl_endpoint_link_set_property;
|
|
object_class->get_property = wp_impl_endpoint_link_get_property;
|
|
|
|
wpobject_class->activate_execute_step =
|
|
wp_impl_endpoint_link_activate_execute_step;
|
|
|
|
proxy_class->pw_proxy_created = NULL;
|
|
proxy_class->pw_proxy_destroyed = 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));
|
|
}
|
|
|
|
#define pw_endpoint_link_emit(hooks,method,version,...) \
|
|
spa_hook_list_call_simple(hooks, struct pw_endpoint_link_events, \
|
|
method, version, ##__VA_ARGS__)
|
|
|
|
static void
|
|
wp_impl_endpoint_link_emit_info (struct spa_hook_list * hooks, gconstpointer info)
|
|
{
|
|
pw_endpoint_link_emit (hooks, info, 0, info);
|
|
}
|
|
|
|
static void
|
|
wp_impl_endpoint_link_emit_param (struct spa_hook_list * hooks, int seq,
|
|
guint32 id, guint32 index, guint32 next, const struct spa_pod *param)
|
|
{
|
|
pw_endpoint_link_emit (hooks, param, 0, seq, id, index, next, param);
|
|
}
|
|
|
|
static void
|
|
wp_endpoint_link_impl_pw_object_mixin_priv_interface_init (
|
|
WpPwObjectMixinPrivInterface * iface)
|
|
{
|
|
iface->flags |= WP_PW_OBJECT_MIXIN_PRIV_NO_PARAM_CACHE;
|
|
iface->enum_params = NULL;
|
|
iface->set_param = NULL;
|
|
iface->emit_info = wp_impl_endpoint_link_emit_info;
|
|
iface->emit_param = wp_impl_endpoint_link_emit_param;
|
|
}
|
|
|
|
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);
|
|
}
|