lib: remove WpEndpointStream API
Add all that goes with it.
This commit is contained in:
@@ -187,12 +187,8 @@ wp_endpoint_link_pw_object_mixin_priv_interface_init (
|
|||||||
* @self: the endpoint link
|
* @self: the endpoint link
|
||||||
* @output_endpoint: (out) (optional): the bound id of the output (source)
|
* @output_endpoint: (out) (optional): the bound id of the output (source)
|
||||||
* endpoint
|
* 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)
|
* @input_endpoint: (out) (optional): the bound id of the input (sink)
|
||||||
* endpoint
|
* 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
|
* 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
|
void
|
||||||
wp_endpoint_link_get_linked_object_ids (WpEndpointLink * self,
|
wp_endpoint_link_get_linked_object_ids (WpEndpointLink * self,
|
||||||
guint32 * output_endpoint, guint32 * output_stream,
|
guint32 * output_endpoint, guint32 * input_endpoint)
|
||||||
guint32 * input_endpoint, guint32 * input_stream)
|
|
||||||
{
|
{
|
||||||
g_return_if_fail (WP_IS_ENDPOINT_LINK (self));
|
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)
|
if (output_endpoint)
|
||||||
*output_endpoint = info->output_endpoint_id;
|
*output_endpoint = info->output_endpoint_id;
|
||||||
if (output_stream)
|
|
||||||
*output_stream = info->output_stream_id;
|
|
||||||
if (input_endpoint)
|
if (input_endpoint)
|
||||||
*input_endpoint = info->input_endpoint_id;
|
*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 (GVariant) info = NULL;
|
||||||
g_autoptr (GVariantIter) immutable_props = NULL;
|
g_autoptr (GVariantIter) immutable_props = NULL;
|
||||||
const gchar *key, *value;
|
const gchar *key, *value;
|
||||||
WpSiStream *stream;
|
WpSiEndpoint *endpoint;
|
||||||
|
|
||||||
self->info.version = PW_VERSION_ENDPOINT_LINK_INFO;
|
self->info.version = PW_VERSION_ENDPOINT_LINK_INFO;
|
||||||
self->info.error = NULL;
|
self->info.error = NULL;
|
||||||
@@ -426,21 +417,17 @@ wp_impl_endpoint_link_constructed (GObject * object)
|
|||||||
? PW_ENDPOINT_LINK_STATE_ACTIVE
|
? PW_ENDPOINT_LINK_STATE_ACTIVE
|
||||||
: PW_ENDPOINT_LINK_STATE_INACTIVE;
|
: 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 (
|
self->info.session_id = wp_session_item_get_associated_proxy_id (
|
||||||
WP_SESSION_ITEM (self->item), WP_TYPE_SESSION);
|
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 (
|
self->info.output_endpoint_id = wp_session_item_get_associated_proxy_id (
|
||||||
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT);
|
WP_SESSION_ITEM (endpoint), WP_TYPE_ENDPOINT);
|
||||||
self->info.output_stream_id = wp_session_item_get_associated_proxy_id (
|
|
||||||
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT_STREAM);
|
|
||||||
|
|
||||||
stream = wp_si_link_get_in_stream (self->item);
|
endpoint = wp_si_link_get_in_endpoint (self->item);
|
||||||
self->info.input_endpoint_id = wp_session_item_get_associated_proxy_id (
|
self->info.input_endpoint_id = wp_session_item_get_associated_proxy_id (
|
||||||
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT);
|
WP_SESSION_ITEM (endpoint), WP_TYPE_ENDPOINT);
|
||||||
self->info.input_stream_id = wp_session_item_get_associated_proxy_id (
|
|
||||||
WP_SESSION_ITEM (stream), WP_TYPE_ENDPOINT_STREAM);
|
|
||||||
|
|
||||||
/* construct export properties (these will come back through
|
/* construct export properties (these will come back through
|
||||||
the registry and appear in wp_proxy_get_global_properties) */
|
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);
|
PW_KEY_SESSION_ID, "%d", self->info.session_id);
|
||||||
wp_properties_setf (self->immutable_props,
|
wp_properties_setf (self->immutable_props,
|
||||||
PW_KEY_ENDPOINT_LINK_OUTPUT_ENDPOINT, "%d", self->info.output_endpoint_id);
|
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,
|
wp_properties_setf (self->immutable_props,
|
||||||
PW_KEY_ENDPOINT_LINK_INPUT_ENDPOINT, "%d", self->info.input_endpoint_id);
|
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 */
|
/* populate immutable (global) properties */
|
||||||
while (g_variant_iter_next (immutable_props, "{&s&s}", &key, &value))
|
while (g_variant_iter_next (immutable_props, "{&s&s}", &key, &value))
|
||||||
|
@@ -44,8 +44,7 @@ struct _WpEndpointLinkClass
|
|||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
void wp_endpoint_link_get_linked_object_ids (WpEndpointLink * self,
|
void wp_endpoint_link_get_linked_object_ids (WpEndpointLink * self,
|
||||||
guint32 * output_endpoint, guint32 * output_stream,
|
guint32 * output_endpoint, guint32 * input_endpoint);
|
||||||
guint32 * input_endpoint, guint32 * input_stream);
|
|
||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
WpEndpointLinkState wp_endpoint_link_get_state (WpEndpointLink * self,
|
WpEndpointLinkState wp_endpoint_link_get_state (WpEndpointLink * self,
|
||||||
|
@@ -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);
|
|
||||||
}
|
|
@@ -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
|
|
@@ -36,17 +36,10 @@ enum {
|
|||||||
PROP_DIRECTION,
|
PROP_DIRECTION,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
|
||||||
SIGNAL_STREAMS_CHANGED,
|
|
||||||
N_SIGNALS,
|
|
||||||
};
|
|
||||||
|
|
||||||
static guint32 signals[N_SIGNALS] = {0};
|
|
||||||
|
|
||||||
typedef struct _WpEndpointPrivate WpEndpointPrivate;
|
typedef struct _WpEndpointPrivate WpEndpointPrivate;
|
||||||
struct _WpEndpointPrivate
|
struct _WpEndpointPrivate
|
||||||
{
|
{
|
||||||
WpObjectManager *streams_om;
|
gint place_holder;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void wp_endpoint_pw_object_mixin_priv_interface_init (
|
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
|
static WpObjectFeatures
|
||||||
wp_endpoint_get_supported_features (WpObject * object)
|
wp_endpoint_get_supported_features (WpObject * object)
|
||||||
{
|
{
|
||||||
return wp_pw_object_mixin_get_supported_features(object)
|
return wp_pw_object_mixin_get_supported_features(object);
|
||||||
| WP_ENDPOINT_FEATURE_STREAMS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
|
||||||
STEP_STREAMS = WP_PW_OBJECT_MIXIN_STEP_CUSTOM_START,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wp_endpoint_activate_execute_step (WpObject * object,
|
wp_endpoint_activate_execute_step (WpObject * object,
|
||||||
WpFeatureActivationTransition * transition, guint step,
|
WpFeatureActivationTransition * transition, guint step,
|
||||||
@@ -187,9 +116,6 @@ wp_endpoint_activate_execute_step (WpObject * object,
|
|||||||
case WP_PW_OBJECT_MIXIN_STEP_CACHE_PARAMS:
|
case WP_PW_OBJECT_MIXIN_STEP_CACHE_PARAMS:
|
||||||
wp_pw_object_mixin_cache_params (object, missing);
|
wp_pw_object_mixin_cache_params (object, missing);
|
||||||
break;
|
break;
|
||||||
case STEP_STREAMS:
|
|
||||||
wp_endpoint_enable_feature_streams (WP_ENDPOINT (object));
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
@@ -199,14 +125,6 @@ static void
|
|||||||
wp_endpoint_deactivate (WpObject * object, WpObjectFeatures features)
|
wp_endpoint_deactivate (WpObject * object, WpObjectFeatures features)
|
||||||
{
|
{
|
||||||
wp_pw_object_mixin_deactivate (object, 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);
|
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
|
static void
|
||||||
wp_endpoint_pw_proxy_destroyed (WpProxy * proxy)
|
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);
|
wp_pw_object_mixin_handle_pw_proxy_destroyed (proxy);
|
||||||
|
|
||||||
g_clear_object (&priv->streams_om);
|
wp_object_update_features (WP_OBJECT (proxy), 0, 0);
|
||||||
wp_object_update_features (WP_OBJECT (proxy), 0,
|
|
||||||
WP_ENDPOINT_FEATURE_STREAMS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -258,17 +171,6 @@ wp_endpoint_class_init (WpEndpointClass * klass)
|
|||||||
|
|
||||||
wp_pw_object_mixin_class_override_properties (object_class);
|
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:
|
* WpEndpoint:name:
|
||||||
*
|
*
|
||||||
@@ -381,138 +283,6 @@ wp_endpoint_get_direction (WpEndpoint * self)
|
|||||||
return (WpDirection) ((struct pw_endpoint_info *) d->info)->direction;
|
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:
|
* wp_endpoint_create_link:
|
||||||
* @self: the endpoint
|
* @self: the endpoint
|
||||||
@@ -523,15 +293,8 @@ wp_endpoint_lookup_stream_full (WpEndpoint * self, WpObjectInterest * interest)
|
|||||||
* @props may contain:
|
* @props may contain:
|
||||||
* - `endpoint-link.output.endpoint`: the bound id of the endpoint
|
* - `endpoint-link.output.endpoint`: the bound id of the endpoint
|
||||||
* that is in the %WP_DIRECTION_OUTPUT direction
|
* 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
|
* - `endpoint-link.input.endpoint`: the bound id of the endpoint
|
||||||
* that is in the %WP_DIRECTION_INPUT direction
|
* 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
|
* The id of @self is not necessary to be specified, so only one of
|
||||||
* `endpoint-link.output.endpoint`, `endpoint-link.input.endpoint`
|
* `endpoint-link.output.endpoint`, `endpoint-link.input.endpoint`
|
||||||
@@ -596,14 +359,11 @@ static int
|
|||||||
impl_create_link (void *object, const struct spa_dict *props)
|
impl_create_link (void *object, const struct spa_dict *props)
|
||||||
{
|
{
|
||||||
WpImplEndpoint *self = WP_IMPL_ENDPOINT (object);
|
WpImplEndpoint *self = WP_IMPL_ENDPOINT (object);
|
||||||
const gchar *self_ep, *self_stream, *peer_ep, *peer_stream;
|
const gchar *self_ep, *peer_ep;
|
||||||
guint32 self_ep_id, self_stream_id, peer_ep_id, peer_stream_id;
|
guint32 peer_ep_id;
|
||||||
WpSiStream *self_si_stream = NULL;
|
g_autoptr (WpSiEndpoint) peer_si_endpoint = NULL;
|
||||||
g_autoptr (WpSiStream) peer_si_stream = NULL;
|
|
||||||
g_autoptr (WpSession) session = NULL;
|
g_autoptr (WpSession) session = NULL;
|
||||||
g_autoptr (WpEndpointStream) self_stream_proxy = NULL;
|
|
||||||
g_autoptr (WpEndpoint) peer_ep_proxy = NULL;
|
g_autoptr (WpEndpoint) peer_ep_proxy = NULL;
|
||||||
g_autoptr (WpEndpointStream) peer_stream_proxy = NULL;
|
|
||||||
|
|
||||||
/* find the session */
|
/* find the session */
|
||||||
session = wp_session_item_get_associated_proxy (
|
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) {
|
if (self->info.direction == PW_DIRECTION_OUTPUT) {
|
||||||
self_ep = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_OUTPUT_ENDPOINT);
|
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_ep = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_INPUT_ENDPOINT);
|
||||||
peer_stream = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_INPUT_STREAM);
|
|
||||||
} else {
|
} else {
|
||||||
self_ep = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_INPUT_ENDPOINT);
|
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_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]",
|
wp_debug_object (self, "requested link between %s [self] & %s [peer]",
|
||||||
self_ep, self_stream, peer_ep, peer_stream);
|
self_ep, peer_ep);
|
||||||
|
|
||||||
/* verify arguments */
|
/* verify arguments */
|
||||||
if (!peer_ep) {
|
if (!peer_ep) {
|
||||||
@@ -638,41 +394,10 @@ impl_create_link (void *object, const struct spa_dict *props)
|
|||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert to int - allow unspecified streams */
|
/* convert to int */
|
||||||
self_ep_id = wp_proxy_get_bound_id (WP_PROXY (self));
|
|
||||||
self_stream_id = self_stream ? (guint32) atoi (self_stream) : SPA_ID_INVALID;
|
|
||||||
peer_ep_id = (guint32) atoi (peer_ep);
|
peer_ep_id = (guint32) atoi (peer_ep);
|
||||||
peer_stream_id = peer_stream ? (guint32) atoi (peer_stream) : SPA_ID_INVALID;
|
|
||||||
|
|
||||||
/* find our stream */
|
/* find the peer endpoint */
|
||||||
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 */
|
|
||||||
peer_ep_proxy = wp_session_lookup_endpoint (session,
|
peer_ep_proxy = wp_session_lookup_endpoint (session,
|
||||||
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", peer_ep_id, NULL);
|
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", peer_ep_id, NULL);
|
||||||
if (!peer_ep_proxy) {
|
if (!peer_ep_proxy) {
|
||||||
@@ -680,44 +405,21 @@ impl_create_link (void *object, const struct spa_dict *props)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peer_stream_id != SPA_ID_INVALID) {
|
g_object_get (peer_ep_proxy, "item", &peer_si_endpoint, NULL);
|
||||||
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);
|
|
||||||
|
|
||||||
wp_info_object (self, "creating endpoint link between "
|
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_get_name (WP_ENDPOINT (self)),
|
||||||
wp_endpoint_stream_get_name (self_stream_proxy),
|
WP_OBJECT_ARGS (self->item),
|
||||||
WP_OBJECT_ARGS (self_si_stream),
|
|
||||||
wp_endpoint_get_name (peer_ep_proxy),
|
wp_endpoint_get_name (peer_ep_proxy),
|
||||||
wp_endpoint_stream_get_name (peer_stream_proxy),
|
WP_OBJECT_ARGS (peer_si_endpoint));
|
||||||
WP_OBJECT_ARGS (peer_si_stream));
|
|
||||||
|
|
||||||
/* create the link */
|
/* create the link */
|
||||||
{
|
{
|
||||||
g_autoptr (WpSessionItem) link = NULL;
|
g_autoptr (WpSessionItem) link = NULL;
|
||||||
g_autoptr (WpCore) core = NULL;
|
g_autoptr (WpCore) core = NULL;
|
||||||
GVariantBuilder b;
|
GVariantBuilder b;
|
||||||
guint64 out_stream_i, in_stream_i;
|
guint64 out_endpoint_i, in_endpoint_i;
|
||||||
|
|
||||||
core = wp_object_get_core (WP_OBJECT (self));
|
core = wp_object_get_core (WP_OBJECT (self));
|
||||||
link = wp_session_item_make (core, "si-standard-link");
|
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) {
|
if (self->info.direction == PW_DIRECTION_OUTPUT) {
|
||||||
out_stream_i = (guint64) self_si_stream;
|
out_endpoint_i = (guint64) self->item;
|
||||||
in_stream_i = (guint64) peer_si_stream;
|
in_endpoint_i = (guint64) peer_si_endpoint;
|
||||||
} else {
|
} else {
|
||||||
out_stream_i = (guint64) peer_si_stream;
|
out_endpoint_i = (guint64) peer_si_endpoint;
|
||||||
in_stream_i = (guint64) self_si_stream;
|
in_endpoint_i = (guint64) self->item;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
||||||
g_variant_builder_add (&b, "{sv}", "out-stream",
|
g_variant_builder_add (&b, "{sv}", "out-endpoint",
|
||||||
g_variant_new_uint64 (out_stream_i));
|
g_variant_new_uint64 (out_endpoint_i));
|
||||||
g_variant_builder_add (&b, "{sv}", "in-stream",
|
g_variant_builder_add (&b, "{sv}", "in-endpoint",
|
||||||
g_variant_new_uint64 (in_stream_i));
|
g_variant_new_uint64 (in_endpoint_i));
|
||||||
g_variant_builder_add (&b, "{sv}", "manage-lifetime",
|
g_variant_builder_add (&b, "{sv}", "manage-lifetime",
|
||||||
g_variant_new_boolean (TRUE));
|
g_variant_new_boolean (TRUE));
|
||||||
if (G_UNLIKELY (!wp_session_item_configure (link, g_variant_builder_end (&b)))) {
|
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.media_class, &direction, &immutable_props);
|
||||||
|
|
||||||
self->info.direction = (enum pw_direction) direction;
|
self->info.direction = (enum pw_direction) direction;
|
||||||
self->info.n_streams = wp_si_endpoint_get_n_streams (self->item);
|
|
||||||
|
|
||||||
/* associate with the session */
|
/* associate with the session */
|
||||||
self->info.session_id = wp_session_item_get_associated_proxy_id (
|
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 {
|
enum {
|
||||||
STEP_ACTIVATE_NODE = STEP_STREAMS + 1,
|
STEP_ACTIVATE_NODE = WP_PW_OBJECT_MIXIN_STEP_CUSTOM_START + 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static guint
|
static guint
|
||||||
@@ -1020,12 +721,7 @@ wp_impl_endpoint_activate_execute_step (WpObject * object,
|
|||||||
static void
|
static void
|
||||||
wp_impl_endpoint_pw_proxy_destroyed (WpProxy * proxy)
|
wp_impl_endpoint_pw_proxy_destroyed (WpProxy * proxy)
|
||||||
{
|
{
|
||||||
WpEndpointPrivate *priv =
|
wp_object_update_features (WP_OBJECT (proxy), 0, 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -11,24 +11,11 @@
|
|||||||
|
|
||||||
#include "global-proxy.h"
|
#include "global-proxy.h"
|
||||||
#include "port.h"
|
#include "port.h"
|
||||||
#include "endpoint-stream.h"
|
|
||||||
#include "iterator.h"
|
#include "iterator.h"
|
||||||
#include "object-interest.h"
|
#include "object-interest.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
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:
|
* WP_TYPE_ENDPOINT:
|
||||||
*
|
*
|
||||||
@@ -52,28 +39,6 @@ const gchar * wp_endpoint_get_media_class (WpEndpoint * self);
|
|||||||
WP_API
|
WP_API
|
||||||
WpDirection wp_endpoint_get_direction (WpEndpoint * self);
|
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
|
WP_API
|
||||||
void wp_endpoint_create_link (WpEndpoint * self, WpProperties * props);
|
void wp_endpoint_create_link (WpEndpoint * self, WpProperties * props);
|
||||||
|
|
||||||
|
@@ -7,7 +7,6 @@ wp_lib_sources = files(
|
|||||||
'device.c',
|
'device.c',
|
||||||
'endpoint.c',
|
'endpoint.c',
|
||||||
'endpoint-link.c',
|
'endpoint-link.c',
|
||||||
'endpoint-stream.c',
|
|
||||||
'error.c',
|
'error.c',
|
||||||
'global-proxy.c',
|
'global-proxy.c',
|
||||||
'iterator.c',
|
'iterator.c',
|
||||||
@@ -43,7 +42,6 @@ wp_lib_headers = files(
|
|||||||
'device.h',
|
'device.h',
|
||||||
'endpoint.h',
|
'endpoint.h',
|
||||||
'endpoint-link.h',
|
'endpoint-link.h',
|
||||||
'endpoint-stream.h',
|
|
||||||
'error.h',
|
'error.h',
|
||||||
'global-proxy.h',
|
'global-proxy.h',
|
||||||
'iterator.h',
|
'iterator.h',
|
||||||
|
@@ -10,7 +10,6 @@
|
|||||||
#define __WIREPLUMBER_PRIVATE_IMPL_ENDPOINT_H__
|
#define __WIREPLUMBER_PRIVATE_IMPL_ENDPOINT_H__
|
||||||
|
|
||||||
#include "endpoint.h"
|
#include "endpoint.h"
|
||||||
#include "endpoint-stream.h"
|
|
||||||
#include "endpoint-link.h"
|
#include "endpoint-link.h"
|
||||||
#include "si-interfaces.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);
|
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 */
|
/* impl endpoint link */
|
||||||
|
|
||||||
#define WP_TYPE_IMPL_ENDPOINT_LINK (wp_impl_endpoint_link_get_type ())
|
#define WP_TYPE_IMPL_ENDPOINT_LINK (wp_impl_endpoint_link_get_type ())
|
||||||
|
@@ -88,7 +88,6 @@ struct _WpSessionItemPrivate
|
|||||||
WpImplEndpoint *impl_endpoint;
|
WpImplEndpoint *impl_endpoint;
|
||||||
WpImplEndpointLink *impl_link;
|
WpImplEndpointLink *impl_link;
|
||||||
};
|
};
|
||||||
GHashTable *impl_streams;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -146,17 +145,9 @@ static gpointer
|
|||||||
wp_session_item_default_get_associated_proxy (WpSessionItem * self,
|
wp_session_item_default_get_associated_proxy (WpSessionItem * self,
|
||||||
GType proxy_type)
|
GType proxy_type)
|
||||||
{
|
{
|
||||||
WpSessionItemPrivate *priv;
|
WpSessionItemPrivate *priv = wp_session_item_get_instance_private (self);
|
||||||
gpointer ret = NULL;
|
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) {
|
if (proxy_type == WP_TYPE_SESSION) {
|
||||||
ret = g_weak_ref_get (&priv->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))
|
if (priv->impl_proxy && WP_IS_ENDPOINT_LINK (priv->impl_proxy))
|
||||||
ret = g_object_ref (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,
|
wp_trace_object (self, "associated %s: " WP_OBJECT_FORMAT,
|
||||||
g_type_name (proxy_type), WP_OBJECT_ARGS (ret));
|
g_type_name (proxy_type), WP_OBJECT_ARGS (ret));
|
||||||
@@ -191,8 +177,6 @@ wp_session_item_default_activate_get_next_step (WpSessionItem * self,
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
EXPORT_STEP_ENDPOINT = WP_TRANSITION_STEP_CUSTOM_START,
|
EXPORT_STEP_ENDPOINT = WP_TRANSITION_STEP_CUSTOM_START,
|
||||||
EXPORT_STEP_STREAMS,
|
|
||||||
EXPORT_STEP_ENDPOINT_FT_STREAMS,
|
|
||||||
EXPORT_STEP_LINK,
|
EXPORT_STEP_LINK,
|
||||||
EXPORT_STEP_CONNECT_DESTROYED,
|
EXPORT_STEP_CONNECT_DESTROYED,
|
||||||
};
|
};
|
||||||
@@ -201,8 +185,6 @@ static guint
|
|||||||
wp_session_item_default_export_get_next_step (WpSessionItem * self,
|
wp_session_item_default_export_get_next_step (WpSessionItem * self,
|
||||||
WpTransition * transition, guint step)
|
WpTransition * transition, guint step)
|
||||||
{
|
{
|
||||||
WpSessionItemPrivate *priv = wp_session_item_get_instance_private (self);
|
|
||||||
|
|
||||||
switch (step) {
|
switch (step) {
|
||||||
case WP_TRANSITION_STEP_NONE:
|
case WP_TRANSITION_STEP_NONE:
|
||||||
if (WP_IS_SI_ENDPOINT (self))
|
if (WP_IS_SI_ENDPOINT (self))
|
||||||
@@ -219,20 +201,6 @@ wp_session_item_default_export_get_next_step (WpSessionItem * self,
|
|||||||
|
|
||||||
case EXPORT_STEP_ENDPOINT:
|
case EXPORT_STEP_ENDPOINT:
|
||||||
g_return_val_if_fail (WP_IS_SI_ENDPOINT (self), WP_TRANSITION_STEP_ERROR);
|
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;
|
return WP_TRANSITION_STEP_NONE;
|
||||||
|
|
||||||
case EXPORT_STEP_LINK:
|
case EXPORT_STEP_LINK:
|
||||||
@@ -252,7 +220,6 @@ on_export_proxy_activated (WpObject * proxy, GAsyncResult * res, gpointer data)
|
|||||||
{
|
{
|
||||||
WpTransition *transition = WP_TRANSITION (data);
|
WpTransition *transition = WP_TRANSITION (data);
|
||||||
WpSessionItem *self = wp_transition_get_source_object (transition);
|
WpSessionItem *self = wp_transition_get_source_object (transition);
|
||||||
WpSessionItemPrivate *priv = wp_session_item_get_instance_private (self);
|
|
||||||
g_autoptr (GError) error = NULL;
|
g_autoptr (GError) error = NULL;
|
||||||
|
|
||||||
if (!wp_object_activate_finish (proxy, res, &error)) {
|
if (!wp_object_activate_finish (proxy, res, &error)) {
|
||||||
@@ -260,15 +227,6 @@ on_export_proxy_activated (WpObject * proxy, GAsyncResult * res, gpointer data)
|
|||||||
return;
|
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_debug_object (self, "export proxy " WP_OBJECT_FORMAT " activated",
|
||||||
WP_OBJECT_ARGS (proxy));
|
WP_OBJECT_ARGS (proxy));
|
||||||
|
|
||||||
@@ -324,39 +282,6 @@ wp_session_item_default_export_execute_step (WpSessionItem * self,
|
|||||||
transition);
|
transition);
|
||||||
break;
|
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:
|
case EXPORT_STEP_LINK:
|
||||||
priv->impl_link = wp_impl_endpoint_link_new (core, WP_SI_LINK (self));
|
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);
|
WpSessionItemPrivate *priv = wp_session_item_get_instance_private (self);
|
||||||
if (priv->impl_proxy)
|
if (priv->impl_proxy)
|
||||||
g_signal_handlers_disconnect_by_data (priv->impl_proxy, self);
|
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_clear_object (&priv->impl_proxy);
|
||||||
g_weak_ref_set (&priv->session, NULL);
|
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 exported #WpSiEndpoint should have at least:
|
||||||
* - an associated #WpEndpoint
|
* - an associated #WpEndpoint
|
||||||
* - an associated #WpSession
|
* - 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
|
* - In cases where the item wraps a single PipeWire node, it should also
|
||||||
* have an associated #WpNode
|
* have an associated #WpNode
|
||||||
*
|
*
|
||||||
|
@@ -29,8 +29,8 @@ wp_si_endpoint_default_get_properties (WpSiEndpoint * self)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WpSiStreamAcquisition *
|
static WpSiEndpointAcquisition *
|
||||||
wp_si_endpoint_default_get_stream_acquisition (WpSiEndpoint * self)
|
wp_si_endpoint_default_get_endpoint_acquisition (WpSiEndpoint * self)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -39,13 +39,11 @@ static void
|
|||||||
wp_si_endpoint_default_init (WpSiEndpointInterface * iface)
|
wp_si_endpoint_default_init (WpSiEndpointInterface * iface)
|
||||||
{
|
{
|
||||||
iface->get_properties = wp_si_endpoint_default_get_properties;
|
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_new ("endpoint-properties-changed", G_TYPE_FROM_INTERFACE (iface),
|
||||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
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
|
* @self: the session item
|
||||||
*
|
*
|
||||||
* Returns: the number of streams in the endpoint
|
* Returns: (transfer none) (nullable): the endpoint acquisition interface
|
||||||
*/
|
|
||||||
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
|
|
||||||
* associated with this endpoint, or %NULL if this endpoint does not require
|
* associated with this endpoint, or %NULL if this endpoint does not require
|
||||||
* acquiring streams before linking them
|
* acquiring endpoints before linking them
|
||||||
*/
|
*/
|
||||||
WpSiStreamAcquisition *
|
WpSiEndpointAcquisition *
|
||||||
wp_si_endpoint_get_stream_acquisition (WpSiEndpoint * self)
|
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_IS_SI_ENDPOINT (self), NULL);
|
||||||
g_return_val_if_fail (WP_SI_ENDPOINT_GET_IFACE (self)->get_stream_acquisition,
|
g_return_val_if_fail (
|
||||||
NULL);
|
WP_SI_ENDPOINT_GET_IFACE (self)->get_endpoint_acquisition, NULL);
|
||||||
|
|
||||||
return WP_SI_ENDPOINT_GET_IFACE (self)->get_stream_acquisition (self);
|
return WP_SI_ENDPOINT_GET_IFACE (self)->get_endpoint_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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -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
|
* @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 *
|
WpSiEndpoint *
|
||||||
wp_si_link_get_out_stream (WpSiLink * self)
|
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_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
|
* @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 *
|
WpSiEndpoint *
|
||||||
wp_si_link_get_in_stream (WpSiLink * self)
|
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_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 information is used to create links in the nodes graph.
|
||||||
*
|
*
|
||||||
* This is normally implemented by the same session items that implement
|
* This is normally implemented by the same session items that implement
|
||||||
* #WpSiStream. The standard link implementation expects to be able to cast
|
* #WpSiEndpoint. The standard link implementation expects to be able to cast
|
||||||
* a #WpSiStream into a #WpSiPortInfo.
|
* a #WpSiEndpoint into a #WpSiPortInfo.
|
||||||
*/
|
*/
|
||||||
G_DEFINE_INTERFACE (WpSiPortInfo, wp_si_port_info, WP_TYPE_SESSION_ITEM)
|
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
|
* Contexts other than %NULL may only be used internally to ease the
|
||||||
* implementation of more complex endpoint relationships. For example, a
|
* implementation of more complex endpoint relationships. For example, a
|
||||||
* #WpSessionItem that is in control of an input (sink) adapter node may
|
* #WpSessionItem that is in control of an input (sink) adapter node may
|
||||||
* implement #WpSiStream and #WpSiPortInfo where the %NULL context will return
|
* implement #WpSiPortInfo where the %NULL context will return the standard
|
||||||
* the standard input ports and the "monitor" context will return the adapter's
|
* input ports and the "monitor" context will return the adapter's monitor
|
||||||
* monitor ports. When linking this stream to another stream, the %NULL context
|
* ports. When linking this endpoint to another endpoint, the %NULL context
|
||||||
* will always be used, but the item may internally spawn a secondary
|
* will always be used, but the item may internally spawn a secondary
|
||||||
* #WpSessionItem that implements the "monitor" endpoint & stream. That
|
* #WpSessionItem that implements the "monitor" endpoint. That secondary
|
||||||
* secondary stream may implement #WpSiPortInfo, chaining calls to the
|
* endpoint may implement #WpSiPortInfo, chaining calls to the #WpSiPortInfo
|
||||||
* #WpSiPortInfo of the original item using the "monitor" context. This way,
|
* of the original item using the "monitor" context. This way, the monitor
|
||||||
* the monitor #WpSessionItem does not need to share control of the underlying
|
* #WpSessionItem does not need to share control of the underlying node; it
|
||||||
* node; it only proxies calls to satisfy the API.
|
* only proxies calls to satisfy the API.
|
||||||
*
|
*
|
||||||
* Returns: (transfer full): a #GVariant containing information about the
|
* Returns: (transfer full): a #GVariant containing information about the
|
||||||
* ports of this item
|
* 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
|
* This interface provides a way to request an endpoint for linking before doing
|
||||||
* so. This allows endpoint implementations to apply internal policy rules
|
* so. This allows endpoint implementations to apply internal policy rules.
|
||||||
* (such as, streams that can only be linked once or mutually exclusive streams).
|
|
||||||
*
|
*
|
||||||
* A #WpSiStreamAcquisition is associated directly with a #WpSiEndpoint via
|
* A #WpSiEndpointAcquisition is associated directly with a #WpSiEndpoint via
|
||||||
* wp_si_endpoint_get_stream_acquisition(). In order to allow switching policies,
|
* wp_si_endpoint_get_endpoint_acquisition(). In order to allow switching
|
||||||
* it is recommended that endpoint implementations use a separate session item
|
* policies, it is recommended that endpoint implementations use a separate
|
||||||
* to implement this interface and allow replacing it.
|
* 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)
|
WP_TYPE_SESSION_ITEM)
|
||||||
|
|
||||||
static void
|
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
|
* @self: the session item
|
||||||
* @acquisitor: the link that is trying to acquire a stream
|
* @acquisitor: the link that is trying to acquire an endpoint
|
||||||
* @stream: the stream that is being acquired
|
* @endpoint: the endpoint that is being acquired
|
||||||
* @callback: (scope async): the callback to call when the operation is done
|
* @callback: (scope async): the callback to call when the operation is done
|
||||||
* @data: (closure): user data for @callback
|
* @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
|
* When a link is not allowed by policy, this operation should return
|
||||||
* an error.
|
* an error.
|
||||||
*
|
*
|
||||||
* When a link needs to be delayed for a short amount of time (ex. to apply
|
* 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,
|
* delay. It is safe to assume that after this operation completes,
|
||||||
* the stream will be linked immediately.
|
* the endpoint will be linked immediately.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
wp_si_stream_acquisition_acquire (WpSiStreamAcquisition * self,
|
wp_si_endpoint_acquisition_acquire (WpSiEndpointAcquisition * self,
|
||||||
WpSiLink * acquisitor, WpSiStream * stream,
|
WpSiLink * acquisitor, WpSiEndpoint * endpoint,
|
||||||
GAsyncReadyCallback callback, gpointer data)
|
GAsyncReadyCallback callback, gpointer data)
|
||||||
{
|
{
|
||||||
g_return_if_fail (WP_IS_SI_STREAM_ACQUISITION (self));
|
g_return_if_fail (WP_IS_SI_ENDPOINT_ACQUISITION (self));
|
||||||
g_return_if_fail (WP_SI_STREAM_ACQUISITION_GET_IFACE (self)->acquire);
|
g_return_if_fail (WP_SI_ENDPOINT_ACQUISITION_GET_IFACE (self)->acquire);
|
||||||
|
|
||||||
WP_SI_STREAM_ACQUISITION_GET_IFACE (self)->acquire (self, acquisitor, stream,
|
WP_SI_ENDPOINT_ACQUISITION_GET_IFACE (self)->acquire (self, acquisitor,
|
||||||
callback, data);
|
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
|
* @self: the session item
|
||||||
* @res: the async result
|
* @res: the async result
|
||||||
* @error: (out) (optional): the operation's error, if it occurred
|
* @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.
|
* 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
|
* Returns: %TRUE on success, %FALSE if there was an error
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
wp_si_stream_acquisition_acquire_finish (WpSiStreamAcquisition * self,
|
wp_si_endpoint_acquisition_acquire_finish (WpSiEndpointAcquisition * self,
|
||||||
GAsyncResult * res, GError ** error)
|
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 (
|
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);
|
error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wp_si_stream_acquisition_release: (virtual release)
|
* wp_si_endpoint_acquisition_release: (virtual release)
|
||||||
* @self: the session item
|
* @self: the session item
|
||||||
* @acquisitor: the link that had previously acquired the stream
|
* @acquisitor: the link that had previously acquired the endpoint
|
||||||
* @stream: the stream that is being released
|
* @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
|
void
|
||||||
wp_si_stream_acquisition_release (WpSiStreamAcquisition * self,
|
wp_si_endpoint_acquisition_release (WpSiEndpointAcquisition * self,
|
||||||
WpSiLink * acquisitor, WpSiStream * stream)
|
WpSiLink * acquisitor, WpSiEndpoint * endpoint)
|
||||||
{
|
{
|
||||||
g_return_if_fail (WP_IS_SI_STREAM_ACQUISITION (self));
|
g_return_if_fail (WP_IS_SI_ENDPOINT_ACQUISITION (self));
|
||||||
g_return_if_fail (WP_SI_STREAM_ACQUISITION_GET_IFACE (self)->release);
|
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);
|
||||||
}
|
}
|
||||||
|
@@ -16,8 +16,7 @@
|
|||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
typedef struct _WpSiStream WpSiStream;
|
typedef struct _WpSiEndpointAcquisition WpSiEndpointAcquisition;
|
||||||
typedef struct _WpSiStreamAcquisition WpSiStreamAcquisition;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WP_TYPE_SI_ENDPOINT:
|
* WP_TYPE_SI_ENDPOINT:
|
||||||
@@ -36,10 +35,7 @@ struct _WpSiEndpointInterface
|
|||||||
GVariant * (*get_registration_info) (WpSiEndpoint * self);
|
GVariant * (*get_registration_info) (WpSiEndpoint * self);
|
||||||
WpProperties * (*get_properties) (WpSiEndpoint * self);
|
WpProperties * (*get_properties) (WpSiEndpoint * self);
|
||||||
|
|
||||||
guint (*get_n_streams) (WpSiEndpoint * self);
|
WpSiEndpointAcquisition * (*get_endpoint_acquisition) (WpSiEndpoint * self);
|
||||||
WpSiStream * (*get_stream) (WpSiEndpoint * self, guint index);
|
|
||||||
|
|
||||||
WpSiStreamAcquisition * (*get_stream_acquisition) (WpSiEndpoint * self);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
@@ -49,42 +45,8 @@ WP_API
|
|||||||
WpProperties * wp_si_endpoint_get_properties (WpSiEndpoint * self);
|
WpProperties * wp_si_endpoint_get_properties (WpSiEndpoint * self);
|
||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
guint wp_si_endpoint_get_n_streams (WpSiEndpoint * self);
|
WpSiEndpointAcquisition * wp_si_endpoint_get_endpoint_acquisition (
|
||||||
|
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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WP_TYPE_SI_LINK:
|
* WP_TYPE_SI_LINK:
|
||||||
@@ -103,8 +65,8 @@ struct _WpSiLinkInterface
|
|||||||
GVariant * (*get_registration_info) (WpSiLink * self);
|
GVariant * (*get_registration_info) (WpSiLink * self);
|
||||||
WpProperties * (*get_properties) (WpSiLink * self);
|
WpProperties * (*get_properties) (WpSiLink * self);
|
||||||
|
|
||||||
WpSiStream * (*get_out_stream) (WpSiLink * self);
|
WpSiEndpoint * (*get_out_endpoint) (WpSiLink * self);
|
||||||
WpSiStream * (*get_in_stream) (WpSiLink * self);
|
WpSiEndpoint * (*get_in_endpoint) (WpSiLink * self);
|
||||||
};
|
};
|
||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
@@ -114,10 +76,10 @@ WP_API
|
|||||||
WpProperties * wp_si_link_get_properties (WpSiLink * self);
|
WpProperties * wp_si_link_get_properties (WpSiLink * self);
|
||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
WpSiStream * wp_si_link_get_out_stream (WpSiLink * self);
|
WpSiEndpoint * wp_si_link_get_out_endpoint (WpSiLink * self);
|
||||||
|
|
||||||
WP_API
|
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:
|
* WP_TYPE_SI_PORT_INFO:
|
||||||
@@ -141,40 +103,40 @@ GVariant * wp_si_port_info_get_ports (WpSiPortInfo * self,
|
|||||||
const gchar * context);
|
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
|
WP_API
|
||||||
G_DECLARE_INTERFACE (WpSiStreamAcquisition, wp_si_stream_acquisition,
|
G_DECLARE_INTERFACE (WpSiEndpointAcquisition, wp_si_endpoint_acquisition,
|
||||||
WP, SI_STREAM_ACQUISITION, WpSessionItem)
|
WP, SI_ENDPOINT_ACQUISITION, WpSessionItem)
|
||||||
|
|
||||||
struct _WpSiStreamAcquisitionInterface
|
struct _WpSiEndpointAcquisitionInterface
|
||||||
{
|
{
|
||||||
GTypeInterface interface;
|
GTypeInterface interface;
|
||||||
|
|
||||||
void (*acquire) (WpSiStreamAcquisition * self, WpSiLink * acquisitor,
|
void (*acquire) (WpSiEndpointAcquisition * self, WpSiLink * acquisitor,
|
||||||
WpSiStream * stream, GAsyncReadyCallback callback, gpointer data);
|
WpSiEndpoint * endpoint, GAsyncReadyCallback callback, gpointer data);
|
||||||
gboolean (*acquire_finish) (WpSiStreamAcquisition * self,
|
gboolean (*acquire_finish) (WpSiEndpointAcquisition * self,
|
||||||
GAsyncResult * res, GError ** error);
|
GAsyncResult * res, GError ** error);
|
||||||
|
|
||||||
void (*release) (WpSiStreamAcquisition * self, WpSiLink * acquisitor,
|
void (*release) (WpSiEndpointAcquisition * self, WpSiLink * acquisitor,
|
||||||
WpSiStream * stream);
|
WpSiEndpoint * endpoint);
|
||||||
};
|
};
|
||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
void wp_si_stream_acquisition_acquire (WpSiStreamAcquisition * self,
|
void wp_si_endpoint_acquisition_acquire (WpSiEndpointAcquisition * self,
|
||||||
WpSiLink * acquisitor, WpSiStream * stream,
|
WpSiLink * acquisitor, WpSiEndpoint * endpoint,
|
||||||
GAsyncReadyCallback callback, gpointer data);
|
GAsyncReadyCallback callback, gpointer data);
|
||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
gboolean wp_si_stream_acquisition_acquire_finish (WpSiStreamAcquisition * self,
|
gboolean wp_si_endpoint_acquisition_acquire_finish (
|
||||||
GAsyncResult * res, GError ** error);
|
WpSiEndpointAcquisition * self, GAsyncResult * res, GError ** error);
|
||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
void wp_si_stream_acquisition_release (WpSiStreamAcquisition * self,
|
void wp_si_endpoint_acquisition_release (WpSiEndpointAcquisition * self,
|
||||||
WpSiLink * acquisitor, WpSiStream * stream);
|
WpSiLink * acquisitor, WpSiEndpoint * endpoint);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
@@ -71,7 +71,6 @@ wp_init (WpInitFlags flags)
|
|||||||
g_type_ensure (WP_TYPE_DEVICE);
|
g_type_ensure (WP_TYPE_DEVICE);
|
||||||
g_type_ensure (WP_TYPE_ENDPOINT);
|
g_type_ensure (WP_TYPE_ENDPOINT);
|
||||||
g_type_ensure (WP_TYPE_ENDPOINT_LINK);
|
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_LINK);
|
||||||
g_type_ensure (WP_TYPE_METADATA);
|
g_type_ensure (WP_TYPE_METADATA);
|
||||||
g_type_ensure (WP_TYPE_NODE);
|
g_type_ensure (WP_TYPE_NODE);
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "endpoint.h"
|
#include "endpoint.h"
|
||||||
#include "endpoint-link.h"
|
#include "endpoint-link.h"
|
||||||
#include "endpoint-stream.h"
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "global-proxy.h"
|
#include "global-proxy.h"
|
||||||
#include "iterator.h"
|
#include "iterator.h"
|
||||||
|
@@ -112,17 +112,6 @@ shared_library(
|
|||||||
dependencies : [wp_dep, pipewire_dep],
|
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(
|
shared_library(
|
||||||
'wireplumber-module-si-simple-node-endpoint',
|
'wireplumber-module-si-simple-node-endpoint',
|
||||||
[
|
[
|
||||||
@@ -134,17 +123,6 @@ shared_library(
|
|||||||
dependencies : [wp_dep, pipewire_dep],
|
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(
|
shared_library(
|
||||||
'wireplumber-module-si-monitor-endpoint',
|
'wireplumber-module-si-monitor-endpoint',
|
||||||
[
|
[
|
||||||
@@ -156,18 +134,6 @@ shared_library(
|
|||||||
dependencies : [wp_dep, pipewire_dep],
|
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(
|
shared_library(
|
||||||
'wireplumber-module-si-standard-link',
|
'wireplumber-module-si-standard-link',
|
||||||
[
|
[
|
||||||
|
@@ -754,22 +754,6 @@ static const luaL_Reg impl_session_methods[] = {
|
|||||||
|
|
||||||
/* WpEndpoint */
|
/* 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
|
static int
|
||||||
endpoint_create_link (lua_State *L)
|
endpoint_create_link (lua_State *L)
|
||||||
{
|
{
|
||||||
@@ -781,8 +765,6 @@ endpoint_create_link (lua_State *L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const luaL_Reg endpoint_methods[] = {
|
static const luaL_Reg endpoint_methods[] = {
|
||||||
{ "get_n_streams", endpoint_get_n_streams },
|
|
||||||
{ "iterate_streams", endpoint_iterate_streams },
|
|
||||||
{ "create_link", endpoint_create_link },
|
{ "create_link", endpoint_create_link },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
@@ -817,16 +799,13 @@ static int
|
|||||||
endpoint_link_get_linked_object_ids (lua_State *L)
|
endpoint_link_get_linked_object_ids (lua_State *L)
|
||||||
{
|
{
|
||||||
WpEndpointLink *eplink = wplua_checkobject (L, 1, WP_TYPE_ENDPOINT_LINK);
|
WpEndpointLink *eplink = wplua_checkobject (L, 1, WP_TYPE_ENDPOINT_LINK);
|
||||||
guint32 output_endpoint, output_stream;
|
guint32 output_endpoint;
|
||||||
guint32 input_endpoint, input_stream;
|
guint32 input_endpoint;
|
||||||
wp_endpoint_link_get_linked_object_ids (eplink,
|
wp_endpoint_link_get_linked_object_ids (eplink, &output_endpoint,
|
||||||
&output_endpoint, &output_stream,
|
&input_endpoint);
|
||||||
&input_endpoint, &input_stream);
|
|
||||||
lua_pushinteger (L, output_endpoint);
|
lua_pushinteger (L, output_endpoint);
|
||||||
lua_pushinteger (L, output_stream);
|
|
||||||
lua_pushinteger (L, input_endpoint);
|
lua_pushinteger (L, input_endpoint);
|
||||||
lua_pushinteger (L, input_stream);
|
return 2;
|
||||||
return 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const luaL_Reg endpoint_link_methods[] = {
|
static const luaL_Reg endpoint_link_methods[] = {
|
||||||
|
@@ -42,13 +42,11 @@ struct _WpSiAdapter
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void si_adapter_endpoint_init (WpSiEndpointInterface * iface);
|
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);
|
static void si_adapter_port_info_init (WpSiPortInfoInterface * iface);
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE(WpSiAdapter, si_adapter, WP, SI_ADAPTER, WpSessionItem)
|
G_DECLARE_FINAL_TYPE(WpSiAdapter, si_adapter, WP, SI_ADAPTER, WpSessionItem)
|
||||||
G_DEFINE_TYPE_WITH_CODE (WpSiAdapter, si_adapter, WP_TYPE_SESSION_ITEM,
|
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_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))
|
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_PORT_INFO, si_adapter_port_info_init))
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -431,62 +429,11 @@ si_adapter_get_properties (WpSiEndpoint * item)
|
|||||||
return result;
|
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
|
static void
|
||||||
si_adapter_endpoint_init (WpSiEndpointInterface * iface)
|
si_adapter_endpoint_init (WpSiEndpointInterface * iface)
|
||||||
{
|
{
|
||||||
iface->get_registration_info = si_adapter_get_registration_info;
|
iface->get_registration_info = si_adapter_get_registration_info;
|
||||||
iface->get_properties = si_adapter_get_properties;
|
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 *
|
static GVariant *
|
||||||
|
@@ -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;
|
|
||||||
}
|
|
@@ -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;
|
|
||||||
}
|
|
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <wp/wp.h>
|
#include <wp/wp.h>
|
||||||
#include <pipewire/pipewire.h>
|
#include <pipewire/pipewire.h>
|
||||||
|
#include <pipewire/extensions/session-manager/keys.h>
|
||||||
|
|
||||||
#include <spa/utils/names.h>
|
#include <spa/utils/names.h>
|
||||||
#include <spa/param/format.h>
|
#include <spa/param/format.h>
|
||||||
@@ -35,12 +36,12 @@ struct _WpSiConvert
|
|||||||
WpSessionItem *link_to_target;
|
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);
|
static void si_convert_port_info_init (WpSiPortInfoInterface * iface);
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE(WpSiConvert, si_convert, WP, SI_CONVERT, WpSessionItem)
|
G_DECLARE_FINAL_TYPE(WpSiConvert, si_convert, WP, SI_CONVERT, WpSessionItem)
|
||||||
G_DEFINE_TYPE_WITH_CODE (WpSiConvert, si_convert, WP_TYPE_SESSION_ITEM,
|
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))
|
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_PORT_INFO, si_convert_port_info_init))
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -174,19 +175,19 @@ do_link_to_target (WpSiConvert *self)
|
|||||||
|
|
||||||
if (self->direction == WP_DIRECTION_INPUT) {
|
if (self->direction == WP_DIRECTION_INPUT) {
|
||||||
/* Playback */
|
/* Playback */
|
||||||
g_variant_builder_add (&b, "{sv}", "out-stream",
|
g_variant_builder_add (&b, "{sv}", "out-endpoint",
|
||||||
g_variant_new_uint64 ((guint64) WP_SI_STREAM (self)));
|
g_variant_new_uint64 ((guint64) WP_SI_ENDPOINT (self)));
|
||||||
g_variant_builder_add (&b, "{sv}", "out-stream-port-context",
|
g_variant_builder_add (&b, "{sv}", "out-endpoint-port-context",
|
||||||
g_variant_new_string ("reverse"));
|
g_variant_new_string ("reverse"));
|
||||||
g_variant_builder_add (&b, "{sv}", "in-stream",
|
g_variant_builder_add (&b, "{sv}", "in-endpoint",
|
||||||
g_variant_new_uint64 ((guint64) WP_SI_STREAM (self->target)));
|
g_variant_new_uint64 ((guint64) WP_SI_ENDPOINT (self->target)));
|
||||||
} else {
|
} else {
|
||||||
/* Capture */
|
/* Capture */
|
||||||
g_variant_builder_add (&b, "{sv}", "out-stream",
|
g_variant_builder_add (&b, "{sv}", "out-endpoint",
|
||||||
g_variant_new_uint64 ((guint64) WP_SI_STREAM (self->target)));
|
g_variant_new_uint64 ((guint64) WP_SI_ENDPOINT (self->target)));
|
||||||
g_variant_builder_add (&b, "{sv}", "in-stream",
|
g_variant_builder_add (&b, "{sv}", "in-endpoint",
|
||||||
g_variant_new_uint64 ((guint64) WP_SI_STREAM (self)));
|
g_variant_new_uint64 ((guint64) WP_SI_ENDPOINT (self)));
|
||||||
g_variant_builder_add (&b, "{sv}", "in-stream-port-context",
|
g_variant_builder_add (&b, "{sv}", "in-endpoint-port-context",
|
||||||
g_variant_new_string ("reverse"));
|
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),
|
wp_properties_get (node_props, PW_KEY_NODE_NAME),
|
||||||
self->name);
|
self->name);
|
||||||
wp_properties_setf (props, PW_KEY_NODE_DESCRIPTION,
|
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);
|
wp_properties_get (node_props, PW_KEY_NODE_DESCRIPTION), self->name);
|
||||||
|
|
||||||
/* Create the node */
|
/* Create the node */
|
||||||
@@ -389,36 +390,43 @@ si_convert_activate_rollback (WpSessionItem * item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GVariant *
|
static GVariant *
|
||||||
si_convert_get_stream_registration_info (WpSiStream * item)
|
si_convert_get_registration_info (WpSiEndpoint * item)
|
||||||
{
|
{
|
||||||
WpSiConvert *self = WP_SI_CONVERT (item);
|
WpSiConvert *self = WP_SI_CONVERT (item);
|
||||||
GVariantBuilder b;
|
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", 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);
|
g_variant_builder_add (&b, "a{ss}", NULL);
|
||||||
|
|
||||||
return g_variant_builder_end (&b);
|
return g_variant_builder_end (&b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WpProperties *
|
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 *
|
wp_properties_set (result, "endpoint.priority", NULL);
|
||||||
si_convert_get_stream_parent_endpoint (WpSiStream * self)
|
wp_properties_setf (result, "endpoint.description", "%s", "Audio Converter");
|
||||||
{
|
wp_properties_setf (result, PW_KEY_ENDPOINT_AUTOCONNECT, "%d", FALSE);
|
||||||
return WP_SI_ENDPOINT (wp_session_item_get_parent (WP_SESSION_ITEM (self)));
|
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
|
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_registration_info = si_convert_get_registration_info;
|
||||||
iface->get_properties = si_convert_get_stream_properties;
|
iface->get_properties = si_convert_get_properties;
|
||||||
iface->get_parent_endpoint = si_convert_get_stream_parent_endpoint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GVariant *
|
static GVariant *
|
||||||
|
@@ -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;
|
|
||||||
}
|
|
@@ -25,14 +25,12 @@ struct _WpSiMonitorEndpoint
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void si_monitor_endpoint_endpoint_init (WpSiEndpointInterface * iface);
|
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);
|
static void si_monitor_endpoint_port_info_init (WpSiPortInfoInterface * iface);
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE(WpSiMonitorEndpoint, si_monitor_endpoint,
|
G_DECLARE_FINAL_TYPE(WpSiMonitorEndpoint, si_monitor_endpoint,
|
||||||
WP, SI_MONITOR_ENDPOINT, WpSessionItem)
|
WP, SI_MONITOR_ENDPOINT, WpSessionItem)
|
||||||
G_DEFINE_TYPE_WITH_CODE (WpSiMonitorEndpoint, si_monitor_endpoint, WP_TYPE_SESSION_ITEM,
|
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_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))
|
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_PORT_INFO, si_monitor_endpoint_port_info_init))
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -224,53 +222,11 @@ si_monitor_endpoint_get_properties (WpSiEndpoint * item)
|
|||||||
return properties;
|
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
|
static void
|
||||||
si_monitor_endpoint_endpoint_init (WpSiEndpointInterface * iface)
|
si_monitor_endpoint_endpoint_init (WpSiEndpointInterface * iface)
|
||||||
{
|
{
|
||||||
iface->get_registration_info = si_monitor_endpoint_get_registration_info;
|
iface->get_registration_info = si_monitor_endpoint_get_registration_info;
|
||||||
iface->get_properties = si_monitor_endpoint_get_properties;
|
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 *
|
static GVariant *
|
||||||
|
@@ -30,14 +30,12 @@ struct _WpSiSimpleNodeEndpoint
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void si_simple_node_endpoint_endpoint_init (WpSiEndpointInterface * iface);
|
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);
|
static void si_simple_node_endpoint_port_info_init (WpSiPortInfoInterface * iface);
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE(WpSiSimpleNodeEndpoint, si_simple_node_endpoint,
|
G_DECLARE_FINAL_TYPE(WpSiSimpleNodeEndpoint, si_simple_node_endpoint,
|
||||||
WP, SI_SIMPLE_NODE_ENDPOINT, WpSessionItem)
|
WP, SI_SIMPLE_NODE_ENDPOINT, WpSessionItem)
|
||||||
G_DEFINE_TYPE_WITH_CODE (WpSiSimpleNodeEndpoint, si_simple_node_endpoint, WP_TYPE_SESSION_ITEM,
|
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_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))
|
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_PORT_INFO, si_simple_node_endpoint_port_info_init))
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -292,53 +290,11 @@ si_simple_node_endpoint_get_properties (WpSiEndpoint * item)
|
|||||||
return result;
|
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
|
static void
|
||||||
si_simple_node_endpoint_endpoint_init (WpSiEndpointInterface * iface)
|
si_simple_node_endpoint_endpoint_init (WpSiEndpointInterface * iface)
|
||||||
{
|
{
|
||||||
iface->get_registration_info = si_simple_node_endpoint_get_registration_info;
|
iface->get_registration_info = si_simple_node_endpoint_get_registration_info;
|
||||||
iface->get_properties = si_simple_node_endpoint_get_properties;
|
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 *
|
static GVariant *
|
||||||
|
@@ -20,10 +20,10 @@ struct _WpSiStandardLink
|
|||||||
{
|
{
|
||||||
WpSessionItem parent;
|
WpSessionItem parent;
|
||||||
|
|
||||||
WpSiStream *out_stream;
|
WpSiEndpoint *out_endpoint;
|
||||||
WpSiStream *in_stream;
|
WpSiEndpoint *in_endpoint;
|
||||||
gchar *out_stream_port_context;
|
gchar *out_endpoint_port_context;
|
||||||
gchar *in_stream_port_context;
|
gchar *in_endpoint_port_context;
|
||||||
gboolean manage_lifetime;
|
gboolean manage_lifetime;
|
||||||
gboolean passive;
|
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))
|
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_LINK, si_standard_link_link_init))
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_stream_flags_changed (WpSessionItem * stream, WpSiFlags flags,
|
on_flags_changed (WpSessionItem * endpoint, WpSiFlags flags,
|
||||||
WpSessionItem * link)
|
WpSessionItem * link)
|
||||||
{
|
{
|
||||||
/* stream was deactivated; destroy the associated link */
|
/* endpoint was deactivated; destroy the associated link */
|
||||||
if (!(flags & WP_SI_FLAG_ACTIVE)) {
|
if (!(flags & WP_SI_FLAG_ACTIVE)) {
|
||||||
wp_trace_object (link, "destroying because stream " WP_OBJECT_FORMAT
|
wp_trace_object (link, "destroying because endpoint " WP_OBJECT_FORMAT
|
||||||
" was deactivated", WP_OBJECT_ARGS (stream));
|
" was deactivated", WP_OBJECT_ARGS (endpoint));
|
||||||
wp_session_item_reset (link);
|
wp_session_item_reset (link);
|
||||||
g_object_unref (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);
|
WP_SESSION_ITEM_CLASS (si_standard_link_parent_class)->reset (item);
|
||||||
|
|
||||||
if (self->manage_lifetime) {
|
if (self->manage_lifetime) {
|
||||||
g_signal_handlers_disconnect_by_func (self->out_stream,
|
g_signal_handlers_disconnect_by_func (self->out_endpoint,
|
||||||
G_CALLBACK (on_stream_flags_changed), self);
|
G_CALLBACK (on_flags_changed), self);
|
||||||
g_signal_handlers_disconnect_by_func (self->in_stream,
|
g_signal_handlers_disconnect_by_func (self->in_endpoint,
|
||||||
G_CALLBACK (on_stream_flags_changed), self);
|
G_CALLBACK (on_flags_changed), self);
|
||||||
g_signal_handlers_disconnect_by_func (self,
|
g_signal_handlers_disconnect_by_func (self,
|
||||||
G_CALLBACK (on_link_flags_changed), NULL);
|
G_CALLBACK (on_link_flags_changed), NULL);
|
||||||
}
|
}
|
||||||
self->manage_lifetime = FALSE;
|
self->manage_lifetime = FALSE;
|
||||||
self->passive = FALSE;
|
self->passive = FALSE;
|
||||||
self->out_stream = NULL;
|
self->out_endpoint = NULL;
|
||||||
self->in_stream = NULL;
|
self->in_endpoint = NULL;
|
||||||
g_clear_pointer (&self->out_stream_port_context, g_free);
|
g_clear_pointer (&self->out_endpoint_port_context, g_free);
|
||||||
g_clear_pointer (&self->in_stream_port_context, g_free);
|
g_clear_pointer (&self->in_endpoint_port_context, g_free);
|
||||||
|
|
||||||
wp_session_item_clear_flag (item, WP_SI_FLAG_CONFIGURED);
|
wp_session_item_clear_flag (item, WP_SI_FLAG_CONFIGURED);
|
||||||
}
|
}
|
||||||
@@ -100,15 +100,15 @@ si_standard_link_get_configuration (WpSessionItem * item)
|
|||||||
/* Set the properties */
|
/* Set the properties */
|
||||||
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
||||||
g_variant_builder_add (&b, "{sv}",
|
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}",
|
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}",
|
g_variant_builder_add (&b, "{sv}",
|
||||||
"out-stream-port-context",
|
"out-endpoint-port-context",
|
||||||
g_variant_new_string (self->out_stream_port_context));
|
g_variant_new_string (self->out_endpoint_port_context));
|
||||||
g_variant_builder_add (&b, "{sv}",
|
g_variant_builder_add (&b, "{sv}",
|
||||||
"in-stream-port-context",
|
"in-endpoint-port-context",
|
||||||
g_variant_new_string (self->in_stream_port_context));
|
g_variant_new_string (self->in_endpoint_port_context));
|
||||||
g_variant_builder_add (&b, "{sv}",
|
g_variant_builder_add (&b, "{sv}",
|
||||||
"manage-lifetime", g_variant_new_boolean (self->manage_lifetime));
|
"manage-lifetime", g_variant_new_boolean (self->manage_lifetime));
|
||||||
g_variant_builder_add (&b, "{sv}",
|
g_variant_builder_add (&b, "{sv}",
|
||||||
@@ -120,52 +120,52 @@ static gboolean
|
|||||||
si_standard_link_configure (WpSessionItem * item, GVariant * args)
|
si_standard_link_configure (WpSessionItem * item, GVariant * args)
|
||||||
{
|
{
|
||||||
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
|
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
|
||||||
guint64 out_stream_i, in_stream_i;
|
guint64 out_endpoint_i, in_endpoint_i;
|
||||||
WpSessionItem *out_stream, *in_stream;
|
WpSessionItem *out_endpoint, *in_endpoint;
|
||||||
|
|
||||||
if (wp_session_item_get_flags (item) &
|
if (wp_session_item_get_flags (item) &
|
||||||
(WP_SI_FLAG_ACTIVATING | WP_SI_FLAG_ACTIVE |
|
(WP_SI_FLAG_ACTIVATING | WP_SI_FLAG_ACTIVE |
|
||||||
WP_SI_FLAG_EXPORTING | WP_SI_FLAG_EXPORTED))
|
WP_SI_FLAG_EXPORTING | WP_SI_FLAG_EXPORTED))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (!g_variant_lookup (args, "out-stream", "t", &out_stream_i) ||
|
if (!g_variant_lookup (args, "out-endpoint", "t", &out_endpoint_i) ||
|
||||||
!g_variant_lookup (args, "in-stream", "t", &in_stream_i))
|
!g_variant_lookup (args, "in-endpoint", "t", &in_endpoint_i))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
out_stream = GUINT_TO_POINTER (out_stream_i);
|
out_endpoint = GUINT_TO_POINTER (out_endpoint_i);
|
||||||
in_stream = GUINT_TO_POINTER (in_stream_i);
|
in_endpoint = GUINT_TO_POINTER (in_endpoint_i);
|
||||||
|
|
||||||
if (!WP_IS_SI_STREAM (out_stream) || !WP_IS_SI_STREAM (in_stream) ||
|
if (!WP_IS_SI_ENDPOINT (out_endpoint) || !WP_IS_SI_ENDPOINT (in_endpoint) ||
|
||||||
!WP_IS_SI_PORT_INFO (out_stream) || !WP_IS_SI_PORT_INFO (in_stream) ||
|
!WP_IS_SI_PORT_INFO (out_endpoint) || !WP_IS_SI_PORT_INFO (in_endpoint) ||
|
||||||
!(wp_session_item_get_flags (out_stream) & WP_SI_FLAG_ACTIVE) ||
|
!(wp_session_item_get_flags (out_endpoint) & WP_SI_FLAG_ACTIVE) ||
|
||||||
!(wp_session_item_get_flags (in_stream) & WP_SI_FLAG_ACTIVE))
|
!(wp_session_item_get_flags (in_endpoint) & WP_SI_FLAG_ACTIVE))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* clear previous configuration; we are not active or exported,
|
/* clear previous configuration; we are not active or exported,
|
||||||
so this doesn't have any other side-effects */
|
so this doesn't have any other side-effects */
|
||||||
wp_session_item_reset (item);
|
wp_session_item_reset (item);
|
||||||
|
|
||||||
self->out_stream = WP_SI_STREAM (out_stream);
|
self->out_endpoint = WP_SI_ENDPOINT (out_endpoint);
|
||||||
self->in_stream = WP_SI_STREAM (in_stream);
|
self->in_endpoint = WP_SI_ENDPOINT (in_endpoint);
|
||||||
|
|
||||||
g_variant_lookup (args, "out-stream-port-context", "s",
|
g_variant_lookup (args, "out-endpoint-port-context", "s",
|
||||||
&self->out_stream_port_context);
|
&self->out_endpoint_port_context);
|
||||||
g_variant_lookup (args, "in-stream-port-context", "s",
|
g_variant_lookup (args, "in-endpoint-port-context", "s",
|
||||||
&self->in_stream_port_context);
|
&self->in_endpoint_port_context);
|
||||||
g_variant_lookup (args, "passive", "b", &self->passive);
|
g_variant_lookup (args, "passive", "b", &self->passive);
|
||||||
|
|
||||||
/* manage-lifetime == TRUE means that this si-standard-link item is
|
/* manage-lifetime == TRUE means that this si-standard-link item is
|
||||||
* responsible for self-destructing if either
|
* 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
|
* - if the WpImplEndpointLink is destroyed upon request
|
||||||
* (wp_proxy_request_destroy())
|
* (wp_proxy_request_destroy())
|
||||||
*/
|
*/
|
||||||
if (g_variant_lookup (args, "manage-lifetime", "b", &self->manage_lifetime)
|
if (g_variant_lookup (args, "manage-lifetime", "b", &self->manage_lifetime)
|
||||||
&& self->manage_lifetime) {
|
&& self->manage_lifetime) {
|
||||||
g_signal_connect_object (self->out_stream, "flags-changed",
|
g_signal_connect_object (self->out_endpoint, "flags-changed",
|
||||||
G_CALLBACK (on_stream_flags_changed), self, 0);
|
G_CALLBACK (on_flags_changed), self, 0);
|
||||||
g_signal_connect_object (self->in_stream, "flags-changed",
|
g_signal_connect_object (self->in_endpoint, "flags-changed",
|
||||||
G_CALLBACK (on_stream_flags_changed), self, 0);
|
G_CALLBACK (on_flags_changed), self, 0);
|
||||||
g_signal_connect (self, "flags-changed",
|
g_signal_connect (self, "flags-changed",
|
||||||
G_CALLBACK (on_link_flags_changed), NULL);
|
G_CALLBACK (on_link_flags_changed), NULL);
|
||||||
}
|
}
|
||||||
@@ -203,13 +203,13 @@ si_standard_link_activate_get_next_step (WpSessionItem * item,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_stream_acquired (WpSiStreamAcquisition * acq, GAsyncResult * res,
|
on_endpoint_acquired (WpSiEndpointAcquisition * acq, GAsyncResult * res,
|
||||||
WpTransition * transition)
|
WpTransition * transition)
|
||||||
{
|
{
|
||||||
WpSiStandardLink *self = wp_transition_get_source_object (transition);
|
WpSiStandardLink *self = wp_transition_get_source_object (transition);
|
||||||
g_autoptr (GError) error = NULL;
|
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));
|
wp_transition_return_error (transition, g_steal_pointer (&error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -239,12 +239,12 @@ find_core (WpSiStandardLink * self)
|
|||||||
{
|
{
|
||||||
/* session items are not associated with a core, but surely when linking
|
/* 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
|
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 (
|
g_autoptr (WpObject) proxy = wp_session_item_get_associated_proxy (
|
||||||
WP_SESSION_ITEM (self), WP_TYPE_ENDPOINT_LINK);
|
WP_SESSION_ITEM (self), WP_TYPE_ENDPOINT_LINK);
|
||||||
if (!proxy)
|
if (!proxy)
|
||||||
proxy = wp_session_item_get_associated_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;
|
return proxy ? wp_object_get_core (proxy) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,14 +372,12 @@ si_standard_link_activate_execute_step (WpSessionItem * item,
|
|||||||
|
|
||||||
switch (step) {
|
switch (step) {
|
||||||
case STEP_ACQUIRE: {
|
case STEP_ACQUIRE: {
|
||||||
g_autoptr (WpSiEndpoint) out_endpoint = NULL;
|
WpSiEndpointAcquisition *out_acquisition, *in_acquisition;
|
||||||
g_autoptr (WpSiEndpoint) in_endpoint = NULL;
|
|
||||||
WpSiStreamAcquisition *out_acquisition, *in_acquisition;
|
|
||||||
|
|
||||||
out_endpoint = wp_si_stream_get_parent_endpoint (self->out_stream);
|
out_acquisition = wp_si_endpoint_get_endpoint_acquisition (
|
||||||
in_endpoint = wp_si_stream_get_parent_endpoint (self->in_stream);
|
self->out_endpoint);
|
||||||
out_acquisition = wp_si_endpoint_get_stream_acquisition (out_endpoint);
|
in_acquisition = wp_si_endpoint_get_endpoint_acquisition (
|
||||||
in_acquisition = wp_si_endpoint_get_stream_acquisition (in_endpoint);
|
self->in_endpoint);
|
||||||
|
|
||||||
if (out_acquisition && in_acquisition)
|
if (out_acquisition && in_acquisition)
|
||||||
self->n_async_ops_wait = 2;
|
self->n_async_ops_wait = 2;
|
||||||
@@ -392,13 +390,13 @@ si_standard_link_activate_execute_step (WpSessionItem * item,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (out_acquisition) {
|
if (out_acquisition) {
|
||||||
wp_si_stream_acquisition_acquire (out_acquisition, WP_SI_LINK (self),
|
wp_si_endpoint_acquisition_acquire (out_acquisition, WP_SI_LINK (self),
|
||||||
self->out_stream, (GAsyncReadyCallback) on_stream_acquired,
|
self->out_endpoint, (GAsyncReadyCallback) on_endpoint_acquired,
|
||||||
transition);
|
transition);
|
||||||
}
|
}
|
||||||
if (in_acquisition) {
|
if (in_acquisition) {
|
||||||
wp_si_stream_acquisition_acquire (in_acquisition, WP_SI_LINK (self),
|
wp_si_endpoint_acquisition_acquire (in_acquisition, WP_SI_LINK (self),
|
||||||
self->in_stream, (GAsyncReadyCallback) on_stream_acquired,
|
self->in_endpoint, (GAsyncReadyCallback) on_endpoint_acquired,
|
||||||
transition);
|
transition);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -407,15 +405,15 @@ si_standard_link_activate_execute_step (WpSessionItem * item,
|
|||||||
g_autoptr (GVariant) out_ports = NULL;
|
g_autoptr (GVariant) out_ports = NULL;
|
||||||
g_autoptr (GVariant) in_ports = NULL;
|
g_autoptr (GVariant) in_ports = NULL;
|
||||||
|
|
||||||
out_ports = wp_si_port_info_get_ports (WP_SI_PORT_INFO (self->out_stream),
|
out_ports = wp_si_port_info_get_ports (WP_SI_PORT_INFO (self->out_endpoint),
|
||||||
self->out_stream_port_context);
|
self->out_endpoint_port_context);
|
||||||
in_ports = wp_si_port_info_get_ports (WP_SI_PORT_INFO (self->in_stream),
|
in_ports = wp_si_port_info_get_ports (WP_SI_PORT_INFO (self->in_endpoint),
|
||||||
self->in_stream_port_context);
|
self->in_endpoint_port_context);
|
||||||
|
|
||||||
if (!create_links (self, transition, out_ports, in_ports)) {
|
if (!create_links (self, transition, out_ports, in_ports)) {
|
||||||
wp_transition_return_error (transition, g_error_new (WP_DOMAIN_LIBRARY,
|
wp_transition_return_error (transition, g_error_new (WP_DOMAIN_LIBRARY,
|
||||||
WP_LIBRARY_ERROR_INVARIANT,
|
WP_LIBRARY_ERROR_INVARIANT,
|
||||||
"Bad port info returned from one of the streams"));
|
"Bad port info returned from one of the endpoints"));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -428,27 +426,21 @@ static void
|
|||||||
si_standard_link_activate_rollback (WpSessionItem * item)
|
si_standard_link_activate_rollback (WpSessionItem * item)
|
||||||
{
|
{
|
||||||
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
|
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
|
||||||
g_autoptr (WpSiEndpoint) out_endpoint = NULL;
|
WpSiEndpointAcquisition *out_acquisition, *in_acquisition;
|
||||||
g_autoptr (WpSiEndpoint) in_endpoint = NULL;
|
|
||||||
WpSiStreamAcquisition *out_acquisition, *in_acquisition;
|
|
||||||
|
|
||||||
if (self->out_stream) {
|
if (self->out_endpoint) {
|
||||||
out_endpoint = wp_si_stream_get_parent_endpoint (self->out_stream);
|
out_acquisition =
|
||||||
if (out_endpoint) {
|
wp_si_endpoint_get_endpoint_acquisition (self->out_endpoint);
|
||||||
out_acquisition = wp_si_endpoint_get_stream_acquisition (out_endpoint);
|
if (out_acquisition)
|
||||||
if (out_acquisition)
|
wp_si_endpoint_acquisition_release (out_acquisition, WP_SI_LINK (self),
|
||||||
wp_si_stream_acquisition_release (out_acquisition, WP_SI_LINK (self),
|
self->out_endpoint);
|
||||||
self->out_stream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (self->in_stream) {
|
if (self->in_endpoint) {
|
||||||
in_endpoint = wp_si_stream_get_parent_endpoint (self->in_stream);
|
in_acquisition =
|
||||||
if (in_endpoint) {
|
wp_si_endpoint_get_endpoint_acquisition (self->in_endpoint);
|
||||||
in_acquisition = wp_si_endpoint_get_stream_acquisition (in_endpoint);
|
if (in_acquisition)
|
||||||
if (in_acquisition)
|
wp_si_endpoint_acquisition_release (in_acquisition, WP_SI_LINK (self),
|
||||||
wp_si_stream_acquisition_release (in_acquisition, WP_SI_LINK (self),
|
self->in_endpoint);
|
||||||
self->in_stream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_clear_pointer (&self->node_links, g_ptr_array_unref);
|
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);
|
return g_variant_builder_end (&b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WpSiStream *
|
static WpSiEndpoint *
|
||||||
si_standard_link_get_out_stream (WpSiLink * item)
|
si_standard_link_get_out_endpoint (WpSiLink * item)
|
||||||
{
|
{
|
||||||
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
|
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
|
||||||
return self->out_stream;
|
return self->out_endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WpSiStream *
|
static WpSiEndpoint *
|
||||||
si_standard_link_get_in_stream (WpSiLink * item)
|
si_standard_link_get_in_endpoint (WpSiLink * item)
|
||||||
{
|
{
|
||||||
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
|
WpSiStandardLink *self = WP_SI_STANDARD_LINK (item);
|
||||||
return self->in_stream;
|
return self->in_endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
si_standard_link_link_init (WpSiLinkInterface * iface)
|
si_standard_link_link_init (WpSiLinkInterface * iface)
|
||||||
{
|
{
|
||||||
iface->get_registration_info = si_standard_link_get_registration_info;
|
iface->get_registration_info = si_standard_link_get_registration_info;
|
||||||
iface->get_out_stream = si_standard_link_get_out_stream;
|
iface->get_out_endpoint = si_standard_link_get_out_endpoint;
|
||||||
iface->get_in_stream = si_standard_link_get_in_stream;
|
iface->get_in_endpoint = si_standard_link_get_in_endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
WP_PLUGIN_EXPORT gboolean
|
WP_PLUGIN_EXPORT gboolean
|
||||||
@@ -503,13 +495,13 @@ wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
|
|||||||
GVariantBuilder b;
|
GVariantBuilder b;
|
||||||
|
|
||||||
g_variant_builder_init (&b, G_VARIANT_TYPE ("a(ssymv)"));
|
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);
|
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);
|
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);
|
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);
|
WP_SI_CONFIG_OPTION_WRITEABLE, NULL);
|
||||||
g_variant_builder_add (&b, "(ssymv)", "manage-lifetime", "b",
|
g_variant_builder_add (&b, "(ssymv)", "manage-lifetime", "b",
|
||||||
WP_SI_CONFIG_OPTION_WRITEABLE, NULL);
|
WP_SI_CONFIG_OPTION_WRITEABLE, NULL);
|
||||||
|
@@ -17,10 +17,7 @@ function endpoint_support.enable()
|
|||||||
-- Session item factories, building blocks for the session management graph
|
-- Session item factories, building blocks for the session management graph
|
||||||
-- Do not disable these unless you really know what you are doing
|
-- Do not disable these unless you really know what you are doing
|
||||||
load_module("si-adapter")
|
load_module("si-adapter")
|
||||||
load_module("si-audio-softdsp-endpoint")
|
|
||||||
load_module("si-bluez5-endpoint")
|
|
||||||
load_module("si-convert")
|
load_module("si-convert")
|
||||||
load_module("si-fake-stream")
|
|
||||||
load_module("si-monitor-endpoint")
|
load_module("si-monitor-endpoint")
|
||||||
load_module("si-simple-node-endpoint")
|
load_module("si-simple-node-endpoint")
|
||||||
load_module("si-standard-link")
|
load_module("si-standard-link")
|
||||||
|
@@ -49,25 +49,23 @@ default_endpoint_target = {
|
|||||||
auto_linked_endpoints = {}
|
auto_linked_endpoints = {}
|
||||||
|
|
||||||
function createLink (ep, target)
|
function createLink (ep, target)
|
||||||
if ep:get_n_streams() > 0 and target:get_n_streams() > 0 then
|
local ep_id = ep['bound-id']
|
||||||
local ep_id = ep['bound-id']
|
local target_id = target['bound-id']
|
||||||
local target_id = target['bound-id']
|
local ep_is_output = (ep.direction == "output")
|
||||||
local ep_is_output = (ep.direction == "output")
|
local props = {
|
||||||
local props = {
|
['endpoint-link.output.endpoint'] = (ep_is_output and ep_id) or target_id,
|
||||||
['endpoint-link.output.endpoint'] = (ep_is_output and ep_id) or target_id,
|
['endpoint-link.output.stream'] = -1,
|
||||||
['endpoint-link.output.stream'] = -1,
|
['endpoint-link.input.endpoint'] = (ep_is_output and target_id) or ep_id,
|
||||||
['endpoint-link.input.endpoint'] = (ep_is_output and target_id) or ep_id,
|
['endpoint-link.input.stream'] = -1,
|
||||||
['endpoint-link.input.stream'] = -1,
|
}
|
||||||
}
|
ep:create_link (props)
|
||||||
ep:create_link (props)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function isEndpointLinkedWith (session, ep, target)
|
function isEndpointLinkedWith (session, ep, target)
|
||||||
local ep_id = ep["bound_id"]
|
local ep_id = ep["bound_id"]
|
||||||
local target_id = target["bound_id"]
|
local target_id = target["bound_id"]
|
||||||
for link in session:iterate_links() do
|
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
|
if (out_ep == ep_id and in_ep == target_id) or
|
||||||
(out_ep == target_id and in_ep == ep_id) then
|
(out_ep == target_id and in_ep == ep_id) then
|
||||||
return true
|
return true
|
||||||
@@ -89,7 +87,7 @@ function moveEndpoint (session, ep, target)
|
|||||||
|
|
||||||
-- destroy all previous links
|
-- destroy all previous links
|
||||||
for link in session:iterate_links() do
|
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
|
if (ep_is_output and out_ep == ep_id) or
|
||||||
(not ep_is_output and in_ep == ep_id) then
|
(not ep_is_output and in_ep == ep_id) then
|
||||||
local curr_target = nil
|
local curr_target = nil
|
||||||
@@ -224,7 +222,7 @@ function handleEndpoint (session, ep)
|
|||||||
|
|
||||||
-- check if this endpoint is already linked
|
-- check if this endpoint is already linked
|
||||||
for link in session:iterate_links() do
|
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
|
if out_ep == ep_id or in_ep == ep_id then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@@ -72,14 +72,10 @@ on_endpoints_changed (WpSession * session, AppData * d)
|
|||||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, "media.class", "=s", "Audio/Sink", NULL);
|
WP_CONSTRAINT_TYPE_PW_PROPERTY, "media.class", "=s", "Audio/Sink", NULL);
|
||||||
|
|
||||||
if (src) {
|
if (src) {
|
||||||
g_print ("Got endpoint src: %s (%u streams)\n",
|
g_print ("Got endpoint src: %s\n", wp_endpoint_get_name (src));
|
||||||
wp_endpoint_get_name (src),
|
|
||||||
wp_endpoint_get_n_streams (src));
|
|
||||||
}
|
}
|
||||||
if (sink) {
|
if (sink) {
|
||||||
g_print ("Got endpoint sink: %s (%u streams)\n",
|
g_print ("Got endpoint sink: %s\n", wp_endpoint_get_name (sink));
|
||||||
wp_endpoint_get_name (sink),
|
|
||||||
wp_endpoint_get_n_streams (sink));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src && sink) {
|
if (src && sink) {
|
||||||
@@ -356,10 +352,6 @@ appdata_init (AppData * d, GError ** error)
|
|||||||
"libwireplumber-module-si-simple-node-endpoint", "module", NULL, error)))
|
"libwireplumber-module-si-simple-node-endpoint", "module", NULL, error)))
|
||||||
return FALSE;
|
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,
|
if (!(wp_core_load_component (d->core,
|
||||||
"libwireplumber-module-si-adapter", "module", NULL, error)))
|
"libwireplumber-module-si-adapter", "module", NULL, error)))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@@ -35,8 +35,15 @@ test(
|
|||||||
)
|
)
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'test-si-audio-softdsp-endpoint',
|
'test-si-adapter',
|
||||||
executable('test-si-audio-softdsp-endpoint', 'si-audio-softdsp-endpoint.c',
|
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),
|
dependencies: common_deps, c_args: common_args),
|
||||||
env: common_env,
|
env: common_env,
|
||||||
)
|
)
|
||||||
|
@@ -13,7 +13,7 @@ typedef struct {
|
|||||||
} TestFixture;
|
} TestFixture;
|
||||||
|
|
||||||
static void
|
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);
|
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);
|
"fake*", "test/libspa-test"), ==, 0);
|
||||||
g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context,
|
g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context,
|
||||||
"audiotestsrc", "audiotestsrc/libspa-audiotestsrc"), ==, 0);
|
"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,
|
g_assert_nonnull (pw_context_load_module (f->base.server.context,
|
||||||
"libpipewire-module-spa-node-factory", NULL, NULL));
|
"libpipewire-module-spa-node-factory", NULL, NULL));
|
||||||
g_assert_nonnull (pw_context_load_module (f->base.server.context,
|
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);
|
"libwireplumber-module-si-adapter", "module", NULL, &error);
|
||||||
g_assert_no_error (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
|
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);
|
wp_base_test_fixture_teardown (&f->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_si_audio_softdsp_endpoint_configure_activate (TestFixture * f,
|
test_si_adapter_configure_activate (TestFixture * f,
|
||||||
gconstpointer user_data)
|
gconstpointer user_data)
|
||||||
{
|
{
|
||||||
guint requested_streams = GPOINTER_TO_UINT (user_data);
|
|
||||||
g_autoptr (WpNode) node = NULL;
|
g_autoptr (WpNode) node = NULL;
|
||||||
g_autoptr (WpSessionItem) adapter = NULL;
|
g_autoptr (WpSessionItem) adapter = NULL;
|
||||||
g_autoptr (WpSessionItem) endpoint = NULL;
|
|
||||||
|
|
||||||
/* create audiotestsrc adapter node */
|
/* create audiotestsrc adapter node */
|
||||||
node = wp_node_new_from_factory (f->base.core,
|
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);
|
g_assert_cmpuint (channels, ==, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create audio softdsp endpoint */
|
/* activate adapter */
|
||||||
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 */
|
|
||||||
{
|
{
|
||||||
g_auto (GVariantBuilder) b =
|
wp_session_item_activate (adapter,
|
||||||
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,
|
|
||||||
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
|
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
|
||||||
g_main_loop_run (f->base.loop);
|
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), ==,
|
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);
|
||||||
g_assert_cmphex (wp_object_get_active_features (WP_OBJECT (node)), ==,
|
g_assert_cmphex (wp_object_get_active_features (WP_OBJECT (node)), ==,
|
||||||
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL | WP_NODE_FEATURE_PORTS);
|
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 */
|
/* deactivate - configuration should not be altered */
|
||||||
|
|
||||||
wp_session_item_deactivate (endpoint);
|
wp_session_item_deactivate (adapter);
|
||||||
|
|
||||||
g_assert_cmphex (wp_session_item_get_flags (endpoint), ==,
|
|
||||||
WP_SI_FLAG_CONFIGURED);
|
|
||||||
g_assert_cmphex (wp_session_item_get_flags (adapter), ==, 0);
|
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
|
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 (WpNode) node = NULL;
|
||||||
g_autoptr (WpSession) session = NULL;
|
g_autoptr (WpSession) session = NULL;
|
||||||
g_autoptr (WpSessionItem) item = NULL;
|
|
||||||
g_autoptr (WpSessionItem) adapter = NULL;
|
g_autoptr (WpSessionItem) adapter = NULL;
|
||||||
g_autoptr (WpObjectManager) clients_om = NULL;
|
g_autoptr (WpObjectManager) clients_om = NULL;
|
||||||
g_autoptr (WpClient) self_client = 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)));
|
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 */
|
/* activate */
|
||||||
|
|
||||||
{
|
{
|
||||||
wp_session_item_activate (item,
|
wp_session_item_activate (adapter,
|
||||||
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
|
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
}
|
}
|
||||||
@@ -312,14 +190,12 @@ test_si_audio_softdsp_endpoint_export (TestFixture * f, gconstpointer user_data)
|
|||||||
|
|
||||||
/* export */
|
/* export */
|
||||||
|
|
||||||
wp_session_item_export (item, session,
|
wp_session_item_export (adapter, session,
|
||||||
(GAsyncReadyCallback) test_si_export_finish_cb, f);
|
(GAsyncReadyCallback) test_si_export_finish_cb, f);
|
||||||
g_main_loop_run (f->base.loop);
|
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), ==,
|
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;
|
g_autoptr (WpEndpoint) ep = NULL;
|
||||||
@@ -327,7 +203,7 @@ test_si_audio_softdsp_endpoint_export (TestFixture * f, gconstpointer user_data)
|
|||||||
gchar *tmp;
|
gchar *tmp;
|
||||||
|
|
||||||
g_assert_nonnull (
|
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 (
|
g_assert_nonnull (
|
||||||
props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (ep)));
|
props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (ep)));
|
||||||
|
|
||||||
@@ -362,25 +238,19 @@ main (gint argc, gchar *argv[])
|
|||||||
|
|
||||||
/* configure-activate */
|
/* configure-activate */
|
||||||
|
|
||||||
g_test_add ("/modules/si-audio-softdsp-endpoint/configure-activate/single-stream",
|
g_test_add ("/modules/si-adapter/configure-activate",
|
||||||
TestFixture, GUINT_TO_POINTER (1),
|
TestFixture, NULL,
|
||||||
test_si_audio_softdsp_endpoint_setup,
|
test_si_adapter_setup,
|
||||||
test_si_audio_softdsp_endpoint_configure_activate,
|
test_si_adapter_configure_activate,
|
||||||
test_si_audio_softdsp_endpoint_teardown);
|
test_si_adapter_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);
|
|
||||||
|
|
||||||
/* export */
|
/* export */
|
||||||
|
|
||||||
g_test_add ("/modules/si-audio-softdsp-endpoint/export",
|
g_test_add ("/modules/si-adapter/export",
|
||||||
TestFixture, NULL,
|
TestFixture, NULL,
|
||||||
test_si_audio_softdsp_endpoint_setup,
|
test_si_adapter_setup,
|
||||||
test_si_audio_softdsp_endpoint_export,
|
test_si_adapter_export,
|
||||||
test_si_audio_softdsp_endpoint_teardown);
|
test_si_adapter_teardown);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
296
tests/modules/si-convert.c
Normal file
296
tests/modules/si-convert.c
Normal 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 ();
|
||||||
|
}
|
@@ -58,14 +58,12 @@ test_si_simple_node_endpoint_configure_activate (TestFixture * f,
|
|||||||
const TestData *data = user_data;
|
const TestData *data = user_data;
|
||||||
g_autoptr (WpNode) node = NULL;
|
g_autoptr (WpNode) node = NULL;
|
||||||
g_autoptr (WpSessionItem) item = NULL;
|
g_autoptr (WpSessionItem) item = NULL;
|
||||||
WpSiStream *stream;
|
|
||||||
|
|
||||||
/* create item */
|
/* create item */
|
||||||
|
|
||||||
item = wp_session_item_make (f->base.core, "si-simple-node-endpoint");
|
item = wp_session_item_make (f->base.core, "si-simple-node-endpoint");
|
||||||
g_assert_nonnull (item);
|
g_assert_nonnull (item);
|
||||||
g_assert_true (WP_IS_SI_ENDPOINT (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));
|
g_assert_true (WP_IS_SI_PORT_INFO (item));
|
||||||
|
|
||||||
node = wp_node_new_from_factory (f->base.core,
|
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)), ==,
|
g_assert_cmphex (wp_object_get_active_features (WP_OBJECT (node)), ==,
|
||||||
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL | WP_NODE_FEATURE_PORTS);
|
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)
|
if (data->expected_direction == WP_DIRECTION_INPUT)
|
||||||
g_assert_cmpuint (wp_node_get_n_input_ports (node, NULL), ==, 1);
|
g_assert_cmpuint (wp_node_get_n_input_ports (node, NULL), ==, 1);
|
||||||
else
|
else
|
||||||
@@ -144,7 +137,7 @@ test_si_simple_node_endpoint_configure_activate (TestFixture * f,
|
|||||||
{
|
{
|
||||||
guint32 node_id, port_id, channel;
|
guint32 node_id, port_id, channel;
|
||||||
g_autoptr (GVariant) v =
|
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_true (g_variant_is_of_type (v, G_VARIANT_TYPE ("a(uuu)")));
|
||||||
g_assert_cmpint (g_variant_n_children (v), ==, 1);
|
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 (WpSessionItem) item = NULL;
|
||||||
g_autoptr (WpObjectManager) clients_om = NULL;
|
g_autoptr (WpObjectManager) clients_om = NULL;
|
||||||
g_autoptr (WpClient) self_client = NULL;
|
g_autoptr (WpClient) self_client = NULL;
|
||||||
WpSiStream *stream;
|
|
||||||
|
|
||||||
/* find self_client, to be used for verifying endpoint.client.id */
|
/* 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);
|
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
|
||||||
g_main_loop_run (f->base.loop);
|
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 */
|
/* create session */
|
||||||
|
|
||||||
session = WP_SESSION (wp_impl_session_new (f->base.core));
|
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_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);
|
wp_session_item_reset (item);
|
||||||
g_assert_cmphex (wp_session_item_get_flags (item), ==, 0);
|
g_assert_cmphex (wp_session_item_get_flags (item), ==, 0);
|
||||||
}
|
}
|
||||||
|
@@ -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,
|
g_assert_nonnull (sink_ep = wp_session_lookup_endpoint (session_proxy,
|
||||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, "endpoint.name", "=s", "fakesink",
|
WP_CONSTRAINT_TYPE_PW_PROPERTY, "endpoint.name", "=s", "fakesink",
|
||||||
NULL));
|
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 */
|
/* 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));
|
g_assert_nonnull (ep_link = wp_session_lookup_link (session_proxy, NULL));
|
||||||
|
|
||||||
{
|
{
|
||||||
guint32 out_ep, out_stream, in_ep, in_stream;
|
guint32 out_ep, in_ep;
|
||||||
g_autoptr (WpEndpointStream) src_stream = NULL;
|
|
||||||
g_autoptr (WpEndpointStream) sink_stream = NULL;
|
|
||||||
|
|
||||||
g_assert_nonnull (src_stream = wp_endpoint_lookup_stream (src_ep, NULL));
|
wp_endpoint_link_get_linked_object_ids (ep_link, &out_ep, &in_ep);
|
||||||
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);
|
|
||||||
g_assert_cmpuint (out_ep, ==, wp_proxy_get_bound_id (WP_PROXY (src_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 (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 (p);
|
||||||
g_assert_nonnull (wp_properties_get (p, "endpoint-link.input.endpoint"));
|
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.endpoint"));
|
||||||
g_assert_nonnull (wp_properties_get (p, "endpoint-link.output.stream"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -367,13 +355,11 @@ test_si_standard_link_destroy (TestFixture * f, gconstpointer user_data)
|
|||||||
/* find the endpoints */
|
/* find the endpoints */
|
||||||
|
|
||||||
g_assert_nonnull (src_ep = wp_session_lookup_endpoint (session_proxy,
|
g_assert_nonnull (src_ep = wp_session_lookup_endpoint (session_proxy,
|
||||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, "endpoint.name", "=s", "audiotestsrc",
|
WP_CONSTRAINT_TYPE_PW_PROPERTY, "endpoint.name", "=s", "audiotestsrc",
|
||||||
NULL));
|
NULL));
|
||||||
g_assert_nonnull (sink_ep = wp_session_lookup_endpoint (session_proxy,
|
g_assert_nonnull (sink_ep = wp_session_lookup_endpoint (session_proxy,
|
||||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, "endpoint.name", "=s", "fakesink",
|
WP_CONSTRAINT_TYPE_PW_PROPERTY, "endpoint.name", "=s", "fakesink",
|
||||||
NULL));
|
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 */
|
/* create the link */
|
||||||
{
|
{
|
||||||
|
@@ -47,63 +47,15 @@ test_si_endpoint_get_properties (WpSiEndpoint * item)
|
|||||||
return wp_properties_new ("test.property", "test-value", NULL);
|
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
|
static void
|
||||||
test_si_endpoint_endpoint_init (WpSiEndpointInterface * iface)
|
test_si_endpoint_endpoint_init (WpSiEndpointInterface * iface)
|
||||||
{
|
{
|
||||||
iface->get_registration_info = test_si_endpoint_get_registration_info;
|
iface->get_registration_info = test_si_endpoint_get_registration_info;
|
||||||
iface->get_properties = test_si_endpoint_get_properties;
|
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_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_ENDPOINT, test_si_endpoint_endpoint_init))
|
||||||
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_STREAM, test_si_endpoint_stream_init))
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_si_endpoint_init (TestSiEndpoint * self)
|
test_si_endpoint_init (TestSiEndpoint * self)
|
||||||
|
@@ -26,10 +26,6 @@ struct _WpCtl
|
|||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
union {
|
union {
|
||||||
struct {
|
|
||||||
gboolean show_streams;
|
|
||||||
} status;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
guint32 id;
|
guint32 id;
|
||||||
gboolean show_referenced;
|
gboolean show_referenced;
|
||||||
@@ -119,19 +115,6 @@ print_controls (WpPipewireObject * pwobj)
|
|||||||
printf ("\n");
|
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 *
|
static const gchar *
|
||||||
get_endpoint_friendly_name (WpEndpoint * ep)
|
get_endpoint_friendly_name (WpEndpoint * ep)
|
||||||
{
|
{
|
||||||
@@ -152,13 +135,6 @@ print_endpoint (const GValue *item, gpointer data)
|
|||||||
printf (TREE_INDENT_LINE "%c %4u. %-60s",
|
printf (TREE_INDENT_LINE "%c %4u. %-60s",
|
||||||
(default_id == id) ? '*' : ' ', id, get_endpoint_friendly_name (ep));
|
(default_id == id) ? '*' : ' ', id, get_endpoint_friendly_name (ep));
|
||||||
print_controls (WP_PIPEWIRE_OBJECT (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
|
static void
|
||||||
@@ -167,30 +143,20 @@ print_endpoint_link (const GValue *item, gpointer data)
|
|||||||
WpEndpointLink *link = g_value_get_object (item);
|
WpEndpointLink *link = g_value_get_object (item);
|
||||||
WpSession *session = data;
|
WpSession *session = data;
|
||||||
guint32 id = wp_proxy_get_bound_id (WP_PROXY (link));
|
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) out_ep = NULL;
|
||||||
g_autoptr (WpEndpoint) in_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,
|
wp_endpoint_link_get_linked_object_ids (link, &out_ep_id, &in_ep_id);
|
||||||
&out_ep_id, &out_stream_id, &in_ep_id, &in_stream_id);
|
|
||||||
|
|
||||||
out_ep = wp_session_lookup_endpoint (session,
|
out_ep = wp_session_lookup_endpoint (session,
|
||||||
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", out_ep_id, NULL);
|
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", out_ep_id, NULL);
|
||||||
in_ep = wp_session_lookup_endpoint (session,
|
in_ep = wp_session_lookup_endpoint (session,
|
||||||
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", in_ep_id, NULL);
|
WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", in_ep_id, NULL);
|
||||||
|
|
||||||
out_stream = wp_endpoint_lookup_stream (out_ep,
|
printf (TREE_INDENT_EMPTY " %4u. [%u. %s] ➞ [%u. %s]\n", id,
|
||||||
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,
|
|
||||||
out_ep_id, get_endpoint_friendly_name (out_ep),
|
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));
|
||||||
in_ep_id, get_endpoint_friendly_name (in_ep),
|
|
||||||
wp_endpoint_stream_get_name (in_stream));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -625,10 +591,6 @@ set_volume_prepare (WpCtl * self, GError ** error)
|
|||||||
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
|
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
|
||||||
"object.id", "=u", cmdline.set_volume.id,
|
"object.id", "=u", cmdline.set_volume.id,
|
||||||
NULL);
|
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_object_manager_add_interest (self->om, WP_TYPE_NODE,
|
||||||
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
|
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
|
||||||
"object.id", "=u", cmdline.set_volume.id,
|
"object.id", "=u", cmdline.set_volume.id,
|
||||||
@@ -714,10 +676,6 @@ set_mute_prepare (WpCtl * self, GError ** error)
|
|||||||
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
|
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
|
||||||
"object.id", "=u", cmdline.set_mute.id,
|
"object.id", "=u", cmdline.set_mute.id,
|
||||||
NULL);
|
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_object_manager_add_interest (self->om, WP_TYPE_NODE,
|
||||||
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
|
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
|
||||||
"object.id", "=u", cmdline.set_mute.id,
|
"object.id", "=u", cmdline.set_mute.id,
|
||||||
@@ -851,11 +809,7 @@ static const struct subcommand {
|
|||||||
.positional_args = "",
|
.positional_args = "",
|
||||||
.summary = "Displays the current state of objects in PipeWire",
|
.summary = "Displays the current state of objects in PipeWire",
|
||||||
.description = NULL,
|
.description = NULL,
|
||||||
.entries = {
|
.entries = { { NULL } },
|
||||||
{ "streams", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE,
|
|
||||||
&cmdline.status.show_streams, "Also show endpoint streams", NULL },
|
|
||||||
{ NULL }
|
|
||||||
},
|
|
||||||
.parse_positional = NULL,
|
.parse_positional = NULL,
|
||||||
.prepare = status_prepare,
|
.prepare = status_prepare,
|
||||||
.run = status_run,
|
.run = status_run,
|
||||||
|
Reference in New Issue
Block a user