lib: remove WpEndpointStream API

Add all that goes with it.
This commit is contained in:
Julian Bouzas
2021-03-09 13:13:14 -05:00
parent 9609a79903
commit 12b2c00d0b
33 changed files with 609 additions and 3078 deletions

View File

@@ -187,12 +187,8 @@ wp_endpoint_link_pw_object_mixin_priv_interface_init (
* @self: the endpoint link
* @output_endpoint: (out) (optional): the bound id of the output (source)
* endpoint
* @output_stream: (out) (optional): the bound id of the output (source)
* endpoint's stream
* @input_endpoint: (out) (optional): the bound id of the input (sink)
* endpoint
* @input_stream: (out) (optional): the bound id of the input (sink)
* endpoint's stream
*
* Retrieves the ids of the objects that are linked by this endpoint link
*
@@ -200,8 +196,7 @@ wp_endpoint_link_pw_object_mixin_priv_interface_init (
*/
void
wp_endpoint_link_get_linked_object_ids (WpEndpointLink * self,
guint32 * output_endpoint, guint32 * output_stream,
guint32 * input_endpoint, guint32 * input_stream)
guint32 * output_endpoint, guint32 * input_endpoint)
{
g_return_if_fail (WP_IS_ENDPOINT_LINK (self));
@@ -211,12 +206,8 @@ wp_endpoint_link_get_linked_object_ids (WpEndpointLink * self,
if (output_endpoint)
*output_endpoint = info->output_endpoint_id;
if (output_stream)
*output_stream = info->output_stream_id;
if (input_endpoint)
*input_endpoint = info->input_endpoint_id;
if (input_stream)
*input_stream = info->input_stream_id;
}
/**
@@ -408,7 +399,7 @@ wp_impl_endpoint_link_constructed (GObject * object)
g_autoptr (GVariant) info = NULL;
g_autoptr (GVariantIter) immutable_props = NULL;
const gchar *key, *value;
WpSiStream *stream;
WpSiEndpoint *endpoint;
self->info.version = PW_VERSION_ENDPOINT_LINK_INFO;
self->info.error = NULL;
@@ -426,21 +417,17 @@ wp_impl_endpoint_link_constructed (GObject * object)
? PW_ENDPOINT_LINK_STATE_ACTIVE
: PW_ENDPOINT_LINK_STATE_INACTIVE;
/* associate with the session, the endpoints and the streams */
/* 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);
stream = wp_si_link_get_out_stream (self->item);
endpoint = wp_si_link_get_out_endpoint (self->item);
self->info.output_endpoint_id = wp_session_item_get_associated_proxy_id (
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT);
self->info.output_stream_id = wp_session_item_get_associated_proxy_id (
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT_STREAM);
WP_SESSION_ITEM (endpoint), WP_TYPE_ENDPOINT);
stream = wp_si_link_get_in_stream (self->item);
endpoint = wp_si_link_get_in_endpoint (self->item);
self->info.input_endpoint_id = wp_session_item_get_associated_proxy_id (
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT);
self->info.input_stream_id = wp_session_item_get_associated_proxy_id (
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT_STREAM);
WP_SESSION_ITEM (endpoint), WP_TYPE_ENDPOINT);
/* construct export properties (these will come back through
the registry and appear in wp_proxy_get_global_properties) */
@@ -449,12 +436,8 @@ wp_impl_endpoint_link_constructed (GObject * object)
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_OUTPUT_STREAM, "%d", self->info.output_stream_id);
wp_properties_setf (self->immutable_props,
PW_KEY_ENDPOINT_LINK_INPUT_ENDPOINT, "%d", self->info.input_endpoint_id);
wp_properties_setf (self->immutable_props,
PW_KEY_ENDPOINT_LINK_INPUT_STREAM, "%d", self->info.input_stream_id);
/* populate immutable (global) properties */
while (g_variant_iter_next (immutable_props, "{&s&s}", &key, &value))

View File

@@ -44,8 +44,7 @@ struct _WpEndpointLinkClass
WP_API
void wp_endpoint_link_get_linked_object_ids (WpEndpointLink * self,
guint32 * output_endpoint, guint32 * output_stream,
guint32 * input_endpoint, guint32 * input_stream);
guint32 * output_endpoint, guint32 * input_endpoint);
WP_API
WpEndpointLinkState wp_endpoint_link_get_state (WpEndpointLink * self,

View File

@@ -1,591 +0,0 @@
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
/**
* SECTION: endpoint-stream
* @title: PipeWire Endpoint Stream
*/
#define G_LOG_DOMAIN "wp-endpoint-stream"
#include "endpoint-stream.h"
#include "node.h"
#include "error.h"
#include "debug.h"
#include "spa-type.h"
#include "private/impl-endpoint.h"
#include "private/pipewire-object-mixin.h"
#include <pipewire/extensions/session-manager.h>
#include <pipewire/extensions/session-manager/introspect-funcs.h>
enum {
PROP_NAME = WP_PW_OBJECT_MIXIN_PROP_CUSTOM_START,
};
static void wp_endpoint_stream_pw_object_mixin_priv_interface_init (
WpPwObjectMixinPrivInterface * iface);
/**
* WpEndpointStream:
*
* The #WpEndpointStream class allows accessing the properties and methods of a
* PipeWire endpoint stream object (`struct pw_endpoint_stream` from the
* session-manager extension).
*
* A #WpEndpointStream is constructed internally when a new endpoint appears on
* the PipeWire registry and it is made available through the #WpObjectManager
* API.
*/
G_DEFINE_TYPE_WITH_CODE (WpEndpointStream, wp_endpoint_stream, 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_stream_pw_object_mixin_priv_interface_init))
static void
wp_endpoint_stream_init (WpEndpointStream * self)
{
}
static void
wp_endpoint_stream_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_stream_info *) d->info)->name : NULL);
break;
default:
wp_pw_object_mixin_get_property (object, property_id, value, pspec);
break;
}
}
static void
wp_endpoint_stream_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_stream_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_stream_deactivate (WpObject * object, WpObjectFeatures features)
{
wp_pw_object_mixin_deactivate (object, features);
WP_OBJECT_CLASS (wp_endpoint_stream_parent_class)->deactivate (object, features);
}
static const struct pw_endpoint_stream_events endpoint_stream_events = {
PW_VERSION_ENDPOINT_STREAM_EVENTS,
.info = (HandleEventInfoFunc(endpoint_stream)) wp_pw_object_mixin_handle_event_info,
.param = wp_pw_object_mixin_handle_event_param,
};
static void
wp_endpoint_stream_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
{
wp_pw_object_mixin_handle_pw_proxy_created (proxy, pw_proxy,
endpoint_stream, &endpoint_stream_events);
}
static void
wp_endpoint_stream_class_init (WpEndpointStreamClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpObjectClass *wpobject_class = (WpObjectClass *) klass;
WpProxyClass *proxy_class = (WpProxyClass *) klass;
object_class->get_property = wp_endpoint_stream_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_stream_activate_execute_step;
wpobject_class->deactivate = wp_endpoint_stream_deactivate;
proxy_class->pw_iface_type = PW_TYPE_INTERFACE_EndpointStream;
proxy_class->pw_iface_version = PW_VERSION_ENDPOINT_STREAM;
proxy_class->pw_proxy_created = wp_endpoint_stream_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);
/**
* WpEndpointStream:name:
*
* The name of the endpoint stream
*/
g_object_class_install_property (object_class, PROP_NAME,
g_param_spec_string ("name", "name", "name", NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
}
static gint
wp_endpoint_stream_enum_params (gpointer instance, guint32 id,
guint32 start, guint32 num, WpSpaPod *filter)
{
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (instance);
return pw_endpoint_stream_enum_params (d->iface, 0, id, start, num,
filter ? wp_spa_pod_get_spa_pod (filter) : NULL);
}
static gint
wp_endpoint_stream_set_param (gpointer instance, guint32 id, guint32 flags,
WpSpaPod * param)
{
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (instance);
return pw_endpoint_stream_set_param (d->iface, id, flags,
wp_spa_pod_get_spa_pod (param));
}
static void
wp_endpoint_stream_pw_object_mixin_priv_interface_init (
WpPwObjectMixinPrivInterface * iface)
{
wp_pw_object_mixin_priv_interface_info_init (iface,
endpoint_stream, ENDPOINT_STREAM);
iface->enum_params = wp_endpoint_stream_enum_params;
iface->set_param = wp_endpoint_stream_set_param;
}
/**
* wp_endpoint_stream_get_name:
* @self: the endpoint stream
*
* Returns: the name of the endpoint stream
*/
const gchar *
wp_endpoint_stream_get_name (WpEndpointStream * self)
{
g_return_val_if_fail (WP_IS_ENDPOINT_STREAM (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_stream_info *) d->info)->name;
}
/* WpImplEndpointStream */
enum {
IMPL_PROP_0,
IMPL_PROP_ITEM,
};
struct _WpImplEndpointStream
{
WpEndpointStream parent;
struct spa_interface iface;
struct pw_endpoint_stream_info info;
WpProperties *immutable_props;
WpSiStream *item;
};
static void wp_endpoint_stream_impl_pw_object_mixin_priv_interface_init (
WpPwObjectMixinPrivInterface * iface);
G_DEFINE_TYPE_WITH_CODE (WpImplEndpointStream, wp_impl_endpoint_stream, WP_TYPE_ENDPOINT_STREAM,
G_IMPLEMENT_INTERFACE (WP_TYPE_PW_OBJECT_MIXIN_PRIV,
wp_endpoint_stream_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 const struct pw_endpoint_stream_methods impl_endpoint_stream = {
PW_VERSION_ENDPOINT_STREAM_METHODS,
.add_listener =
(ImplAddListenerFunc(endpoint_stream)) 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,
};
static void
wp_impl_endpoint_stream_init (WpImplEndpointStream * self)
{
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
self->iface = SPA_INTERFACE_INIT (
PW_TYPE_INTERFACE_EndpointStream,
PW_VERSION_ENDPOINT_STREAM,
&impl_endpoint_stream, self);
d->info = &self->info;
d->iface = &self->iface;
}
static void
populate_properties (WpImplEndpointStream * self)
{
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
g_clear_pointer (&d->properties, wp_properties_unref);
d->properties = wp_si_stream_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_stream_properties_changed (WpSiStream * item, WpImplEndpointStream * self)
{
populate_properties (self);
wp_pw_object_mixin_notify_info (self, PW_ENDPOINT_STREAM_CHANGE_MASK_PROPS);
}
static void
on_node_params_changed (WpNode * node, guint32 param_id, WpImplEndpoint * self)
{
if (param_id == SPA_PARAM_PropInfo || param_id == SPA_PARAM_Props)
wp_pw_object_mixin_notify_params_changed (self, param_id);
}
static void
wp_impl_endpoint_stream_constructed (GObject * object)
{
WpImplEndpointStream *self = WP_IMPL_ENDPOINT_STREAM (object);
g_autoptr (GVariant) info = NULL;
g_autoptr (GVariantIter) immutable_props = NULL;
g_autoptr (WpObject) node = NULL;
const gchar *key, *value;
self->info.version = PW_VERSION_ENDPOINT_STREAM_INFO;
/* get info from the interface */
info = wp_si_stream_get_registration_info (self->item);
g_variant_get (info, "(sa{ss})", &self->info.name, &immutable_props);
/* associate with the endpoint */
self->info.endpoint_id = wp_session_item_get_associated_proxy_id (
WP_SESSION_ITEM (self->item), 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 (
PW_KEY_ENDPOINT_STREAM_NAME, self->info.name,
NULL);
wp_properties_setf (self->immutable_props, PW_KEY_ENDPOINT_ID,
"%d", self->info.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, "stream-properties-changed",
G_CALLBACK (on_si_stream_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_stream_parent_class)->constructed (object);
}
static void
wp_impl_endpoint_stream_dispose (GObject * object)
{
WpImplEndpointStream *self = WP_IMPL_ENDPOINT_STREAM (object);
g_clear_pointer (&self->immutable_props, wp_properties_unref);
g_clear_pointer (&self->info.name, 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_stream_parent_class)->dispose (object);
}
static void
wp_impl_endpoint_stream_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
WpImplEndpointStream *self = WP_IMPL_ENDPOINT_STREAM (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_stream_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
WpImplEndpointStream *self = WP_IMPL_ENDPOINT_STREAM (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,
};
static guint
wp_impl_endpoint_stream_activate_get_next_step (WpObject * object,
WpFeatureActivationTransition * transition, guint step,
WpObjectFeatures missing)
{
WpImplEndpointStream *self = WP_IMPL_ENDPOINT_STREAM (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_stream_parent_class)->
activate_get_next_step (object, transition, step, missing);
}
static void
wp_impl_endpoint_stream_node_activated (WpObject * node,
GAsyncResult * res, WpTransition * transition)
{
WpImplEndpointStream *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_STREAM_CHANGE_MASK_PARAMS);
}
static void
wp_impl_endpoint_stream_activate_execute_step (WpObject * object,
WpFeatureActivationTransition * transition, guint step,
WpObjectFeatures missing)
{
WpImplEndpointStream *self = WP_IMPL_ENDPOINT_STREAM (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_stream_node_activated,
transition);
break;
}
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_EndpointStream,
wp_properties_peek_dict (self->immutable_props),
&self->iface, 0));
break;
}
default:
WP_OBJECT_CLASS (wp_impl_endpoint_stream_parent_class)->
activate_execute_step (object, transition, step, missing);
break;
}
}
static void
wp_impl_endpoint_stream_class_init (WpImplEndpointStreamClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpObjectClass *wpobject_class = (WpObjectClass *) klass;
WpProxyClass *proxy_class = (WpProxyClass *) klass;
object_class->constructed = wp_impl_endpoint_stream_constructed;
object_class->dispose = wp_impl_endpoint_stream_dispose;
object_class->set_property = wp_impl_endpoint_stream_set_property;
object_class->get_property = wp_impl_endpoint_stream_get_property;
wpobject_class->activate_get_next_step =
wp_impl_endpoint_stream_activate_get_next_step;
wpobject_class->activate_execute_step =
wp_impl_endpoint_stream_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_STREAM,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
static GPtrArray *
wp_impl_endpoint_stream_enum_params_sync (gpointer instance, guint32 id,
guint32 start, guint32 num, WpSpaPod *filter)
{
WpImplEndpointStream *self = WP_IMPL_ENDPOINT_STREAM (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_stream_set_param (gpointer instance, guint32 id, guint32 flags,
WpSpaPod * param)
{
WpImplEndpointStream *self = WP_IMPL_ENDPOINT_STREAM (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_stream_emit(hooks,method,version,...) \
spa_hook_list_call_simple(hooks, struct pw_endpoint_stream_events, \
method, version, ##__VA_ARGS__)
static void
wp_impl_endpoint_stream_emit_info (struct spa_hook_list * hooks, gconstpointer info)
{
pw_endpoint_stream_emit (hooks, info, 0, info);
}
static void
wp_impl_endpoint_stream_emit_param (struct spa_hook_list * hooks, int seq,
guint32 id, guint32 index, guint32 next, const struct spa_pod *param)
{
pw_endpoint_stream_emit (hooks, param, 0, seq, id, index, next, param);
}
static void
wp_endpoint_stream_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_stream_enum_params_sync;
iface->set_param = wp_impl_endpoint_stream_set_param;
iface->emit_info = wp_impl_endpoint_stream_emit_info;
iface->emit_param = wp_impl_endpoint_stream_emit_param;
}
WpImplEndpointStream *
wp_impl_endpoint_stream_new (WpCore * core, WpSiStream * item)
{
g_return_val_if_fail (WP_IS_CORE (core), NULL);
return g_object_new (WP_TYPE_IMPL_ENDPOINT_STREAM,
"core", core,
"item", item,
NULL);
}

View File

@@ -1,36 +0,0 @@
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#ifndef __WIREPLUMBER_ENDPOINT_STREAM_H__
#define __WIREPLUMBER_ENDPOINT_STREAM_H__
#include "global-proxy.h"
G_BEGIN_DECLS
/**
* WP_TYPE_ENDPOINT_STREAM:
*
* The #WpEndpointStream #GType
*/
#define WP_TYPE_ENDPOINT_STREAM (wp_endpoint_stream_get_type ())
WP_API
G_DECLARE_DERIVABLE_TYPE (WpEndpointStream, wp_endpoint_stream,
WP, ENDPOINT_STREAM, WpGlobalProxy)
struct _WpEndpointStreamClass
{
WpGlobalProxyClass parent_class;
};
WP_API
const gchar * wp_endpoint_stream_get_name (WpEndpointStream * self);
G_END_DECLS
#endif

View File

@@ -36,17 +36,10 @@ enum {
PROP_DIRECTION,
};
enum {
SIGNAL_STREAMS_CHANGED,
N_SIGNALS,
};
static guint32 signals[N_SIGNALS] = {0};
typedef struct _WpEndpointPrivate WpEndpointPrivate;
struct _WpEndpointPrivate
{
WpObjectManager *streams_om;
gint place_holder;
};
static void wp_endpoint_pw_object_mixin_priv_interface_init (
@@ -99,76 +92,12 @@ wp_endpoint_get_property (GObject * object, guint property_id,
}
}
static void
wp_endpoint_on_streams_om_installed (WpObjectManager *streams_om,
WpEndpoint * self)
{
wp_object_update_features (WP_OBJECT (self), WP_ENDPOINT_FEATURE_STREAMS, 0);
}
static void
wp_endpoint_emit_streams_changed (WpObjectManager *streams_om,
WpEndpoint * self)
{
g_signal_emit (self, signals[SIGNAL_STREAMS_CHANGED], 0);
wp_object_update_features (WP_OBJECT (self), WP_ENDPOINT_FEATURE_STREAMS, 0);
}
static void
wp_endpoint_enable_feature_streams (WpEndpoint * self)
{
WpPwObjectMixinData *d = wp_pw_object_mixin_get_data (self);
WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self);
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
guint32 bound_id = wp_proxy_get_bound_id (WP_PROXY (self));
guint32 n_streams = ((struct pw_endpoint_info *) d->info)->n_streams;
wp_debug_object (self, "enabling WP_ENDPOINT_FEATURE_STREAMS, bound_id:%u, "
"n_streams:%u", bound_id, n_streams);
priv->streams_om = wp_object_manager_new ();
/* proxy endpoint stream -> check for endpoint.id in global properties */
wp_object_manager_add_interest (priv->streams_om,
WP_TYPE_ENDPOINT_STREAM,
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY, PW_KEY_ENDPOINT_ID, "=u", bound_id,
NULL);
/* impl endpoint stream -> check for endpoint.id in standard properties */
wp_object_manager_add_interest (priv->streams_om,
WP_TYPE_IMPL_ENDPOINT_STREAM,
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_ENDPOINT_ID, "=u", bound_id,
NULL);
wp_object_manager_request_object_features (priv->streams_om,
WP_TYPE_ENDPOINT_STREAM, WP_OBJECT_FEATURES_ALL);
/* endpoints, under normal circumstances, always have streams.
When we export (self is a WpImplEndpoint), we have to export first
the endpoint and afterwards the streams (so that the streams can be
associated with the endpoint's bound id), but then the issue is that
the "installed" signal gets fired here without any streams being ready
and we get an endpoint with 0 streams in the WpSession's endpoints
object manager... so, unless the endpoint really has no streams,
wait for them to be prepared by waiting for the "objects-changed" only */
if (G_UNLIKELY (n_streams == 0)) {
g_signal_connect_object (priv->streams_om, "installed",
G_CALLBACK (wp_endpoint_on_streams_om_installed), self, 0);
}
g_signal_connect_object (priv->streams_om, "objects-changed",
G_CALLBACK (wp_endpoint_emit_streams_changed), self, 0);
wp_core_install_object_manager (core, priv->streams_om);
}
static WpObjectFeatures
wp_endpoint_get_supported_features (WpObject * object)
{
return wp_pw_object_mixin_get_supported_features(object)
| WP_ENDPOINT_FEATURE_STREAMS;
return wp_pw_object_mixin_get_supported_features(object);
}
enum {
STEP_STREAMS = WP_PW_OBJECT_MIXIN_STEP_CUSTOM_START,
};
static void
wp_endpoint_activate_execute_step (WpObject * object,
WpFeatureActivationTransition * transition, guint step,
@@ -187,9 +116,6 @@ wp_endpoint_activate_execute_step (WpObject * object,
case WP_PW_OBJECT_MIXIN_STEP_CACHE_PARAMS:
wp_pw_object_mixin_cache_params (object, missing);
break;
case STEP_STREAMS:
wp_endpoint_enable_feature_streams (WP_ENDPOINT (object));
break;
default:
g_assert_not_reached ();
}
@@ -199,14 +125,6 @@ static void
wp_endpoint_deactivate (WpObject * object, WpObjectFeatures features)
{
wp_pw_object_mixin_deactivate (object, features);
if (features & WP_ENDPOINT_FEATURE_STREAMS) {
WpEndpoint *self = WP_ENDPOINT (object);
WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self);
g_clear_object (&priv->streams_om);
wp_object_update_features (object, 0, WP_ENDPOINT_FEATURE_STREAMS);
}
WP_OBJECT_CLASS (wp_endpoint_parent_class)->deactivate (object, features);
}
@@ -226,14 +144,9 @@ wp_endpoint_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
static void
wp_endpoint_pw_proxy_destroyed (WpProxy * proxy)
{
WpEndpoint *self = WP_ENDPOINT (proxy);
WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self);
wp_pw_object_mixin_handle_pw_proxy_destroyed (proxy);
g_clear_object (&priv->streams_om);
wp_object_update_features (WP_OBJECT (proxy), 0,
WP_ENDPOINT_FEATURE_STREAMS);
wp_object_update_features (WP_OBJECT (proxy), 0, 0);
}
static void
@@ -258,17 +171,6 @@ wp_endpoint_class_init (WpEndpointClass * klass)
wp_pw_object_mixin_class_override_properties (object_class);
/**
* WpEndpoint::streams-changed:
* @self: the endpoint
*
* Emitted when the endpoints's streams change. This is only emitted
* when %WP_ENDPOINT_FEATURE_STREAMS is enabled.
*/
signals[SIGNAL_STREAMS_CHANGED] = g_signal_new (
"streams-changed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
/**
* WpEndpoint:name:
*
@@ -381,138 +283,6 @@ wp_endpoint_get_direction (WpEndpoint * self)
return (WpDirection) ((struct pw_endpoint_info *) d->info)->direction;
}
/**
* wp_endpoint_get_n_streams:
* @self: the endpoint
*
* Requires %WP_ENDPOINT_FEATURE_STREAMS
*
* Returns: the number of streams of this endpoint
*/
guint
wp_endpoint_get_n_streams (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_ENDPOINT_FEATURE_STREAMS, 0);
WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self);
return wp_object_manager_get_n_objects (priv->streams_om);
}
/**
* wp_endpoint_new_streams_iterator:
* @self: the endpoint
*
* Requires %WP_ENDPOINT_FEATURE_STREAMS
*
* Returns: (transfer full): a #WpIterator that iterates over all
* the endpoint streams that belong to this endpoint
*/
WpIterator *
wp_endpoint_new_streams_iterator (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_ENDPOINT_FEATURE_STREAMS, NULL);
WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self);
return wp_object_manager_new_iterator (priv->streams_om);
}
/**
* wp_endpoint_new_streams_filtered_iterator:
* @self: the endpoint
* @...: a list of constraints, terminated by %NULL
*
* Requires %WP_ENDPOINT_FEATURE_STREAMS
*
* The constraints specified in the variable arguments must follow the rules
* documented in wp_object_interest_new().
*
* Returns: (transfer full): a #WpIterator that iterates over all
* the streams that belong to this endpoint and match the constraints
*/
WpIterator *
wp_endpoint_new_streams_filtered_iterator (WpEndpoint * self, ...)
{
WpObjectInterest *interest;
va_list args;
va_start (args, self);
interest = wp_object_interest_new_valist (WP_TYPE_ENDPOINT_STREAM, &args);
va_end (args);
return wp_endpoint_new_streams_filtered_iterator_full (self, interest);
}
/**
* wp_endpoint_new_streams_filtered_iterator_full: (rename-to wp_endpoint_new_streams_filtered_iterator)
* @self: the endpoint
* @interest: (transfer full): the interest
*
* Requires %WP_ENDPOINT_FEATURE_STREAMS
*
* Returns: (transfer full): a #WpIterator that iterates over all
* the streams that belong to this endpoint and match the @interest
*/
WpIterator *
wp_endpoint_new_streams_filtered_iterator_full (WpEndpoint * self,
WpObjectInterest * interest)
{
g_return_val_if_fail (WP_IS_ENDPOINT (self), NULL);
g_return_val_if_fail (wp_object_get_active_features (WP_OBJECT (self)) &
WP_ENDPOINT_FEATURE_STREAMS, NULL);
WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self);
return wp_object_manager_new_filtered_iterator_full (priv->streams_om,
interest);
}
/**
* wp_endpoint_lookup_stream:
* @self: the endpoint
* @...: a list of constraints, terminated by %NULL
*
* Requires %WP_ENDPOINT_FEATURE_STREAMS
*
* The constraints specified in the variable arguments must follow the rules
* documented in wp_object_interest_new().
*
* Returns: (transfer full) (nullable): the first stream that matches the
* constraints, or %NULL if there is no such stream
*/
WpEndpointStream *
wp_endpoint_lookup_stream (WpEndpoint * self, ...)
{
WpObjectInterest *interest;
va_list args;
va_start (args, self);
interest = wp_object_interest_new_valist (WP_TYPE_ENDPOINT_STREAM, &args);
va_end (args);
return wp_endpoint_lookup_stream_full (self, interest);
}
/**
* wp_endpoint_lookup_stream_full: (rename-to wp_endpoint_lookup_stream)
* @self: the endpoint
* @interest: (transfer full): the interest
*
* Requires %WP_ENDPOINT_FEATURE_STREAMS
*
* Returns: (transfer full) (nullable): the first stream that matches the
* @interest, or %NULL if there is no such stream
*/
WpEndpointStream *
wp_endpoint_lookup_stream_full (WpEndpoint * self, WpObjectInterest * interest)
{
g_return_val_if_fail (WP_IS_ENDPOINT (self), NULL);
g_return_val_if_fail (wp_object_get_active_features (WP_OBJECT (self)) &
WP_ENDPOINT_FEATURE_STREAMS, NULL);
WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self);
return (WpEndpointStream *)
wp_object_manager_lookup_full (priv->streams_om, interest);
}
/**
* wp_endpoint_create_link:
* @self: the endpoint
@@ -523,15 +293,8 @@ wp_endpoint_lookup_stream_full (WpEndpoint * self, WpObjectInterest * interest)
* @props may contain:
* - `endpoint-link.output.endpoint`: the bound id of the endpoint
* that is in the %WP_DIRECTION_OUTPUT direction
* - `endpoint-link.output.stream`: the bound id of the endpoint stream
* that is in the %WP_DIRECTION_OUTPUT direction
* - `endpoint-link.input.endpoint`: the bound id of the endpoint
* that is in the %WP_DIRECTION_INPUT direction
* - `endpoint-link.input.stream`: the bound id of the endpoint stream
* that is in the %WP_DIRECTION_INPUT direction
*
* If either stream id are not specified (or set to -1), then the first
* available stream of this endpoint is used for the link.
*
* The id of @self is not necessary to be specified, so only one of
* `endpoint-link.output.endpoint`, `endpoint-link.input.endpoint`
@@ -596,14 +359,11 @@ static int
impl_create_link (void *object, const struct spa_dict *props)
{
WpImplEndpoint *self = WP_IMPL_ENDPOINT (object);
const gchar *self_ep, *self_stream, *peer_ep, *peer_stream;
guint32 self_ep_id, self_stream_id, peer_ep_id, peer_stream_id;
WpSiStream *self_si_stream = NULL;
g_autoptr (WpSiStream) peer_si_stream = NULL;
const gchar *self_ep, *peer_ep;
guint32 peer_ep_id;
g_autoptr (WpSiEndpoint) peer_si_endpoint = NULL;
g_autoptr (WpSession) session = NULL;
g_autoptr (WpEndpointStream) self_stream_proxy = NULL;
g_autoptr (WpEndpoint) peer_ep_proxy = NULL;
g_autoptr (WpEndpointStream) peer_stream_proxy = NULL;
/* find the session */
session = wp_session_item_get_associated_proxy (
@@ -612,18 +372,14 @@ impl_create_link (void *object, const struct spa_dict *props)
if (self->info.direction == PW_DIRECTION_OUTPUT) {
self_ep = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_OUTPUT_ENDPOINT);
self_stream = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_OUTPUT_STREAM);
peer_ep = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_INPUT_ENDPOINT);
peer_stream = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_INPUT_STREAM);
} else {
self_ep = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_INPUT_ENDPOINT);
self_stream = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_INPUT_STREAM);
peer_ep = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_OUTPUT_ENDPOINT);
peer_stream = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_OUTPUT_STREAM);
}
wp_debug_object (self, "requested link between %s:%s [self] & %s:%s [peer]",
self_ep, self_stream, peer_ep, peer_stream);
wp_debug_object (self, "requested link between %s [self] & %s [peer]",
self_ep, peer_ep);
/* verify arguments */
if (!peer_ep) {
@@ -638,41 +394,10 @@ impl_create_link (void *object, const struct spa_dict *props)
return -EACCES;
}
/* convert to int - allow unspecified streams */
self_ep_id = wp_proxy_get_bound_id (WP_PROXY (self));
self_stream_id = self_stream ? (guint32) atoi (self_stream) : SPA_ID_INVALID;
/* convert to int */
peer_ep_id = (guint32) atoi (peer_ep);
peer_stream_id = peer_stream ? (guint32) atoi (peer_stream) : SPA_ID_INVALID;
/* find our stream */
if (self_stream_id != SPA_ID_INVALID) {
WpSiStream *tmp;
guint32 tmp_id;
for (guint i = 0; i < wp_si_endpoint_get_n_streams (self->item); i++) {
tmp = wp_si_endpoint_get_stream (self->item, i);
tmp_id = wp_session_item_get_associated_proxy_id (WP_SESSION_ITEM (tmp),
WP_TYPE_ENDPOINT_STREAM);
if (tmp_id == self_stream_id) {
self_si_stream = tmp;
break;
}
}
} else {
self_si_stream = wp_si_endpoint_get_stream (self->item, 0);
}
if (!self_si_stream) {
wp_warning_object (self, "stream %d not found in %d", self_stream_id,
self_ep_id);
return -EINVAL;
}
self_stream_proxy = wp_session_item_get_associated_proxy (
WP_SESSION_ITEM (self_si_stream), WP_TYPE_ENDPOINT_STREAM);
/* find the peer stream */
/* find the peer endpoint */
peer_ep_proxy = wp_session_lookup_endpoint (session,
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", peer_ep_id, NULL);
if (!peer_ep_proxy) {
@@ -680,44 +405,21 @@ impl_create_link (void *object, const struct spa_dict *props)
return -EINVAL;
}
if (peer_stream_id != SPA_ID_INVALID) {
peer_stream_proxy = wp_endpoint_lookup_stream (peer_ep_proxy,
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", peer_stream_id, NULL);
} else {
peer_stream_proxy = wp_endpoint_lookup_stream (peer_ep_proxy, NULL);
}
if (!peer_stream_proxy) {
wp_warning_object (self, "stream %d not found in %d", peer_stream_id,
peer_ep_id);
return -EINVAL;
}
if (!WP_IS_IMPL_ENDPOINT_STREAM (peer_stream_proxy)) {
/* TODO - if the stream is not implemented by our session manager,
we can still make things work by calling the peer endpoint's
create_link() and negotiating ports, while creating a dummy
WpSiEndpoint / WpSiStream on our end to satisfy the API */
return -ENAVAIL;
}
g_object_get (peer_stream_proxy, "item", &peer_si_stream, NULL);
g_object_get (peer_ep_proxy, "item", &peer_si_endpoint, NULL);
wp_info_object (self, "creating endpoint link between "
"%s|%s " WP_OBJECT_FORMAT ", %s|%s " WP_OBJECT_FORMAT,
"%s " WP_OBJECT_FORMAT ", %s " WP_OBJECT_FORMAT,
wp_endpoint_get_name (WP_ENDPOINT (self)),
wp_endpoint_stream_get_name (self_stream_proxy),
WP_OBJECT_ARGS (self_si_stream),
WP_OBJECT_ARGS (self->item),
wp_endpoint_get_name (peer_ep_proxy),
wp_endpoint_stream_get_name (peer_stream_proxy),
WP_OBJECT_ARGS (peer_si_stream));
WP_OBJECT_ARGS (peer_si_endpoint));
/* create the link */
{
g_autoptr (WpSessionItem) link = NULL;
g_autoptr (WpCore) core = NULL;
GVariantBuilder b;
guint64 out_stream_i, in_stream_i;
guint64 out_endpoint_i, in_endpoint_i;
core = wp_object_get_core (WP_OBJECT (self));
link = wp_session_item_make (core, "si-standard-link");
@@ -727,18 +429,18 @@ impl_create_link (void *object, const struct spa_dict *props)
}
if (self->info.direction == PW_DIRECTION_OUTPUT) {
out_stream_i = (guint64) self_si_stream;
in_stream_i = (guint64) peer_si_stream;
out_endpoint_i = (guint64) self->item;
in_endpoint_i = (guint64) peer_si_endpoint;
} else {
out_stream_i = (guint64) peer_si_stream;
in_stream_i = (guint64) self_si_stream;
out_endpoint_i = (guint64) peer_si_endpoint;
in_endpoint_i = (guint64) self->item;
}
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}", "out-stream",
g_variant_new_uint64 (out_stream_i));
g_variant_builder_add (&b, "{sv}", "in-stream",
g_variant_new_uint64 (in_stream_i));
g_variant_builder_add (&b, "{sv}", "out-endpoint",
g_variant_new_uint64 (out_endpoint_i));
g_variant_builder_add (&b, "{sv}", "in-endpoint",
g_variant_new_uint64 (in_endpoint_i));
g_variant_builder_add (&b, "{sv}", "manage-lifetime",
g_variant_new_boolean (TRUE));
if (G_UNLIKELY (!wp_session_item_configure (link, g_variant_builder_end (&b)))) {
@@ -824,7 +526,6 @@ wp_impl_endpoint_constructed (GObject * object)
&self->info.media_class, &direction, &immutable_props);
self->info.direction = (enum pw_direction) direction;
self->info.n_streams = wp_si_endpoint_get_n_streams (self->item);
/* associate with the session */
self->info.session_id = wp_session_item_get_associated_proxy_id (
@@ -922,7 +623,7 @@ wp_impl_endpoint_get_property (GObject * object, guint property_id,
}
enum {
STEP_ACTIVATE_NODE = STEP_STREAMS + 1,
STEP_ACTIVATE_NODE = WP_PW_OBJECT_MIXIN_STEP_CUSTOM_START + 1,
};
static guint
@@ -1020,12 +721,7 @@ wp_impl_endpoint_activate_execute_step (WpObject * object,
static void
wp_impl_endpoint_pw_proxy_destroyed (WpProxy * proxy)
{
WpEndpointPrivate *priv =
wp_endpoint_get_instance_private (WP_ENDPOINT (proxy));
g_clear_object (&priv->streams_om);
wp_object_update_features (WP_OBJECT (proxy), 0,
WP_ENDPOINT_FEATURE_STREAMS);
wp_object_update_features (WP_OBJECT (proxy), 0, 0);
}
static void

View File

@@ -11,24 +11,11 @@
#include "global-proxy.h"
#include "port.h"
#include "endpoint-stream.h"
#include "iterator.h"
#include "object-interest.h"
G_BEGIN_DECLS
/**
* WpEndpointFeatures:
* @WP_ENDPOINT_FEATURE_STREAMS: caches information about streams, enabling
* the use of wp_endpoint_get_n_streams(), wp_endpoint_lookup_stream(),
* wp_endpoint_new_streams_iterator() and related methods
*
* An extension of #WpProxyFeatures
*/
typedef enum { /*< flags >*/
WP_ENDPOINT_FEATURE_STREAMS = (WP_PROXY_FEATURE_CUSTOM_START << 0),
} WpEndpointFeatures;
/**
* WP_TYPE_ENDPOINT:
*
@@ -52,28 +39,6 @@ const gchar * wp_endpoint_get_media_class (WpEndpoint * self);
WP_API
WpDirection wp_endpoint_get_direction (WpEndpoint * self);
WP_API
guint wp_endpoint_get_n_streams (WpEndpoint * self);
WP_API
WpIterator * wp_endpoint_new_streams_iterator (WpEndpoint * self);
WP_API
WpIterator * wp_endpoint_new_streams_filtered_iterator (WpEndpoint * self, ...)
G_GNUC_NULL_TERMINATED;
WP_API
WpIterator * wp_endpoint_new_streams_filtered_iterator_full (WpEndpoint * self,
WpObjectInterest * interest);
WP_API
WpEndpointStream * wp_endpoint_lookup_stream (WpEndpoint * self, ...)
G_GNUC_NULL_TERMINATED;
WP_API
WpEndpointStream * wp_endpoint_lookup_stream_full (WpEndpoint * self,
WpObjectInterest * interest);
WP_API
void wp_endpoint_create_link (WpEndpoint * self, WpProperties * props);

View File

@@ -7,7 +7,6 @@ wp_lib_sources = files(
'device.c',
'endpoint.c',
'endpoint-link.c',
'endpoint-stream.c',
'error.c',
'global-proxy.c',
'iterator.c',
@@ -43,7 +42,6 @@ wp_lib_headers = files(
'device.h',
'endpoint.h',
'endpoint-link.h',
'endpoint-stream.h',
'error.h',
'global-proxy.h',
'iterator.h',

View File

@@ -10,7 +10,6 @@
#define __WIREPLUMBER_PRIVATE_IMPL_ENDPOINT_H__
#include "endpoint.h"
#include "endpoint-stream.h"
#include "endpoint-link.h"
#include "si-interfaces.h"
@@ -24,15 +23,6 @@ G_DECLARE_FINAL_TYPE (WpImplEndpoint, wp_impl_endpoint,
WpImplEndpoint * wp_impl_endpoint_new (WpCore * core, WpSiEndpoint * item);
/* impl endpoint stream */
#define WP_TYPE_IMPL_ENDPOINT_STREAM (wp_impl_endpoint_stream_get_type ())
G_DECLARE_FINAL_TYPE (WpImplEndpointStream, wp_impl_endpoint_stream,
WP, IMPL_ENDPOINT_STREAM, WpEndpointStream)
WpImplEndpointStream * wp_impl_endpoint_stream_new (WpCore * core,
WpSiStream * item);
/* impl endpoint link */
#define WP_TYPE_IMPL_ENDPOINT_LINK (wp_impl_endpoint_link_get_type ())

View File

@@ -88,7 +88,6 @@ struct _WpSessionItemPrivate
WpImplEndpoint *impl_endpoint;
WpImplEndpointLink *impl_link;
};
GHashTable *impl_streams;
};
enum {
@@ -146,17 +145,9 @@ static gpointer
wp_session_item_default_get_associated_proxy (WpSessionItem * self,
GType proxy_type)
{
WpSessionItemPrivate *priv;
WpSessionItemPrivate *priv = wp_session_item_get_instance_private (self);
gpointer ret = NULL;
if (WP_IS_SI_STREAM (self)) {
g_autoptr (WpSiEndpoint) ep =
wp_si_stream_get_parent_endpoint (WP_SI_STREAM (self));
priv = wp_session_item_get_instance_private (WP_SESSION_ITEM (ep));
} else {
priv = wp_session_item_get_instance_private (self);
}
if (proxy_type == WP_TYPE_SESSION) {
ret = g_weak_ref_get (&priv->session);
}
@@ -168,11 +159,6 @@ wp_session_item_default_get_associated_proxy (WpSessionItem * self,
if (priv->impl_proxy && WP_IS_ENDPOINT_LINK (priv->impl_proxy))
ret = g_object_ref (priv->impl_proxy);
}
else if (proxy_type == WP_TYPE_ENDPOINT_STREAM) {
gpointer impl_stream = priv->impl_streams ?
g_hash_table_lookup (priv->impl_streams, self) : NULL;
ret = impl_stream ? g_object_ref (impl_stream) : NULL;
}
wp_trace_object (self, "associated %s: " WP_OBJECT_FORMAT,
g_type_name (proxy_type), WP_OBJECT_ARGS (ret));
@@ -191,8 +177,6 @@ wp_session_item_default_activate_get_next_step (WpSessionItem * self,
enum {
EXPORT_STEP_ENDPOINT = WP_TRANSITION_STEP_CUSTOM_START,
EXPORT_STEP_STREAMS,
EXPORT_STEP_ENDPOINT_FT_STREAMS,
EXPORT_STEP_LINK,
EXPORT_STEP_CONNECT_DESTROYED,
};
@@ -201,8 +185,6 @@ static guint
wp_session_item_default_export_get_next_step (WpSessionItem * self,
WpTransition * transition, guint step)
{
WpSessionItemPrivate *priv = wp_session_item_get_instance_private (self);
switch (step) {
case WP_TRANSITION_STEP_NONE:
if (WP_IS_SI_ENDPOINT (self))
@@ -219,20 +201,6 @@ wp_session_item_default_export_get_next_step (WpSessionItem * self,
case EXPORT_STEP_ENDPOINT:
g_return_val_if_fail (WP_IS_SI_ENDPOINT (self), WP_TRANSITION_STEP_ERROR);
return EXPORT_STEP_STREAMS;
case EXPORT_STEP_STREAMS:
g_return_val_if_fail (WP_IS_SI_ENDPOINT (self), WP_TRANSITION_STEP_ERROR);
g_return_val_if_fail (priv->impl_streams, WP_TRANSITION_STEP_ERROR);
/* go to next step only when all impl proxies are activated */
if (g_hash_table_size (priv->impl_streams) ==
wp_si_endpoint_get_n_streams (WP_SI_ENDPOINT (self)))
return EXPORT_STEP_ENDPOINT_FT_STREAMS;
else
return step;
case EXPORT_STEP_ENDPOINT_FT_STREAMS:
return WP_TRANSITION_STEP_NONE;
case EXPORT_STEP_LINK:
@@ -252,7 +220,6 @@ on_export_proxy_activated (WpObject * proxy, GAsyncResult * res, gpointer data)
{
WpTransition *transition = WP_TRANSITION (data);
WpSessionItem *self = wp_transition_get_source_object (transition);
WpSessionItemPrivate *priv = wp_session_item_get_instance_private (self);
g_autoptr (GError) error = NULL;
if (!wp_object_activate_finish (proxy, res, &error)) {
@@ -260,15 +227,6 @@ on_export_proxy_activated (WpObject * proxy, GAsyncResult * res, gpointer data)
return;
}
if (WP_IS_IMPL_ENDPOINT_STREAM (proxy)) {
g_autoptr (WpSiStream) si_stream = NULL;
g_object_get (proxy, "item", &si_stream, NULL);
g_return_if_fail (si_stream != NULL);
g_hash_table_insert (priv->impl_streams, si_stream, g_object_ref (proxy));
}
wp_debug_object (self, "export proxy " WP_OBJECT_FORMAT " activated",
WP_OBJECT_ARGS (proxy));
@@ -324,39 +282,6 @@ wp_session_item_default_export_execute_step (WpSessionItem * self,
transition);
break;
case EXPORT_STEP_STREAMS: {
guint i, n_streams;
priv->impl_streams = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, g_object_unref);
n_streams = wp_si_endpoint_get_n_streams (WP_SI_ENDPOINT (self));
for (i = 0; i < n_streams; i++) {
WpSiStream *stream = wp_si_endpoint_get_stream (WP_SI_ENDPOINT (self), i);
WpImplEndpointStream *impl_stream =
wp_impl_endpoint_stream_new (core, stream);
wp_object_activate (WP_OBJECT (impl_stream),
WP_OBJECT_FEATURES_ALL, NULL,
(GAsyncReadyCallback) on_export_proxy_activated,
transition);
/* the augment task holds a ref; object will be added to
priv->impl_streams when activated */
g_object_unref (impl_stream);
}
break;
}
case EXPORT_STEP_ENDPOINT_FT_STREAMS:
/* add feature streams only after the streams are exported, otherwise
the endpoint will never be activated in the first place (because it
internally waits for the streams to be ready) */
wp_object_activate (WP_OBJECT (priv->impl_endpoint),
WP_ENDPOINT_FEATURE_STREAMS, NULL,
(GAsyncReadyCallback) on_export_proxy_activated,
transition);
break;
case EXPORT_STEP_LINK:
priv->impl_link = wp_impl_endpoint_link_new (core, WP_SI_LINK (self));
@@ -383,7 +308,6 @@ wp_session_item_default_export_rollback (WpSessionItem * self)
WpSessionItemPrivate *priv = wp_session_item_get_instance_private (self);
if (priv->impl_proxy)
g_signal_handlers_disconnect_by_data (priv->impl_proxy, self);
g_clear_pointer (&priv->impl_streams, g_hash_table_unref);
g_clear_object (&priv->impl_proxy);
g_weak_ref_set (&priv->session, NULL);
}
@@ -546,9 +470,6 @@ wp_session_item_clear_flag (WpSessionItem * self, WpSiFlags flag)
* - An exported #WpSiEndpoint should have at least:
* - an associated #WpEndpoint
* - an associated #WpSession
* - An exported #WpSiStream should have at least:
* - an associated #WpEndpointStream
* - an associated #WpEndpoint
* - In cases where the item wraps a single PipeWire node, it should also
* have an associated #WpNode
*

View File

@@ -29,8 +29,8 @@ wp_si_endpoint_default_get_properties (WpSiEndpoint * self)
return NULL;
}
static WpSiStreamAcquisition *
wp_si_endpoint_default_get_stream_acquisition (WpSiEndpoint * self)
static WpSiEndpointAcquisition *
wp_si_endpoint_default_get_endpoint_acquisition (WpSiEndpoint * self)
{
return NULL;
}
@@ -39,13 +39,11 @@ static void
wp_si_endpoint_default_init (WpSiEndpointInterface * iface)
{
iface->get_properties = wp_si_endpoint_default_get_properties;
iface->get_stream_acquisition = wp_si_endpoint_default_get_stream_acquisition;
iface->get_endpoint_acquisition =
wp_si_endpoint_default_get_endpoint_acquisition;
g_signal_new ("endpoint-properties-changed", G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
g_signal_new ("endpoint-streams-changed", G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/**
@@ -86,125 +84,21 @@ wp_si_endpoint_get_properties (WpSiEndpoint * self)
}
/**
* wp_si_endpoint_get_n_streams: (virtual get_n_streams)
* wp_si_endpoint_get_endpoint_acquisition: (virtual get_endpoint_acquisition)
* @self: the session item
*
* Returns: the number of streams in the endpoint
*/
guint
wp_si_endpoint_get_n_streams (WpSiEndpoint * self)
{
g_return_val_if_fail (WP_IS_SI_ENDPOINT (self), 0);
g_return_val_if_fail (WP_SI_ENDPOINT_GET_IFACE (self)->get_n_streams, 0);
return WP_SI_ENDPOINT_GET_IFACE (self)->get_n_streams (self);
}
/**
* wp_si_endpoint_get_stream: (virtual get_stream)
* @self: the session item
* @index: the stream index, from 0 up to and excluding
* wp_si_endpoint_get_n_streams()
*
* Returns: (transfer none): the stream at @index
*/
WpSiStream *
wp_si_endpoint_get_stream (WpSiEndpoint * self, guint index)
{
g_return_val_if_fail (WP_IS_SI_ENDPOINT (self), NULL);
g_return_val_if_fail (WP_SI_ENDPOINT_GET_IFACE (self)->get_stream, NULL);
return WP_SI_ENDPOINT_GET_IFACE (self)->get_stream (self, index);
}
/**
* wp_si_endpoint_get_stream_acquisition: (virtual get_stream_acquisition)
* @self: the session item
*
* Returns: (transfer none) (nullable): the stream acquisition interface
* Returns: (transfer none) (nullable): the endpoint acquisition interface
* associated with this endpoint, or %NULL if this endpoint does not require
* acquiring streams before linking them
* acquiring endpoints before linking them
*/
WpSiStreamAcquisition *
wp_si_endpoint_get_stream_acquisition (WpSiEndpoint * self)
WpSiEndpointAcquisition *
wp_si_endpoint_get_endpoint_acquisition (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_stream_acquisition,
NULL);
g_return_val_if_fail (
WP_SI_ENDPOINT_GET_IFACE (self)->get_endpoint_acquisition, NULL);
return WP_SI_ENDPOINT_GET_IFACE (self)->get_stream_acquisition (self);
}
/**
* WpSiStream:
*
* An interface for session items that provide a PipeWire endpoint stream.
*/
G_DEFINE_INTERFACE (WpSiStream, wp_si_stream, WP_TYPE_SESSION_ITEM)
static WpProperties *
wp_si_stream_default_get_properties (WpSiStream * self)
{
return NULL;
}
static void
wp_si_stream_default_init (WpSiStreamInterface * iface)
{
iface->get_properties = wp_si_stream_default_get_properties;
g_signal_new ("stream-properties-changed", G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/**
* wp_si_stream_get_registration_info: (virtual get_registration_info)
* @self: the session item
*
* This should return information that is used for registering the stream,
* as a GVariant tuple of type (sa{ss}) that contains, in order:
* - s: the stream's name
* - a{ss}: additional properties to be added to the list of global properties
*
* Returns: (transfer full): registration info for the stream
*/
GVariant *
wp_si_stream_get_registration_info (WpSiStream * self)
{
g_return_val_if_fail (WP_IS_SI_STREAM (self), NULL);
g_return_val_if_fail (WP_SI_STREAM_GET_IFACE (self)->get_registration_info, NULL);
return WP_SI_STREAM_GET_IFACE (self)->get_registration_info (self);
}
/**
* wp_si_stream_get_properties: (virtual get_properties)
* @self: the session item
*
* Returns: (transfer full) (nullable): the properties of the stream
*/
WpProperties *
wp_si_stream_get_properties (WpSiStream * self)
{
g_return_val_if_fail (WP_IS_SI_STREAM (self), NULL);
g_return_val_if_fail (WP_SI_STREAM_GET_IFACE (self)->get_properties, NULL);
return WP_SI_STREAM_GET_IFACE (self)->get_properties (self);
}
/**
* wp_si_stream_get_parent_endpoint: (virtual get_parent_endpoint)
* @self: the session item
*
* Returns: (transfer full): the endpoint that this stream belongs to
*/
WpSiEndpoint *
wp_si_stream_get_parent_endpoint (WpSiStream * self)
{
g_return_val_if_fail (WP_IS_SI_STREAM (self), NULL);
g_return_val_if_fail (WP_SI_STREAM_GET_IFACE (self)->get_parent_endpoint, NULL);
return WP_SI_STREAM_GET_IFACE (self)->get_parent_endpoint (self);
return WP_SI_ENDPOINT_GET_IFACE (self)->get_endpoint_acquisition (self);
}
/**
@@ -264,33 +158,33 @@ wp_si_link_get_properties (WpSiLink * self)
}
/**
* wp_si_link_get_out_stream: (virtual get_out_stream)
* wp_si_link_get_out_endpoint: (virtual get_out_endpoint)
* @self: the session item
*
* Returns: (transfer none): the output stream that is linked by this link
* Returns: (transfer none): the output endpoint that is linked by this link
*/
WpSiStream *
wp_si_link_get_out_stream (WpSiLink * self)
WpSiEndpoint *
wp_si_link_get_out_endpoint (WpSiLink * self)
{
g_return_val_if_fail (WP_IS_SI_LINK (self), NULL);
g_return_val_if_fail (WP_SI_LINK_GET_IFACE (self)->get_out_stream, NULL);
g_return_val_if_fail (WP_SI_LINK_GET_IFACE (self)->get_out_endpoint, NULL);
return WP_SI_LINK_GET_IFACE (self)->get_out_stream (self);
return WP_SI_LINK_GET_IFACE (self)->get_out_endpoint (self);
}
/**
* wp_si_link_get_in_stream: (virtual get_in_stream)
* wp_si_link_get_in_endpoint: (virtual get_in_endpoint)
* @self: the session item
*
* Returns: (transfer none): the input stream that is linked by this link
* Returns: (transfer none): the input endpoint that is linked by this link
*/
WpSiStream *
wp_si_link_get_in_stream (WpSiLink * self)
WpSiEndpoint *
wp_si_link_get_in_endpoint (WpSiLink * self)
{
g_return_val_if_fail (WP_IS_SI_LINK (self), NULL);
g_return_val_if_fail (WP_SI_LINK_GET_IFACE (self)->get_in_stream, NULL);
g_return_val_if_fail (WP_SI_LINK_GET_IFACE (self)->get_in_endpoint, NULL);
return WP_SI_LINK_GET_IFACE (self)->get_in_stream (self);
return WP_SI_LINK_GET_IFACE (self)->get_in_endpoint (self);
}
/**
@@ -300,8 +194,8 @@ wp_si_link_get_in_stream (WpSiLink * self)
* This information is used to create links in the nodes graph.
*
* This is normally implemented by the same session items that implement
* #WpSiStream. The standard link implementation expects to be able to cast
* a #WpSiStream into a #WpSiPortInfo.
* #WpSiEndpoint. The standard link implementation expects to be able to cast
* a #WpSiEndpoint into a #WpSiPortInfo.
*/
G_DEFINE_INTERFACE (WpSiPortInfo, wp_si_port_info, WP_TYPE_SESSION_ITEM)
@@ -338,15 +232,15 @@ wp_si_port_info_default_init (WpSiPortInfoInterface * iface)
* Contexts other than %NULL may only be used internally to ease the
* implementation of more complex endpoint relationships. For example, a
* #WpSessionItem that is in control of an input (sink) adapter node may
* implement #WpSiStream and #WpSiPortInfo where the %NULL context will return
* the standard input ports and the "monitor" context will return the adapter's
* monitor ports. When linking this stream to another stream, the %NULL context
* implement #WpSiPortInfo where the %NULL context will return the standard
* input ports and the "monitor" context will return the adapter's monitor
* ports. When linking this endpoint to another endpoint, the %NULL context
* will always be used, but the item may internally spawn a secondary
* #WpSessionItem that implements the "monitor" endpoint & stream. That
* secondary stream may implement #WpSiPortInfo, chaining calls to the
* #WpSiPortInfo of the original item using the "monitor" context. This way,
* the monitor #WpSessionItem does not need to share control of the underlying
* node; it only proxies calls to satisfy the API.
* #WpSessionItem that implements the "monitor" endpoint. That secondary
* endpoint may implement #WpSiPortInfo, chaining calls to the #WpSiPortInfo
* of the original item using the "monitor" context. This way, the monitor
* #WpSessionItem does not need to share control of the underlying node; it
* only proxies calls to satisfy the API.
*
* Returns: (transfer full): a #GVariant containing information about the
* ports of this item
@@ -361,92 +255,93 @@ wp_si_port_info_get_ports (WpSiPortInfo * self, const gchar * context)
}
/**
* WpSiStreamAcquisition:
* WpSiEndpointAcquisition:
*
* This interface provides a way to request a stream for linking before doing
* so. This allows endpoint implementations to apply internal policy rules
* (such as, streams that can only be linked once or mutually exclusive streams).
* This interface provides a way to request an endpoint for linking before doing
* so. This allows endpoint implementations to apply internal policy rules.
*
* A #WpSiStreamAcquisition is associated directly with a #WpSiEndpoint via
* wp_si_endpoint_get_stream_acquisition(). In order to allow switching policies,
* it is recommended that endpoint implementations use a separate session item
* to implement this interface and allow replacing it.
* A #WpSiEndpointAcquisition is associated directly with a #WpSiEndpoint via
* wp_si_endpoint_get_endpoint_acquisition(). In order to allow switching
* policies, it is recommended that endpoint implementations use a separate
* session item to implement this interface and allow replacing it.
*/
G_DEFINE_INTERFACE (WpSiStreamAcquisition, wp_si_stream_acquisition,
G_DEFINE_INTERFACE (WpSiEndpointAcquisition, wp_si_endpoint_acquisition,
WP_TYPE_SESSION_ITEM)
static void
wp_si_stream_acquisition_default_init (WpSiStreamAcquisitionInterface * iface)
wp_si_endpoint_acquisition_default_init (
WpSiEndpointAcquisitionInterface * iface)
{
}
/**
* wp_si_stream_acquisition_acquire: (virtual acquire)
* wp_si_endpoint_acquisition_acquire: (virtual acquire)
* @self: the session item
* @acquisitor: the link that is trying to acquire a stream
* @stream: the stream that is being acquired
* @acquisitor: the link that is trying to acquire an endpoint
* @endpoint: the endpoint that is being acquired
* @callback: (scope async): the callback to call when the operation is done
* @data: (closure): user data for @callback
*
* Acquires the @stream for linking by @acquisitor.
* Acquires the @endpoint for linking by @acquisitor.
*
* When a link is not allowed by policy, this operation should return
* an error.
*
* When a link needs to be delayed for a short amount of time (ex. to apply
* a fade out effect on another stream), this operation should finish with a
* a fade out effect on another endpoint), this operation should finish with a
* delay. It is safe to assume that after this operation completes,
* the stream will be linked immediately.
* the endpoint will be linked immediately.
*/
void
wp_si_stream_acquisition_acquire (WpSiStreamAcquisition * self,
WpSiLink * acquisitor, WpSiStream * stream,
wp_si_endpoint_acquisition_acquire (WpSiEndpointAcquisition * self,
WpSiLink * acquisitor, WpSiEndpoint * endpoint,
GAsyncReadyCallback callback, gpointer data)
{
g_return_if_fail (WP_IS_SI_STREAM_ACQUISITION (self));
g_return_if_fail (WP_SI_STREAM_ACQUISITION_GET_IFACE (self)->acquire);
g_return_if_fail (WP_IS_SI_ENDPOINT_ACQUISITION (self));
g_return_if_fail (WP_SI_ENDPOINT_ACQUISITION_GET_IFACE (self)->acquire);
WP_SI_STREAM_ACQUISITION_GET_IFACE (self)->acquire (self, acquisitor, stream,
callback, data);
WP_SI_ENDPOINT_ACQUISITION_GET_IFACE (self)->acquire (self, acquisitor,
endpoint, callback, data);
}
/**
* wp_si_stream_acquisition_acquire_finish: (virtual acquire_finish)
* wp_si_endpoint_acquisition_acquire_finish: (virtual acquire_finish)
* @self: the session item
* @res: the async result
* @error: (out) (optional): the operation's error, if it occurred
*
* Finishes the operation started by wp_si_stream_acquisition_acquire().
* Finishes the operation started by wp_si_endpoint_acquisition_acquire().
* This is meant to be called in the callback that was passed to that method.
*
* Returns: %TRUE on success, %FALSE if there was an error
*/
gboolean
wp_si_stream_acquisition_acquire_finish (WpSiStreamAcquisition * self,
wp_si_endpoint_acquisition_acquire_finish (WpSiEndpointAcquisition * self,
GAsyncResult * res, GError ** error)
{
g_return_val_if_fail (WP_IS_SI_STREAM_ACQUISITION (self), FALSE);
g_return_val_if_fail (WP_IS_SI_ENDPOINT_ACQUISITION (self), FALSE);
g_return_val_if_fail (
WP_SI_STREAM_ACQUISITION_GET_IFACE (self)->acquire_finish, FALSE);
WP_SI_ENDPOINT_ACQUISITION_GET_IFACE (self)->acquire_finish, FALSE);
return WP_SI_STREAM_ACQUISITION_GET_IFACE (self)->acquire_finish (self, res,
return WP_SI_ENDPOINT_ACQUISITION_GET_IFACE (self)->acquire_finish (self, res,
error);
}
/**
* wp_si_stream_acquisition_release: (virtual release)
* wp_si_endpoint_acquisition_release: (virtual release)
* @self: the session item
* @acquisitor: the link that had previously acquired the stream
* @stream: the stream that is being released
* @acquisitor: the link that had previously acquired the endpoint
* @endpoint: the endpoint that is being released
*
* Releases the @stream, which means that it is being unlinked.
* Releases the @endpoint, which means that it is being unlinked.
*/
void
wp_si_stream_acquisition_release (WpSiStreamAcquisition * self,
WpSiLink * acquisitor, WpSiStream * stream)
wp_si_endpoint_acquisition_release (WpSiEndpointAcquisition * self,
WpSiLink * acquisitor, WpSiEndpoint * endpoint)
{
g_return_if_fail (WP_IS_SI_STREAM_ACQUISITION (self));
g_return_if_fail (WP_SI_STREAM_ACQUISITION_GET_IFACE (self)->release);
g_return_if_fail (WP_IS_SI_ENDPOINT_ACQUISITION (self));
g_return_if_fail (WP_SI_ENDPOINT_ACQUISITION_GET_IFACE (self)->release);
WP_SI_STREAM_ACQUISITION_GET_IFACE (self)->release (self, acquisitor, stream);
WP_SI_ENDPOINT_ACQUISITION_GET_IFACE (self)->release (self, acquisitor,
endpoint);
}

View File

@@ -16,8 +16,7 @@
G_BEGIN_DECLS
typedef struct _WpSiStream WpSiStream;
typedef struct _WpSiStreamAcquisition WpSiStreamAcquisition;
typedef struct _WpSiEndpointAcquisition WpSiEndpointAcquisition;
/**
* WP_TYPE_SI_ENDPOINT:
@@ -36,10 +35,7 @@ struct _WpSiEndpointInterface
GVariant * (*get_registration_info) (WpSiEndpoint * self);
WpProperties * (*get_properties) (WpSiEndpoint * self);
guint (*get_n_streams) (WpSiEndpoint * self);
WpSiStream * (*get_stream) (WpSiEndpoint * self, guint index);
WpSiStreamAcquisition * (*get_stream_acquisition) (WpSiEndpoint * self);
WpSiEndpointAcquisition * (*get_endpoint_acquisition) (WpSiEndpoint * self);
};
WP_API
@@ -49,42 +45,8 @@ WP_API
WpProperties * wp_si_endpoint_get_properties (WpSiEndpoint * self);
WP_API
guint wp_si_endpoint_get_n_streams (WpSiEndpoint * self);
WP_API
WpSiStream * wp_si_endpoint_get_stream (WpSiEndpoint * self, guint index);
WP_API
WpSiStreamAcquisition * wp_si_endpoint_get_stream_acquisition (WpSiEndpoint * self);
/**
* WP_TYPE_SI_STREAM:
*
* The #WpSiStream #GType
*/
#define WP_TYPE_SI_STREAM (wp_si_stream_get_type ())
WP_API
G_DECLARE_INTERFACE (WpSiStream, wp_si_stream,
WP, SI_STREAM, WpSessionItem)
struct _WpSiStreamInterface
{
GTypeInterface interface;
GVariant * (*get_registration_info) (WpSiStream * self);
WpProperties * (*get_properties) (WpSiStream * self);
WpSiEndpoint * (*get_parent_endpoint) (WpSiStream * self);
};
WP_API
GVariant * wp_si_stream_get_registration_info (WpSiStream * self);
WP_API
WpProperties * wp_si_stream_get_properties (WpSiStream * self);
WP_API
WpSiEndpoint * wp_si_stream_get_parent_endpoint (WpSiStream * self);
WpSiEndpointAcquisition * wp_si_endpoint_get_endpoint_acquisition (
WpSiEndpoint * self);
/**
* WP_TYPE_SI_LINK:
@@ -103,8 +65,8 @@ struct _WpSiLinkInterface
GVariant * (*get_registration_info) (WpSiLink * self);
WpProperties * (*get_properties) (WpSiLink * self);
WpSiStream * (*get_out_stream) (WpSiLink * self);
WpSiStream * (*get_in_stream) (WpSiLink * self);
WpSiEndpoint * (*get_out_endpoint) (WpSiLink * self);
WpSiEndpoint * (*get_in_endpoint) (WpSiLink * self);
};
WP_API
@@ -114,10 +76,10 @@ WP_API
WpProperties * wp_si_link_get_properties (WpSiLink * self);
WP_API
WpSiStream * wp_si_link_get_out_stream (WpSiLink * self);
WpSiEndpoint * wp_si_link_get_out_endpoint (WpSiLink * self);
WP_API
WpSiStream * wp_si_link_get_in_stream (WpSiLink * self);
WpSiEndpoint * wp_si_link_get_in_endpoint (WpSiLink * self);
/**
* WP_TYPE_SI_PORT_INFO:
@@ -141,40 +103,40 @@ GVariant * wp_si_port_info_get_ports (WpSiPortInfo * self,
const gchar * context);
/**
* WP_TYPE_SI_STREAM_ACQUISITION:
* WP_TYPE_SI_ENDPOINT_ACQUISITION:
*
* The #WpSiStreamAcquisition #GType
* The #WpSiEndpointAcquisition #GType
*/
#define WP_TYPE_SI_STREAM_ACQUISITION (wp_si_stream_acquisition_get_type ())
#define WP_TYPE_SI_ENDPOINT_ACQUISITION (wp_si_endpoint_acquisition_get_type ())
WP_API
G_DECLARE_INTERFACE (WpSiStreamAcquisition, wp_si_stream_acquisition,
WP, SI_STREAM_ACQUISITION, WpSessionItem)
G_DECLARE_INTERFACE (WpSiEndpointAcquisition, wp_si_endpoint_acquisition,
WP, SI_ENDPOINT_ACQUISITION, WpSessionItem)
struct _WpSiStreamAcquisitionInterface
struct _WpSiEndpointAcquisitionInterface
{
GTypeInterface interface;
void (*acquire) (WpSiStreamAcquisition * self, WpSiLink * acquisitor,
WpSiStream * stream, GAsyncReadyCallback callback, gpointer data);
gboolean (*acquire_finish) (WpSiStreamAcquisition * self,
void (*acquire) (WpSiEndpointAcquisition * self, WpSiLink * acquisitor,
WpSiEndpoint * endpoint, GAsyncReadyCallback callback, gpointer data);
gboolean (*acquire_finish) (WpSiEndpointAcquisition * self,
GAsyncResult * res, GError ** error);
void (*release) (WpSiStreamAcquisition * self, WpSiLink * acquisitor,
WpSiStream * stream);
void (*release) (WpSiEndpointAcquisition * self, WpSiLink * acquisitor,
WpSiEndpoint * endpoint);
};
WP_API
void wp_si_stream_acquisition_acquire (WpSiStreamAcquisition * self,
WpSiLink * acquisitor, WpSiStream * stream,
void wp_si_endpoint_acquisition_acquire (WpSiEndpointAcquisition * self,
WpSiLink * acquisitor, WpSiEndpoint * endpoint,
GAsyncReadyCallback callback, gpointer data);
WP_API
gboolean wp_si_stream_acquisition_acquire_finish (WpSiStreamAcquisition * self,
GAsyncResult * res, GError ** error);
gboolean wp_si_endpoint_acquisition_acquire_finish (
WpSiEndpointAcquisition * self, GAsyncResult * res, GError ** error);
WP_API
void wp_si_stream_acquisition_release (WpSiStreamAcquisition * self,
WpSiLink * acquisitor, WpSiStream * stream);
void wp_si_endpoint_acquisition_release (WpSiEndpointAcquisition * self,
WpSiLink * acquisitor, WpSiEndpoint * endpoint);
G_END_DECLS

View File

@@ -71,7 +71,6 @@ wp_init (WpInitFlags flags)
g_type_ensure (WP_TYPE_DEVICE);
g_type_ensure (WP_TYPE_ENDPOINT);
g_type_ensure (WP_TYPE_ENDPOINT_LINK);
g_type_ensure (WP_TYPE_ENDPOINT_STREAM);
g_type_ensure (WP_TYPE_LINK);
g_type_ensure (WP_TYPE_METADATA);
g_type_ensure (WP_TYPE_NODE);

View File

@@ -16,7 +16,6 @@
#include "device.h"
#include "endpoint.h"
#include "endpoint-link.h"
#include "endpoint-stream.h"
#include "error.h"
#include "global-proxy.h"
#include "iterator.h"

View File

@@ -112,17 +112,6 @@ shared_library(
dependencies : [wp_dep, pipewire_dep],
)
shared_library(
'wireplumber-module-si-fake-stream',
[
'module-si-fake-stream.c',
],
c_args : [common_c_args, '-DG_LOG_DOMAIN="m-si-fake-stream"'],
install : true,
install_dir : wireplumber_module_dir,
dependencies : [wp_dep, pipewire_dep],
)
shared_library(
'wireplumber-module-si-simple-node-endpoint',
[
@@ -134,17 +123,6 @@ shared_library(
dependencies : [wp_dep, pipewire_dep],
)
shared_library(
'wireplumber-module-si-audio-softdsp-endpoint',
[
'module-si-audio-softdsp-endpoint.c',
],
c_args : [common_c_args, '-DG_LOG_DOMAIN="m-si-audio-softdsp-endpoint"'],
install : true,
install_dir : wireplumber_module_dir,
dependencies : [wp_dep, pipewire_dep],
)
shared_library(
'wireplumber-module-si-monitor-endpoint',
[
@@ -156,18 +134,6 @@ shared_library(
dependencies : [wp_dep, pipewire_dep],
)
shared_library(
'wireplumber-module-si-bluez5-endpoint',
[
'module-si-bluez5-endpoint.c',
],
c_args : [common_c_args, '-DG_LOG_DOMAIN="m-si-bluez5-endpoint"'],
install : true,
install_dir : wireplumber_module_dir,
dependencies : [wp_dep, pipewire_dep],
)
shared_library(
'wireplumber-module-si-standard-link',
[

View File

@@ -754,22 +754,6 @@ static const luaL_Reg impl_session_methods[] = {
/* WpEndpoint */
static int
endpoint_get_n_streams (lua_State *L)
{
WpEndpoint *ep = wplua_checkobject (L, 1, WP_TYPE_ENDPOINT);
lua_pushnumber (L, wp_endpoint_get_n_streams (ep));
return 1;
}
static int
endpoint_iterate_streams (lua_State *L)
{
WpEndpoint *ep = wplua_checkobject (L, 1, WP_TYPE_ENDPOINT);
WpIterator *it = wp_endpoint_new_streams_iterator (ep);
return push_wpiterator (L, it);
}
static int
endpoint_create_link (lua_State *L)
{
@@ -781,8 +765,6 @@ endpoint_create_link (lua_State *L)
}
static const luaL_Reg endpoint_methods[] = {
{ "get_n_streams", endpoint_get_n_streams },
{ "iterate_streams", endpoint_iterate_streams },
{ "create_link", endpoint_create_link },
{ NULL, NULL }
};
@@ -817,16 +799,13 @@ static int
endpoint_link_get_linked_object_ids (lua_State *L)
{
WpEndpointLink *eplink = wplua_checkobject (L, 1, WP_TYPE_ENDPOINT_LINK);
guint32 output_endpoint, output_stream;
guint32 input_endpoint, input_stream;
wp_endpoint_link_get_linked_object_ids (eplink,
&output_endpoint, &output_stream,
&input_endpoint, &input_stream);
guint32 output_endpoint;
guint32 input_endpoint;
wp_endpoint_link_get_linked_object_ids (eplink, &output_endpoint,
&input_endpoint);
lua_pushinteger (L, output_endpoint);
lua_pushinteger (L, output_stream);
lua_pushinteger (L, input_endpoint);
lua_pushinteger (L, input_stream);
return 4;
return 2;
}
static const luaL_Reg endpoint_link_methods[] = {

View File

@@ -42,13 +42,11 @@ struct _WpSiAdapter
};
static void si_adapter_endpoint_init (WpSiEndpointInterface * iface);
static void si_adapter_stream_init (WpSiStreamInterface * iface);
static void si_adapter_port_info_init (WpSiPortInfoInterface * iface);
G_DECLARE_FINAL_TYPE(WpSiAdapter, si_adapter, WP, SI_ADAPTER, WpSessionItem)
G_DEFINE_TYPE_WITH_CODE (WpSiAdapter, si_adapter, WP_TYPE_SESSION_ITEM,
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ENDPOINT, si_adapter_endpoint_init)
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_STREAM, si_adapter_stream_init)
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_PORT_INFO, si_adapter_port_info_init))
static void
@@ -431,62 +429,11 @@ si_adapter_get_properties (WpSiEndpoint * item)
return result;
}
static guint
si_adapter_get_n_streams (WpSiEndpoint * item)
{
return 1;
}
static WpSiStream *
si_adapter_get_stream (WpSiEndpoint * item, guint index)
{
g_return_val_if_fail (index == 0, NULL);
return WP_SI_STREAM (item);
}
static void
si_adapter_endpoint_init (WpSiEndpointInterface * iface)
{
iface->get_registration_info = si_adapter_get_registration_info;
iface->get_properties = si_adapter_get_properties;
iface->get_n_streams = si_adapter_get_n_streams;
iface->get_stream = si_adapter_get_stream;
}
static GVariant *
si_adapter_get_stream_registration_info (WpSiStream * stream)
{
WpSiAdapter *self = WP_SI_ADAPTER (stream);
GVariantBuilder b;
g_variant_builder_init (&b, G_VARIANT_TYPE ("(sa{ss})"));
g_variant_builder_add (&b, "s", self->name);
g_variant_builder_add (&b, "a{ss}", NULL);
return g_variant_builder_end (&b);
}
static WpProperties *
si_adapter_get_stream_properties (WpSiStream * self)
{
return NULL;
}
static WpSiEndpoint *
si_adapter_get_stream_parent_endpoint (WpSiStream * self)
{
WpSessionItem *parent = wp_session_item_get_parent (WP_SESSION_ITEM (self));
if (!parent)
parent = g_object_ref (WP_SESSION_ITEM (self));
return WP_SI_ENDPOINT (parent);
}
static void
si_adapter_stream_init (WpSiStreamInterface * iface)
{
iface->get_registration_info = si_adapter_get_stream_registration_info;
iface->get_properties = si_adapter_get_stream_properties;
iface->get_parent_endpoint = si_adapter_get_stream_parent_endpoint;
}
static GVariant *

View File

@@ -1,309 +0,0 @@
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include <pipewire/keys.h>
enum {
STEP_VERIFY_CONFIG = WP_TRANSITION_STEP_CUSTOM_START,
STEP_ACTIVATE_ADAPTER,
STEP_ACTIVATE_STREAMS,
};
struct _WpSiAudioSoftdspEndpoint
{
WpSessionBin parent;
/* configuration */
WpSessionItem *adapter;
guint activated_streams;
};
static void si_audio_softdsp_endpoint_endpoint_init (WpSiEndpointInterface * iface);
G_DECLARE_FINAL_TYPE(WpSiAudioSoftdspEndpoint, si_audio_softdsp_endpoint,
WP, SI_AUDIO_SOFTDSP_ENDPOINT, WpSessionBin)
G_DEFINE_TYPE_WITH_CODE (WpSiAudioSoftdspEndpoint, si_audio_softdsp_endpoint, WP_TYPE_SESSION_BIN,
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ENDPOINT, si_audio_softdsp_endpoint_endpoint_init))
static GVariant *
si_audio_softdsp_endpoint_get_registration_info (WpSiEndpoint * item)
{
WpSiAudioSoftdspEndpoint *self = WP_SI_AUDIO_SOFTDSP_ENDPOINT (item);
return wp_si_endpoint_get_registration_info (WP_SI_ENDPOINT (self->adapter));
}
static WpProperties *
si_audio_softdsp_endpoint_get_properties (WpSiEndpoint * item)
{
WpSiAudioSoftdspEndpoint *self = WP_SI_AUDIO_SOFTDSP_ENDPOINT (item);
return wp_si_endpoint_get_properties (WP_SI_ENDPOINT (self->adapter));
}
static guint
si_audio_softdsp_endpoint_get_n_streams (WpSiEndpoint * item)
{
guint n_streams = wp_session_bin_get_n_children (WP_SESSION_BIN (item));
/* n_streams includes the adapter; remove it, unless it's the only one */
return (n_streams > 1) ? (n_streams - 1) : 1;
}
static WpSiStream *
si_audio_softdsp_endpoint_get_stream (WpSiEndpoint * item, guint index)
{
WpSiAudioSoftdspEndpoint *self = WP_SI_AUDIO_SOFTDSP_ENDPOINT (item);
g_autoptr (WpIterator) it =
wp_session_bin_new_iterator (WP_SESSION_BIN (self));
g_auto (GValue) val = G_VALUE_INIT;
if (wp_session_bin_get_n_children (WP_SESSION_BIN (item)) == 1)
return WP_SI_STREAM (self->adapter);
/* TODO: do not asume the items are always sorted */
guint i = 0;
for (; wp_iterator_next (it, &val); g_value_unset (&val)) {
if (index + 1 == i)
return g_value_get_object (&val);
i++;
}
return NULL;
}
static void
si_audio_softdsp_endpoint_endpoint_init (WpSiEndpointInterface * iface)
{
iface->get_registration_info = si_audio_softdsp_endpoint_get_registration_info;
iface->get_properties = si_audio_softdsp_endpoint_get_properties;
iface->get_n_streams = si_audio_softdsp_endpoint_get_n_streams;
iface->get_stream = si_audio_softdsp_endpoint_get_stream;
}
static void
si_audio_softdsp_endpoint_init (WpSiAudioSoftdspEndpoint * self)
{
self->activated_streams = 0;
}
static void
si_audio_softdsp_endpoint_reset (WpSessionItem * item)
{
WpSiAudioSoftdspEndpoint *self = WP_SI_AUDIO_SOFTDSP_ENDPOINT (item);
/* unexport & deactivate first */
WP_SESSION_ITEM_CLASS (si_audio_softdsp_endpoint_parent_class)->reset (item);
g_clear_object (&self->adapter);
self->activated_streams = 0;
wp_session_item_clear_flag (item, WP_SI_FLAG_CONFIGURED);
}
static gpointer
si_audio_softdsp_endpoint_get_associated_proxy (WpSessionItem * item,
GType proxy_type)
{
WpSiAudioSoftdspEndpoint *self = WP_SI_AUDIO_SOFTDSP_ENDPOINT (item);
if (proxy_type == WP_TYPE_NODE)
return wp_session_item_get_associated_proxy (self->adapter, proxy_type);
return WP_SESSION_ITEM_CLASS (
si_audio_softdsp_endpoint_parent_class)->get_associated_proxy (
item, proxy_type);
}
static gboolean
si_audio_softdsp_endpoint_configure (WpSessionItem * item, GVariant * args)
{
WpSiAudioSoftdspEndpoint *self = WP_SI_AUDIO_SOFTDSP_ENDPOINT (item);
guint64 adapter_i;
if (wp_session_item_get_flags (item) & (WP_SI_FLAG_ACTIVATING | WP_SI_FLAG_ACTIVE))
return FALSE;
/* reset previous config */
si_audio_softdsp_endpoint_reset (WP_SESSION_ITEM (self));
/* get the adapter */
if (!g_variant_lookup (args, "adapter", "t", &adapter_i))
return FALSE;
g_return_val_if_fail (WP_IS_SI_ENDPOINT (GUINT_TO_POINTER (adapter_i)), FALSE);
self->adapter = g_object_ref (GUINT_TO_POINTER (adapter_i));
/* add the adapter into the bin */
wp_session_bin_add (WP_SESSION_BIN (self), g_object_ref (self->adapter));
wp_session_item_set_flag (item, WP_SI_FLAG_CONFIGURED);
return TRUE;
}
static GVariant *
si_audio_softdsp_endpoint_get_configuration (WpSessionItem * item)
{
WpSiAudioSoftdspEndpoint *self = WP_SI_AUDIO_SOFTDSP_ENDPOINT (item);
GVariantBuilder b;
/* Set the properties */
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}",
"adapter", g_variant_new_uint64 ((guint64) self->adapter));
return g_variant_builder_end (&b);
}
static guint
si_audio_softdsp_endpoint_activate_get_next_step (WpSessionItem * item,
WpTransition * transition, guint step)
{
WpSiAudioSoftdspEndpoint *self = wp_transition_get_source_object (transition);
switch (step) {
case WP_TRANSITION_STEP_NONE:
return STEP_VERIFY_CONFIG;
case STEP_VERIFY_CONFIG:
return STEP_ACTIVATE_ADAPTER;
case STEP_ACTIVATE_ADAPTER:
if (wp_session_bin_get_n_children (WP_SESSION_BIN (self)) > 1)
return STEP_ACTIVATE_STREAMS;
else
return WP_TRANSITION_STEP_NONE;
case STEP_ACTIVATE_STREAMS:
if ((self->activated_streams + 1) <
wp_session_bin_get_n_children (WP_SESSION_BIN (self)))
return STEP_ACTIVATE_STREAMS;
else
return WP_TRANSITION_STEP_NONE;
default:
return WP_TRANSITION_STEP_ERROR;
}
}
static void
on_adapter_activated (WpSessionItem * item, GAsyncResult * res,
WpTransition *transition)
{
g_autoptr (GError) error = NULL;
if (!wp_session_item_activate_finish (item, res, &error)) {
wp_transition_return_error (transition, g_steal_pointer (&error));
return;
}
wp_transition_advance (transition);
}
static void
on_convert_activated (WpSessionItem * item, GAsyncResult * res,
WpTransition *transition)
{
WpSiAudioSoftdspEndpoint *self = wp_transition_get_source_object (transition);
g_autoptr (GError) error = NULL;
if (!wp_session_item_activate_finish (item, res, &error)) {
wp_transition_return_error (transition, g_steal_pointer (&error));
return;
}
self->activated_streams++;
wp_transition_advance (transition);
}
static void
si_audio_softdsp_endpoint_activate_execute_step (WpSessionItem * item,
WpTransition * transition, guint step)
{
WpSiAudioSoftdspEndpoint *self = WP_SI_AUDIO_SOFTDSP_ENDPOINT (item);
switch (step) {
case STEP_VERIFY_CONFIG:
if (G_UNLIKELY (!(wp_session_item_get_flags (item) & WP_SI_FLAG_CONFIGURED))) {
wp_transition_return_error (transition,
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
"si-audio-softdsp-endpoint: cannot activate item without it "
"being configured first"));
}
wp_transition_advance (transition);
break;
case STEP_ACTIVATE_ADAPTER:
g_return_if_fail (self->activated_streams == 0);
wp_session_item_activate (self->adapter,
(GAsyncReadyCallback) on_adapter_activated, transition);
break;
case STEP_ACTIVATE_STREAMS:
{
g_autoptr (WpIterator) it =
wp_session_bin_new_iterator (WP_SESSION_BIN (self));
g_auto (GValue) val = G_VALUE_INIT;
for (; wp_iterator_next (it, &val); g_value_unset (&val)) {
WpSessionItem *item = g_value_get_object (&val);
if (item == self->adapter)
continue;
wp_session_item_activate (item,
(GAsyncReadyCallback) on_convert_activated, transition);
}
break;
}
default:
g_return_if_reached ();
}
}
static void
si_audio_softdsp_endpoint_activate_rollback (WpSessionItem * item)
{
WpSiAudioSoftdspEndpoint *self = WP_SI_AUDIO_SOFTDSP_ENDPOINT (item);
g_autoptr (WpIterator) it =
wp_session_bin_new_iterator (WP_SESSION_BIN (self));
g_auto (GValue) val = G_VALUE_INIT;
/* deactivate all items */
for (; wp_iterator_next (it, &val); g_value_unset (&val))
wp_session_item_deactivate (g_value_get_object (&val));
self->activated_streams = 0;
}
static void
si_audio_softdsp_endpoint_class_init (WpSiAudioSoftdspEndpointClass * klass)
{
WpSessionItemClass *si_class = (WpSessionItemClass *) klass;
si_class->reset = si_audio_softdsp_endpoint_reset;
si_class->get_associated_proxy = si_audio_softdsp_endpoint_get_associated_proxy;
si_class->configure = si_audio_softdsp_endpoint_configure;
si_class->get_configuration = si_audio_softdsp_endpoint_get_configuration;
si_class->activate_get_next_step =
si_audio_softdsp_endpoint_activate_get_next_step;
si_class->activate_execute_step =
si_audio_softdsp_endpoint_activate_execute_step;
si_class->activate_rollback = si_audio_softdsp_endpoint_activate_rollback;
}
WP_PLUGIN_EXPORT gboolean
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{
GVariantBuilder b;
g_variant_builder_init (&b, G_VARIANT_TYPE ("a(ssymv)"));
g_variant_builder_add (&b, "(ssymv)", "adapter", "t",
WP_SI_CONFIG_OPTION_WRITEABLE | WP_SI_CONFIG_OPTION_REQUIRED, NULL);
wp_si_factory_register (core, wp_si_factory_new_simple (
"si-audio-softdsp-endpoint", si_audio_softdsp_endpoint_get_type (),
g_variant_builder_end (&b)));
return TRUE;
}

View File

@@ -1,573 +0,0 @@
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <pipewire/pipewire.h>
#include <spa/utils/keys.h>
#include <spa/utils/names.h>
#include <wp/wp.h>
enum {
STEP_VERIFY_CONFIG = WP_TRANSITION_STEP_CUSTOM_START,
STEP_ACTIVATE_STREAM_A2DP,
STEP_ACTIVATE_STREAM_SCO,
};
enum {
STREAM_ID_A2DP = 0,
STREAM_ID_SCO = 1,
};
static guint32
get_stream_id_from_profile_name (const gchar *profile_name) {
if (g_str_has_prefix (profile_name, "a2dp"))
return STREAM_ID_A2DP;
else if (g_str_has_prefix (profile_name, "hsp") ||
g_str_has_prefix (profile_name, "hfp"))
return STREAM_ID_SCO;
g_return_val_if_reached (SPA_ID_INVALID);
}
static gint
get_profile_id_from_stream_id (guint32 stream_id)
{
switch (stream_id) {
case STREAM_ID_A2DP:
return 1;
case STREAM_ID_SCO:
return 2;
default:
break;
}
g_return_val_if_reached (0);
}
struct _WpSiBluez5Endpoint
{
WpSessionBin parent;
/* configuration */
WpDevice *device;
WpDirection direction;
WpSessionItem *streams[2];
guint priority;
guint32 stream_id;
gchar name[96];
gboolean control_port;
gboolean monitor;
gint64 last_switch;
};
static void si_bluez5_endpoint_endpoint_init (WpSiEndpointInterface * iface);
static void si_bluez5_endpoint_stream_acquisition_init (WpSiStreamAcquisitionInterface * iface);
G_DECLARE_FINAL_TYPE(WpSiBluez5Endpoint, si_bluez5_endpoint,
WP, SI_BLUEZ5_ENDPOINT, WpSessionBin)
G_DEFINE_TYPE_WITH_CODE (WpSiBluez5Endpoint, si_bluez5_endpoint, WP_TYPE_SESSION_BIN,
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ENDPOINT, si_bluez5_endpoint_endpoint_init)
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_STREAM_ACQUISITION, si_bluez5_endpoint_stream_acquisition_init))
static void
si_bluez5_endpoint_init (WpSiBluez5Endpoint * self)
{
}
static void
si_bluez5_endpoint_reset (WpSessionItem * item)
{
WpSiBluez5Endpoint *self = WP_SI_BLUEZ5_ENDPOINT (item);
/* unexport & deactivate first */
WP_SESSION_ITEM_CLASS (si_bluez5_endpoint_parent_class)->reset (item);
g_clear_object (&self->streams[STREAM_ID_A2DP]);
g_clear_object (&self->streams[STREAM_ID_SCO]);
self->direction = WP_DIRECTION_INPUT;
self->stream_id = 0;
self->name[0] = '\0';
self->control_port = FALSE;
self->monitor = FALSE;
wp_session_item_clear_flag (item, WP_SI_FLAG_CONFIGURED);
}
static gpointer
si_bluez5_endpoint_get_associated_proxy (WpSessionItem * item, GType proxy_type)
{
WpSiBluez5Endpoint *self = WP_SI_BLUEZ5_ENDPOINT (item);
if (proxy_type == WP_TYPE_NODE) {
if (self->streams[STREAM_ID_A2DP])
return wp_session_item_get_associated_proxy (
self->streams[STREAM_ID_A2DP], proxy_type);
if (self->streams[STREAM_ID_SCO])
return wp_session_item_get_associated_proxy (
self->streams[STREAM_ID_SCO], proxy_type);
return NULL;
}
return WP_SESSION_ITEM_CLASS (si_bluez5_endpoint_parent_class)->
get_associated_proxy (item, proxy_type);
}
static GVariant *
si_bluez5_endpoint_get_configuration (WpSessionItem * item)
{
WpSiBluez5Endpoint *self = WP_SI_BLUEZ5_ENDPOINT (item);
g_autoptr (WpNode) node = NULL;
GVariantBuilder b;
/* Get the bluez5 node */
if (self->streams[self->stream_id])
node = wp_session_item_get_associated_proxy (self->streams[self->stream_id],
WP_TYPE_NODE);
/* Set the properties */
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}", "device",
g_variant_new_uint64 ((guint64) self->device));
g_variant_builder_add (&b, "{sv}", "name",
g_variant_new_string (self->name));
g_variant_builder_add (&b, "{sv}", "direction",
g_variant_new_uint32 (self->direction));
g_variant_builder_add (&b, "{sv}", "s2dp-stream",
g_variant_new_boolean (self->streams[STREAM_ID_A2DP] != NULL));
g_variant_builder_add (&b, "{sv}", "sco-stream",
g_variant_new_boolean (self->streams[STREAM_ID_SCO] != NULL));
g_variant_builder_add (&b, "{sv}", "node",
g_variant_new_uint64 ((guint64) node));
g_variant_builder_add (&b, "{sv}", "priority",
g_variant_new_uint32 (self->priority));
g_variant_builder_add (&b, "{sv}", "enable-control-port",
g_variant_new_boolean (self->control_port));
g_variant_builder_add (&b, "{sv}", "enable-monitor",
g_variant_new_boolean (self->monitor));
return g_variant_builder_end (&b);
}
static void
si_bluez5_endpoint_add_stream (WpSiBluez5Endpoint * self, guint32 stream_id,
const gchar *name, WpNode *node)
{
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self->device));
g_auto (GVariantBuilder) b = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
/* Bluez5 stream or Fake stream */
if (self->stream_id == stream_id && node) {
self->streams[stream_id] = wp_session_item_make (core, "si-adapter");
g_variant_builder_add (&b, "{sv}", "node",
g_variant_new_uint64 ((guint64) node));
g_variant_builder_add (&b, "{sv}", "name",
g_variant_new_string (name));
g_variant_builder_add (&b, "{sv}", "enable-control-port",
g_variant_new_boolean (self->control_port));
g_variant_builder_add (&b, "{sv}", "enable-monitor",
g_variant_new_boolean (self->monitor));
}
else {
self->streams[stream_id] = wp_session_item_make (core, "si-fake-stream");
g_variant_builder_add (&b, "{sv}", "name",
g_variant_new_string (name));
}
/* Configure */
wp_session_item_configure (self->streams[stream_id],
g_variant_builder_end (&b));
/* Add stream to the bin */
wp_session_bin_add (WP_SESSION_BIN (self),
g_object_ref (self->streams[stream_id]));
}
static gboolean
si_bluez5_endpoint_configure (WpSessionItem * item, GVariant * args)
{
WpSiBluez5Endpoint *self = WP_SI_BLUEZ5_ENDPOINT (item);
guint64 device_i, node_i;
const gchar *name;
WpNode *node = NULL;
gboolean a2dp_stream = FALSE, sco_stream = FALSE;
if (wp_session_item_get_flags (item) & (WP_SI_FLAG_ACTIVATING | WP_SI_FLAG_ACTIVE))
return FALSE;
/* reset previous config */
si_bluez5_endpoint_reset (WP_SESSION_ITEM (self));
/* get the device */
if (!g_variant_lookup (args, "device", "t", &device_i))
return FALSE;
g_return_val_if_fail (WP_IS_DEVICE (GUINT_TO_POINTER (device_i)), FALSE);
self->device = g_object_ref (GUINT_TO_POINTER (device_i));
/* get the name */
if (!g_variant_lookup (args, "name", "&s", &name))
return FALSE;
strncpy (self->name, name, sizeof (self->name) - 1);
/* get the node */
if (g_variant_lookup (args, "node", "t", &node_i))
node = GUINT_TO_POINTER (node_i);
/* get the direction */
if (node) {
const gchar *media_class = wp_pipewire_object_get_property (
WP_PIPEWIRE_OBJECT (node), PW_KEY_MEDIA_CLASS);
self->direction = g_strcmp0 (media_class, "Audio/Sink") == 0 ?
WP_DIRECTION_INPUT : WP_DIRECTION_OUTPUT;
} else {
if (!g_variant_lookup (args, "direction", "u", &self->direction)) {
wp_warning_object (self, "direction not specified");
return FALSE;
}
}
/* get the a2dp-stream value */
if (!g_variant_lookup (args, "a2dp-stream", "b", &a2dp_stream))
return FALSE;
if (!g_variant_lookup (args, "sco-stream", "b", &sco_stream))
return FALSE;
if (!a2dp_stream && !sco_stream)
return FALSE;
/* get priority, control-port and monitor */
g_variant_lookup (args, "priority", "b", &self->priority);
g_variant_lookup (args, "enable-control-port", "b", &self->control_port);
g_variant_lookup (args, "enable-monitor", "b", &self->monitor);
/* get the current stream id */
if (node) {
self->stream_id = get_stream_id_from_profile_name (
wp_pipewire_object_get_property (WP_PIPEWIRE_OBJECT (node),
SPA_KEY_API_BLUEZ5_PROFILE));
} else {
/* Otherwise, the device is set with the oposite profile */
if (a2dp_stream && !sco_stream)
self->stream_id = STREAM_ID_SCO;
else if (sco_stream && !a2dp_stream)
self->stream_id = STREAM_ID_A2DP;
else
return FALSE;
}
/* create the streams and add them into the bin */
if (a2dp_stream)
si_bluez5_endpoint_add_stream (self, STREAM_ID_A2DP, "Multimedia", node);
if (sco_stream)
si_bluez5_endpoint_add_stream (self, STREAM_ID_SCO, "Call", node);
/* update last profile switch time */
self->last_switch = g_get_monotonic_time ();
wp_session_item_set_flag (item, WP_SI_FLAG_CONFIGURED);
return TRUE;
}
static guint
si_bluez5_endpoint_activate_get_next_step (WpSessionItem * item,
WpTransition * transition, guint step)
{
switch (step) {
case WP_TRANSITION_STEP_NONE:
return STEP_VERIFY_CONFIG;
case STEP_VERIFY_CONFIG:
return STEP_ACTIVATE_STREAM_A2DP;
case STEP_ACTIVATE_STREAM_A2DP:
return STEP_ACTIVATE_STREAM_SCO;
case STEP_ACTIVATE_STREAM_SCO:
return WP_TRANSITION_STEP_NONE;
default:
return WP_TRANSITION_STEP_ERROR;
}
}
static void
on_item_activated (WpSessionItem * item, GAsyncResult * res,
WpTransition *transition)
{
g_autoptr (GError) error = NULL;
if (!wp_session_item_activate_finish (item, res, &error)) {
wp_transition_return_error (transition, g_steal_pointer (&error));
return;
}
wp_transition_advance (transition);
}
static void
activate_stream (WpSiBluez5Endpoint *self, guint32 id, WpTransition *transition)
{
if (self->streams[id])
wp_session_item_activate (self->streams[id],
(GAsyncReadyCallback) on_item_activated, transition);
else
wp_transition_advance (transition);
}
static void
si_bluez5_endpoint_activate_execute_step (WpSessionItem * item,
WpTransition * transition, guint step)
{
WpSiBluez5Endpoint *self = WP_SI_BLUEZ5_ENDPOINT (item);
switch (step) {
case STEP_VERIFY_CONFIG:
if (G_UNLIKELY (!(wp_session_item_get_flags (item) & WP_SI_FLAG_CONFIGURED))) {
wp_transition_return_error (transition,
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
"si-bluez5-endpoint: cannot activate item without it "
"being configured first"));
}
wp_transition_advance (transition);
break;
case STEP_ACTIVATE_STREAM_A2DP:
activate_stream (self, STREAM_ID_A2DP, transition);
break;
case STEP_ACTIVATE_STREAM_SCO:
activate_stream (self, STREAM_ID_SCO, transition);
break;
default:
g_return_if_reached ();
}
}
static void
si_bluez5_endpoint_activate_rollback (WpSessionItem * item)
{
WpSiBluez5Endpoint *self = WP_SI_BLUEZ5_ENDPOINT (item);
g_autoptr (WpIterator) it =
wp_session_bin_new_iterator (WP_SESSION_BIN (self));
g_auto (GValue) val = G_VALUE_INIT;
/* deactivate all items */
for (; wp_iterator_next (it, &val); g_value_unset (&val))
wp_session_item_deactivate (g_value_get_object (&val));
}
static void
si_bluez5_endpoint_class_init (WpSiBluez5EndpointClass * klass)
{
WpSessionItemClass *si_class = (WpSessionItemClass *) klass;
si_class->reset = si_bluez5_endpoint_reset;
si_class->get_associated_proxy = si_bluez5_endpoint_get_associated_proxy;
si_class->configure = si_bluez5_endpoint_configure;
si_class->get_configuration = si_bluez5_endpoint_get_configuration;
si_class->activate_get_next_step = si_bluez5_endpoint_activate_get_next_step;
si_class->activate_execute_step = si_bluez5_endpoint_activate_execute_step;
si_class->activate_rollback = si_bluez5_endpoint_activate_rollback;
}
static GVariant *
si_bluez5_endpoint_get_registration_info (WpSiEndpoint * item)
{
WpSiBluez5Endpoint *self = WP_SI_BLUEZ5_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->direction == WP_DIRECTION_INPUT ?
"Audio/Sink" : "Audio/Source");
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_bluez5_endpoint_get_properties (WpSiEndpoint * item)
{
WpSiBluez5Endpoint *self = WP_SI_BLUEZ5_ENDPOINT (item);
WpProperties *properties;
g_autofree gchar *description = NULL;
properties =
wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (self->device));
properties = wp_properties_ensure_unique_owner (properties);
description = g_strdup_printf ("Bluez5-%s of %s",
self->direction == WP_DIRECTION_INPUT ? "Sink" : "Source",
wp_properties_get (properties, PW_KEY_DEVICE_NAME));
wp_properties_set (properties, "endpoint.description", description);
wp_properties_setf (properties, "endpoint.priority", "%d", self->priority);
return properties;
}
static guint
si_bluez5_endpoint_get_n_streams (WpSiEndpoint * item)
{
WpSiBluez5Endpoint *self = WP_SI_BLUEZ5_ENDPOINT (item);
guint res = 0;
if (self->streams[STREAM_ID_A2DP])
res++;
if (self->streams[STREAM_ID_SCO])
res++;
return res;
}
static WpSiStream *
si_bluez5_endpoint_get_stream (WpSiEndpoint * item, guint index)
{
WpSiBluez5Endpoint *self = WP_SI_BLUEZ5_ENDPOINT (item);
guint n_streams = si_bluez5_endpoint_get_n_streams (item);
WpSessionItem *res = NULL;
g_return_val_if_fail (index < n_streams, NULL);
if (!self->streams[STREAM_ID_A2DP])
index++;
res = self->streams[index];
g_return_val_if_fail (res, NULL);
return WP_SI_STREAM (g_object_ref (res));
}
static WpSiStreamAcquisition *
si_bluez5_endpoint_get_stream_acquisition (WpSiEndpoint * self)
{
return WP_SI_STREAM_ACQUISITION (self);
}
static void
si_bluez5_endpoint_endpoint_init (WpSiEndpointInterface * iface)
{
iface->get_registration_info = si_bluez5_endpoint_get_registration_info;
iface->get_properties = si_bluez5_endpoint_get_properties;
iface->get_n_streams = si_bluez5_endpoint_get_n_streams;
iface->get_stream = si_bluez5_endpoint_get_stream;
iface->get_stream_acquisition = si_bluez5_endpoint_get_stream_acquisition;
}
static void
set_device_profile (WpDevice *device, gint index)
{
g_return_if_fail (device);
g_autoptr (WpSpaPod) profile = wp_spa_pod_new_object (
"Spa:Pod:Object:Param:Profile", "Profile",
"index", "i", index,
NULL);
wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (device),
"Profile", 0, profile);
}
static void
abort_acquisition (WpSessionItem * ac, GTask *task, const gchar *msg)
{
g_autoptr (WpGlobalProxy) link = NULL;
/* return error to abort the link activation */
g_task_return_new_error (task, WP_DOMAIN_LIBRARY,
WP_LIBRARY_ERROR_OPERATION_FAILED, "%s", msg);
/* destroy the link */
link = wp_session_item_get_associated_proxy (ac, WP_TYPE_ENDPOINT_LINK);
g_return_if_fail (link);
wp_global_proxy_request_destroy (link);
}
static void
si_bluez5_endpoint_stream_acquisition_acquire (WpSiStreamAcquisition * sa,
WpSiLink * acquisitor, WpSiStream * stream, GAsyncReadyCallback callback,
gpointer data)
{
WpSiBluez5Endpoint *self = WP_SI_BLUEZ5_ENDPOINT (sa);
g_autoptr (GTask) task = NULL;
gint64 now = g_get_monotonic_time ();
/* create the task */
task = g_task_new (self, NULL, callback, data);
/* accept acquisition if stream is valid */
if (WP_SESSION_ITEM (stream) == self->streams[self->stream_id]) {
g_task_return_boolean (task, TRUE);
return;
}
/* abort acquisition if we changed the bluez5 profile less than a second ago.
* This prevents an switch profile infinite loop caused by the policy module
* when 2 or more clients with different profiles want to link with the same
* bluez5 endpoint */
if (now - self->last_switch < 1000000) {
abort_acquisition (WP_SESSION_ITEM (acquisitor), task,
"already switched bluez5 profile recently");
return;
}
/* switch profile */
set_device_profile (self->device,
get_profile_id_from_stream_id (self->stream_id) == 1 ? 2 : 1);
/* update last switch time */
self->last_switch = now;
/* abort acquisition */
abort_acquisition (WP_SESSION_ITEM (acquisitor), task,
"new bluez5 profile set");
}
static void
si_bluez5_endpoint_stream_acquisition_release (WpSiStreamAcquisition * sa,
WpSiLink * acquisitor, WpSiStream * stream)
{
}
static gboolean
si_bluez5_endpoint_stream_acquisition_acquire_finish (
WpSiStreamAcquisition * sa, GAsyncResult * res, GError ** error)
{
g_return_val_if_fail (WP_IS_SI_STREAM_ACQUISITION (sa), FALSE);
g_return_val_if_fail (g_task_is_valid (res, sa), FALSE);
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
si_bluez5_endpoint_stream_acquisition_init (
WpSiStreamAcquisitionInterface * iface)
{
iface->acquire = si_bluez5_endpoint_stream_acquisition_acquire;
iface->acquire_finish = si_bluez5_endpoint_stream_acquisition_acquire_finish;
iface->release = si_bluez5_endpoint_stream_acquisition_release;
}
WP_PLUGIN_EXPORT gboolean
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{
GVariantBuilder b;
g_variant_builder_init (&b, G_VARIANT_TYPE ("a(ssymv)"));
g_variant_builder_add (&b, "(ssymv)", "device", "t",
WP_SI_CONFIG_OPTION_WRITEABLE | WP_SI_CONFIG_OPTION_REQUIRED, NULL);
g_variant_builder_add (&b, "(ssymv)", "name", "s",
WP_SI_CONFIG_OPTION_WRITEABLE | WP_SI_CONFIG_OPTION_REQUIRED, NULL);
g_variant_builder_add (&b, "(ssymv)", "direction", "u",
WP_SI_CONFIG_OPTION_WRITEABLE | WP_SI_CONFIG_OPTION_REQUIRED, NULL);
g_variant_builder_add (&b, "(ssymv)", "a2dp-stream", "b",
WP_SI_CONFIG_OPTION_WRITEABLE | WP_SI_CONFIG_OPTION_REQUIRED, NULL);
g_variant_builder_add (&b, "(ssymv)", "sco-stream", "b",
WP_SI_CONFIG_OPTION_WRITEABLE | WP_SI_CONFIG_OPTION_REQUIRED, NULL);
g_variant_builder_add (&b, "(ssymv)", "node", "t",
WP_SI_CONFIG_OPTION_WRITEABLE, NULL);
g_variant_builder_add (&b, "(ssymv)", "priority", "u",
WP_SI_CONFIG_OPTION_WRITEABLE, NULL);
g_variant_builder_add (&b, "(ssymv)", "enable-control-port", "b",
WP_SI_CONFIG_OPTION_WRITEABLE, NULL);
g_variant_builder_add (&b, "(ssymv)", "enable-monitor", "b",
WP_SI_CONFIG_OPTION_WRITEABLE, NULL);
wp_si_factory_register (core, wp_si_factory_new_simple (
"si-bluez5-endpoint", si_bluez5_endpoint_get_type (),
g_variant_builder_end (&b)));
return TRUE;
}

View File

@@ -8,6 +8,7 @@
#include <wp/wp.h>
#include <pipewire/pipewire.h>
#include <pipewire/extensions/session-manager/keys.h>
#include <spa/utils/names.h>
#include <spa/param/format.h>
@@ -35,12 +36,12 @@ struct _WpSiConvert
WpSessionItem *link_to_target;
};
static void si_convert_stream_init (WpSiStreamInterface * iface);
static void si_convert_endpoint_init (WpSiEndpointInterface * iface);
static void si_convert_port_info_init (WpSiPortInfoInterface * iface);
G_DECLARE_FINAL_TYPE(WpSiConvert, si_convert, WP, SI_CONVERT, WpSessionItem)
G_DEFINE_TYPE_WITH_CODE (WpSiConvert, si_convert, WP_TYPE_SESSION_ITEM,
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_STREAM, si_convert_stream_init)
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ENDPOINT, si_convert_endpoint_init)
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_PORT_INFO, si_convert_port_info_init))
static void
@@ -174,19 +175,19 @@ do_link_to_target (WpSiConvert *self)
if (self->direction == WP_DIRECTION_INPUT) {
/* Playback */
g_variant_builder_add (&b, "{sv}", "out-stream",
g_variant_new_uint64 ((guint64) WP_SI_STREAM (self)));
g_variant_builder_add (&b, "{sv}", "out-stream-port-context",
g_variant_builder_add (&b, "{sv}", "out-endpoint",
g_variant_new_uint64 ((guint64) WP_SI_ENDPOINT (self)));
g_variant_builder_add (&b, "{sv}", "out-endpoint-port-context",
g_variant_new_string ("reverse"));
g_variant_builder_add (&b, "{sv}", "in-stream",
g_variant_new_uint64 ((guint64) WP_SI_STREAM (self->target)));
g_variant_builder_add (&b, "{sv}", "in-endpoint",
g_variant_new_uint64 ((guint64) WP_SI_ENDPOINT (self->target)));
} else {
/* Capture */
g_variant_builder_add (&b, "{sv}", "out-stream",
g_variant_new_uint64 ((guint64) WP_SI_STREAM (self->target)));
g_variant_builder_add (&b, "{sv}", "in-stream",
g_variant_new_uint64 ((guint64) WP_SI_STREAM (self)));
g_variant_builder_add (&b, "{sv}", "in-stream-port-context",
g_variant_builder_add (&b, "{sv}", "out-endpoint",
g_variant_new_uint64 ((guint64) WP_SI_ENDPOINT (self->target)));
g_variant_builder_add (&b, "{sv}", "in-endpoint",
g_variant_new_uint64 ((guint64) WP_SI_ENDPOINT (self)));
g_variant_builder_add (&b, "{sv}", "in-endpoint-port-context",
g_variant_new_string ("reverse"));
}
@@ -280,7 +281,7 @@ si_convert_activate_execute_step (WpSessionItem * item,
wp_properties_get (node_props, PW_KEY_NODE_NAME),
self->name);
wp_properties_setf (props, PW_KEY_NODE_DESCRIPTION,
"Stream volume for %s: %s",
"Converter volume for %s: %s",
wp_properties_get (node_props, PW_KEY_NODE_DESCRIPTION), self->name);
/* Create the node */
@@ -389,36 +390,43 @@ si_convert_activate_rollback (WpSessionItem * item)
}
static GVariant *
si_convert_get_stream_registration_info (WpSiStream * item)
si_convert_get_registration_info (WpSiEndpoint * item)
{
WpSiConvert *self = WP_SI_CONVERT (item);
GVariantBuilder b;
g_variant_builder_init (&b, G_VARIANT_TYPE ("(sa{ss})"));
g_variant_builder_init (&b, G_VARIANT_TYPE ("(ssya{ss})"));
g_variant_builder_add (&b, "s", self->name);
g_variant_builder_add (&b, "s", "Audio/Convert");
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 *
si_convert_get_stream_properties (WpSiStream * self)
si_convert_get_properties (WpSiEndpoint * item)
{
return NULL;
}
WpSiConvert *self = WP_SI_CONVERT (item);
WpProperties *result = wp_properties_new_empty ();
static WpSiEndpoint *
si_convert_get_stream_parent_endpoint (WpSiStream * self)
{
return WP_SI_ENDPOINT (wp_session_item_get_parent (WP_SESSION_ITEM (self)));
wp_properties_set (result, "endpoint.priority", NULL);
wp_properties_setf (result, "endpoint.description", "%s", "Audio Converter");
wp_properties_setf (result, PW_KEY_ENDPOINT_AUTOCONNECT, "%d", FALSE);
wp_properties_set (result, PW_KEY_ENDPOINT_CLIENT_ID, NULL);
/* associate with the node */
wp_properties_setf (result, PW_KEY_NODE_ID, "%d",
wp_proxy_get_bound_id (WP_PROXY (self->node)));
return result;
}
static void
si_convert_stream_init (WpSiStreamInterface * iface)
si_convert_endpoint_init (WpSiEndpointInterface * iface)
{
iface->get_registration_info = si_convert_get_stream_registration_info;
iface->get_properties = si_convert_get_stream_properties;
iface->get_parent_endpoint = si_convert_get_stream_parent_endpoint;
iface->get_registration_info = si_convert_get_registration_info;
iface->get_properties = si_convert_get_properties;
}
static GVariant *

View File

@@ -1,189 +0,0 @@
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include <pipewire/pipewire.h>
enum {
STEP_VERIFY_CONFIG = WP_TRANSITION_STEP_CUSTOM_START,
};
struct _WpSiFakeStream
{
WpSessionItem parent;
/* configuration */
gchar name[96];
};
static void si_fake_stream_stream_init (WpSiStreamInterface * iface);
static void si_fake_stream_port_info_init (WpSiPortInfoInterface * iface);
G_DECLARE_FINAL_TYPE(WpSiFakeStream, si_fake_stream, WP, SI_FAKE_STREAM, WpSessionItem)
G_DEFINE_TYPE_WITH_CODE (WpSiFakeStream, si_fake_stream, WP_TYPE_SESSION_ITEM,
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_STREAM, si_fake_stream_stream_init)
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_PORT_INFO, si_fake_stream_port_info_init))
static void
si_fake_stream_init (WpSiFakeStream * self)
{
}
static void
si_fake_stream_reset (WpSessionItem * item)
{
WpSiFakeStream *self = WP_SI_FAKE_STREAM (item);
/* unexport & deactivate first */
WP_SESSION_ITEM_CLASS (si_fake_stream_parent_class)->reset (item);
self->name[0] = '\0';
wp_session_item_clear_flag (item, WP_SI_FLAG_CONFIGURED);
}
static gboolean
si_fake_stream_configure (WpSessionItem * item, GVariant * args)
{
WpSiFakeStream *self = WP_SI_FAKE_STREAM (item);
const gchar *name;
if (wp_session_item_get_flags (item) & (WP_SI_FLAG_ACTIVATING | WP_SI_FLAG_ACTIVE))
return FALSE;
/* reset previous config */
si_fake_stream_reset (item);
/* get name */
if (!g_variant_lookup (args, "name", "&s", &name))
return FALSE;
strncpy (self->name, name, sizeof (self->name) - 1);
wp_session_item_set_flag (item, WP_SI_FLAG_CONFIGURED);
return TRUE;
}
static GVariant *
si_fake_stream_get_configuration (WpSessionItem * item)
{
WpSiFakeStream *self = WP_SI_FAKE_STREAM (item);
GVariantBuilder b;
/* Set the properties */
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}",
"name", g_variant_new_string (self->name));
return g_variant_builder_end (&b);
}
static guint
si_fake_stream_activate_get_next_step (WpSessionItem * item,
WpTransition * transition, guint step)
{
switch (step) {
case WP_TRANSITION_STEP_NONE:
return STEP_VERIFY_CONFIG;
case STEP_VERIFY_CONFIG:
return WP_TRANSITION_STEP_NONE;
default:
return WP_TRANSITION_STEP_ERROR;
}
}
static void
si_fake_stream_activate_execute_step (WpSessionItem * item,
WpTransition * transition, guint step)
{
switch (step) {
case STEP_VERIFY_CONFIG:
if (G_UNLIKELY (!(wp_session_item_get_flags (item) & WP_SI_FLAG_CONFIGURED))) {
wp_transition_return_error (transition,
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
"si-fake-stream: cannot activate item without it "
"being configured first"));
}
wp_transition_advance (transition);
break;
default:
g_return_if_reached ();
}
}
static GVariant *
si_fake_stream_get_stream_registration_info (WpSiStream * item)
{
WpSiFakeStream *self = WP_SI_FAKE_STREAM (item);
GVariantBuilder b;
g_variant_builder_init (&b, G_VARIANT_TYPE ("(sa{ss})"));
g_variant_builder_add (&b, "s", self->name);
g_variant_builder_add (&b, "a{ss}", NULL);
return g_variant_builder_end (&b);
}
static WpProperties *
si_fake_stream_get_stream_properties (WpSiStream * self)
{
return NULL;
}
static WpSiEndpoint *
si_fake_stream_get_stream_parent_endpoint (WpSiStream * self)
{
return WP_SI_ENDPOINT (wp_session_item_get_parent (WP_SESSION_ITEM (self)));
}
static void
si_fake_stream_stream_init (WpSiStreamInterface * iface)
{
iface->get_registration_info = si_fake_stream_get_stream_registration_info;
iface->get_properties = si_fake_stream_get_stream_properties;
iface->get_parent_endpoint = si_fake_stream_get_stream_parent_endpoint;
}
static void
si_fake_stream_class_init (WpSiFakeStreamClass * klass)
{
WpSessionItemClass *si_class = (WpSessionItemClass *) klass;
si_class->reset = si_fake_stream_reset;
si_class->configure = si_fake_stream_configure;
si_class->get_configuration = si_fake_stream_get_configuration;
si_class->activate_get_next_step = si_fake_stream_activate_get_next_step;
si_class->activate_execute_step = si_fake_stream_activate_execute_step;
}
static GVariant *
si_fake_stream_get_ports (WpSiPortInfo * item, const gchar * context)
{
return NULL;
}
static void
si_fake_stream_port_info_init (WpSiPortInfoInterface * iface)
{
iface->get_ports = si_fake_stream_get_ports;
}
WP_PLUGIN_EXPORT gboolean
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{
GVariantBuilder b;
g_variant_builder_init (&b, G_VARIANT_TYPE ("a(ssymv)"));
g_variant_builder_add (&b, "(ssymv)", "name", "s",
WP_SI_CONFIG_OPTION_WRITEABLE | WP_SI_CONFIG_OPTION_REQUIRED, NULL);
wp_si_factory_register (core, wp_si_factory_new_simple (
"si-fake-stream", si_fake_stream_get_type (), g_variant_builder_end (&b)));
return TRUE;
}

View File

@@ -25,14 +25,12 @@ struct _WpSiMonitorEndpoint
};
static void si_monitor_endpoint_endpoint_init (WpSiEndpointInterface * iface);
static void si_monitor_endpoint_stream_init (WpSiStreamInterface * iface);
static void si_monitor_endpoint_port_info_init (WpSiPortInfoInterface * iface);
G_DECLARE_FINAL_TYPE(WpSiMonitorEndpoint, si_monitor_endpoint,
WP, SI_MONITOR_ENDPOINT, WpSessionItem)
G_DEFINE_TYPE_WITH_CODE (WpSiMonitorEndpoint, si_monitor_endpoint, WP_TYPE_SESSION_ITEM,
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ENDPOINT, si_monitor_endpoint_endpoint_init)
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_STREAM, si_monitor_endpoint_stream_init)
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_PORT_INFO, si_monitor_endpoint_port_info_init))
static void
@@ -224,53 +222,11 @@ si_monitor_endpoint_get_properties (WpSiEndpoint * item)
return properties;
}
static guint
si_monitor_endpoint_get_n_streams (WpSiEndpoint * item)
{
return 1;
}
static WpSiStream *
si_monitor_endpoint_get_stream (WpSiEndpoint * item, guint index)
{
g_return_val_if_fail (index == 0, NULL);
return WP_SI_STREAM (item);
}
static void
si_monitor_endpoint_endpoint_init (WpSiEndpointInterface * iface)
{
iface->get_registration_info = si_monitor_endpoint_get_registration_info;
iface->get_properties = si_monitor_endpoint_get_properties;
iface->get_n_streams = si_monitor_endpoint_get_n_streams;
iface->get_stream = si_monitor_endpoint_get_stream;
}
static GVariant *
si_monitor_endpoint_get_stream_registration_info (WpSiStream * self)
{
GVariantBuilder b;
g_variant_builder_init (&b, G_VARIANT_TYPE ("(sa{ss})"));
g_variant_builder_add (&b, "s", "default");
g_variant_builder_add (&b, "a{ss}", NULL);
return g_variant_builder_end (&b);
}
static WpSiEndpoint *
si_monitor_endpoint_get_stream_parent_endpoint (WpSiStream * self)
{
return WP_SI_ENDPOINT (g_object_ref (self));
}
static void
si_monitor_endpoint_stream_init (WpSiStreamInterface * iface)
{
iface->get_registration_info =
si_monitor_endpoint_get_stream_registration_info;
iface->get_parent_endpoint =
si_monitor_endpoint_get_stream_parent_endpoint;
}
static GVariant *

View File

@@ -30,14 +30,12 @@ struct _WpSiSimpleNodeEndpoint
};
static void si_simple_node_endpoint_endpoint_init (WpSiEndpointInterface * iface);
static void si_simple_node_endpoint_stream_init (WpSiStreamInterface * iface);
static void si_simple_node_endpoint_port_info_init (WpSiPortInfoInterface * iface);
G_DECLARE_FINAL_TYPE(WpSiSimpleNodeEndpoint, si_simple_node_endpoint,
WP, SI_SIMPLE_NODE_ENDPOINT, WpSessionItem)
G_DEFINE_TYPE_WITH_CODE (WpSiSimpleNodeEndpoint, si_simple_node_endpoint, WP_TYPE_SESSION_ITEM,
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ENDPOINT, si_simple_node_endpoint_endpoint_init)
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_STREAM, si_simple_node_endpoint_stream_init)
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_PORT_INFO, si_simple_node_endpoint_port_info_init))
static void
@@ -292,53 +290,11 @@ si_simple_node_endpoint_get_properties (WpSiEndpoint * item)
return result;
}
static guint
si_simple_node_endpoint_get_n_streams (WpSiEndpoint * item)
{
return 1;
}
static WpSiStream *
si_simple_node_endpoint_get_stream (WpSiEndpoint * item, guint index)
{
g_return_val_if_fail (index == 0, NULL);
return WP_SI_STREAM (item);
}
static void
si_simple_node_endpoint_endpoint_init (WpSiEndpointInterface * iface)
{
iface->get_registration_info = si_simple_node_endpoint_get_registration_info;
iface->get_properties = si_simple_node_endpoint_get_properties;
iface->get_n_streams = si_simple_node_endpoint_get_n_streams;
iface->get_stream = si_simple_node_endpoint_get_stream;
}
static GVariant *
si_simple_node_endpoint_get_stream_registration_info (WpSiStream * self)
{
GVariantBuilder b;
g_variant_builder_init (&b, G_VARIANT_TYPE ("(sa{ss})"));
g_variant_builder_add (&b, "s", "default");
g_variant_builder_add (&b, "a{ss}", NULL);
return g_variant_builder_end (&b);
}
static WpSiEndpoint *
si_simple_node_endpoint_get_stream_parent_endpoint (WpSiStream * self)
{
return WP_SI_ENDPOINT (g_object_ref (self));
}
static void
si_simple_node_endpoint_stream_init (WpSiStreamInterface * iface)
{
iface->get_registration_info =
si_simple_node_endpoint_get_stream_registration_info;
iface->get_parent_endpoint =
si_simple_node_endpoint_get_stream_parent_endpoint;
}
static GVariant *

View File

@@ -20,10 +20,10 @@ struct _WpSiStandardLink
{
WpSessionItem parent;
WpSiStream *out_stream;
WpSiStream *in_stream;
gchar *out_stream_port_context;
gchar *in_stream_port_context;
WpSiEndpoint *out_endpoint;
WpSiEndpoint *in_endpoint;
gchar *out_endpoint_port_context;
gchar *in_endpoint_port_context;
gboolean manage_lifetime;
gboolean passive;
@@ -38,13 +38,13 @@ G_DEFINE_TYPE_WITH_CODE (WpSiStandardLink, si_standard_link, WP_TYPE_SESSION_ITE
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_LINK, si_standard_link_link_init))
static void
on_stream_flags_changed (WpSessionItem * stream, WpSiFlags flags,
on_flags_changed (WpSessionItem * endpoint, WpSiFlags flags,
WpSessionItem * link)
{
/* stream was deactivated; destroy the associated link */
/* endpoint was deactivated; destroy the associated link */
if (!(flags & WP_SI_FLAG_ACTIVE)) {
wp_trace_object (link, "destroying because stream " WP_OBJECT_FORMAT
" was deactivated", WP_OBJECT_ARGS (stream));
wp_trace_object (link, "destroying because endpoint " WP_OBJECT_FORMAT
" was deactivated", WP_OBJECT_ARGS (endpoint));
wp_session_item_reset (link);
g_object_unref (link);
}
@@ -74,19 +74,19 @@ si_standard_link_reset (WpSessionItem * item)
WP_SESSION_ITEM_CLASS (si_standard_link_parent_class)->reset (item);
if (self->manage_lifetime) {
g_signal_handlers_disconnect_by_func (self->out_stream,
G_CALLBACK (on_stream_flags_changed), self);
g_signal_handlers_disconnect_by_func (self->in_stream,
G_CALLBACK (on_stream_flags_changed), self);
g_signal_handlers_disconnect_by_func (self->out_endpoint,
G_CALLBACK (on_flags_changed), self);
g_signal_handlers_disconnect_by_func (self->in_endpoint,
G_CALLBACK (on_flags_changed), self);
g_signal_handlers_disconnect_by_func (self,
G_CALLBACK (on_link_flags_changed), NULL);
}
self->manage_lifetime = FALSE;
self->passive = FALSE;
self->out_stream = NULL;
self->in_stream = NULL;
g_clear_pointer (&self->out_stream_port_context, g_free);
g_clear_pointer (&self->in_stream_port_context, g_free);
self->out_endpoint = NULL;
self->in_endpoint = NULL;
g_clear_pointer (&self->out_endpoint_port_context, g_free);
g_clear_pointer (&self->in_endpoint_port_context, g_free);
wp_session_item_clear_flag (item, WP_SI_FLAG_CONFIGURED);
}
@@ -100,15 +100,15 @@ si_standard_link_get_configuration (WpSessionItem * item)
/* Set the properties */
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}",
"out-stream", g_variant_new_uint64 ((guint64) self->out_stream));
"out-endpoint", g_variant_new_uint64 ((guint64) self->out_endpoint));
g_variant_builder_add (&b, "{sv}",
"in-stream", g_variant_new_uint64 ((guint64) self->in_stream));
"in-endpoint", g_variant_new_uint64 ((guint64) self->in_endpoint));
g_variant_builder_add (&b, "{sv}",
"out-stream-port-context",
g_variant_new_string (self->out_stream_port_context));
"out-endpoint-port-context",
g_variant_new_string (self->out_endpoint_port_context));
g_variant_builder_add (&b, "{sv}",
"in-stream-port-context",
g_variant_new_string (self->in_stream_port_context));
"in-endpoint-port-context",
g_variant_new_string (self->in_endpoint_port_context));
g_variant_builder_add (&b, "{sv}",
"manage-lifetime", g_variant_new_boolean (self->manage_lifetime));
g_variant_builder_add (&b, "{sv}",
@@ -120,52 +120,52 @@ static gboolean
si_standard_link_configure (WpSessionItem * item, GVariant * args)
{
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
guint64 out_stream_i, in_stream_i;
WpSessionItem *out_stream, *in_stream;
guint64 out_endpoint_i, in_endpoint_i;
WpSessionItem *out_endpoint, *in_endpoint;
if (wp_session_item_get_flags (item) &
(WP_SI_FLAG_ACTIVATING | WP_SI_FLAG_ACTIVE |
WP_SI_FLAG_EXPORTING | WP_SI_FLAG_EXPORTED))
return FALSE;
if (!g_variant_lookup (args, "out-stream", "t", &out_stream_i) ||
!g_variant_lookup (args, "in-stream", "t", &in_stream_i))
if (!g_variant_lookup (args, "out-endpoint", "t", &out_endpoint_i) ||
!g_variant_lookup (args, "in-endpoint", "t", &in_endpoint_i))
return FALSE;
out_stream = GUINT_TO_POINTER (out_stream_i);
in_stream = GUINT_TO_POINTER (in_stream_i);
out_endpoint = GUINT_TO_POINTER (out_endpoint_i);
in_endpoint = GUINT_TO_POINTER (in_endpoint_i);
if (!WP_IS_SI_STREAM (out_stream) || !WP_IS_SI_STREAM (in_stream) ||
!WP_IS_SI_PORT_INFO (out_stream) || !WP_IS_SI_PORT_INFO (in_stream) ||
!(wp_session_item_get_flags (out_stream) & WP_SI_FLAG_ACTIVE) ||
!(wp_session_item_get_flags (in_stream) & WP_SI_FLAG_ACTIVE))
if (!WP_IS_SI_ENDPOINT (out_endpoint) || !WP_IS_SI_ENDPOINT (in_endpoint) ||
!WP_IS_SI_PORT_INFO (out_endpoint) || !WP_IS_SI_PORT_INFO (in_endpoint) ||
!(wp_session_item_get_flags (out_endpoint) & WP_SI_FLAG_ACTIVE) ||
!(wp_session_item_get_flags (in_endpoint) & WP_SI_FLAG_ACTIVE))
return FALSE;
/* clear previous configuration; we are not active or exported,
so this doesn't have any other side-effects */
wp_session_item_reset (item);
self->out_stream = WP_SI_STREAM (out_stream);
self->in_stream = WP_SI_STREAM (in_stream);
self->out_endpoint = WP_SI_ENDPOINT (out_endpoint);
self->in_endpoint = WP_SI_ENDPOINT (in_endpoint);
g_variant_lookup (args, "out-stream-port-context", "s",
&self->out_stream_port_context);
g_variant_lookup (args, "in-stream-port-context", "s",
&self->in_stream_port_context);
g_variant_lookup (args, "out-endpoint-port-context", "s",
&self->out_endpoint_port_context);
g_variant_lookup (args, "in-endpoint-port-context", "s",
&self->in_endpoint_port_context);
g_variant_lookup (args, "passive", "b", &self->passive);
/* manage-lifetime == TRUE means that this si-standard-link item is
* responsible for self-destructing if either
* - one of the streams is deactivated
* - one of the endpoints is deactivated
* - if the WpImplEndpointLink is destroyed upon request
* (wp_proxy_request_destroy())
*/
if (g_variant_lookup (args, "manage-lifetime", "b", &self->manage_lifetime)
&& self->manage_lifetime) {
g_signal_connect_object (self->out_stream, "flags-changed",
G_CALLBACK (on_stream_flags_changed), self, 0);
g_signal_connect_object (self->in_stream, "flags-changed",
G_CALLBACK (on_stream_flags_changed), self, 0);
g_signal_connect_object (self->out_endpoint, "flags-changed",
G_CALLBACK (on_flags_changed), self, 0);
g_signal_connect_object (self->in_endpoint, "flags-changed",
G_CALLBACK (on_flags_changed), self, 0);
g_signal_connect (self, "flags-changed",
G_CALLBACK (on_link_flags_changed), NULL);
}
@@ -203,13 +203,13 @@ si_standard_link_activate_get_next_step (WpSessionItem * item,
}
static void
on_stream_acquired (WpSiStreamAcquisition * acq, GAsyncResult * res,
on_endpoint_acquired (WpSiEndpointAcquisition * acq, GAsyncResult * res,
WpTransition * transition)
{
WpSiStandardLink *self = wp_transition_get_source_object (transition);
g_autoptr (GError) error = NULL;
if (!wp_si_stream_acquisition_acquire_finish (acq, res, &error)) {
if (!wp_si_endpoint_acquisition_acquire_finish (acq, res, &error)) {
wp_transition_return_error (transition, g_steal_pointer (&error));
return;
}
@@ -239,12 +239,12 @@ find_core (WpSiStandardLink * self)
{
/* session items are not associated with a core, but surely when linking
we should be able to find a WpImplEndpointLink associated, or at the very
least a WpNode associated with one of the streams... */
least a WpNode associated with one of the endpoints... */
g_autoptr (WpObject) proxy = wp_session_item_get_associated_proxy (
WP_SESSION_ITEM (self), WP_TYPE_ENDPOINT_LINK);
if (!proxy)
proxy = wp_session_item_get_associated_proxy (
WP_SESSION_ITEM (self->out_stream), WP_TYPE_NODE);
WP_SESSION_ITEM (self->out_endpoint), WP_TYPE_NODE);
return proxy ? wp_object_get_core (proxy) : NULL;
}
@@ -372,14 +372,12 @@ si_standard_link_activate_execute_step (WpSessionItem * item,
switch (step) {
case STEP_ACQUIRE: {
g_autoptr (WpSiEndpoint) out_endpoint = NULL;
g_autoptr (WpSiEndpoint) in_endpoint = NULL;
WpSiStreamAcquisition *out_acquisition, *in_acquisition;
WpSiEndpointAcquisition *out_acquisition, *in_acquisition;
out_endpoint = wp_si_stream_get_parent_endpoint (self->out_stream);
in_endpoint = wp_si_stream_get_parent_endpoint (self->in_stream);
out_acquisition = wp_si_endpoint_get_stream_acquisition (out_endpoint);
in_acquisition = wp_si_endpoint_get_stream_acquisition (in_endpoint);
out_acquisition = wp_si_endpoint_get_endpoint_acquisition (
self->out_endpoint);
in_acquisition = wp_si_endpoint_get_endpoint_acquisition (
self->in_endpoint);
if (out_acquisition && in_acquisition)
self->n_async_ops_wait = 2;
@@ -392,13 +390,13 @@ si_standard_link_activate_execute_step (WpSessionItem * item,
}
if (out_acquisition) {
wp_si_stream_acquisition_acquire (out_acquisition, WP_SI_LINK (self),
self->out_stream, (GAsyncReadyCallback) on_stream_acquired,
wp_si_endpoint_acquisition_acquire (out_acquisition, WP_SI_LINK (self),
self->out_endpoint, (GAsyncReadyCallback) on_endpoint_acquired,
transition);
}
if (in_acquisition) {
wp_si_stream_acquisition_acquire (in_acquisition, WP_SI_LINK (self),
self->in_stream, (GAsyncReadyCallback) on_stream_acquired,
wp_si_endpoint_acquisition_acquire (in_acquisition, WP_SI_LINK (self),
self->in_endpoint, (GAsyncReadyCallback) on_endpoint_acquired,
transition);
}
break;
@@ -407,15 +405,15 @@ si_standard_link_activate_execute_step (WpSessionItem * item,
g_autoptr (GVariant) out_ports = NULL;
g_autoptr (GVariant) in_ports = NULL;
out_ports = wp_si_port_info_get_ports (WP_SI_PORT_INFO (self->out_stream),
self->out_stream_port_context);
in_ports = wp_si_port_info_get_ports (WP_SI_PORT_INFO (self->in_stream),
self->in_stream_port_context);
out_ports = wp_si_port_info_get_ports (WP_SI_PORT_INFO (self->out_endpoint),
self->out_endpoint_port_context);
in_ports = wp_si_port_info_get_ports (WP_SI_PORT_INFO (self->in_endpoint),
self->in_endpoint_port_context);
if (!create_links (self, transition, out_ports, in_ports)) {
wp_transition_return_error (transition, g_error_new (WP_DOMAIN_LIBRARY,
WP_LIBRARY_ERROR_INVARIANT,
"Bad port info returned from one of the streams"));
"Bad port info returned from one of the endpoints"));
}
break;
}
@@ -428,27 +426,21 @@ static void
si_standard_link_activate_rollback (WpSessionItem * item)
{
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
g_autoptr (WpSiEndpoint) out_endpoint = NULL;
g_autoptr (WpSiEndpoint) in_endpoint = NULL;
WpSiStreamAcquisition *out_acquisition, *in_acquisition;
WpSiEndpointAcquisition *out_acquisition, *in_acquisition;
if (self->out_stream) {
out_endpoint = wp_si_stream_get_parent_endpoint (self->out_stream);
if (out_endpoint) {
out_acquisition = wp_si_endpoint_get_stream_acquisition (out_endpoint);
if (self->out_endpoint) {
out_acquisition =
wp_si_endpoint_get_endpoint_acquisition (self->out_endpoint);
if (out_acquisition)
wp_si_stream_acquisition_release (out_acquisition, WP_SI_LINK (self),
self->out_stream);
wp_si_endpoint_acquisition_release (out_acquisition, WP_SI_LINK (self),
self->out_endpoint);
}
}
if (self->in_stream) {
in_endpoint = wp_si_stream_get_parent_endpoint (self->in_stream);
if (in_endpoint) {
in_acquisition = wp_si_endpoint_get_stream_acquisition (in_endpoint);
if (self->in_endpoint) {
in_acquisition =
wp_si_endpoint_get_endpoint_acquisition (self->in_endpoint);
if (in_acquisition)
wp_si_stream_acquisition_release (in_acquisition, WP_SI_LINK (self),
self->in_stream);
}
wp_si_endpoint_acquisition_release (in_acquisition, WP_SI_LINK (self),
self->in_endpoint);
}
g_clear_pointer (&self->node_links, g_ptr_array_unref);
@@ -475,26 +467,26 @@ si_standard_link_get_registration_info (WpSiLink * item)
return g_variant_builder_end (&b);
}
static WpSiStream *
si_standard_link_get_out_stream (WpSiLink * item)
static WpSiEndpoint *
si_standard_link_get_out_endpoint (WpSiLink * item)
{
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
return self->out_stream;
return self->out_endpoint;
}
static WpSiStream *
si_standard_link_get_in_stream (WpSiLink * item)
static WpSiEndpoint *
si_standard_link_get_in_endpoint (WpSiLink * item)
{
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
return self->in_stream;
return self->in_endpoint;
}
static void
si_standard_link_link_init (WpSiLinkInterface * iface)
{
iface->get_registration_info = si_standard_link_get_registration_info;
iface->get_out_stream = si_standard_link_get_out_stream;
iface->get_in_stream = si_standard_link_get_in_stream;
iface->get_out_endpoint = si_standard_link_get_out_endpoint;
iface->get_in_endpoint = si_standard_link_get_in_endpoint;
}
WP_PLUGIN_EXPORT gboolean
@@ -503,13 +495,13 @@ wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
GVariantBuilder b;
g_variant_builder_init (&b, G_VARIANT_TYPE ("a(ssymv)"));
g_variant_builder_add (&b, "(ssymv)", "out-stream", "t",
g_variant_builder_add (&b, "(ssymv)", "out-endpoint", "t",
WP_SI_CONFIG_OPTION_WRITEABLE | WP_SI_CONFIG_OPTION_REQUIRED, NULL);
g_variant_builder_add (&b, "(ssymv)", "in-stream", "t",
g_variant_builder_add (&b, "(ssymv)", "in-endpoint", "t",
WP_SI_CONFIG_OPTION_WRITEABLE | WP_SI_CONFIG_OPTION_REQUIRED, NULL);
g_variant_builder_add (&b, "(ssymv)", "out-stream-port-context", "s",
g_variant_builder_add (&b, "(ssymv)", "out-endpoint-port-context", "s",
WP_SI_CONFIG_OPTION_WRITEABLE, NULL);
g_variant_builder_add (&b, "(ssymv)", "in-stream-port-context", "s",
g_variant_builder_add (&b, "(ssymv)", "in-endpoint-port-context", "s",
WP_SI_CONFIG_OPTION_WRITEABLE, NULL);
g_variant_builder_add (&b, "(ssymv)", "manage-lifetime", "b",
WP_SI_CONFIG_OPTION_WRITEABLE, NULL);

View File

@@ -17,10 +17,7 @@ function endpoint_support.enable()
-- Session item factories, building blocks for the session management graph
-- Do not disable these unless you really know what you are doing
load_module("si-adapter")
load_module("si-audio-softdsp-endpoint")
load_module("si-bluez5-endpoint")
load_module("si-convert")
load_module("si-fake-stream")
load_module("si-monitor-endpoint")
load_module("si-simple-node-endpoint")
load_module("si-standard-link")

View File

@@ -49,7 +49,6 @@ default_endpoint_target = {
auto_linked_endpoints = {}
function createLink (ep, target)
if ep:get_n_streams() > 0 and target:get_n_streams() > 0 then
local ep_id = ep['bound-id']
local target_id = target['bound-id']
local ep_is_output = (ep.direction == "output")
@@ -60,14 +59,13 @@ function createLink (ep, target)
['endpoint-link.input.stream'] = -1,
}
ep:create_link (props)
end
end
function isEndpointLinkedWith (session, ep, target)
local ep_id = ep["bound_id"]
local target_id = target["bound_id"]
for link in session:iterate_links() do
local out_ep, _, in_ep, _ = link:get_linked_object_ids()
local out_ep, in_ep = link:get_linked_object_ids()
if (out_ep == ep_id and in_ep == target_id) or
(out_ep == target_id and in_ep == ep_id) then
return true
@@ -89,7 +87,7 @@ function moveEndpoint (session, ep, target)
-- destroy all previous links
for link in session:iterate_links() do
local out_ep, _, in_ep, _ = link:get_linked_object_ids()
local out_ep, in_ep = link:get_linked_object_ids()
if (ep_is_output and out_ep == ep_id) or
(not ep_is_output and in_ep == ep_id) then
local curr_target = nil
@@ -224,7 +222,7 @@ function handleEndpoint (session, ep)
-- check if this endpoint is already linked
for link in session:iterate_links() do
local out_ep, _, in_ep, _ = link:get_linked_object_ids()
local out_ep, in_ep = link:get_linked_object_ids()
if out_ep == ep_id or in_ep == ep_id then
return
end

View File

@@ -72,14 +72,10 @@ on_endpoints_changed (WpSession * session, AppData * d)
WP_CONSTRAINT_TYPE_PW_PROPERTY, "media.class", "=s", "Audio/Sink", NULL);
if (src) {
g_print ("Got endpoint src: %s (%u streams)\n",
wp_endpoint_get_name (src),
wp_endpoint_get_n_streams (src));
g_print ("Got endpoint src: %s\n", wp_endpoint_get_name (src));
}
if (sink) {
g_print ("Got endpoint sink: %s (%u streams)\n",
wp_endpoint_get_name (sink),
wp_endpoint_get_n_streams (sink));
g_print ("Got endpoint sink: %s\n", wp_endpoint_get_name (sink));
}
if (src && sink) {
@@ -356,10 +352,6 @@ appdata_init (AppData * d, GError ** error)
"libwireplumber-module-si-simple-node-endpoint", "module", NULL, error)))
return FALSE;
if (!(wp_core_load_component (d->core,
"libwireplumber-module-si-audio-softdsp-endpoint", "module", NULL, error)))
return FALSE;
if (!(wp_core_load_component (d->core,
"libwireplumber-module-si-adapter", "module", NULL, error)))
return FALSE;

View File

@@ -35,8 +35,15 @@ test(
)
test(
'test-si-audio-softdsp-endpoint',
executable('test-si-audio-softdsp-endpoint', 'si-audio-softdsp-endpoint.c',
'test-si-adapter',
executable('test-si-adapter', 'si-adapter.c',
dependencies: common_deps, c_args: common_args),
env: common_env,
)
test(
'test-si-convert',
executable('test-si-convert', 'si-convert.c',
dependencies: common_deps, c_args: common_args),
env: common_env,
)

View File

@@ -13,7 +13,7 @@ typedef struct {
} TestFixture;
static void
test_si_audio_softdsp_endpoint_setup (TestFixture * f, gconstpointer user_data)
test_si_adapter_setup (TestFixture * f, gconstpointer user_data)
{
wp_base_test_fixture_setup (&f->base, 0);
@@ -26,8 +26,6 @@ test_si_audio_softdsp_endpoint_setup (TestFixture * f, gconstpointer user_data)
"fake*", "test/libspa-test"), ==, 0);
g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context,
"audiotestsrc", "audiotestsrc/libspa-audiotestsrc"), ==, 0);
g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context,
"audio.convert", "audioconvert/libspa-audioconvert"), ==, 0);
g_assert_nonnull (pw_context_load_module (f->base.server.context,
"libpipewire-module-spa-node-factory", NULL, NULL));
g_assert_nonnull (pw_context_load_module (f->base.server.context,
@@ -39,34 +37,20 @@ test_si_audio_softdsp_endpoint_setup (TestFixture * f, gconstpointer user_data)
"libwireplumber-module-si-adapter", "module", NULL, &error);
g_assert_no_error (error);
}
{
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core,
"libwireplumber-module-si-convert", "module", NULL, &error);
g_assert_no_error (error);
}
{
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core,
"libwireplumber-module-si-audio-softdsp-endpoint", "module", NULL, &error);
g_assert_no_error (error);
}
}
static void
test_si_audio_softdsp_endpoint_teardown (TestFixture * f, gconstpointer user_data)
test_si_adapter_teardown (TestFixture * f, gconstpointer user_data)
{
wp_base_test_fixture_teardown (&f->base);
}
static void
test_si_audio_softdsp_endpoint_configure_activate (TestFixture * f,
test_si_adapter_configure_activate (TestFixture * f,
gconstpointer user_data)
{
guint requested_streams = GPOINTER_TO_UINT (user_data);
g_autoptr (WpNode) node = NULL;
g_autoptr (WpSessionItem) adapter = NULL;
g_autoptr (WpSessionItem) endpoint = NULL;
/* create audiotestsrc adapter node */
node = wp_node_new_from_factory (f->base.core,
@@ -120,122 +104,29 @@ test_si_audio_softdsp_endpoint_configure_activate (TestFixture * f,
g_assert_cmpuint (channels, ==, 0);
}
/* create audio softdsp endpoint */
endpoint = wp_session_item_make (f->base.core, "si-audio-softdsp-endpoint");
g_assert_nonnull (endpoint);
g_assert_true (WP_IS_SI_ENDPOINT (endpoint));
/* configure audio softdsp endpoint */
/* activate adapter */
{
g_auto (GVariantBuilder) b =
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}", "adapter",
g_variant_new_uint64 ((guint64) adapter));
g_assert_true (
wp_session_item_configure (endpoint, g_variant_builder_end (&b)));
}
g_assert_cmphex (wp_session_item_get_flags (endpoint), ==,
WP_SI_FLAG_CONFIGURED);
{
g_autoptr (GVariant) v = wp_session_item_get_configuration (endpoint);
guint64 adapter_i;
g_assert_nonnull (v);
g_assert_true (g_variant_lookup (v, "adapter", "t", &adapter_i));
g_assert_cmpuint (adapter_i, ==, (guint64) adapter);
}
if (requested_streams > 1) {
for (guint i = 0; i < requested_streams; i++) {
g_autoptr (WpSessionItem) stream =
wp_session_item_make (f->base.core, "si-convert");
g_assert_nonnull (stream);
g_assert_true (WP_IS_SI_STREAM (stream));
{
g_auto (GVariantBuilder) b =
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}", "target",
g_variant_new_uint64 ((guint64) adapter));
g_variant_builder_add (&b, "{sv}", "name",
g_variant_new_printf ("stream-%u", i));
g_assert_true (
wp_session_item_configure (stream, g_variant_builder_end (&b)));
}
g_assert_cmphex (wp_session_item_get_flags (stream), ==,
WP_SI_FLAG_CONFIGURED);
g_assert_true (wp_session_bin_add (WP_SESSION_BIN (endpoint),
g_steal_pointer (&stream)));
}
}
/* activate audio softdsp endpoint */
{
wp_session_item_activate (endpoint,
wp_session_item_activate (adapter,
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
g_main_loop_run (f->base.loop);
}
g_assert_cmphex (wp_session_item_get_flags (endpoint), ==,
WP_SI_FLAG_CONFIGURED | WP_SI_FLAG_ACTIVE);
g_assert_cmphex (wp_session_item_get_flags (adapter), ==,
WP_SI_FLAG_CONFIGURED | WP_SI_FLAG_ACTIVE);
g_assert_cmphex (wp_object_get_active_features (WP_OBJECT (node)), ==,
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL | WP_NODE_FEATURE_PORTS);
/* check streams */
g_assert_cmpuint (wp_si_endpoint_get_n_streams (WP_SI_ENDPOINT (endpoint)),
==, requested_streams);
if (requested_streams == 1) {
WpSiStream *stream =
wp_si_endpoint_get_stream (WP_SI_ENDPOINT (endpoint), 0);
g_autoptr (GVariant) info = wp_si_stream_get_registration_info (stream);
const gchar *stream_name;
g_variant_get (info, "(&sa{ss})", &stream_name, NULL);
g_assert_cmpstr (stream_name, ==, "audiotestsrc.adapter");
g_assert_true ((gpointer) stream == (gpointer) adapter);
} else {
for (guint i = 0; i < requested_streams; i++) {
WpSiStream *stream =
wp_si_endpoint_get_stream (WP_SI_ENDPOINT (endpoint), i);
g_autoptr (GVariant) info = wp_si_stream_get_registration_info (stream);
g_autofree gchar *expected_name = g_strdup_printf ("stream-%u", i);
const gchar *stream_name;
g_variant_get (info, "(&sa{ss})", &stream_name, NULL);
g_assert_cmpstr (stream_name, ==, expected_name);
g_assert_true ((gpointer) stream != (gpointer) adapter);
}
}
/* deactivate - configuration should not be altered */
wp_session_item_deactivate (endpoint);
g_assert_cmphex (wp_session_item_get_flags (endpoint), ==,
WP_SI_FLAG_CONFIGURED);
wp_session_item_deactivate (adapter);
g_assert_cmphex (wp_session_item_get_flags (adapter), ==, 0);
{
g_autoptr (GVariant) v = wp_session_item_get_configuration (endpoint);
guint64 adapter_i;
g_assert_nonnull (v);
g_assert_true (g_variant_lookup (v, "adapter", "t", &adapter_i));
g_assert_cmpuint (adapter_i, ==, (guint64) adapter);
}
}
static void
test_si_audio_softdsp_endpoint_export (TestFixture * f, gconstpointer user_data)
test_si_adapter_export (TestFixture * f, gconstpointer user_data)
{
g_autoptr (WpNode) node = NULL;
g_autoptr (WpSession) session = NULL;
g_autoptr (WpSessionItem) item = NULL;
g_autoptr (WpSessionItem) adapter = NULL;
g_autoptr (WpObjectManager) clients_om = NULL;
g_autoptr (WpClient) self_client = NULL;
@@ -280,23 +171,10 @@ test_si_audio_softdsp_endpoint_export (TestFixture * f, gconstpointer user_data)
wp_session_item_configure (adapter, g_variant_builder_end (&b)));
}
item = wp_session_item_make (f->base.core, "si-audio-softdsp-endpoint");
g_assert_nonnull (item);
g_assert_true (WP_IS_SI_ENDPOINT (item));
{
g_auto (GVariantBuilder) b =
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}", "adapter",
g_variant_new_uint64 ((guint64) adapter));
g_assert_true (
wp_session_item_configure (item, g_variant_builder_end (&b)));
}
/* activate */
{
wp_session_item_activate (item,
wp_session_item_activate (adapter,
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
g_main_loop_run (f->base.loop);
}
@@ -312,14 +190,12 @@ test_si_audio_softdsp_endpoint_export (TestFixture * f, gconstpointer user_data)
/* export */
wp_session_item_export (item, session,
wp_session_item_export (adapter, session,
(GAsyncReadyCallback) test_si_export_finish_cb, f);
g_main_loop_run (f->base.loop);
g_assert_cmphex (wp_session_item_get_flags (item), ==,
WP_SI_FLAG_CONFIGURED | WP_SI_FLAG_ACTIVE | WP_SI_FLAG_EXPORTED);
g_assert_cmphex (wp_session_item_get_flags (adapter), ==,
WP_SI_FLAG_CONFIGURED | WP_SI_FLAG_ACTIVE);
WP_SI_FLAG_CONFIGURED | WP_SI_FLAG_ACTIVE | WP_SI_FLAG_EXPORTED);
{
g_autoptr (WpEndpoint) ep = NULL;
@@ -327,7 +203,7 @@ test_si_audio_softdsp_endpoint_export (TestFixture * f, gconstpointer user_data)
gchar *tmp;
g_assert_nonnull (
ep = wp_session_item_get_associated_proxy (item, WP_TYPE_ENDPOINT));
ep = wp_session_item_get_associated_proxy (adapter, WP_TYPE_ENDPOINT));
g_assert_nonnull (
props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (ep)));
@@ -362,25 +238,19 @@ main (gint argc, gchar *argv[])
/* configure-activate */
g_test_add ("/modules/si-audio-softdsp-endpoint/configure-activate/single-stream",
TestFixture, GUINT_TO_POINTER (1),
test_si_audio_softdsp_endpoint_setup,
test_si_audio_softdsp_endpoint_configure_activate,
test_si_audio_softdsp_endpoint_teardown);
g_test_add ("/modules/si-audio-softdsp-endpoint/configure-activate/multi-stream",
TestFixture, GUINT_TO_POINTER (5),
test_si_audio_softdsp_endpoint_setup,
test_si_audio_softdsp_endpoint_configure_activate,
test_si_audio_softdsp_endpoint_teardown);
g_test_add ("/modules/si-adapter/configure-activate",
TestFixture, NULL,
test_si_adapter_setup,
test_si_adapter_configure_activate,
test_si_adapter_teardown);
/* export */
g_test_add ("/modules/si-audio-softdsp-endpoint/export",
g_test_add ("/modules/si-adapter/export",
TestFixture, NULL,
test_si_audio_softdsp_endpoint_setup,
test_si_audio_softdsp_endpoint_export,
test_si_audio_softdsp_endpoint_teardown);
test_si_adapter_setup,
test_si_adapter_export,
test_si_adapter_teardown);
return g_test_run ();
}

296
tests/modules/si-convert.c Normal file
View File

@@ -0,0 +1,296 @@
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include "../common/base-test-fixture.h"
typedef struct {
WpBaseTestFixture base;
} TestFixture;
static void
test_si_convert_setup (TestFixture * f, gconstpointer user_data)
{
wp_base_test_fixture_setup (&f->base, 0);
/* load modules */
{
g_autoptr (WpTestServerLocker) lock =
wp_test_server_locker_new (&f->base.server);
g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context,
"fake*", "test/libspa-test"), ==, 0);
g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context,
"audiotestsrc", "audiotestsrc/libspa-audiotestsrc"), ==, 0);
g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context,
"audio.convert", "audioconvert/libspa-audioconvert"), ==, 0);
g_assert_nonnull (pw_context_load_module (f->base.server.context,
"libpipewire-module-spa-node-factory", NULL, NULL));
g_assert_nonnull (pw_context_load_module (f->base.server.context,
"libpipewire-module-adapter", NULL, NULL));
}
{
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core,
"libwireplumber-module-si-adapter", "module", NULL, &error);
g_assert_no_error (error);
}
{
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core,
"libwireplumber-module-si-convert", "module", NULL, &error);
g_assert_no_error (error);
}
}
static void
test_si_convert_teardown (TestFixture * f, gconstpointer user_data)
{
wp_base_test_fixture_teardown (&f->base);
}
static void
test_si_convert_configure_activate (TestFixture * f,
gconstpointer user_data)
{
g_autoptr (WpNode) target_node = NULL;
g_autoptr (WpSessionItem) target = NULL;
g_autoptr (WpSessionItem) convert = NULL;
/* create target node */
target_node = wp_node_new_from_factory (f->base.core,
"adapter",
wp_properties_new (
"factory.name", "audiotestsrc",
"node.name", "audiotestsrc.adapter",
NULL));
g_assert_nonnull (target_node);
wp_object_activate (WP_OBJECT (target_node),
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL, NULL,
(GAsyncReadyCallback) test_object_activate_finish_cb, f);
g_main_loop_run (f->base.loop);
/* create target */
target = wp_session_item_make (f->base.core, "si-adapter");
g_assert_nonnull (target);
g_assert_true (WP_IS_SI_ENDPOINT (target));
/* configure target */
{
g_auto (GVariantBuilder) b =
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}", "node",
g_variant_new_uint64 ((guint64) target_node));
g_assert_true (
wp_session_item_configure (target, g_variant_builder_end (&b)));
}
g_assert_cmphex (wp_session_item_get_flags (target), ==,
WP_SI_FLAG_CONFIGURED);
/* create convert */
convert = wp_session_item_make (f->base.core, "si-convert");
g_assert_nonnull (convert);
g_assert_true (WP_IS_SI_ENDPOINT (convert));
/* configure convert */
{
g_auto (GVariantBuilder) b =
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}", "target",
g_variant_new_uint64 ((guint64) target));
g_variant_builder_add (&b, "{sv}", "name",
g_variant_new_string ("convert"));
g_assert_true (
wp_session_item_configure (convert, g_variant_builder_end (&b)));
g_assert_cmphex (wp_session_item_get_flags (convert), ==,
WP_SI_FLAG_CONFIGURED);
}
{
g_autoptr (GVariant) v = wp_session_item_get_configuration (convert);
guint64 target_i;
const gchar *name;
g_assert_nonnull (v);
g_assert_true (g_variant_lookup (v, "target", "t", &target_i));
g_assert_cmpuint (target_i, ==, (guint64) target);
g_assert_true (g_variant_lookup (v, "name", "&s", &name));
g_assert_cmpstr (name, ==, "convert");
}
/* activate convert */
{
wp_session_item_activate (convert,
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
g_main_loop_run (f->base.loop);
}
g_assert_cmphex (wp_session_item_get_flags (convert), ==,
WP_SI_FLAG_CONFIGURED | WP_SI_FLAG_ACTIVE);
/* deactivate */
wp_session_item_deactivate (convert);
}
static void
test_si_convert_export (TestFixture * f, gconstpointer user_data)
{
g_autoptr (WpNode) target_node = NULL;
g_autoptr (WpSessionItem) target = NULL;
g_autoptr (WpSessionItem) convert = NULL;
g_autoptr (WpSession) session = NULL;
g_autoptr (WpObjectManager) clients_om = NULL;
g_autoptr (WpClient) self_client = NULL;
/* find self_client, to be used for verifying endpoint.client.id */
clients_om = wp_object_manager_new ();
wp_object_manager_add_interest (clients_om, WP_TYPE_CLIENT, NULL);
wp_object_manager_request_object_features (clients_om,
WP_TYPE_CLIENT, WP_PROXY_FEATURE_BOUND);
g_signal_connect_swapped (clients_om, "objects-changed",
G_CALLBACK (g_main_loop_quit), f->base.loop);
wp_core_install_object_manager (f->base.core, clients_om);
g_main_loop_run (f->base.loop);
g_assert_nonnull (self_client =
wp_object_manager_lookup (clients_om, WP_TYPE_CLIENT, NULL));
/* create target node */
target_node = wp_node_new_from_factory (f->base.core,
"adapter",
wp_properties_new (
"factory.name", "audiotestsrc",
"node.name", "audiotestsrc.adapter",
NULL));
g_assert_nonnull (target_node);
wp_object_activate (WP_OBJECT (target_node),
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL, NULL,
(GAsyncReadyCallback) test_object_activate_finish_cb, f);
g_main_loop_run (f->base.loop);
/* create target */
target = wp_session_item_make (f->base.core, "si-adapter");
g_assert_nonnull (target);
g_assert_true (WP_IS_SI_ENDPOINT (target));
/* configure target */
{
g_auto (GVariantBuilder) b =
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}", "node",
g_variant_new_uint64 ((guint64) target_node));
g_assert_true (
wp_session_item_configure (target, g_variant_builder_end (&b)));
g_assert_cmphex (wp_session_item_get_flags (target), ==,
WP_SI_FLAG_CONFIGURED);
}
/* create convert */
convert = wp_session_item_make (f->base.core, "si-convert");
g_assert_nonnull (convert);
/* configure convert */
{
g_auto (GVariantBuilder) b =
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}", "target",
g_variant_new_uint64 ((guint64) target));
g_variant_builder_add (&b, "{sv}", "name",
g_variant_new_string ("convert"));
g_assert_true (
wp_session_item_configure (convert, g_variant_builder_end (&b)));
g_assert_cmphex (wp_session_item_get_flags (convert), ==,
WP_SI_FLAG_CONFIGURED);
}
/* activate convert */
{
wp_session_item_activate (convert,
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
g_main_loop_run (f->base.loop);
}
/* create session */
session = WP_SESSION (wp_impl_session_new (f->base.core));
g_assert_nonnull (session);
wp_object_activate (WP_OBJECT (session), WP_OBJECT_FEATURES_ALL, NULL,
(GAsyncReadyCallback) test_object_activate_finish_cb, f);
g_main_loop_run (f->base.loop);
/* export */
wp_session_item_export (convert, session,
(GAsyncReadyCallback) test_si_export_finish_cb, f);
g_main_loop_run (f->base.loop);
g_assert_cmphex (wp_session_item_get_flags (convert), ==,
WP_SI_FLAG_CONFIGURED | WP_SI_FLAG_ACTIVE | WP_SI_FLAG_EXPORTED);
{
g_autoptr (WpEndpoint) ep = NULL;
g_autoptr (WpProperties) props = NULL;
gchar *tmp;
g_assert_nonnull (
ep = wp_session_item_get_associated_proxy (convert, WP_TYPE_ENDPOINT));
g_assert_nonnull (
props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (ep)));
g_assert_cmpstr (wp_endpoint_get_name (ep), ==, "convert");
g_assert_cmpstr (wp_endpoint_get_media_class (ep), ==,
"Audio/Convert");
g_assert_cmpint (wp_endpoint_get_direction (ep), ==, WP_DIRECTION_OUTPUT);
g_assert_cmpstr (wp_properties_get (props, "endpoint.name"), ==,
"convert");
g_assert_cmpstr (wp_properties_get (props, "media.class"), ==,
"Audio/Convert");
tmp = g_strdup_printf ("%d", wp_proxy_get_bound_id (WP_PROXY (session)));
g_assert_cmpstr (wp_properties_get (props, "session.id"), ==, tmp);
g_free (tmp);
}
}
gint
main (gint argc, gchar *argv[])
{
g_test_init (&argc, &argv, NULL);
wp_init (WP_INIT_ALL);
/* configure-activate */
g_test_add ("/modules/si-convert/configure-activate",
TestFixture, NULL,
test_si_convert_setup,
test_si_convert_configure_activate,
test_si_convert_teardown);
/* export */
g_test_add ("/modules/si-convert/export",
TestFixture, NULL,
test_si_convert_setup,
test_si_convert_export,
test_si_convert_teardown);
return g_test_run ();
}

View File

@@ -58,14 +58,12 @@ test_si_simple_node_endpoint_configure_activate (TestFixture * f,
const TestData *data = user_data;
g_autoptr (WpNode) node = NULL;
g_autoptr (WpSessionItem) item = NULL;
WpSiStream *stream;
/* create item */
item = wp_session_item_make (f->base.core, "si-simple-node-endpoint");
g_assert_nonnull (item);
g_assert_true (WP_IS_SI_ENDPOINT (item));
g_assert_true (WP_IS_SI_STREAM (item));
g_assert_true (WP_IS_SI_PORT_INFO (item));
node = wp_node_new_from_factory (f->base.core,
@@ -130,11 +128,6 @@ test_si_simple_node_endpoint_configure_activate (TestFixture * f,
g_assert_cmphex (wp_object_get_active_features (WP_OBJECT (node)), ==,
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL | WP_NODE_FEATURE_PORTS);
g_assert_cmpint (
wp_si_endpoint_get_n_streams (WP_SI_ENDPOINT (item)), ==, 1);
g_assert_nonnull (
stream = wp_si_endpoint_get_stream (WP_SI_ENDPOINT (item), 0));
if (data->expected_direction == WP_DIRECTION_INPUT)
g_assert_cmpuint (wp_node_get_n_input_ports (node, NULL), ==, 1);
else
@@ -144,7 +137,7 @@ test_si_simple_node_endpoint_configure_activate (TestFixture * f,
{
guint32 node_id, port_id, channel;
g_autoptr (GVariant) v =
wp_si_port_info_get_ports (WP_SI_PORT_INFO (stream), NULL);
wp_si_port_info_get_ports (WP_SI_PORT_INFO (item), NULL);
g_assert_true (g_variant_is_of_type (v, G_VARIANT_TYPE ("a(uuu)")));
g_assert_cmpint (g_variant_n_children (v), ==, 1);
@@ -229,7 +222,6 @@ test_si_simple_node_endpoint_export (TestFixture * f, gconstpointer user_data)
g_autoptr (WpSessionItem) item = NULL;
g_autoptr (WpObjectManager) clients_om = NULL;
g_autoptr (WpClient) self_client = NULL;
WpSiStream *stream;
/* find self_client, to be used for verifying endpoint.client.id */
@@ -284,11 +276,6 @@ test_si_simple_node_endpoint_export (TestFixture * f, gconstpointer user_data)
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
g_main_loop_run (f->base.loop);
g_assert_cmpint (
wp_si_endpoint_get_n_streams (WP_SI_ENDPOINT (item)), ==, 1);
g_assert_nonnull (
stream = wp_si_endpoint_get_stream (WP_SI_ENDPOINT (item), 0));
/* create session */
session = WP_SESSION (wp_impl_session_new (f->base.core));
@@ -342,27 +329,6 @@ test_si_simple_node_endpoint_export (TestFixture * f, gconstpointer user_data)
g_free (tmp);
}
{
g_autoptr (WpEndpointStream) epstr = NULL;
g_autoptr (WpProperties) props = NULL;
gchar *tmp;
g_assert_nonnull (
epstr = wp_session_item_get_associated_proxy (WP_SESSION_ITEM (stream),
WP_TYPE_ENDPOINT_STREAM));
g_assert_nonnull (
props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (epstr)));
g_assert_cmpstr (wp_endpoint_stream_get_name (epstr), ==, "default");
g_assert_cmpstr (wp_properties_get (props, "endpoint-stream.name"), ==,
"default");
tmp = g_strdup_printf ("%d", wp_session_item_get_associated_proxy_id (
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT));
g_assert_cmpstr (wp_properties_get (props, "endpoint.id"), ==, tmp);
g_free (tmp);
}
wp_session_item_reset (item);
g_assert_cmphex (wp_session_item_get_flags (item), ==, 0);
}

View File

@@ -173,8 +173,6 @@ test_si_standard_link_main (TestFixture * f, gconstpointer user_data)
g_assert_nonnull (sink_ep = wp_session_lookup_endpoint (session_proxy,
WP_CONSTRAINT_TYPE_PW_PROPERTY, "endpoint.name", "=s", "fakesink",
NULL));
g_assert_cmpuint (wp_endpoint_get_n_streams (src_ep), ==, 1);
g_assert_cmpuint (wp_endpoint_get_n_streams (sink_ep), ==, 1);
/* create the link */
{
@@ -198,19 +196,11 @@ test_si_standard_link_main (TestFixture * f, gconstpointer user_data)
g_assert_nonnull (ep_link = wp_session_lookup_link (session_proxy, NULL));
{
guint32 out_ep, out_stream, in_ep, in_stream;
g_autoptr (WpEndpointStream) src_stream = NULL;
g_autoptr (WpEndpointStream) sink_stream = NULL;
guint32 out_ep, in_ep;
g_assert_nonnull (src_stream = wp_endpoint_lookup_stream (src_ep, NULL));
g_assert_nonnull (sink_stream = wp_endpoint_lookup_stream (sink_ep, NULL));
wp_endpoint_link_get_linked_object_ids (ep_link, &out_ep, &out_stream,
&in_ep, &in_stream);
wp_endpoint_link_get_linked_object_ids (ep_link, &out_ep, &in_ep);
g_assert_cmpuint (out_ep, ==, wp_proxy_get_bound_id (WP_PROXY (src_ep)));
g_assert_cmpuint (in_ep, ==, wp_proxy_get_bound_id (WP_PROXY (sink_ep)));
g_assert_cmpuint (out_stream, ==, wp_proxy_get_bound_id (WP_PROXY (src_stream)));
g_assert_cmpuint (in_stream, ==, wp_proxy_get_bound_id (WP_PROXY (sink_stream)));
}
{
@@ -219,9 +209,7 @@ test_si_standard_link_main (TestFixture * f, gconstpointer user_data)
g_assert_nonnull (p);
g_assert_nonnull (wp_properties_get (p, "endpoint-link.input.endpoint"));
g_assert_nonnull (wp_properties_get (p, "endpoint-link.input.stream"));
g_assert_nonnull (wp_properties_get (p, "endpoint-link.output.endpoint"));
g_assert_nonnull (wp_properties_get (p, "endpoint-link.output.stream"));
}
{
@@ -372,8 +360,6 @@ test_si_standard_link_destroy (TestFixture * f, gconstpointer user_data)
g_assert_nonnull (sink_ep = wp_session_lookup_endpoint (session_proxy,
WP_CONSTRAINT_TYPE_PW_PROPERTY, "endpoint.name", "=s", "fakesink",
NULL));
g_assert_cmpuint (wp_endpoint_get_n_streams (src_ep), ==, 1);
g_assert_cmpuint (wp_endpoint_get_n_streams (sink_ep), ==, 1);
/* create the link */
{

View File

@@ -47,63 +47,15 @@ test_si_endpoint_get_properties (WpSiEndpoint * item)
return wp_properties_new ("test.property", "test-value", NULL);
}
static guint
test_si_endpoint_get_n_streams (WpSiEndpoint * item)
{
return 1;
}
static WpSiStream *
test_si_endpoint_get_stream (WpSiEndpoint * item, guint index)
{
g_return_val_if_fail (index == 0, NULL);
return WP_SI_STREAM (item);
}
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;
iface->get_n_streams = test_si_endpoint_get_n_streams;
iface->get_stream = test_si_endpoint_get_stream;
}
static GVariant *
test_si_endpoint_get_stream_registration_info (WpSiStream * self)
{
GVariantBuilder b;
g_variant_builder_init (&b, G_VARIANT_TYPE ("(sa{ss})"));
g_variant_builder_add (&b, "s", "default");
g_variant_builder_add (&b, "a{ss}", NULL);
return g_variant_builder_end (&b);
}
static WpProperties *
test_si_endpoint_get_stream_properties (WpSiStream * self)
{
return wp_properties_new ("stream.property", "test-value-2", NULL);
}
static WpSiEndpoint *
test_si_endpoint_get_stream_parent_endpoint (WpSiStream * self)
{
return WP_SI_ENDPOINT (g_object_ref (self));
}
static void
test_si_endpoint_stream_init (WpSiStreamInterface * iface)
{
iface->get_registration_info = test_si_endpoint_get_stream_registration_info;
iface->get_properties = test_si_endpoint_get_stream_properties;
iface->get_parent_endpoint = test_si_endpoint_get_stream_parent_endpoint;
}
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)
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_STREAM, test_si_endpoint_stream_init))
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ENDPOINT, test_si_endpoint_endpoint_init))
static void
test_si_endpoint_init (TestSiEndpoint * self)

View File

@@ -26,10 +26,6 @@ struct _WpCtl
static struct {
union {
struct {
gboolean show_streams;
} status;
struct {
guint32 id;
gboolean show_referenced;
@@ -119,19 +115,6 @@ print_controls (WpPipewireObject * pwobj)
printf ("\n");
}
static void
print_stream (const GValue *item, gpointer data)
{
WpEndpointStream *stream = g_value_get_object (item);
guint32 id = wp_proxy_get_bound_id (WP_PROXY (stream));
guint *n_streams = data;
printf (TREE_INDENT_LINE TREE_INDENT_EMPTY " %s%4u. %-53s",
(--(*n_streams) == 0) ? TREE_INDENT_END : TREE_INDENT_NODE,
id, wp_endpoint_stream_get_name (stream));
print_controls (WP_PIPEWIRE_OBJECT (stream));
}
static const gchar *
get_endpoint_friendly_name (WpEndpoint * ep)
{
@@ -152,13 +135,6 @@ print_endpoint (const GValue *item, gpointer data)
printf (TREE_INDENT_LINE "%c %4u. %-60s",
(default_id == id) ? '*' : ' ', id, get_endpoint_friendly_name (ep));
print_controls (WP_PIPEWIRE_OBJECT (ep));
if (cmdline.status.show_streams) {
g_autoptr (WpIterator) it = wp_endpoint_new_streams_iterator (ep);
guint n_streams = wp_endpoint_get_n_streams (ep);
wp_iterator_foreach (it, print_stream, &n_streams);
printf (TREE_INDENT_LINE "\n");
}
}
static void
@@ -167,30 +143,20 @@ print_endpoint_link (const GValue *item, gpointer data)
WpEndpointLink *link = g_value_get_object (item);
WpSession *session = data;
guint32 id = wp_proxy_get_bound_id (WP_PROXY (link));
guint32 out_ep_id, out_stream_id, in_ep_id, in_stream_id;
guint32 out_ep_id, in_ep_id;
g_autoptr (WpEndpoint) out_ep = NULL;
g_autoptr (WpEndpoint) in_ep = NULL;
g_autoptr (WpEndpointStream) out_stream = NULL;
g_autoptr (WpEndpointStream) in_stream = NULL;
wp_endpoint_link_get_linked_object_ids (link,
&out_ep_id, &out_stream_id, &in_ep_id, &in_stream_id);
wp_endpoint_link_get_linked_object_ids (link, &out_ep_id, &in_ep_id);
out_ep = wp_session_lookup_endpoint (session,
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", out_ep_id, NULL);
in_ep = wp_session_lookup_endpoint (session,
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", in_ep_id, NULL);
out_stream = wp_endpoint_lookup_stream (out_ep,
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", out_stream_id, NULL);
in_stream = wp_endpoint_lookup_stream (in_ep,
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", in_stream_id, NULL);
printf (TREE_INDENT_EMPTY " %4u. [%u. %s|%s] ➞ [%u. %s|%s]\n", id,
printf (TREE_INDENT_EMPTY " %4u. [%u. %s] ➞ [%u. %s]\n", id,
out_ep_id, get_endpoint_friendly_name (out_ep),
wp_endpoint_stream_get_name (out_stream),
in_ep_id, get_endpoint_friendly_name (in_ep),
wp_endpoint_stream_get_name (in_stream));
in_ep_id, get_endpoint_friendly_name (in_ep));
}
static void
@@ -625,10 +591,6 @@ set_volume_prepare (WpCtl * self, GError ** error)
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
"object.id", "=u", cmdline.set_volume.id,
NULL);
wp_object_manager_add_interest (self->om, WP_TYPE_ENDPOINT_STREAM,
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
"object.id", "=u", cmdline.set_volume.id,
NULL);
wp_object_manager_add_interest (self->om, WP_TYPE_NODE,
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
"object.id", "=u", cmdline.set_volume.id,
@@ -714,10 +676,6 @@ set_mute_prepare (WpCtl * self, GError ** error)
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
"object.id", "=u", cmdline.set_mute.id,
NULL);
wp_object_manager_add_interest (self->om, WP_TYPE_ENDPOINT_STREAM,
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
"object.id", "=u", cmdline.set_mute.id,
NULL);
wp_object_manager_add_interest (self->om, WP_TYPE_NODE,
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
"object.id", "=u", cmdline.set_mute.id,
@@ -851,11 +809,7 @@ static const struct subcommand {
.positional_args = "",
.summary = "Displays the current state of objects in PipeWire",
.description = NULL,
.entries = {
{ "streams", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE,
&cmdline.status.show_streams, "Also show endpoint streams", NULL },
{ NULL }
},
.entries = { { NULL } },
.parse_positional = NULL,
.prepare = status_prepare,
.run = status_run,