mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-08 15:08:04 +02:00
lib: remove WpEndpoint and WpSiEndpoint APIs
This commit is contained in:
parent
d43b55d01e
commit
9004362cda
21 changed files with 11 additions and 1871 deletions
|
|
@ -24,7 +24,6 @@ C API Documentation
|
|||
c_api/device_api.rst
|
||||
c_api/client_api.rst
|
||||
c_api/metadata_api.rst
|
||||
c_api/endpoint_api.rst
|
||||
c_api/spa_device_api.rst
|
||||
c_api/impl_node_api.rst
|
||||
c_api/impl_module_api.rst
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
.. _endpoint_api:
|
||||
|
||||
PipeWire Endpoint
|
||||
=================
|
||||
.. graphviz::
|
||||
:align: center
|
||||
|
||||
digraph inheritance {
|
||||
rankdir=LR;
|
||||
GObject -> WpObject;
|
||||
WpObject -> WpProxy;
|
||||
WpProxy -> WpGlobalProxy;
|
||||
WpGlobalProxy -> WpEndpoint;
|
||||
GInterface -> WpPipewireObject;
|
||||
WpPipewireObject -> WpEndpoint;
|
||||
WpEndpoint -> WpImplEndpoint;
|
||||
}
|
||||
|
||||
.. doxygenstruct:: WpEndpoint
|
||||
|
||||
.. doxygenstruct:: WpImplEndpoint
|
||||
|
||||
.. doxygengroup:: wpendpoint
|
||||
:content-only:
|
||||
|
|
@ -4,7 +4,6 @@ sphinx_files += files(
|
|||
'component_loader_api.rst',
|
||||
'core_api.rst',
|
||||
'device_api.rst',
|
||||
'endpoint_api.rst',
|
||||
'global_proxy_api.rst',
|
||||
'impl_module_api.rst',
|
||||
'impl_node_api.rst',
|
||||
|
|
|
|||
|
|
@ -7,17 +7,12 @@ Session Items Interfaces
|
|||
|
||||
digraph inheritance {
|
||||
rankdir=LR;
|
||||
GInterface -> WpSiEndpoint;
|
||||
GInterface -> WpSiAdapter;
|
||||
GInterface -> WpSiLinkable;
|
||||
GInterface -> WpSiLink;
|
||||
GInterface -> WpSiAcquisition;
|
||||
}
|
||||
|
||||
.. doxygenstruct:: WpSiEndpoint
|
||||
|
||||
.. doxygenstruct:: _WpSiEndpointInterface
|
||||
|
||||
.. doxygenstruct:: WpSiAdapter
|
||||
|
||||
.. doxygenstruct:: _WpSiAdapterInterface
|
||||
|
|
|
|||
|
|
@ -1,698 +0,0 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "wp-endpoint"
|
||||
|
||||
#include "endpoint.h"
|
||||
#include "node.h"
|
||||
#include "object-manager.h"
|
||||
#include "error.h"
|
||||
#include "log.h"
|
||||
#include "wpenums.h"
|
||||
#include "spa-type.h"
|
||||
#include "si-factory.h"
|
||||
#include "private/pipewire-object-mixin.h"
|
||||
|
||||
#include <pipewire/extensions/session-manager.h>
|
||||
#include <pipewire/extensions/session-manager/introspect-funcs.h>
|
||||
#include <spa/utils/result.h>
|
||||
|
||||
/*! \defgroup wpendpoint WpEndpoint */
|
||||
/*!
|
||||
* \struct WpEndpoint
|
||||
*
|
||||
* The WpEndpoint class allows accessing the properties and methods of a
|
||||
* PipeWire endpoint object (`struct pw_endpoint` from the session-manager extension).
|
||||
*
|
||||
* A WpEndpoint is constructed internally when a new endpoint appears on the
|
||||
* PipeWire registry and it is made available through the WpObjectManager API.
|
||||
*
|
||||
* \gproperties
|
||||
*
|
||||
* \gproperty{name, gchar *, G_PARAM_READABLE, The name of the endpoint}
|
||||
*
|
||||
* \gproperty{media-class, gchar *, G_PARAM_READABLE,
|
||||
* The media class of the endpoint (ex. "Audio/Sink")}
|
||||
*
|
||||
* \gproperty{direction, WpDirection, G_PARAM_READABLE,
|
||||
* The direction of the endpoint}
|
||||
*/
|
||||
|
||||
enum {
|
||||
PROP_NAME = WP_PW_OBJECT_MIXIN_PROP_CUSTOM_START,
|
||||
PROP_MEDIA_CLASS,
|
||||
PROP_DIRECTION,
|
||||
};
|
||||
|
||||
typedef struct _WpEndpointPrivate WpEndpointPrivate;
|
||||
struct _WpEndpointPrivate
|
||||
{
|
||||
gint place_holder;
|
||||
};
|
||||
|
||||
static void wp_endpoint_pw_object_mixin_priv_interface_init (
|
||||
WpPwObjectMixinPrivInterface * iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (WpEndpoint, wp_endpoint, WP_TYPE_GLOBAL_PROXY,
|
||||
G_ADD_PRIVATE (WpEndpoint)
|
||||
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_pw_object_mixin_priv_interface_init))
|
||||
|
||||
static void
|
||||
wp_endpoint_init (WpEndpoint * self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wp_endpoint_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, d->info ?
|
||||
((struct pw_endpoint_info *) d->info)->name : NULL);
|
||||
break;
|
||||
case PROP_MEDIA_CLASS:
|
||||
g_value_set_string (value, d->info ?
|
||||
((struct pw_endpoint_info *) d->info)->media_class : NULL);
|
||||
break;
|
||||
case PROP_DIRECTION:
|
||||
g_value_set_enum (value, d->info ?
|
||||
((struct pw_endpoint_info *) d->info)->direction : 0);
|
||||
break;
|
||||
default:
|
||||
wp_pw_object_mixin_get_property (object, property_id, value, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static WpObjectFeatures
|
||||
wp_endpoint_get_supported_features (WpObject * object)
|
||||
{
|
||||
return wp_pw_object_mixin_get_supported_features(object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_endpoint_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_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_deactivate (WpObject * object, WpObjectFeatures features)
|
||||
{
|
||||
wp_pw_object_mixin_deactivate (object, features);
|
||||
WP_OBJECT_CLASS (wp_endpoint_parent_class)->deactivate (object, features);
|
||||
}
|
||||
|
||||
static const struct pw_endpoint_events endpoint_events = {
|
||||
PW_VERSION_ENDPOINT_EVENTS,
|
||||
.info = (HandleEventInfoFunc(endpoint)) wp_pw_object_mixin_handle_event_info,
|
||||
.param = wp_pw_object_mixin_handle_event_param,
|
||||
};
|
||||
|
||||
static void
|
||||
wp_endpoint_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
|
||||
{
|
||||
wp_pw_object_mixin_handle_pw_proxy_created (proxy, pw_proxy,
|
||||
endpoint, &endpoint_events);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_endpoint_pw_proxy_destroyed (WpProxy * proxy)
|
||||
{
|
||||
wp_pw_object_mixin_handle_pw_proxy_destroyed (proxy);
|
||||
|
||||
WP_PROXY_CLASS (wp_endpoint_parent_class)->pw_proxy_destroyed (proxy);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_endpoint_class_init (WpEndpointClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
WpObjectClass *wpobject_class = (WpObjectClass *) klass;
|
||||
WpProxyClass *proxy_class = (WpProxyClass *) klass;
|
||||
|
||||
object_class->get_property = wp_endpoint_get_property;
|
||||
|
||||
wpobject_class->get_supported_features = wp_endpoint_get_supported_features;
|
||||
wpobject_class->activate_get_next_step =
|
||||
wp_pw_object_mixin_activate_get_next_step;
|
||||
wpobject_class->activate_execute_step = wp_endpoint_activate_execute_step;
|
||||
wpobject_class->deactivate = wp_endpoint_deactivate;
|
||||
|
||||
proxy_class->pw_iface_type = PW_TYPE_INTERFACE_Endpoint;
|
||||
proxy_class->pw_iface_version = PW_VERSION_ENDPOINT;
|
||||
proxy_class->pw_proxy_created = wp_endpoint_pw_proxy_created;
|
||||
proxy_class->pw_proxy_destroyed = wp_endpoint_pw_proxy_destroyed;
|
||||
|
||||
wp_pw_object_mixin_class_override_properties (object_class);
|
||||
|
||||
g_object_class_install_property (object_class, PROP_NAME,
|
||||
g_param_spec_string ("name", "name", "name", NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_MEDIA_CLASS,
|
||||
g_param_spec_string ("media-class", "media-class", "media-class", NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_DIRECTION,
|
||||
g_param_spec_enum ("direction", "direction", "direction",
|
||||
WP_TYPE_DIRECTION, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static gint
|
||||
wp_endpoint_enum_params (gpointer instance, guint32 id,
|
||||
guint32 start, guint32 num, WpSpaPod *filter)
|
||||
{
|
||||
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (instance);
|
||||
return pw_endpoint_enum_params (d->iface, 0, id, start, num,
|
||||
filter ? wp_spa_pod_get_spa_pod (filter) : NULL);
|
||||
}
|
||||
|
||||
static gint
|
||||
wp_endpoint_set_param (gpointer instance, guint32 id, guint32 flags,
|
||||
WpSpaPod * param)
|
||||
{
|
||||
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (instance);
|
||||
g_autoptr (WpSpaPod) p = param;
|
||||
return pw_endpoint_set_param (d->iface, id, flags,
|
||||
wp_spa_pod_get_spa_pod (p));
|
||||
}
|
||||
|
||||
static void
|
||||
wp_endpoint_pw_object_mixin_priv_interface_init (
|
||||
WpPwObjectMixinPrivInterface * iface)
|
||||
{
|
||||
wp_pw_object_mixin_priv_interface_info_init (iface, endpoint, ENDPOINT);
|
||||
iface->enum_params = wp_endpoint_enum_params;
|
||||
iface->set_param = wp_endpoint_set_param;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the name of the endpoint
|
||||
* \remarks Requires WP_PIPEWIRE_OBJECT_FEATURE_INFO
|
||||
* \ingroup wpendpoint
|
||||
* \param self the endpoint
|
||||
* \returns the name of the endpoint
|
||||
*/
|
||||
const gchar *
|
||||
wp_endpoint_get_name (WpEndpoint * self)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_ENDPOINT (self), NULL);
|
||||
g_return_val_if_fail (wp_object_get_active_features (WP_OBJECT (self)) &
|
||||
WP_PIPEWIRE_OBJECT_FEATURE_INFO, NULL);
|
||||
|
||||
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
|
||||
return ((struct pw_endpoint_info *) d->info)->name;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the media class of the endpoint (ex. "Audio/Sink")
|
||||
* \remarks Requires WP_PIPEWIRE_OBJECT_FEATURE_INFO
|
||||
* \ingroup wpendpoint
|
||||
* \param self the endpoint
|
||||
* \returns the media class of the endpoint
|
||||
*/
|
||||
const gchar *
|
||||
wp_endpoint_get_media_class (WpEndpoint * self)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_ENDPOINT (self), NULL);
|
||||
g_return_val_if_fail (wp_object_get_active_features (WP_OBJECT (self)) &
|
||||
WP_PIPEWIRE_OBJECT_FEATURE_INFO, NULL);
|
||||
|
||||
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
|
||||
return ((struct pw_endpoint_info *) d->info)->media_class;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the direction of the endpoint
|
||||
* \remarks Requires WP_PIPEWIRE_OBJECT_FEATURE_INFO
|
||||
* \ingroup wpendpoint
|
||||
* \param self the endpoint
|
||||
* \returns the direction of this endpoint
|
||||
*/
|
||||
WpDirection
|
||||
wp_endpoint_get_direction (WpEndpoint * self)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_ENDPOINT (self), 0);
|
||||
g_return_val_if_fail (wp_object_get_active_features (WP_OBJECT (self)) &
|
||||
WP_PIPEWIRE_OBJECT_FEATURE_INFO, 0);
|
||||
|
||||
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
|
||||
return (WpDirection) ((struct pw_endpoint_info *) d->info)->direction;
|
||||
}
|
||||
|
||||
/* WpImplEndpoint */
|
||||
|
||||
enum {
|
||||
IMPL_PROP_0,
|
||||
IMPL_PROP_ITEM,
|
||||
};
|
||||
|
||||
struct _WpImplEndpoint
|
||||
{
|
||||
WpEndpoint parent;
|
||||
|
||||
struct spa_interface iface;
|
||||
struct pw_endpoint_info info;
|
||||
WpProperties *immutable_props;
|
||||
|
||||
WpSiEndpoint *item;
|
||||
};
|
||||
|
||||
static void wp_endpoint_impl_pw_object_mixin_priv_interface_init (
|
||||
WpPwObjectMixinPrivInterface * iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (WpImplEndpoint, wp_impl_endpoint, WP_TYPE_ENDPOINT,
|
||||
G_IMPLEMENT_INTERFACE (WP_TYPE_PW_OBJECT_MIXIN_PRIV,
|
||||
wp_endpoint_impl_pw_object_mixin_priv_interface_init))
|
||||
|
||||
static struct spa_param_info impl_param_info[] = {
|
||||
SPA_PARAM_INFO (SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE),
|
||||
SPA_PARAM_INFO (SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ)
|
||||
};
|
||||
|
||||
static int
|
||||
impl_create_link (void *object, const struct spa_dict *props)
|
||||
{
|
||||
/* not implemented */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct pw_endpoint_methods impl_endpoint = {
|
||||
PW_VERSION_ENDPOINT_METHODS,
|
||||
.add_listener =
|
||||
(ImplAddListenerFunc(endpoint)) 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,
|
||||
.create_link = impl_create_link,
|
||||
};
|
||||
|
||||
static void
|
||||
wp_impl_endpoint_init (WpImplEndpoint * self)
|
||||
{
|
||||
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
|
||||
|
||||
self->iface = SPA_INTERFACE_INIT (
|
||||
PW_TYPE_INTERFACE_Endpoint,
|
||||
PW_VERSION_ENDPOINT,
|
||||
&impl_endpoint, self);
|
||||
|
||||
d->info = &self->info;
|
||||
d->iface = &self->iface;
|
||||
}
|
||||
|
||||
static void
|
||||
populate_properties (WpImplEndpoint * self)
|
||||
{
|
||||
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
|
||||
|
||||
g_clear_pointer (&d->properties, wp_properties_unref);
|
||||
d->properties = wp_si_endpoint_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_endpoint_properties_changed (WpSiEndpoint * item, WpImplEndpoint * self)
|
||||
{
|
||||
populate_properties (self);
|
||||
wp_pw_object_mixin_notify_info (self, PW_ENDPOINT_CHANGE_MASK_PROPS);
|
||||
}
|
||||
|
||||
static void
|
||||
on_node_params_changed (WpNode * node, const gchar *param_name,
|
||||
WpImplEndpoint * self)
|
||||
{
|
||||
if (!g_strcmp0 (param_name, "PropInfo") || !g_strcmp0 (param_name, "Props")) {
|
||||
guint32 param_id = wp_spa_id_value_number (
|
||||
wp_spa_id_value_from_short_name ("Spa:Enum:ParamId", param_name));
|
||||
wp_pw_object_mixin_notify_params_changed (self, param_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_impl_endpoint_constructed (GObject * object)
|
||||
{
|
||||
WpImplEndpoint *self = WP_IMPL_ENDPOINT (object);
|
||||
g_autoptr (GVariant) info = NULL;
|
||||
g_autoptr (GVariantIter) immutable_props = NULL;
|
||||
g_autoptr (WpObject) node = NULL;
|
||||
const gchar *key, *value;
|
||||
guchar direction;
|
||||
|
||||
self->info.version = PW_VERSION_ENDPOINT_INFO;
|
||||
|
||||
info = wp_si_endpoint_get_registration_info (self->item);
|
||||
g_variant_get (info, "(ssya{ss})", &self->info.name,
|
||||
&self->info.media_class, &direction, &immutable_props);
|
||||
|
||||
self->info.direction = (enum pw_direction) direction;
|
||||
|
||||
/* associate with the session (no session anymore, use -1) */
|
||||
self->info.session_id = SPA_ID_INVALID;
|
||||
|
||||
/* construct export properties (these will come back through
|
||||
the registry and appear in wp_proxy_get_global_properties) */
|
||||
self->immutable_props = wp_properties_new (
|
||||
PW_KEY_ENDPOINT_NAME, self->info.name,
|
||||
PW_KEY_MEDIA_CLASS, self->info.media_class,
|
||||
NULL);
|
||||
wp_properties_setf (self->immutable_props, PW_KEY_SESSION_ID,
|
||||
"%d", self->info.session_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, "endpoint-properties-changed",
|
||||
G_CALLBACK (on_si_endpoint_properties_changed), self, 0);
|
||||
|
||||
/* if the item has a node, proxy its ParamProps */
|
||||
node = wp_session_item_get_associated_proxy (
|
||||
WP_SESSION_ITEM (self->item), WP_TYPE_NODE);
|
||||
if (node && (wp_object_get_active_features (node) &
|
||||
WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PROPS)) {
|
||||
self->info.params = impl_param_info;
|
||||
self->info.n_params = G_N_ELEMENTS (impl_param_info);
|
||||
|
||||
g_signal_connect_object (node, "params-changed",
|
||||
G_CALLBACK (on_node_params_changed), self, 0);
|
||||
|
||||
wp_object_update_features (WP_OBJECT (self),
|
||||
WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PROPS, 0);
|
||||
} else {
|
||||
self->info.params = NULL;
|
||||
self->info.n_params = 0;
|
||||
}
|
||||
|
||||
wp_object_update_features (WP_OBJECT (self),
|
||||
WP_PIPEWIRE_OBJECT_FEATURE_INFO, 0);
|
||||
|
||||
G_OBJECT_CLASS (wp_impl_endpoint_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_impl_endpoint_dispose (GObject * object)
|
||||
{
|
||||
WpImplEndpoint *self = WP_IMPL_ENDPOINT (object);
|
||||
|
||||
g_clear_pointer (&self->immutable_props, wp_properties_unref);
|
||||
g_clear_pointer (&self->info.name, g_free);
|
||||
g_clear_pointer (&self->info.media_class, g_free);
|
||||
|
||||
wp_object_update_features (WP_OBJECT (self), 0,
|
||||
WP_PIPEWIRE_OBJECT_FEATURE_INFO |
|
||||
WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PROPS);
|
||||
|
||||
G_OBJECT_CLASS (wp_impl_endpoint_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_impl_endpoint_set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpImplEndpoint *self = WP_IMPL_ENDPOINT (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_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpImplEndpoint *self = WP_IMPL_ENDPOINT (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;
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
STEP_ACTIVATE_NODE = WP_PW_OBJECT_MIXIN_STEP_CUSTOM_START + 1,
|
||||
};
|
||||
|
||||
static guint
|
||||
wp_impl_endpoint_activate_get_next_step (WpObject * object,
|
||||
WpFeatureActivationTransition * transition, guint step,
|
||||
WpObjectFeatures missing)
|
||||
{
|
||||
WpImplEndpoint *self = WP_IMPL_ENDPOINT (object);
|
||||
|
||||
/* before anything else, if the item has a node,
|
||||
cache its props so that enum_params works */
|
||||
if (missing & WP_PIPEWIRE_OBJECT_FEATURES_ALL) {
|
||||
g_autoptr (WpObject) node = wp_session_item_get_associated_proxy (
|
||||
WP_SESSION_ITEM (self->item), WP_TYPE_NODE);
|
||||
|
||||
if (node && (wp_object_get_supported_features (node) &
|
||||
WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PROPS) &&
|
||||
!(wp_object_get_active_features (node) &
|
||||
WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PROPS))
|
||||
return STEP_ACTIVATE_NODE;
|
||||
}
|
||||
|
||||
return WP_OBJECT_CLASS (wp_impl_endpoint_parent_class)->
|
||||
activate_get_next_step (object, transition, step, missing);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_impl_endpoint_node_activated (WpObject * node,
|
||||
GAsyncResult * res, WpTransition * transition)
|
||||
{
|
||||
WpImplEndpoint *self = wp_transition_get_source_object (transition);
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
if (!wp_object_activate_finish (node, res, &error)) {
|
||||
wp_transition_return_error (transition, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
self->info.params = impl_param_info;
|
||||
self->info.n_params = G_N_ELEMENTS (impl_param_info);
|
||||
|
||||
g_signal_connect_object (node, "params-changed",
|
||||
G_CALLBACK (on_node_params_changed), self, 0);
|
||||
|
||||
wp_object_update_features (WP_OBJECT (self),
|
||||
WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PROPS, 0);
|
||||
wp_pw_object_mixin_notify_info (self, PW_ENDPOINT_CHANGE_MASK_PARAMS);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_impl_endpoint_activate_execute_step (WpObject * object,
|
||||
WpFeatureActivationTransition * transition, guint step,
|
||||
WpObjectFeatures missing)
|
||||
{
|
||||
WpImplEndpoint *self = WP_IMPL_ENDPOINT (object);
|
||||
|
||||
switch (step) {
|
||||
case STEP_ACTIVATE_NODE: {
|
||||
g_autoptr (WpObject) node = wp_session_item_get_associated_proxy (
|
||||
WP_SESSION_ITEM (self->item), WP_TYPE_NODE);
|
||||
|
||||
wp_object_activate (node,
|
||||
WP_PROXY_FEATURE_BOUND | WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PROPS,
|
||||
NULL, (GAsyncReadyCallback) wp_impl_endpoint_node_activated,
|
||||
transition);
|
||||
break;
|
||||
}
|
||||
case WP_PW_OBJECT_MIXIN_STEP_BIND: {
|
||||
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
|
||||
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_Endpoint,
|
||||
wp_properties_peek_dict (self->immutable_props),
|
||||
&self->iface, 0));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WP_OBJECT_CLASS (wp_impl_endpoint_parent_class)->
|
||||
activate_execute_step (object, transition, step, missing);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \struct WpImplEndpoint
|
||||
*
|
||||
* \gproperties
|
||||
*
|
||||
* \gproperty{item, WpSiEndpoint *, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY,
|
||||
* The session item that implements this endpoint}
|
||||
*/
|
||||
static void
|
||||
wp_impl_endpoint_class_init (WpImplEndpointClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
WpObjectClass *wpobject_class = (WpObjectClass *) klass;
|
||||
WpProxyClass *proxy_class = (WpProxyClass *) klass;
|
||||
|
||||
object_class->constructed = wp_impl_endpoint_constructed;
|
||||
object_class->dispose = wp_impl_endpoint_dispose;
|
||||
object_class->set_property = wp_impl_endpoint_set_property;
|
||||
object_class->get_property = wp_impl_endpoint_get_property;
|
||||
|
||||
wpobject_class->activate_get_next_step =
|
||||
wp_impl_endpoint_activate_get_next_step;
|
||||
wpobject_class->activate_execute_step =
|
||||
wp_impl_endpoint_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_ENDPOINT,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
wp_impl_endpoint_enum_params_sync (gpointer instance, guint32 id,
|
||||
guint32 start, guint32 num, WpSpaPod *filter)
|
||||
{
|
||||
WpImplEndpoint *self = WP_IMPL_ENDPOINT (instance);
|
||||
g_autoptr (WpPipewireObject) node = wp_session_item_get_associated_proxy (
|
||||
WP_SESSION_ITEM (self->item), WP_TYPE_NODE);
|
||||
|
||||
if (!node) {
|
||||
wp_warning_object (self, "associated node is no longer available");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* bypass a few things, knowing that the node
|
||||
caches params in the mixin param store */
|
||||
WpPwObjectMixinData *data = wp_pw_object_mixin_get_data (node);
|
||||
GPtrArray *params = wp_pw_object_mixin_get_stored_params (data, id);
|
||||
/* TODO filter */
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
static gint
|
||||
wp_impl_endpoint_set_param (gpointer instance, guint32 id, guint32 flags,
|
||||
WpSpaPod * param)
|
||||
{
|
||||
WpImplEndpoint *self = WP_IMPL_ENDPOINT (instance);
|
||||
g_autoptr (WpPipewireObject) node = wp_session_item_get_associated_proxy (
|
||||
WP_SESSION_ITEM (self->item), WP_TYPE_NODE);
|
||||
|
||||
if (!node) {
|
||||
wp_warning_object (self, "associated node is no longer available");
|
||||
return -EPIPE;
|
||||
}
|
||||
|
||||
WpSpaIdValue idval = wp_spa_id_value_from_number ("Spa:Enum:ParamId", id);
|
||||
if (!idval) {
|
||||
wp_critical_object (self, "invalid param id: %u", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return wp_pipewire_object_set_param (node, wp_spa_id_value_short_name (idval),
|
||||
flags, param) ? 0 : -EIO;
|
||||
}
|
||||
|
||||
#define pw_endpoint_emit(hooks,method,version,...) \
|
||||
spa_hook_list_call_simple(hooks, struct pw_endpoint_events, \
|
||||
method, version, ##__VA_ARGS__)
|
||||
|
||||
static void
|
||||
wp_impl_endpoint_emit_info (struct spa_hook_list * hooks, gconstpointer info)
|
||||
{
|
||||
pw_endpoint_emit (hooks, info, 0, info);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_impl_endpoint_emit_param (struct spa_hook_list * hooks, int seq,
|
||||
guint32 id, guint32 index, guint32 next, const struct spa_pod *param)
|
||||
{
|
||||
pw_endpoint_emit (hooks, param, 0, seq, id, index, next, param);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_endpoint_impl_pw_object_mixin_priv_interface_init (
|
||||
WpPwObjectMixinPrivInterface * iface)
|
||||
{
|
||||
iface->flags |= WP_PW_OBJECT_MIXIN_PRIV_NO_PARAM_CACHE;
|
||||
iface->enum_params_sync = wp_impl_endpoint_enum_params_sync;
|
||||
iface->set_param = wp_impl_endpoint_set_param;
|
||||
iface->emit_info = wp_impl_endpoint_emit_info;
|
||||
iface->emit_param = wp_impl_endpoint_emit_param;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates a new endpoint implementation
|
||||
*
|
||||
* \ingroup wpendpoint
|
||||
* \param core the core
|
||||
* \param item the session item that implements the endpoint
|
||||
* \returns (transfer full): a new WpImplEndpoint
|
||||
*/
|
||||
WpImplEndpoint *
|
||||
wp_impl_endpoint_new (WpCore * core, WpSiEndpoint * item)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_CORE (core), NULL);
|
||||
|
||||
return g_object_new (WP_TYPE_IMPL_ENDPOINT,
|
||||
"core", core,
|
||||
"item", item,
|
||||
NULL);
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __WIREPLUMBER_ENDPOINT_H__
|
||||
#define __WIREPLUMBER_ENDPOINT_H__
|
||||
|
||||
#include "global-proxy.h"
|
||||
#include "port.h"
|
||||
#include "iterator.h"
|
||||
#include "object-interest.h"
|
||||
#include "si-interfaces.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*!
|
||||
* \brief The WpEndpoint GType
|
||||
* \ingroup wpendpoint
|
||||
*/
|
||||
#define WP_TYPE_ENDPOINT (wp_endpoint_get_type ())
|
||||
WP_API
|
||||
G_DECLARE_DERIVABLE_TYPE (WpEndpoint, wp_endpoint, WP, ENDPOINT, WpGlobalProxy)
|
||||
|
||||
struct _WpEndpointClass
|
||||
{
|
||||
WpGlobalProxyClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
WP_PADDING(4)
|
||||
};
|
||||
|
||||
WP_API
|
||||
const gchar * wp_endpoint_get_name (WpEndpoint * self);
|
||||
|
||||
WP_API
|
||||
const gchar * wp_endpoint_get_media_class (WpEndpoint * self);
|
||||
|
||||
WP_API
|
||||
WpDirection wp_endpoint_get_direction (WpEndpoint * self);
|
||||
|
||||
/*!
|
||||
* \brief The WpImplEndpoint GType
|
||||
* \ingroup wpendpoint
|
||||
*/
|
||||
#define WP_TYPE_IMPL_ENDPOINT (wp_impl_endpoint_get_type ())
|
||||
WP_API
|
||||
G_DECLARE_FINAL_TYPE (WpImplEndpoint, wp_impl_endpoint,
|
||||
WP, IMPL_ENDPOINT, WpEndpoint)
|
||||
|
||||
WP_API
|
||||
WpImplEndpoint * wp_impl_endpoint_new (WpCore * core, WpSiEndpoint * item);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
@ -5,7 +5,6 @@ wp_lib_sources = files(
|
|||
'core.c',
|
||||
'dbus.c',
|
||||
'device.c',
|
||||
'endpoint.c',
|
||||
'error.c',
|
||||
'event.c',
|
||||
'event-dispatcher.c',
|
||||
|
|
@ -50,7 +49,6 @@ wp_lib_headers = files(
|
|||
'dbus.h',
|
||||
'defs.h',
|
||||
'device.h',
|
||||
'endpoint.h',
|
||||
'error.h',
|
||||
'event.h',
|
||||
'event-dispatcher.h',
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
* instance that created them appears in the WpObjectManager (as soon as
|
||||
* its WP_PROXY_FEATURE_BOUND is enabled)
|
||||
* * local PipeWire objects that are being exported to PipeWire
|
||||
* (WpImplMetadata, WpImplEndpoint, etc); these appear in the
|
||||
* (WpImplMetadata, WpImplNode, etc); these appear in the
|
||||
* WpObjectManager as soon as they are exported (so, when their
|
||||
* WP_PROXY_FEATURE_BOUND is enabled)
|
||||
* * WirePlumber-specific objects, such as plugins, factories and session items
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ typedef struct _WpPwObjectMixinData WpPwObjectMixinData;
|
|||
struct _WpPwObjectMixinData
|
||||
{
|
||||
gpointer info; /* pointer to the info struct */
|
||||
gpointer iface; /* pointer to the interface (ex. pw_endpoint) */
|
||||
gpointer iface; /* pointer to the interface (ex. pw_node) */
|
||||
struct spa_hook listener;
|
||||
struct spa_hook_list hooks;
|
||||
WpProperties *properties;
|
||||
|
|
|
|||
|
|
@ -256,12 +256,7 @@ wp_session_item_is_configured (WpSessionItem * self)
|
|||
|
||||
/*!
|
||||
* \brief An associated proxy is a WpProxy subclass instance that
|
||||
* is somehow related to this item. For example:
|
||||
* - An exported WpSiEndpoint should have at least:
|
||||
* - an associated WpSiEndpoint
|
||||
* - an associated WpSession
|
||||
* - In cases where the item wraps a single PipeWire node, it should also
|
||||
* have an associated WpNode
|
||||
* is somehow related to this item.
|
||||
*
|
||||
* \ingroup wpsessionitem
|
||||
* \param self the session item
|
||||
|
|
|
|||
|
|
@ -13,82 +13,6 @@
|
|||
|
||||
/*! \defgroup wpsiinterfaces Session Item Interfaces */
|
||||
|
||||
/*!
|
||||
* \struct WpSiEndpoint
|
||||
*
|
||||
* An interface for session items that implement a PipeWire endpoint.
|
||||
*
|
||||
* \gsignals
|
||||
*
|
||||
* \par endpoint-properties-changed
|
||||
* \parblock
|
||||
* \code
|
||||
* void
|
||||
* endpoint_properties_changed_callback (WpSiEndpoint * self,
|
||||
* gpointer user_data)
|
||||
* \endcode
|
||||
* Emitted when the endpoint properties change
|
||||
*
|
||||
* Flags: G_SIGNAL_RUN_LAST
|
||||
* \endparblock
|
||||
*/
|
||||
G_DEFINE_INTERFACE (WpSiEndpoint, wp_si_endpoint, WP_TYPE_SESSION_ITEM)
|
||||
|
||||
static WpProperties *
|
||||
wp_si_endpoint_default_get_properties (WpSiEndpoint * self)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_si_endpoint_default_init (WpSiEndpointInterface * iface)
|
||||
{
|
||||
iface->get_properties = wp_si_endpoint_default_get_properties;
|
||||
|
||||
g_signal_new ("endpoint-properties-changed", G_TYPE_FROM_INTERFACE (iface),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief This should return information that is used for registering the
|
||||
* endpoint.
|
||||
*
|
||||
* The return value should be a GVariant tuple of type (ssya{ss}) that contains,
|
||||
* in order:
|
||||
* - s: the endpoint's name
|
||||
* - s: the media class
|
||||
* - y: the direction
|
||||
* - a{ss}: additional properties to be added to the list of global properties
|
||||
*
|
||||
* \ingroup wpsiinterfaces
|
||||
* \param self the session item
|
||||
* \returns (transfer full): registration info for the endpoint
|
||||
*/
|
||||
GVariant *
|
||||
wp_si_endpoint_get_registration_info (WpSiEndpoint * self)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_SI_ENDPOINT (self), NULL);
|
||||
g_return_val_if_fail (WP_SI_ENDPOINT_GET_IFACE (self)->get_registration_info, NULL);
|
||||
|
||||
return WP_SI_ENDPOINT_GET_IFACE (self)->get_registration_info (self);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the properties of the endpoint
|
||||
*
|
||||
* \ingroup wpsiinterfaces
|
||||
* \param self the session item
|
||||
* \returns (transfer full) (nullable): the properties of the endpoint
|
||||
*/
|
||||
WpProperties *
|
||||
wp_si_endpoint_get_properties (WpSiEndpoint * self)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_SI_ENDPOINT (self), NULL);
|
||||
g_return_val_if_fail (WP_SI_ENDPOINT_GET_IFACE (self)->get_properties, NULL);
|
||||
|
||||
return WP_SI_ENDPOINT_GET_IFACE (self)->get_properties (self);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \struct WpSiAdapter
|
||||
* An interface for port adapters
|
||||
|
|
@ -210,10 +134,6 @@ wp_si_adapter_set_ports_format_finish (WpSiAdapter * self, GAsyncResult * res,
|
|||
*
|
||||
* An interface for retrieving PipeWire port information from a session item.
|
||||
* This information is used to create links in the nodes graph.
|
||||
*
|
||||
* This is normally implemented by the same session items that implement
|
||||
* WpSiEndpoint. The standard link implementation expects to be able to cast
|
||||
* a WpSiEndpoint into a WpSiLinkable.
|
||||
*/
|
||||
|
||||
G_DEFINE_INTERFACE (WpSiLinkable, wp_si_linkable, WP_TYPE_SESSION_ITEM)
|
||||
|
|
@ -303,7 +223,7 @@ wp_si_linkable_get_acquisition (WpSiLinkable * self)
|
|||
/*!
|
||||
* \struct WpSiLink
|
||||
*
|
||||
* An interface for session items that provide a PipeWire endpoint link.
|
||||
* An interface for session items that provide a PipeWire link.
|
||||
*
|
||||
* \gsignals
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,32 +17,6 @@ G_BEGIN_DECLS
|
|||
|
||||
typedef struct _WpSiAcquisition WpSiAcquisition;
|
||||
|
||||
/*!
|
||||
* \brief The WpSiEndpoint GType
|
||||
* \ingroup wpsiinterfaces
|
||||
*/
|
||||
#define WP_TYPE_SI_ENDPOINT (wp_si_endpoint_get_type ())
|
||||
WP_API
|
||||
G_DECLARE_INTERFACE (WpSiEndpoint, wp_si_endpoint,
|
||||
WP, SI_ENDPOINT, WpSessionItem)
|
||||
|
||||
struct _WpSiEndpointInterface
|
||||
{
|
||||
GTypeInterface interface;
|
||||
|
||||
GVariant * (*get_registration_info) (WpSiEndpoint * self);
|
||||
WpProperties * (*get_properties) (WpSiEndpoint * self);
|
||||
|
||||
/*< private >*/
|
||||
WP_PADDING(6)
|
||||
};
|
||||
|
||||
WP_API
|
||||
GVariant * wp_si_endpoint_get_registration_info (WpSiEndpoint * self);
|
||||
|
||||
WP_API
|
||||
WpProperties * wp_si_endpoint_get_properties (WpSiEndpoint * self);
|
||||
|
||||
/*!
|
||||
* \brief The WpSiAdapter GType
|
||||
* \ingroup wpsiinterfaces
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ wp_init (WpInitFlags flags)
|
|||
to autodetect the GType of proxies created through wp_proxy_new_global() */
|
||||
g_type_ensure (WP_TYPE_CLIENT);
|
||||
g_type_ensure (WP_TYPE_DEVICE);
|
||||
g_type_ensure (WP_TYPE_ENDPOINT);
|
||||
g_type_ensure (WP_TYPE_LINK);
|
||||
g_type_ensure (WP_TYPE_METADATA);
|
||||
g_type_ensure (WP_TYPE_NODE);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#include "core.h"
|
||||
#include "dbus.h"
|
||||
#include "device.h"
|
||||
#include "endpoint.h"
|
||||
#include "error.h"
|
||||
#include "event-dispatcher.h"
|
||||
#include "event-hook.h"
|
||||
|
|
|
|||
|
|
@ -875,12 +875,6 @@ impl_metadata_new (lua_State *L)
|
|||
return m ? 1 : 0;
|
||||
}
|
||||
|
||||
/* WpEndpoint */
|
||||
|
||||
static const luaL_Reg endpoint_methods[] = {
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* Device */
|
||||
|
||||
static int
|
||||
|
|
@ -2340,8 +2334,6 @@ wp_lua_scripting_api_init (lua_State *L)
|
|||
NULL, metadata_methods);
|
||||
wplua_register_type_methods (L, WP_TYPE_IMPL_METADATA,
|
||||
impl_metadata_new, NULL);
|
||||
wplua_register_type_methods (L, WP_TYPE_ENDPOINT,
|
||||
NULL, endpoint_methods);
|
||||
wplua_register_type_methods (L, WP_TYPE_DEVICE,
|
||||
device_new, NULL);
|
||||
wplua_register_type_methods (L, WP_TYPE_SPA_DEVICE,
|
||||
|
|
|
|||
|
|
@ -29,12 +29,8 @@ struct _WpSiAudioEndpoint
|
|||
/* activation */
|
||||
WpNode *node;
|
||||
WpSiAdapter *adapter;
|
||||
|
||||
/* export */
|
||||
WpImplEndpoint *impl_endpoint;
|
||||
};
|
||||
|
||||
static void si_audio_endpoint_endpoint_init (WpSiEndpointInterface * iface);
|
||||
static void si_audio_endpoint_linkable_init (WpSiLinkableInterface * iface);
|
||||
static void si_audio_endpoint_adapter_init (WpSiAdapterInterface * iface);
|
||||
|
||||
|
|
@ -42,7 +38,6 @@ G_DECLARE_FINAL_TYPE(WpSiAudioEndpoint, si_audio_endpoint, WP,
|
|||
SI_AUDIO_ENDPOINT, WpSessionItem)
|
||||
G_DEFINE_TYPE_WITH_CODE (WpSiAudioEndpoint, si_audio_endpoint,
|
||||
WP_TYPE_SESSION_ITEM,
|
||||
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ENDPOINT, si_audio_endpoint_endpoint_init)
|
||||
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_LINKABLE,
|
||||
si_audio_endpoint_linkable_init)
|
||||
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ADAPTER, si_audio_endpoint_adapter_init))
|
||||
|
|
@ -125,9 +120,6 @@ si_audio_endpoint_get_associated_proxy (WpSessionItem * item, GType proxy_type)
|
|||
{
|
||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (item);
|
||||
|
||||
if (proxy_type == WP_TYPE_ENDPOINT)
|
||||
return self->impl_endpoint ? g_object_ref (self->impl_endpoint) : NULL;
|
||||
|
||||
return wp_session_item_get_associated_proxy (
|
||||
WP_SESSION_ITEM (self->adapter), proxy_type);
|
||||
}
|
||||
|
|
@ -148,7 +140,6 @@ si_audio_endpoint_disable_exported (WpSessionItem *si)
|
|||
{
|
||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (si);
|
||||
|
||||
g_clear_object (&self->impl_endpoint);
|
||||
wp_object_update_features (WP_OBJECT (self), 0,
|
||||
WP_SESSION_ITEM_FEATURE_EXPORTED);
|
||||
}
|
||||
|
|
@ -268,36 +259,13 @@ si_audio_endpoint_enable_active (WpSessionItem *si, WpTransition *transition)
|
|||
(GAsyncReadyCallback) on_node_activate_done, transition);
|
||||
}
|
||||
|
||||
static void
|
||||
on_impl_endpoint_activated (WpObject * object, GAsyncResult * res,
|
||||
WpTransition * transition)
|
||||
{
|
||||
WpSiAudioEndpoint *self = wp_transition_get_source_object (transition);
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
if (!wp_object_activate_finish (object, res, &error)) {
|
||||
wp_transition_return_error (transition, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
wp_object_update_features (WP_OBJECT (self),
|
||||
WP_SESSION_ITEM_FEATURE_EXPORTED, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
si_audio_endpoint_enable_exported (WpSessionItem *si, WpTransition *transition)
|
||||
{
|
||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (si);
|
||||
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
|
||||
|
||||
self->impl_endpoint = wp_impl_endpoint_new (core, WP_SI_ENDPOINT (self));
|
||||
|
||||
g_signal_connect_object (self->impl_endpoint, "pw-proxy-destroyed",
|
||||
G_CALLBACK (wp_session_item_handle_proxy_destroyed), self, 0);
|
||||
|
||||
wp_object_activate (WP_OBJECT (self->impl_endpoint),
|
||||
WP_OBJECT_FEATURES_ALL, NULL,
|
||||
(GAsyncReadyCallback) on_impl_endpoint_activated, transition);
|
||||
wp_object_update_features (WP_OBJECT (self),
|
||||
WP_SESSION_ITEM_FEATURE_EXPORTED, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -314,51 +282,6 @@ si_audio_endpoint_class_init (WpSiAudioEndpointClass * klass)
|
|||
si_class->enable_exported = si_audio_endpoint_enable_exported;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
si_audio_endpoint_get_registration_info (WpSiEndpoint * item)
|
||||
{
|
||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (item);
|
||||
GVariantBuilder b;
|
||||
|
||||
g_variant_builder_init (&b, G_VARIANT_TYPE ("(ssya{ss})"));
|
||||
g_variant_builder_add (&b, "s", self->name);
|
||||
g_variant_builder_add (&b, "s", self->media_class);
|
||||
g_variant_builder_add (&b, "y", self->direction);
|
||||
g_variant_builder_add (&b, "a{ss}", NULL);
|
||||
|
||||
return g_variant_builder_end (&b);
|
||||
}
|
||||
|
||||
static WpProperties *
|
||||
si_audio_endpoint_get_properties (WpSiEndpoint * item)
|
||||
{
|
||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (item);
|
||||
g_autoptr (WpNode) node = wp_session_item_get_associated_proxy (
|
||||
WP_SESSION_ITEM (self->adapter), WP_TYPE_NODE);
|
||||
WpProperties *result = wp_properties_new_empty ();
|
||||
|
||||
wp_properties_set (result, "endpoint.name", self->name);
|
||||
wp_properties_setf (result, "endpoint.priority", "%u", self->priority);
|
||||
wp_properties_setf (result, "endpoint.description", "%s: %s",
|
||||
(self->direction == WP_DIRECTION_OUTPUT) ? "Capture" : "Playback",
|
||||
self->role);
|
||||
wp_properties_set (result, "media.role", self->role);
|
||||
|
||||
/* associate with the node */
|
||||
g_return_val_if_fail (node, NULL);
|
||||
wp_properties_setf (result, PW_KEY_NODE_ID, "%d",
|
||||
wp_proxy_get_bound_id (WP_PROXY (node)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
si_audio_endpoint_endpoint_init (WpSiEndpointInterface * iface)
|
||||
{
|
||||
iface->get_registration_info = si_audio_endpoint_get_registration_info;
|
||||
iface->get_properties = si_audio_endpoint_get_properties;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
si_audio_endpoint_get_ports (WpSiLinkable * item, const gchar * context)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ typedef enum {
|
|||
OBJECT_TYPE_LINK,
|
||||
OBJECT_TYPE_NODE,
|
||||
OBJECT_TYPE_SESSION_ITEM,
|
||||
OBJECT_TYPE_ENDPOINT,
|
||||
OBJECT_TYPE_CLIENT,
|
||||
OBJECT_TYPE_DEVICE,
|
||||
OBJECT_TYPE_METADATA,
|
||||
|
|
@ -87,7 +86,6 @@ object_type_to_gtype (ObjectType type)
|
|||
case OBJECT_TYPE_LINK: return WP_TYPE_LINK;
|
||||
case OBJECT_TYPE_NODE: return WP_TYPE_NODE;
|
||||
case OBJECT_TYPE_SESSION_ITEM: return WP_TYPE_SESSION_ITEM;
|
||||
case OBJECT_TYPE_ENDPOINT: return WP_TYPE_ENDPOINT;
|
||||
case OBJECT_TYPE_CLIENT: return WP_TYPE_CLIENT;
|
||||
case OBJECT_TYPE_DEVICE: return WP_TYPE_DEVICE;
|
||||
case OBJECT_TYPE_METADATA: return WP_TYPE_METADATA;
|
||||
|
|
@ -107,8 +105,6 @@ type_str_to_object_type (const gchar * type_str)
|
|||
return OBJECT_TYPE_NODE;
|
||||
else if (!g_strcmp0 (type_str, "session-item"))
|
||||
return OBJECT_TYPE_SESSION_ITEM;
|
||||
else if (!g_strcmp0 (type_str, "endpoint"))
|
||||
return OBJECT_TYPE_ENDPOINT;
|
||||
else if (!g_strcmp0 (type_str, "client"))
|
||||
return OBJECT_TYPE_CLIENT;
|
||||
else if (!g_strcmp0 (type_str, "device"))
|
||||
|
|
@ -142,8 +138,6 @@ get_object_type (gpointer obj, WpProperties **properties)
|
|||
}
|
||||
return "session-item";
|
||||
}
|
||||
else if (WP_IS_ENDPOINT (obj))
|
||||
return "endpoint";
|
||||
else if (WP_IS_CLIENT (obj))
|
||||
return "client";
|
||||
else if (WP_IS_DEVICE (obj))
|
||||
|
|
|
|||
|
|
@ -189,7 +189,6 @@ status_prepare (WpCtl * self, GError ** error)
|
|||
{
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_CLIENT, NULL);
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_DEVICE, NULL);
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_ENDPOINT, NULL);
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_NODE, NULL);
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_PORT, NULL);
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_LINK, NULL);
|
||||
|
|
@ -259,27 +258,6 @@ print_dev_node (const GValue *item, gpointer data)
|
|||
print_controls (id, context);
|
||||
}
|
||||
|
||||
static void
|
||||
print_endpoint (const GValue *item, gpointer data)
|
||||
{
|
||||
WpPipewireObject *obj = g_value_get_object (item);
|
||||
struct print_context *context = data;
|
||||
guint32 id = wp_proxy_get_bound_id (WP_PROXY (obj));
|
||||
guint32 node_id = -1;
|
||||
gboolean is_default = (context->default_node == id);
|
||||
const gchar *str, *name;
|
||||
|
||||
if ((str = wp_pipewire_object_get_property (obj, "node.id")))
|
||||
node_id = atoi (str);
|
||||
|
||||
name = wp_pipewire_object_get_property (obj, "endpoint.description");
|
||||
if (!name)
|
||||
name = wp_pipewire_object_get_property (obj, "endpoint.name");
|
||||
|
||||
printf (TREE_INDENT_LINE "%c %4u. %-35s", is_default ? '*' : ' ', id, name);
|
||||
print_controls (node_id, context);
|
||||
}
|
||||
|
||||
static void
|
||||
print_stream_node (const GValue *item, gpointer data)
|
||||
{
|
||||
|
|
@ -410,17 +388,6 @@ status_run (WpCtl * self)
|
|||
|
||||
printf (TREE_INDENT_LINE "\n");
|
||||
|
||||
printf (TREE_INDENT_NODE "Sink endpoints:\n");
|
||||
child_it = wp_object_manager_new_filtered_iterator (self->om,
|
||||
WP_TYPE_ENDPOINT,
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", "*/Sink*",
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", media_type_glob,
|
||||
NULL);
|
||||
wp_iterator_foreach (child_it, print_endpoint, (gpointer) &context);
|
||||
g_clear_pointer (&child_it, wp_iterator_unref);
|
||||
|
||||
printf (TREE_INDENT_LINE "\n");
|
||||
|
||||
printf (TREE_INDENT_NODE "Sources:\n");
|
||||
g_snprintf (media_class, sizeof(media_class), "%s/Source", media_type);
|
||||
context.default_node = -1;
|
||||
|
|
@ -437,17 +404,6 @@ status_run (WpCtl * self)
|
|||
|
||||
printf (TREE_INDENT_LINE "\n");
|
||||
|
||||
printf (TREE_INDENT_NODE "Source endpoints:\n");
|
||||
child_it = wp_object_manager_new_filtered_iterator (self->om,
|
||||
WP_TYPE_ENDPOINT,
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", "*/Source*",
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", media_type_glob,
|
||||
NULL);
|
||||
wp_iterator_foreach (child_it, print_endpoint, (gpointer) &context);
|
||||
g_clear_pointer (&child_it, wp_iterator_unref);
|
||||
|
||||
printf (TREE_INDENT_LINE "\n");
|
||||
|
||||
printf (TREE_INDENT_END "Streams:\n");
|
||||
child_it = wp_object_manager_new_filtered_iterator (self->om,
|
||||
WP_TYPE_NODE,
|
||||
|
|
@ -590,14 +546,6 @@ struct {
|
|||
} assoc_keys[] = {
|
||||
{ PW_KEY_CLIENT_ID, "Client" },
|
||||
{ PW_KEY_DEVICE_ID, "Device" },
|
||||
{ PW_KEY_ENDPOINT_CLIENT_ID, NULL },
|
||||
{ "endpoint-link.id", "EndpointLink" },
|
||||
{ PW_KEY_ENDPOINT_STREAM_ID, "EndpointStream" },
|
||||
{ PW_KEY_ENDPOINT_LINK_OUTPUT_ENDPOINT, NULL },
|
||||
{ PW_KEY_ENDPOINT_LINK_OUTPUT_STREAM, NULL },
|
||||
{ PW_KEY_ENDPOINT_LINK_INPUT_ENDPOINT, NULL },
|
||||
{ PW_KEY_ENDPOINT_LINK_INPUT_STREAM, NULL },
|
||||
{ PW_KEY_ENDPOINT_ID, "Endpoint" },
|
||||
{ PW_KEY_LINK_INPUT_NODE, NULL },
|
||||
{ PW_KEY_LINK_INPUT_PORT, NULL },
|
||||
{ PW_KEY_LINK_OUTPUT_NODE, NULL },
|
||||
|
|
@ -894,7 +842,6 @@ set_volume_parse_positional (gint argc, gchar ** argv, GError **error)
|
|||
static gboolean
|
||||
set_volume_prepare (WpCtl * self, GError ** error)
|
||||
{
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_ENDPOINT, NULL);
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_NODE, NULL);
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_CLIENT, NULL);
|
||||
wp_object_manager_request_object_features (self->om, WP_TYPE_GLOBAL_PROXY,
|
||||
|
|
@ -912,15 +859,6 @@ do_set_volume (WpCtl * self, WpPipewireObject *proxy)
|
|||
gdouble curr_volume = 1.0;
|
||||
guint32 id = wp_proxy_get_bound_id (WP_PROXY (proxy));
|
||||
|
||||
if (WP_IS_ENDPOINT (proxy)) {
|
||||
const gchar *str = wp_pipewire_object_get_property (proxy, "node.id");
|
||||
if (!str) {
|
||||
fprintf (stderr, "Endpoint '%d' does not have an associated node\n", id);
|
||||
return FALSE;
|
||||
}
|
||||
id = atoi (str);
|
||||
}
|
||||
|
||||
if (cmdline.set_volume.type == 's') {
|
||||
g_signal_emit_by_name (mixer_api, "get-volume", id, &variant);
|
||||
if (!variant) {
|
||||
|
|
@ -1030,7 +968,6 @@ set_mute_parse_positional (gint argc, gchar ** argv, GError **error)
|
|||
static gboolean
|
||||
set_mute_prepare (WpCtl * self, GError ** error)
|
||||
{
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_ENDPOINT, NULL);
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_NODE, NULL);
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_CLIENT, NULL);
|
||||
wp_object_manager_request_object_features (self->om, WP_TYPE_GLOBAL_PROXY,
|
||||
|
|
@ -1048,15 +985,6 @@ do_set_mute (WpCtl * self, WpPipewireObject *proxy)
|
|||
gboolean mute = FALSE;
|
||||
guint32 id = wp_proxy_get_bound_id (WP_PROXY (proxy));
|
||||
|
||||
if (WP_IS_ENDPOINT (proxy)) {
|
||||
const gchar *str = wp_pipewire_object_get_property (proxy, "node.id");
|
||||
if (!str) {
|
||||
fprintf (stderr, "Endpoint '%d' does not have an associated node\n", id);
|
||||
return FALSE;
|
||||
}
|
||||
id = atoi (str);
|
||||
}
|
||||
|
||||
g_signal_emit_by_name (mixer_api, "get-volume", id, &variant);
|
||||
if (!variant) {
|
||||
fprintf (stderr, "Node %d does not support mute\n", id);
|
||||
|
|
@ -1309,7 +1237,7 @@ static const struct subcommand {
|
|||
{
|
||||
.name = "set-default",
|
||||
.positional_args = "ID",
|
||||
.summary = "Sets ID to be the default endpoint of its kind "
|
||||
.summary = "Sets ID to be the default object of its kind "
|
||||
"(capture/playback) in its session",
|
||||
.description = NULL,
|
||||
.entries = { { NULL } },
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ test_si_audio_endpoint_configure_activate (TestFixture * f,
|
|||
|
||||
endpoint = wp_session_item_make (f->base.core, "si-audio-endpoint");
|
||||
g_assert_nonnull (endpoint);
|
||||
g_assert_true (WP_IS_SI_ENDPOINT (endpoint));
|
||||
|
||||
/* configure endpoint */
|
||||
|
||||
|
|
@ -155,20 +154,14 @@ test_si_audio_endpoint_export (TestFixture * f, gconstpointer user_data)
|
|||
}
|
||||
|
||||
{
|
||||
g_autoptr (WpEndpoint) ep = NULL;
|
||||
g_autoptr (WpNode) n = NULL;
|
||||
g_autoptr (WpProperties) props = NULL;
|
||||
|
||||
ep = wp_session_item_get_associated_proxy (endpoint, WP_TYPE_ENDPOINT);
|
||||
g_assert_nonnull (ep);
|
||||
props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (ep));
|
||||
n = wp_session_item_get_associated_proxy (endpoint, WP_TYPE_NODE);
|
||||
g_assert_nonnull (n);
|
||||
props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (n));
|
||||
g_assert_nonnull (props);
|
||||
|
||||
g_assert_cmpstr (wp_endpoint_get_name (ep), ==, "endpoint");
|
||||
g_assert_cmpstr (wp_endpoint_get_media_class (ep), ==,
|
||||
"Audio/Source");
|
||||
g_assert_cmpint (wp_endpoint_get_direction (ep), ==, WP_DIRECTION_OUTPUT);
|
||||
g_assert_cmpstr (wp_properties_get (props, "endpoint.name"), ==,
|
||||
"endpoint");
|
||||
g_assert_cmpstr (wp_properties_get (props, "media.class"), ==,
|
||||
"Audio/Source");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,780 +0,0 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019-2020 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "../common/base-test-fixture.h"
|
||||
#include <pipewire/extensions/session-manager/keys.h>
|
||||
|
||||
struct _TestSiEndpoint
|
||||
{
|
||||
WpSessionItem parent;
|
||||
const gchar *name;
|
||||
const gchar *media_class;
|
||||
WpNode *node;
|
||||
WpDirection direction;
|
||||
gboolean changed_properties;
|
||||
WpProxy *impl_endpoint;
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (TestSiEndpoint, test_si_endpoint,
|
||||
TEST, SI_ENDPOINT, WpSessionItem)
|
||||
|
||||
static GVariant *
|
||||
test_si_endpoint_get_registration_info (WpSiEndpoint * item)
|
||||
{
|
||||
TestSiEndpoint *self = TEST_SI_ENDPOINT (item);
|
||||
GVariantBuilder b;
|
||||
|
||||
g_variant_builder_init (&b, G_VARIANT_TYPE ("(ssya{ss})"));
|
||||
g_variant_builder_add (&b, "s", self->name);
|
||||
g_variant_builder_add (&b, "s", self->media_class);
|
||||
g_variant_builder_add (&b, "y", (guchar) self->direction);
|
||||
g_variant_builder_add (&b, "a{ss}", NULL);
|
||||
|
||||
return g_variant_builder_end (&b);
|
||||
}
|
||||
|
||||
static WpProperties *
|
||||
test_si_endpoint_get_properties (WpSiEndpoint * item)
|
||||
{
|
||||
TestSiEndpoint *self = TEST_SI_ENDPOINT (item);
|
||||
if (self->changed_properties)
|
||||
return wp_properties_new ("test.property", "changed-value", NULL);
|
||||
else
|
||||
return wp_properties_new ("test.property", "test-value", NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_si_endpoint_endpoint_init (WpSiEndpointInterface * iface)
|
||||
{
|
||||
iface->get_registration_info = test_si_endpoint_get_registration_info;
|
||||
iface->get_properties = test_si_endpoint_get_properties;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (TestSiEndpoint, test_si_endpoint, WP_TYPE_SESSION_ITEM,
|
||||
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ENDPOINT, test_si_endpoint_endpoint_init))
|
||||
|
||||
static void
|
||||
test_si_endpoint_init (TestSiEndpoint * self)
|
||||
{
|
||||
}
|
||||
|
||||
static gpointer
|
||||
si_endpoint_get_associated_proxy (WpSessionItem * item, GType proxy_type)
|
||||
{
|
||||
TestSiEndpoint * self = TEST_SI_ENDPOINT (item);
|
||||
|
||||
if (proxy_type == WP_TYPE_NODE)
|
||||
return self->node ? g_object_ref (self->node) : NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
si_endpoint_reset (WpSessionItem * item)
|
||||
{
|
||||
TestSiEndpoint * self = TEST_SI_ENDPOINT (item);
|
||||
|
||||
wp_object_deactivate (WP_OBJECT (self),
|
||||
WP_SESSION_ITEM_FEATURE_ACTIVE | WP_SESSION_ITEM_FEATURE_EXPORTED);
|
||||
|
||||
g_clear_object (&self->node);
|
||||
|
||||
WP_SESSION_ITEM_CLASS (test_si_endpoint_parent_class)->reset (item);
|
||||
}
|
||||
|
||||
static void
|
||||
si_endpoint_disable_active (WpSessionItem *si)
|
||||
{
|
||||
TestSiEndpoint * self = TEST_SI_ENDPOINT (si);
|
||||
|
||||
wp_object_update_features (WP_OBJECT (self), 0,
|
||||
WP_SESSION_ITEM_FEATURE_ACTIVE);
|
||||
}
|
||||
|
||||
static void
|
||||
si_endpoint_disable_exported (WpSessionItem *si)
|
||||
{
|
||||
TestSiEndpoint * self = TEST_SI_ENDPOINT (si);
|
||||
|
||||
g_clear_object (&self->impl_endpoint);
|
||||
wp_object_update_features (WP_OBJECT (self), 0,
|
||||
WP_SESSION_ITEM_FEATURE_EXPORTED);
|
||||
}
|
||||
|
||||
static void
|
||||
si_endpoint_enable_active (WpSessionItem *si, WpTransition *transition)
|
||||
{
|
||||
TestSiEndpoint * self = TEST_SI_ENDPOINT (si);
|
||||
|
||||
wp_object_update_features (WP_OBJECT (self),
|
||||
WP_SESSION_ITEM_FEATURE_ACTIVE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_impl_endpoint_activated (WpObject * object, GAsyncResult * res,
|
||||
WpTransition * transition)
|
||||
{
|
||||
TestSiEndpoint *self = wp_transition_get_source_object (transition);
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
if (!wp_object_activate_finish (object, res, &error)) {
|
||||
wp_transition_return_error (transition, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
wp_object_update_features (WP_OBJECT (self),
|
||||
WP_SESSION_ITEM_FEATURE_EXPORTED, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
si_endpoint_enable_exported (WpSessionItem *si, WpTransition *transition)
|
||||
{
|
||||
TestSiEndpoint * self = TEST_SI_ENDPOINT (si);
|
||||
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
|
||||
|
||||
self->impl_endpoint = WP_PROXY (wp_impl_endpoint_new (core,
|
||||
WP_SI_ENDPOINT (self)));
|
||||
g_signal_connect_object (self->impl_endpoint, "pw-proxy-destroyed",
|
||||
G_CALLBACK (wp_session_item_handle_proxy_destroyed), self, 0);
|
||||
|
||||
wp_object_activate (WP_OBJECT (self->impl_endpoint),
|
||||
WP_OBJECT_FEATURES_ALL, NULL,
|
||||
(GAsyncReadyCallback) on_impl_endpoint_activated, transition);
|
||||
}
|
||||
|
||||
static void
|
||||
test_si_endpoint_class_init (TestSiEndpointClass * klass)
|
||||
{
|
||||
WpSessionItemClass *item_class = (WpSessionItemClass *) klass;
|
||||
|
||||
item_class->reset = si_endpoint_reset;
|
||||
item_class->get_associated_proxy = si_endpoint_get_associated_proxy;
|
||||
item_class->disable_active = si_endpoint_disable_active;
|
||||
item_class->disable_exported = si_endpoint_disable_exported;
|
||||
item_class->enable_active = si_endpoint_enable_active;
|
||||
item_class->enable_exported = si_endpoint_enable_exported;
|
||||
}
|
||||
|
||||
/*******************/
|
||||
|
||||
typedef struct {
|
||||
WpBaseTestFixture base;
|
||||
|
||||
WpObjectManager *export_om;
|
||||
WpObjectManager *proxy_om;
|
||||
|
||||
WpProxy *impl_endpoint;
|
||||
WpProxy *proxy_endpoint;
|
||||
|
||||
gint n_events;
|
||||
|
||||
} TestEndpointFixture;
|
||||
|
||||
static void
|
||||
test_endpoint_setup (TestEndpointFixture *self, gconstpointer user_data)
|
||||
{
|
||||
wp_base_test_fixture_setup (&self->base, WP_BASE_TEST_FLAG_CLIENT_CORE);
|
||||
self->export_om = wp_object_manager_new ();
|
||||
self->proxy_om = wp_object_manager_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
test_endpoint_teardown (TestEndpointFixture *self, gconstpointer user_data)
|
||||
{
|
||||
g_clear_object (&self->proxy_om);
|
||||
g_clear_object (&self->export_om);
|
||||
wp_base_test_fixture_teardown (&self->base);
|
||||
}
|
||||
|
||||
static void
|
||||
test_endpoint_impl_object_added (WpObjectManager *om,
|
||||
WpEndpoint *endpoint, TestEndpointFixture *fixture)
|
||||
{
|
||||
g_debug ("impl object added");
|
||||
|
||||
g_assert_true (WP_IS_ENDPOINT (endpoint));
|
||||
g_assert_cmpstr (G_OBJECT_TYPE_NAME (endpoint), ==, "WpImplEndpoint");
|
||||
|
||||
g_assert_null (fixture->impl_endpoint);
|
||||
fixture->impl_endpoint = WP_PROXY (endpoint);
|
||||
|
||||
if (++fixture->n_events == 3)
|
||||
g_main_loop_quit (fixture->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_endpoint_impl_object_removed (WpObjectManager *om,
|
||||
WpEndpoint *endpoint, TestEndpointFixture *fixture)
|
||||
{
|
||||
g_debug ("impl object removed");
|
||||
|
||||
g_assert_true (WP_IS_ENDPOINT (endpoint));
|
||||
g_assert_cmpstr (G_OBJECT_TYPE_NAME (endpoint), ==, "WpImplEndpoint");
|
||||
|
||||
g_assert_nonnull (fixture->impl_endpoint);
|
||||
fixture->impl_endpoint = NULL;
|
||||
|
||||
if (++fixture->n_events == 2)
|
||||
g_main_loop_quit (fixture->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_endpoint_proxy_object_added (WpObjectManager *om,
|
||||
WpEndpoint *endpoint, TestEndpointFixture *fixture)
|
||||
{
|
||||
g_debug ("proxy object added");
|
||||
|
||||
g_assert_true (WP_IS_ENDPOINT (endpoint));
|
||||
g_assert_cmpstr (G_OBJECT_TYPE_NAME (endpoint), ==, "WpEndpoint");
|
||||
|
||||
g_assert_null (fixture->proxy_endpoint);
|
||||
fixture->proxy_endpoint = WP_PROXY (endpoint);
|
||||
|
||||
if (++fixture->n_events == 3)
|
||||
g_main_loop_quit (fixture->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_endpoint_proxy_object_removed (WpObjectManager *om,
|
||||
WpEndpoint *endpoint, TestEndpointFixture *fixture)
|
||||
{
|
||||
g_debug ("proxy object removed");
|
||||
|
||||
g_assert_true (WP_IS_ENDPOINT (endpoint));
|
||||
g_assert_cmpstr (G_OBJECT_TYPE_NAME (endpoint), ==, "WpEndpoint");
|
||||
|
||||
g_assert_nonnull (fixture->proxy_endpoint);
|
||||
fixture->proxy_endpoint = NULL;
|
||||
|
||||
if (++fixture->n_events == 2)
|
||||
g_main_loop_quit (fixture->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_endpoint_activate_done (WpObject * object, GAsyncResult * res,
|
||||
TestEndpointFixture *fixture)
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
g_debug ("activate done");
|
||||
|
||||
g_assert_true (wp_object_activate_finish (object, res, &error));
|
||||
g_assert_no_error (error);
|
||||
|
||||
if (++fixture->n_events == 3)
|
||||
g_main_loop_quit (fixture->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_endpoint_params_changed (WpPipewireObject * proxy,
|
||||
const gchar * param_name, TestEndpointFixture *fixture)
|
||||
{
|
||||
wp_debug_object (proxy, "params changed: %s", param_name);
|
||||
|
||||
/* only count changes of id 2 (Props); PipeWire 0.3.22+git changed
|
||||
behaviour and emits changes to PropInfo as well then the Props change */
|
||||
if (!g_strcmp0 (param_name, "Props") && ++fixture->n_events == 3)
|
||||
g_main_loop_quit (fixture->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_endpoint_notify_properties (WpEndpoint * endpoint, GParamSpec * param,
|
||||
TestEndpointFixture *fixture)
|
||||
{
|
||||
g_debug ("properties changed: %s", G_OBJECT_TYPE_NAME (endpoint));
|
||||
|
||||
g_assert_true (WP_IS_ENDPOINT (endpoint));
|
||||
|
||||
if (++fixture->n_events == 2)
|
||||
g_main_loop_quit (fixture->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_endpoint_no_props (TestEndpointFixture *fixture, gconstpointer data)
|
||||
{
|
||||
g_autoptr (TestSiEndpoint) endpoint = NULL;
|
||||
|
||||
/* set up the export side */
|
||||
g_signal_connect (fixture->export_om, "object-added",
|
||||
(GCallback) test_endpoint_impl_object_added, fixture);
|
||||
g_signal_connect (fixture->export_om, "object-removed",
|
||||
(GCallback) test_endpoint_impl_object_removed, fixture);
|
||||
wp_object_manager_add_interest (fixture->export_om, WP_TYPE_ENDPOINT, NULL);
|
||||
wp_object_manager_request_object_features (fixture->export_om,
|
||||
WP_TYPE_ENDPOINT, WP_OBJECT_FEATURES_ALL);
|
||||
wp_core_install_object_manager (fixture->base.core, fixture->export_om);
|
||||
|
||||
/* set up the proxy side */
|
||||
g_signal_connect (fixture->proxy_om, "object-added",
|
||||
(GCallback) test_endpoint_proxy_object_added, fixture);
|
||||
g_signal_connect (fixture->proxy_om, "object-removed",
|
||||
(GCallback) test_endpoint_proxy_object_removed, fixture);
|
||||
wp_object_manager_add_interest (fixture->proxy_om, WP_TYPE_ENDPOINT, NULL);
|
||||
wp_object_manager_request_object_features (fixture->proxy_om,
|
||||
WP_TYPE_ENDPOINT, WP_OBJECT_FEATURES_ALL);
|
||||
wp_core_install_object_manager (fixture->base.client_core, fixture->proxy_om);
|
||||
|
||||
/* create endpoint */
|
||||
endpoint = g_object_new (test_si_endpoint_get_type (),
|
||||
"core", fixture->base.core, NULL);
|
||||
endpoint->name = "test-endpoint";
|
||||
endpoint->media_class = "Audio/Source";
|
||||
endpoint->direction = WP_DIRECTION_OUTPUT;
|
||||
wp_object_activate (WP_OBJECT (endpoint),
|
||||
WP_SESSION_ITEM_FEATURE_ACTIVE | WP_SESSION_ITEM_FEATURE_EXPORTED,
|
||||
NULL, (GAsyncReadyCallback) test_endpoint_activate_done, fixture);
|
||||
|
||||
/* run until objects are created and features are cached */
|
||||
fixture->n_events = 0;
|
||||
g_main_loop_run (fixture->base.loop);
|
||||
g_assert_cmpint (wp_object_get_active_features (WP_OBJECT (endpoint)), ==,
|
||||
WP_SESSION_ITEM_FEATURE_ACTIVE | WP_SESSION_ITEM_FEATURE_EXPORTED);
|
||||
g_assert_cmpint (fixture->n_events, ==, 3);
|
||||
g_assert_nonnull (fixture->impl_endpoint);
|
||||
g_assert_nonnull (fixture->proxy_endpoint);
|
||||
|
||||
/* verify the values on the proxy */
|
||||
|
||||
g_assert_cmphex (
|
||||
wp_object_get_active_features (WP_OBJECT (fixture->proxy_endpoint)), ==,
|
||||
wp_object_get_supported_features (WP_OBJECT (fixture->proxy_endpoint)));
|
||||
g_assert_cmpuint (wp_proxy_get_bound_id (fixture->proxy_endpoint), ==,
|
||||
wp_proxy_get_bound_id (fixture->impl_endpoint));
|
||||
|
||||
g_assert_cmpstr (wp_pipewire_object_get_property (
|
||||
WP_PIPEWIRE_OBJECT (fixture->proxy_endpoint), "test.property"),
|
||||
==, "test-value");
|
||||
|
||||
{
|
||||
g_autoptr (WpProperties) props = wp_global_proxy_get_global_properties (
|
||||
WP_GLOBAL_PROXY (fixture->proxy_endpoint));
|
||||
|
||||
g_assert_cmpstr (wp_properties_get (props, PW_KEY_ENDPOINT_NAME), ==,
|
||||
"test-endpoint");
|
||||
g_assert_cmpstr (wp_properties_get (props, PW_KEY_MEDIA_CLASS), ==,
|
||||
"Audio/Source");
|
||||
}
|
||||
|
||||
g_assert_cmpstr ("test-endpoint", ==,
|
||||
wp_endpoint_get_name (WP_ENDPOINT (fixture->proxy_endpoint)));
|
||||
g_assert_cmpstr ("Audio/Source", ==,
|
||||
wp_endpoint_get_media_class (WP_ENDPOINT (fixture->proxy_endpoint)));
|
||||
g_assert_cmpint (WP_DIRECTION_OUTPUT, ==,
|
||||
wp_endpoint_get_direction (WP_ENDPOINT (fixture->proxy_endpoint)));
|
||||
|
||||
/* test property changes */
|
||||
g_signal_connect (fixture->proxy_endpoint, "notify::properties",
|
||||
(GCallback) test_endpoint_notify_properties, fixture);
|
||||
g_signal_connect (fixture->impl_endpoint, "notify::properties",
|
||||
(GCallback) test_endpoint_notify_properties, fixture);
|
||||
|
||||
/* change a property on the impl */
|
||||
fixture->n_events = 0;
|
||||
endpoint->changed_properties = TRUE;
|
||||
g_signal_emit_by_name (endpoint, "endpoint-properties-changed");
|
||||
|
||||
/* run until the change is on both sides */
|
||||
g_main_loop_run (fixture->base.loop);
|
||||
g_assert_cmpint (fixture->n_events, ==, 2);
|
||||
|
||||
/* verify the property change on both sides */
|
||||
{
|
||||
g_autoptr (WpProperties) props = wp_pipewire_object_get_properties (
|
||||
WP_PIPEWIRE_OBJECT (fixture->impl_endpoint));
|
||||
g_assert_cmpstr (wp_properties_get (props, "test.property"), ==,
|
||||
"changed-value");
|
||||
}
|
||||
{
|
||||
g_autoptr (WpProperties) props = wp_pipewire_object_get_properties (
|
||||
WP_PIPEWIRE_OBJECT (fixture->proxy_endpoint));
|
||||
g_assert_cmpstr (wp_properties_get (props, "test.property"), ==,
|
||||
"changed-value");
|
||||
}
|
||||
|
||||
/* destroy impl endpoint */
|
||||
fixture->n_events = 0;
|
||||
g_clear_object (&endpoint);
|
||||
|
||||
/* run until objects are destroyed */
|
||||
g_main_loop_run (fixture->base.loop);
|
||||
g_assert_cmpint (fixture->n_events, ==, 2);
|
||||
g_assert_null (fixture->impl_endpoint);
|
||||
g_assert_null (fixture->proxy_endpoint);
|
||||
}
|
||||
|
||||
static void
|
||||
test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data)
|
||||
{
|
||||
g_autoptr (TestSiEndpoint) endpoint = NULL;
|
||||
|
||||
/* load modules */
|
||||
{
|
||||
g_autoptr (WpTestServerLocker) lock =
|
||||
wp_test_server_locker_new (&fixture->base.server);
|
||||
|
||||
g_assert_cmpint (pw_context_add_spa_lib (fixture->base.server.context,
|
||||
"audiotestsrc", "audiotestsrc/libspa-audiotestsrc"), ==, 0);
|
||||
if (!test_is_spa_lib_installed (&fixture->base, "audiotestsrc")) {
|
||||
g_test_skip ("The pipewire audiotestsrc factory was not found");
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert_nonnull (pw_context_load_module (fixture->base.server.context,
|
||||
"libpipewire-module-adapter", NULL, NULL));
|
||||
}
|
||||
|
||||
/* set up the export side */
|
||||
g_signal_connect (fixture->export_om, "object-added",
|
||||
(GCallback) test_endpoint_impl_object_added, fixture);
|
||||
g_signal_connect (fixture->export_om, "object-removed",
|
||||
(GCallback) test_endpoint_impl_object_removed, fixture);
|
||||
wp_object_manager_add_interest (fixture->export_om, WP_TYPE_ENDPOINT, NULL);
|
||||
wp_object_manager_request_object_features (fixture->export_om,
|
||||
WP_TYPE_ENDPOINT, WP_OBJECT_FEATURES_ALL);
|
||||
wp_core_install_object_manager (fixture->base.core, fixture->export_om);
|
||||
|
||||
/* set up the proxy side */
|
||||
g_signal_connect (fixture->proxy_om, "object-added",
|
||||
(GCallback) test_endpoint_proxy_object_added, fixture);
|
||||
g_signal_connect (fixture->proxy_om, "object-removed",
|
||||
(GCallback) test_endpoint_proxy_object_removed, fixture);
|
||||
wp_object_manager_add_interest (fixture->proxy_om, WP_TYPE_ENDPOINT, NULL);
|
||||
wp_object_manager_request_object_features (fixture->proxy_om,
|
||||
WP_TYPE_ENDPOINT, WP_OBJECT_FEATURES_ALL);
|
||||
wp_core_install_object_manager (fixture->base.client_core, fixture->proxy_om);
|
||||
|
||||
/* create endpoint */
|
||||
endpoint = g_object_new (test_si_endpoint_get_type (),
|
||||
"core", fixture->base.core, NULL);
|
||||
endpoint->name = "test-endpoint";
|
||||
endpoint->media_class = "Audio/Source";
|
||||
endpoint->direction = WP_DIRECTION_OUTPUT;
|
||||
|
||||
/* associate a node that has props */
|
||||
endpoint->node = wp_node_new_from_factory (fixture->base.core,
|
||||
"adapter",
|
||||
wp_properties_new (
|
||||
"factory.name", "audiotestsrc",
|
||||
"node.name", "audiotestsrc.adapter",
|
||||
NULL));
|
||||
g_assert_nonnull (endpoint->node);
|
||||
wp_object_activate (WP_OBJECT (endpoint->node),
|
||||
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL, NULL,
|
||||
(GAsyncReadyCallback) test_object_activate_finish_cb, fixture);
|
||||
g_main_loop_run (fixture->base.loop);
|
||||
|
||||
g_assert_cmpint (wp_object_get_active_features (WP_OBJECT (endpoint->node)),
|
||||
==, WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL);
|
||||
|
||||
/* activate & export the endpoint */
|
||||
wp_object_activate (WP_OBJECT (endpoint),
|
||||
WP_SESSION_ITEM_FEATURE_ACTIVE | WP_SESSION_ITEM_FEATURE_EXPORTED,
|
||||
NULL, (GAsyncReadyCallback) test_endpoint_activate_done, fixture);
|
||||
|
||||
/* run until objects are created and features are cached */
|
||||
fixture->n_events = 0;
|
||||
g_main_loop_run (fixture->base.loop);
|
||||
g_assert_cmpint (wp_object_get_active_features (WP_OBJECT (endpoint)), ==,
|
||||
WP_SESSION_ITEM_FEATURE_ACTIVE | WP_SESSION_ITEM_FEATURE_EXPORTED);
|
||||
g_assert_cmpint (fixture->n_events, ==, 3);
|
||||
g_assert_nonnull (fixture->impl_endpoint);
|
||||
g_assert_nonnull (fixture->proxy_endpoint);
|
||||
|
||||
/* verify features; the endpoint must have also augmented the node */
|
||||
g_assert_cmpint (
|
||||
wp_object_get_active_features (WP_OBJECT (endpoint->node)), &,
|
||||
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL | WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PROPS);
|
||||
g_assert_cmphex (
|
||||
wp_object_get_active_features (WP_OBJECT (fixture->proxy_endpoint)), &,
|
||||
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL | WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PROPS);
|
||||
|
||||
/* verify props */
|
||||
{
|
||||
g_autoptr (WpIterator) iterator = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpSpaPod) pod = NULL;
|
||||
gfloat float_value = 0.0f;
|
||||
gboolean boolean_value = TRUE;
|
||||
|
||||
iterator = wp_pipewire_object_enum_params_sync (
|
||||
WP_PIPEWIRE_OBJECT (fixture->proxy_endpoint), "Props", NULL);
|
||||
g_assert_nonnull (iterator);
|
||||
|
||||
g_assert_true (wp_iterator_next (iterator, &item));
|
||||
g_assert_nonnull ((pod = g_value_dup_boxed (&item)));
|
||||
|
||||
g_assert_true (wp_spa_pod_get_object (pod, NULL,
|
||||
"volume", "f", &float_value,
|
||||
"mute", "b", &boolean_value,
|
||||
NULL));
|
||||
g_assert_cmpfloat_with_epsilon (float_value, 1.0f, 0.001);
|
||||
g_assert_cmpint (boolean_value, ==, FALSE);
|
||||
}
|
||||
|
||||
/* setup change signals */
|
||||
g_signal_connect (fixture->proxy_endpoint, "params-changed",
|
||||
(GCallback) test_endpoint_params_changed, fixture);
|
||||
g_signal_connect (fixture->impl_endpoint, "params-changed",
|
||||
(GCallback) test_endpoint_params_changed, fixture);
|
||||
g_signal_connect (endpoint->node, "params-changed",
|
||||
(GCallback) test_endpoint_params_changed, fixture);
|
||||
|
||||
/* change control on the proxy */
|
||||
fixture->n_events = 0;
|
||||
wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (fixture->proxy_endpoint),
|
||||
"Props", 0,
|
||||
wp_spa_pod_new_object ("Spa:Pod:Object:Param:Props", "Props",
|
||||
"volume", "f", 0.7f, NULL));
|
||||
|
||||
/* run until the change is on all sides */
|
||||
g_main_loop_run (fixture->base.loop);
|
||||
g_assert_cmpint (fixture->n_events, ==, 3);
|
||||
|
||||
/* verify the value change on all sides */
|
||||
{
|
||||
g_autoptr (WpIterator) iterator = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpSpaPod) pod = NULL;
|
||||
gfloat float_value = 0.0f;
|
||||
gboolean boolean_value = TRUE;
|
||||
|
||||
iterator = wp_pipewire_object_enum_params_sync (
|
||||
WP_PIPEWIRE_OBJECT (fixture->proxy_endpoint), "Props", NULL);
|
||||
g_assert_nonnull (iterator);
|
||||
|
||||
g_assert_true (wp_iterator_next (iterator, &item));
|
||||
pod = g_value_dup_boxed (&item);
|
||||
g_assert_nonnull (pod);
|
||||
|
||||
g_assert_true (wp_spa_pod_get_object (pod, NULL,
|
||||
"volume", "f", &float_value,
|
||||
"mute", "b", &boolean_value,
|
||||
NULL));
|
||||
g_assert_cmpfloat_with_epsilon (float_value, 0.7f, 0.001);
|
||||
g_assert_cmpint (boolean_value, ==, FALSE);
|
||||
}
|
||||
{
|
||||
g_autoptr (WpIterator) iterator = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpSpaPod) pod = NULL;
|
||||
gfloat float_value = 0.0f;
|
||||
gboolean boolean_value = TRUE;
|
||||
|
||||
iterator = wp_pipewire_object_enum_params_sync (
|
||||
WP_PIPEWIRE_OBJECT (fixture->impl_endpoint), "Props", NULL);
|
||||
g_assert_nonnull (iterator);
|
||||
|
||||
g_assert_true (wp_iterator_next (iterator, &item));
|
||||
g_assert_nonnull ((pod = g_value_dup_boxed (&item)));
|
||||
|
||||
g_assert_true (wp_spa_pod_get_object (pod, NULL,
|
||||
"volume", "f", &float_value,
|
||||
"mute", "b", &boolean_value,
|
||||
NULL));
|
||||
g_assert_cmpfloat_with_epsilon (float_value, 0.7f, 0.001);
|
||||
g_assert_cmpint (boolean_value, ==, FALSE);
|
||||
}
|
||||
{
|
||||
g_autoptr (WpIterator) iterator = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpSpaPod) pod = NULL;
|
||||
gfloat float_value = 0.0f;
|
||||
gboolean boolean_value = TRUE;
|
||||
|
||||
iterator = wp_pipewire_object_enum_params_sync (
|
||||
WP_PIPEWIRE_OBJECT (endpoint->node), "Props", NULL);
|
||||
g_assert_nonnull (iterator);
|
||||
|
||||
g_assert_true (wp_iterator_next (iterator, &item));
|
||||
g_assert_nonnull ((pod = g_value_dup_boxed (&item)));
|
||||
|
||||
g_assert_true (wp_spa_pod_get_object (pod, NULL,
|
||||
"volume", "f", &float_value,
|
||||
"mute", "b", &boolean_value,
|
||||
NULL));
|
||||
g_assert_cmpfloat_with_epsilon (float_value, 0.7f, 0.001);
|
||||
g_assert_cmpint (boolean_value, ==, FALSE);
|
||||
}
|
||||
|
||||
/* change control on the impl */
|
||||
fixture->n_events = 0;
|
||||
wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (fixture->impl_endpoint),
|
||||
"Props", 0,
|
||||
wp_spa_pod_new_object ("Spa:Pod:Object:Param:Props", "Props",
|
||||
"mute", "b", TRUE, NULL));
|
||||
|
||||
/* run until the change is on all sides */
|
||||
g_main_loop_run (fixture->base.loop);
|
||||
g_assert_cmpint (fixture->n_events, ==, 3);
|
||||
|
||||
/* verify the value change on all sides */
|
||||
{
|
||||
g_autoptr (WpIterator) iterator = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpSpaPod) pod = NULL;
|
||||
gfloat float_value = 0.0f;
|
||||
gboolean boolean_value = TRUE;
|
||||
|
||||
iterator = wp_pipewire_object_enum_params_sync (
|
||||
WP_PIPEWIRE_OBJECT (fixture->proxy_endpoint), "Props", NULL);
|
||||
g_assert_nonnull (iterator);
|
||||
|
||||
g_assert_true (wp_iterator_next (iterator, &item));
|
||||
pod = g_value_dup_boxed (&item);
|
||||
g_assert_nonnull (pod);
|
||||
|
||||
g_assert_true (wp_spa_pod_get_object (pod, NULL,
|
||||
"volume", "f", &float_value,
|
||||
"mute", "b", &boolean_value,
|
||||
NULL));
|
||||
g_assert_cmpfloat_with_epsilon (float_value, 0.7f, 0.001);
|
||||
g_assert_cmpint (boolean_value, ==, TRUE);
|
||||
}
|
||||
{
|
||||
g_autoptr (WpIterator) iterator = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpSpaPod) pod = NULL;
|
||||
gfloat float_value = 0.0f;
|
||||
gboolean boolean_value = TRUE;
|
||||
|
||||
iterator = wp_pipewire_object_enum_params_sync (
|
||||
WP_PIPEWIRE_OBJECT (fixture->impl_endpoint), "Props", NULL);
|
||||
g_assert_nonnull (iterator);
|
||||
|
||||
g_assert_true (wp_iterator_next (iterator, &item));
|
||||
g_assert_nonnull ((pod = g_value_dup_boxed (&item)));
|
||||
|
||||
g_assert_true (wp_spa_pod_get_object (pod, NULL,
|
||||
"volume", "f", &float_value,
|
||||
"mute", "b", &boolean_value,
|
||||
NULL));
|
||||
g_assert_cmpfloat_with_epsilon (float_value, 0.7f, 0.001);
|
||||
g_assert_cmpint (boolean_value, ==, TRUE);
|
||||
}
|
||||
{
|
||||
g_autoptr (WpIterator) iterator = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpSpaPod) pod = NULL;
|
||||
gfloat float_value = 0.0f;
|
||||
gboolean boolean_value = TRUE;
|
||||
|
||||
iterator = wp_pipewire_object_enum_params_sync (
|
||||
WP_PIPEWIRE_OBJECT (endpoint->node), "Props", NULL);
|
||||
g_assert_nonnull (iterator);
|
||||
|
||||
g_assert_true (wp_iterator_next (iterator, &item));
|
||||
g_assert_nonnull ((pod = g_value_dup_boxed (&item)));
|
||||
|
||||
g_assert_true (wp_spa_pod_get_object (pod, NULL,
|
||||
"volume", "f", &float_value,
|
||||
"mute", "b", &boolean_value,
|
||||
NULL));
|
||||
g_assert_cmpfloat_with_epsilon (float_value, 0.7f, 0.001);
|
||||
g_assert_cmpint (boolean_value, ==, TRUE);
|
||||
}
|
||||
|
||||
/* change control on the node */
|
||||
fixture->n_events = 0;
|
||||
wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (endpoint->node),
|
||||
"Props", 0,
|
||||
wp_spa_pod_new_object ("Spa:Pod:Object:Param:Props", "Props",
|
||||
"volume", "f", 0.2f, NULL));
|
||||
|
||||
/* run until the change is on all sides */
|
||||
g_main_loop_run (fixture->base.loop);
|
||||
g_assert_cmpint (fixture->n_events, ==, 3);
|
||||
|
||||
/* verify the value change on all sides */
|
||||
{
|
||||
g_autoptr (WpIterator) iterator = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpSpaPod) pod = NULL;
|
||||
gfloat float_value = 0.0f;
|
||||
gboolean boolean_value = TRUE;
|
||||
|
||||
iterator = wp_pipewire_object_enum_params_sync (
|
||||
WP_PIPEWIRE_OBJECT (fixture->proxy_endpoint), "Props", NULL);
|
||||
g_assert_nonnull (iterator);
|
||||
|
||||
g_assert_true (wp_iterator_next (iterator, &item));
|
||||
g_assert_nonnull ((pod = g_value_dup_boxed (&item)));
|
||||
|
||||
g_assert_true (wp_spa_pod_get_object (pod, NULL,
|
||||
"volume", "f", &float_value,
|
||||
"mute", "b", &boolean_value,
|
||||
NULL));
|
||||
g_assert_cmpfloat_with_epsilon (float_value, 0.2f, 0.001);
|
||||
g_assert_cmpint (boolean_value, ==, TRUE);
|
||||
}
|
||||
{
|
||||
g_autoptr (WpIterator) iterator = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpSpaPod) pod = NULL;
|
||||
gfloat float_value = 0.0f;
|
||||
gboolean boolean_value = TRUE;
|
||||
|
||||
iterator = wp_pipewire_object_enum_params_sync (
|
||||
WP_PIPEWIRE_OBJECT (fixture->impl_endpoint), "Props", NULL);
|
||||
g_assert_nonnull (iterator);
|
||||
|
||||
g_assert_true (wp_iterator_next (iterator, &item));
|
||||
g_assert_nonnull ((pod = g_value_dup_boxed (&item)));
|
||||
|
||||
g_assert_true (wp_spa_pod_get_object (pod, NULL,
|
||||
"volume", "f", &float_value,
|
||||
"mute", "b", &boolean_value,
|
||||
NULL));
|
||||
g_assert_cmpfloat_with_epsilon (float_value, 0.2f, 0.001);
|
||||
g_assert_cmpint (boolean_value, ==, TRUE);
|
||||
}
|
||||
{
|
||||
g_autoptr (WpIterator) iterator = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpSpaPod) pod = NULL;
|
||||
gfloat float_value = 0.0f;
|
||||
gboolean boolean_value = TRUE;
|
||||
|
||||
iterator = wp_pipewire_object_enum_params_sync (
|
||||
WP_PIPEWIRE_OBJECT (endpoint->node), "Props", NULL);
|
||||
g_assert_nonnull (iterator);
|
||||
|
||||
g_assert_true (wp_iterator_next (iterator, &item));
|
||||
g_assert_nonnull ((pod = g_value_dup_boxed (&item)));
|
||||
|
||||
g_assert_true (wp_spa_pod_get_object (pod, NULL,
|
||||
"volume", "f", &float_value,
|
||||
"mute", "b", &boolean_value,
|
||||
NULL));
|
||||
g_assert_cmpfloat_with_epsilon (float_value, 0.2f, 0.001);
|
||||
g_assert_cmpint (boolean_value, ==, TRUE);
|
||||
}
|
||||
|
||||
/* destroy impl endpoint */
|
||||
fixture->n_events = 0;
|
||||
g_clear_object (&endpoint);
|
||||
|
||||
/* run until objects are destroyed */
|
||||
g_main_loop_run (fixture->base.loop);
|
||||
g_assert_cmpint (fixture->n_events, ==, 2);
|
||||
g_assert_null (fixture->impl_endpoint);
|
||||
g_assert_null (fixture->proxy_endpoint);
|
||||
}
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
wp_init (WP_INIT_ALL);
|
||||
|
||||
g_test_add ("/wp/endpoint/no-props", TestEndpointFixture, NULL,
|
||||
test_endpoint_setup, test_endpoint_no_props, test_endpoint_teardown);
|
||||
g_test_add ("/wp/endpoint/with-props", TestEndpointFixture, NULL,
|
||||
test_endpoint_setup, test_endpoint_with_props, test_endpoint_teardown);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
|
@ -14,13 +14,6 @@ test(
|
|||
env: common_env,
|
||||
)
|
||||
|
||||
test(
|
||||
'test-endpoint',
|
||||
executable('test-endpoint', 'endpoint.c',
|
||||
dependencies: common_deps, c_args: common_args),
|
||||
env: common_env,
|
||||
)
|
||||
|
||||
test(
|
||||
'test-events',
|
||||
executable('test-events', 'events.c',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue