mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-05 12:28:02 +02:00
modules: refactor config-policy to use the new session item API
This commit is contained in:
parent
4b7bc92e4b
commit
6044b23aed
33 changed files with 693 additions and 1947 deletions
|
|
@ -75,8 +75,8 @@ shared_library(
|
|||
shared_library(
|
||||
'wireplumber-module-config-policy',
|
||||
[
|
||||
'module-config-policy/parser-endpoint-link.c',
|
||||
'module-config-policy/config-policy.c',
|
||||
'module-config-policy/parser-endpoint-link.c',
|
||||
'module-config-policy/context.c',
|
||||
'module-config-policy.c',
|
||||
],
|
||||
c_args : [common_c_args, '-DG_LOG_DOMAIN="m-config-policy"'],
|
||||
|
|
|
|||
|
|
@ -8,14 +8,11 @@
|
|||
|
||||
#include <wp/wp.h>
|
||||
|
||||
#include "module-config-policy/config-policy.h"
|
||||
#include "module-config-policy/context.h"
|
||||
|
||||
WP_PLUGIN_EXPORT void
|
||||
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
||||
{
|
||||
g_autoptr (WpConfiguration) config = wp_configuration_get_instance (core);
|
||||
|
||||
/* Create and register the config policy */
|
||||
WpConfigPolicy *cp = wp_config_policy_new (config);
|
||||
wp_policy_register (WP_POLICY (cp), core);
|
||||
WpConfigPolicyContext *ctx = wp_config_policy_context_new (core);
|
||||
wp_module_set_destroy_callback (module, g_object_unref, ctx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,628 +0,0 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <spa/utils/keys.h>
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
#include "config-policy.h"
|
||||
#include "parser-endpoint-link.h"
|
||||
|
||||
#if !defined(HAVE_AUDIOFADE)
|
||||
# define SPA_CONTROL_AUDIO_FADE_TYPE_LOGARITHMIC 2
|
||||
#else
|
||||
# include <spa/param/control/audio.h>
|
||||
#endif
|
||||
|
||||
struct link_info {
|
||||
WpBaseEndpoint *ep;
|
||||
guint32 stream_id;
|
||||
gboolean keep;
|
||||
};
|
||||
|
||||
static void
|
||||
link_info_destroy (gpointer p)
|
||||
{
|
||||
struct link_info *li = p;
|
||||
g_return_if_fail (li);
|
||||
g_clear_object (&li->ep);
|
||||
g_slice_free (struct link_info, li);
|
||||
}
|
||||
|
||||
struct _WpConfigPolicy
|
||||
{
|
||||
WpPolicy parent;
|
||||
|
||||
WpConfiguration *config;
|
||||
|
||||
gboolean pending_rescan;
|
||||
gboolean pending_links;
|
||||
gboolean pending_done;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CONFIG,
|
||||
};
|
||||
|
||||
enum {
|
||||
SIGNAL_DONE,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals[N_SIGNALS];
|
||||
|
||||
G_DEFINE_TYPE (WpConfigPolicy, wp_config_policy, WP_TYPE_POLICY)
|
||||
|
||||
static void
|
||||
wp_config_policy_rescan_done (WpConfigPolicy *self)
|
||||
{
|
||||
/* Reset pending flags */
|
||||
self->pending_rescan = FALSE;
|
||||
self->pending_links = FALSE;
|
||||
self->pending_done = FALSE;
|
||||
|
||||
/* Emit the done signal */
|
||||
g_signal_emit (self, signals[SIGNAL_DONE], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_sync_done (WpCore *core, GAsyncResult *res, gpointer data)
|
||||
{
|
||||
WpConfigPolicy *self = WP_CONFIG_POLICY (data);
|
||||
wp_config_policy_rescan_done (self);
|
||||
}
|
||||
|
||||
static void
|
||||
on_endpoint_link_created (GObject *initable, GAsyncResult *res, gpointer data)
|
||||
{
|
||||
WpConfigPolicy *self = WP_CONFIG_POLICY (data);
|
||||
g_autoptr (WpCore) core = wp_policy_get_core (WP_POLICY (self));
|
||||
g_autoptr (WpBaseEndpointLink) link = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
g_autoptr (WpBaseEndpoint) src_ep = NULL;
|
||||
g_autoptr (WpBaseEndpoint) sink_ep = NULL;
|
||||
|
||||
/* Get the link */
|
||||
link = wp_base_endpoint_link_new_finish(initable, res, &error);
|
||||
|
||||
/* Log linking info */
|
||||
if (error) {
|
||||
g_warning ("Could not link endpoints: %s\n", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
g_return_if_fail (link);
|
||||
src_ep = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink_ep = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_info ("Sucessfully linked '%s' to '%s'\n", wp_base_endpoint_get_name (src_ep),
|
||||
wp_base_endpoint_get_name (sink_ep));
|
||||
|
||||
/* Finish rescanning if no pending done */
|
||||
g_return_if_fail (core);
|
||||
if (!self->pending_done) {
|
||||
self->pending_done = TRUE;
|
||||
wp_core_sync (core, NULL, (GAsyncReadyCallback)wp_config_policy_sync_done,
|
||||
self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_faded_destroy_link (GObject *stream, GAsyncResult *res, gpointer data)
|
||||
{
|
||||
WpBaseEndpointLink *l = WP_BASE_ENDPOINT_LINK (data);
|
||||
g_return_if_fail (l);
|
||||
wp_base_endpoint_link_destroy (l);
|
||||
}
|
||||
|
||||
static void
|
||||
on_faded_done (GObject *stream, GAsyncResult *res, gpointer data)
|
||||
{
|
||||
g_info ("done fading\n");
|
||||
}
|
||||
|
||||
static void
|
||||
fade_out (WpBaseEndpoint *ep, guint stream_id, GAsyncReadyCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
wp_base_endpoint_begin_fade (ep, stream_id, 200, 0.003, PW_DIRECTION_INPUT,
|
||||
SPA_CONTROL_AUDIO_FADE_TYPE_LOGARITHMIC, NULL, callback, data);
|
||||
}
|
||||
|
||||
static void
|
||||
fade_in (WpBaseEndpoint *ep, guint stream_id, GAsyncReadyCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
wp_base_endpoint_begin_fade (ep, stream_id, 200, 0.003, PW_DIRECTION_OUTPUT,
|
||||
SPA_CONTROL_AUDIO_FADE_TYPE_LOGARITHMIC, NULL, callback, data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wp_config_policy_handle_pending_link (WpConfigPolicy *self,
|
||||
struct link_info *li, WpBaseEndpoint *target)
|
||||
{
|
||||
g_autoptr (WpCore) core = wp_policy_get_core (WP_POLICY (self));
|
||||
gboolean is_capture = wp_base_endpoint_get_direction (li->ep) == PW_DIRECTION_INPUT;
|
||||
gboolean is_linked = wp_base_endpoint_is_linked (li->ep);
|
||||
gboolean target_linked = wp_base_endpoint_is_linked (target);
|
||||
|
||||
g_debug ("Trying to link with '%s' to target '%s', ep_capture:%d, "
|
||||
"ep_linked:%d, target_linked:%d", wp_base_endpoint_get_name (li->ep),
|
||||
wp_base_endpoint_get_name (target), is_capture, is_linked, target_linked);
|
||||
|
||||
/* Check if the endpoint is already linked with the proper target */
|
||||
if (is_linked) {
|
||||
GPtrArray *links = wp_base_endpoint_get_links (li->ep);
|
||||
WpBaseEndpointLink *l = g_ptr_array_index (links, 0);
|
||||
g_autoptr (WpBaseEndpoint) src_ep = wp_base_endpoint_link_get_source_endpoint (l);
|
||||
g_autoptr (WpBaseEndpoint) sink_ep = wp_base_endpoint_link_get_sink_endpoint (l);
|
||||
WpBaseEndpoint *existing_target = is_capture ? src_ep : sink_ep;
|
||||
|
||||
if (existing_target == target) {
|
||||
/* linked to correct target so do nothing */
|
||||
g_debug ("Endpoint '%s' is already linked correctly",
|
||||
wp_base_endpoint_get_name (li->ep));
|
||||
return FALSE;
|
||||
} else {
|
||||
/* linked to the wrong target so unlink and continue */
|
||||
g_debug ("Unlinking endpoint '%s' from its previous target",
|
||||
wp_base_endpoint_get_name (li->ep));
|
||||
g_autoptr (WpBaseEndpoint) ep = wp_base_endpoint_link_get_sink_endpoint (l);
|
||||
guint32 stream_id = wp_base_endpoint_link_get_sink_stream (l);
|
||||
fade_out (ep, stream_id, on_faded_destroy_link, l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Unlink the target links that are not kept if endpoint is playback */
|
||||
if (!is_capture && target_linked && !li->keep) {
|
||||
GPtrArray *links = wp_base_endpoint_get_links (target);
|
||||
for (guint i = 0; i < links->len; i++) {
|
||||
WpBaseEndpointLink *l = g_ptr_array_index (links, i);
|
||||
if (!wp_base_endpoint_link_is_kept (l)) {
|
||||
g_autoptr (WpBaseEndpoint) ep = wp_base_endpoint_link_get_sink_endpoint (l);
|
||||
guint32 stream_id = wp_base_endpoint_link_get_sink_stream (l);
|
||||
fade_out (ep, stream_id, on_faded_destroy_link, l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Link the client with the target */
|
||||
if (is_capture) {
|
||||
fade_in (li->ep, WP_STREAM_ID_NONE, on_faded_done, NULL);
|
||||
wp_base_endpoint_link_new (core, target, li->stream_id, li->ep,
|
||||
WP_STREAM_ID_NONE, li->keep, on_endpoint_link_created, self);
|
||||
} else {
|
||||
fade_in (target, li->stream_id, on_faded_done, NULL);
|
||||
wp_base_endpoint_link_new (core, li->ep, WP_STREAM_ID_NONE, target,
|
||||
li->stream_id, li->keep, on_endpoint_link_created, self);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static WpBaseEndpoint*
|
||||
wp_config_policy_get_data_target (WpConfigPolicy *self, const char *ep_role,
|
||||
const struct WpParserEndpointLinkData *data, guint32 *stream_id)
|
||||
{
|
||||
g_autoptr (WpCore) core = wp_policy_get_core (WP_POLICY (self));
|
||||
GVariantBuilder b;
|
||||
GVariant *target_data = NULL;
|
||||
|
||||
g_return_val_if_fail (data, NULL);
|
||||
|
||||
/* Create the target gvariant */
|
||||
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"data", g_variant_new_uint64 ((guint64) data));
|
||||
if (ep_role)
|
||||
g_variant_builder_add (&b, "{sv}", "role", g_variant_new_string (ep_role));
|
||||
target_data = g_variant_builder_end (&b);
|
||||
|
||||
/* Find the target endpoint */
|
||||
return wp_policy_find_endpoint (core, target_data, stream_id);
|
||||
}
|
||||
|
||||
static guint
|
||||
wp_config_policy_get_endpoint_lowest_priority_stream_id (WpBaseEndpoint *ep)
|
||||
{
|
||||
g_autoptr (GVariant) streams = NULL;
|
||||
g_autoptr (GVariant) child = NULL;
|
||||
GVariantIter *iter;
|
||||
guint lowest_priority = G_MAXUINT;
|
||||
guint res = WP_STREAM_ID_NONE;
|
||||
guint priority;
|
||||
guint id;
|
||||
|
||||
g_return_val_if_fail (ep, WP_STREAM_ID_NONE);
|
||||
|
||||
streams = wp_base_endpoint_list_streams (ep);
|
||||
g_return_val_if_fail (streams, WP_STREAM_ID_NONE);
|
||||
|
||||
g_variant_get (streams, "aa{sv}", &iter);
|
||||
while ((child = g_variant_iter_next_value (iter))) {
|
||||
g_variant_lookup (child, "id", "u", &id);
|
||||
g_variant_lookup (child, "priority", "u", &priority);
|
||||
if (priority <= lowest_priority) {
|
||||
lowest_priority = priority;
|
||||
res = id;
|
||||
}
|
||||
}
|
||||
g_variant_iter_free (iter);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static WpBaseEndpoint *
|
||||
wp_config_policy_find_endpoint (WpPolicy *policy, GVariant *props,
|
||||
guint32 *stream_id)
|
||||
{
|
||||
g_autoptr (WpCore) core = wp_policy_get_core (policy);
|
||||
g_autoptr (WpPolicyManager) pmgr = wp_policy_manager_get_instance (core);
|
||||
g_autoptr (WpSession) session = wp_policy_manager_get_session (pmgr);
|
||||
const struct WpParserEndpointLinkData *data = NULL;
|
||||
g_autoptr (GPtrArray) endpoints = NULL;
|
||||
guint i;
|
||||
WpBaseEndpoint *target = NULL;
|
||||
g_autoptr (WpProxy) proxy = NULL;
|
||||
g_autoptr (WpProperties) p = NULL;
|
||||
const char *role = NULL;
|
||||
|
||||
/* Get the data from props */
|
||||
g_variant_lookup (props, "data", "t", &data);
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
/* If target-endpoint data was defined in the configuration file, find the
|
||||
* matching endpoint based on target-endpoint data */
|
||||
if (data->has_te) {
|
||||
/* Get all the endpoints matching the media class */
|
||||
endpoints = wp_policy_manager_list_endpoints (pmgr,
|
||||
data->te.endpoint_data.media_class);
|
||||
if (!endpoints)
|
||||
return NULL;
|
||||
|
||||
/* Get the first endpoint that matches target data */
|
||||
for (i = 0; i < endpoints->len; i++) {
|
||||
target = g_ptr_array_index (endpoints, i);
|
||||
if (wp_parser_endpoint_link_matches_endpoint_data (target,
|
||||
&data->te.endpoint_data))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, use the default session endpoint if the session is valid */
|
||||
else if (session) {
|
||||
/* Get the default type */
|
||||
const gchar * type_name;
|
||||
switch (data->me.endpoint_data.direction) {
|
||||
case PW_DIRECTION_INPUT:
|
||||
type_name = "wp-session-default-endpoint-audio-source";
|
||||
break;
|
||||
case PW_DIRECTION_OUTPUT:
|
||||
type_name = "wp-session-default-endpoint-audio-sink";
|
||||
break;
|
||||
default:
|
||||
g_warn_if_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get all the endpoints */
|
||||
endpoints = wp_policy_manager_list_endpoints (pmgr, NULL);
|
||||
if (!endpoints)
|
||||
return NULL;
|
||||
|
||||
/* Find the default session endpoint */
|
||||
for (i = 0; i < endpoints->len; i++) {
|
||||
target = g_ptr_array_index (endpoints, i);
|
||||
guint def_id = wp_session_get_default_endpoint (session, type_name);
|
||||
if (def_id == wp_base_endpoint_get_global_id (target))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no target data has been defined and session is not valid, return null */
|
||||
else
|
||||
return NULL;
|
||||
|
||||
/* If target did not match any data, return NULL */
|
||||
if (i >= endpoints->len)
|
||||
return NULL;
|
||||
|
||||
/* Set the stream id */
|
||||
if (stream_id) {
|
||||
if (target) {
|
||||
g_variant_lookup (props, "role", "&s", &role);
|
||||
/* The target stream has higher priority than the endpoint stream */
|
||||
const char *prioritized = data->te.stream ? data->te.stream : role;
|
||||
*stream_id = prioritized ?
|
||||
wp_base_endpoint_find_stream (target, prioritized) :
|
||||
wp_config_policy_get_endpoint_lowest_priority_stream_id (target);
|
||||
} else {
|
||||
*stream_id = WP_STREAM_ID_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return g_object_ref (target);
|
||||
}
|
||||
|
||||
static gint
|
||||
link_info_compare_func (gconstpointer a, gconstpointer b, gpointer data)
|
||||
{
|
||||
WpBaseEndpoint *target = data;
|
||||
struct link_info *li_a = *(struct link_info *const *)a;
|
||||
struct link_info *li_b = *(struct link_info *const *)b;
|
||||
g_autoptr (GVariant) stream_a = NULL;
|
||||
g_autoptr (GVariant) stream_b = NULL;
|
||||
guint priority_a = 0;
|
||||
guint priority_b = 0;
|
||||
gint res = 0;
|
||||
|
||||
res = (gint) li_a->keep - (gint) li_b->keep;
|
||||
if (res != 0)
|
||||
return res;
|
||||
|
||||
/* Get the role priority of a */
|
||||
stream_a = wp_base_endpoint_get_stream (target, li_a->stream_id);
|
||||
if (stream_a)
|
||||
g_variant_lookup (stream_a, "priority", "u", &priority_a);
|
||||
|
||||
/* Get the role priority of b */
|
||||
stream_b = wp_base_endpoint_get_stream (target, li_b->stream_id);
|
||||
if (stream_b)
|
||||
g_variant_lookup (stream_b, "priority", "u", &priority_b);
|
||||
|
||||
/* We want to sort from high priority to low priority */
|
||||
res = priority_b - priority_a;
|
||||
|
||||
/* If both priorities are the same, sort by creation time */
|
||||
if (res == 0)
|
||||
res = wp_base_endpoint_get_creation_time (li_b->ep) -
|
||||
wp_base_endpoint_get_creation_time (li_a->ep);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_add_link_info (WpConfigPolicy *self, GHashTable *table,
|
||||
WpBaseEndpoint *ep)
|
||||
{
|
||||
g_autoptr (WpConfigParser) parser = NULL;
|
||||
const struct WpParserEndpointLinkData *data = NULL;
|
||||
const char *ep_role = wp_base_endpoint_get_role (ep);
|
||||
struct link_info *res = NULL;
|
||||
g_autoptr (WpBaseEndpoint) target = NULL;
|
||||
guint32 stream_id = WP_STREAM_ID_NONE;
|
||||
|
||||
/* Get the parser for the endpoint-link extension */
|
||||
parser = wp_configuration_get_parser (self->config,
|
||||
WP_PARSER_ENDPOINT_LINK_EXTENSION);
|
||||
|
||||
/* Get the matched endpoint data from the parser */
|
||||
data = wp_config_parser_get_matched_data (parser, G_OBJECT (ep));
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
/* Get the target */
|
||||
target = wp_config_policy_get_data_target (self, ep_role, data, &stream_id);
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
/* Create the link info */
|
||||
res = g_slice_new0 (struct link_info);
|
||||
res->ep = g_object_ref (ep);
|
||||
res->stream_id = stream_id;
|
||||
res->keep = data->el.keep;
|
||||
|
||||
/* Get the link infos for the target, or create a new one if not found */
|
||||
GPtrArray *link_infos = g_hash_table_lookup (table, target);
|
||||
if (!link_infos) {
|
||||
link_infos = g_ptr_array_new_with_free_func (link_info_destroy);
|
||||
g_ptr_array_add (link_infos, res);
|
||||
g_hash_table_insert (table, g_steal_pointer (&target), link_infos);
|
||||
} else {
|
||||
g_ptr_array_add (link_infos, res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
links_table_handle_foreach (gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
WpConfigPolicy *self = data;
|
||||
WpBaseEndpoint *target = key;
|
||||
GPtrArray *link_infos = value;
|
||||
|
||||
/* Sort the link infos by role and creation time */
|
||||
g_ptr_array_sort_with_data (link_infos, link_info_compare_func, target);
|
||||
|
||||
g_debug ("handling endpoints:");
|
||||
|
||||
/* Handle the first endpoint and also the ones with keep=true */
|
||||
for (guint i = 0; i < link_infos->len; i++) {
|
||||
struct link_info *li = g_ptr_array_index (link_infos, i);
|
||||
|
||||
g_debug (" %2u: %s:%d, keep:%d", i, wp_base_endpoint_get_name (li->ep),
|
||||
li->stream_id, li->keep);
|
||||
|
||||
if (i == 0 || li->keep)
|
||||
if (wp_config_policy_handle_pending_link (self, li, target))
|
||||
self->pending_links = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_sync_rescan (WpCore *core, GAsyncResult *res, gpointer data)
|
||||
{
|
||||
WpConfigPolicy *self = WP_CONFIG_POLICY (data);
|
||||
g_autoptr (WpPolicyManager) pmgr = wp_policy_manager_get_instance (core);
|
||||
g_autoptr (GPtrArray) endpoints = NULL;
|
||||
|
||||
g_debug ("rescanning");
|
||||
|
||||
/* Set pending-links to false */
|
||||
self->pending_links = FALSE;
|
||||
|
||||
/* Handle all endpoints when rescanning */
|
||||
endpoints = wp_policy_manager_list_endpoints (pmgr, NULL);
|
||||
if (endpoints) {
|
||||
/* Create the links table <target, array-of-link-info> */
|
||||
GHashTable *links_table = g_hash_table_new_full (g_direct_hash,
|
||||
g_direct_equal, g_object_unref, (GDestroyNotify) g_ptr_array_unref);
|
||||
|
||||
/* Fill the links table */
|
||||
for (guint i = 0; i < endpoints->len; i++) {
|
||||
WpBaseEndpoint *ep = g_ptr_array_index (endpoints, i);
|
||||
wp_config_policy_add_link_info (self, links_table, ep);
|
||||
}
|
||||
|
||||
/* Handle the links */
|
||||
g_hash_table_foreach (links_table, links_table_handle_foreach, self);
|
||||
|
||||
/* Clean up */
|
||||
g_clear_pointer (&links_table, g_hash_table_unref);
|
||||
}
|
||||
|
||||
/* Finish rescanning if no pending links */
|
||||
if (!self->pending_links)
|
||||
wp_config_policy_rescan_done (self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_rescan (WpConfigPolicy *self)
|
||||
{
|
||||
g_autoptr (WpCore) core = wp_policy_get_core (WP_POLICY (self));
|
||||
if (!core)
|
||||
return;
|
||||
|
||||
/* Scan if no pending scan */
|
||||
|
||||
if (!self->pending_rescan) {
|
||||
self->pending_rescan = TRUE;
|
||||
wp_core_sync (core, NULL, (GAsyncReadyCallback)wp_config_policy_sync_rescan,
|
||||
self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_endpoint_added (WpPolicy *policy, WpBaseEndpoint *ep)
|
||||
{
|
||||
WpConfigPolicy *self = WP_CONFIG_POLICY (policy);
|
||||
wp_config_policy_rescan (self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_endpoint_removed (WpPolicy *policy, WpBaseEndpoint *ep)
|
||||
{
|
||||
WpConfigPolicy *self = WP_CONFIG_POLICY (policy);
|
||||
wp_config_policy_rescan (self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpConfigPolicy *self = WP_CONFIG_POLICY (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_CONFIG:
|
||||
self->config = g_value_dup_object (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpConfigPolicy *self = WP_CONFIG_POLICY (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_CONFIG:
|
||||
g_value_take_object (value, g_object_ref (self->config));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_constructed (GObject * object)
|
||||
{
|
||||
WpConfigPolicy *self = WP_CONFIG_POLICY (object);
|
||||
|
||||
/* Add the parsers */
|
||||
wp_configuration_add_extension (self->config,
|
||||
WP_PARSER_ENDPOINT_LINK_EXTENSION, WP_TYPE_PARSER_ENDPOINT_LINK);
|
||||
|
||||
/* Parse the file */
|
||||
wp_configuration_reload (self->config, WP_PARSER_ENDPOINT_LINK_EXTENSION);
|
||||
|
||||
G_OBJECT_CLASS (wp_config_policy_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_finalize (GObject *object)
|
||||
{
|
||||
WpConfigPolicy *self = WP_CONFIG_POLICY (object);
|
||||
|
||||
/* Remove the extensions from the configuration */
|
||||
wp_configuration_remove_extension (self->config,
|
||||
WP_PARSER_ENDPOINT_LINK_EXTENSION);
|
||||
|
||||
/* Clear the configuration */
|
||||
g_clear_object (&self->config);
|
||||
|
||||
G_OBJECT_CLASS (wp_config_policy_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_init (WpConfigPolicy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_class_init (WpConfigPolicyClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
WpPolicyClass *policy_class = (WpPolicyClass *) klass;
|
||||
|
||||
object_class->constructed = wp_config_policy_constructed;
|
||||
object_class->finalize = wp_config_policy_finalize;
|
||||
object_class->set_property = wp_config_policy_set_property;
|
||||
object_class->get_property = wp_config_policy_get_property;
|
||||
|
||||
policy_class->endpoint_added = wp_config_policy_endpoint_added;
|
||||
policy_class->endpoint_removed = wp_config_policy_endpoint_removed;
|
||||
policy_class->find_endpoint = wp_config_policy_find_endpoint;
|
||||
|
||||
/* Properties */
|
||||
g_object_class_install_property (object_class, PROP_CONFIG,
|
||||
g_param_spec_object ("configuration", "configuration",
|
||||
"The configuration this policy is based on", WP_TYPE_CONFIGURATION,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/* Signals */
|
||||
signals[SIGNAL_DONE] = g_signal_new ("done",
|
||||
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
WpConfigPolicy *
|
||||
wp_config_policy_new (WpConfiguration *config)
|
||||
{
|
||||
return g_object_new (wp_config_policy_get_type (),
|
||||
"rank", WP_POLICY_RANK_UPSTREAM,
|
||||
"configuration", config,
|
||||
NULL);
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __WIREPLUMBER_CONFIG_POLICY_H__
|
||||
#define __WIREPLUMBER_CONFIG_POLICY_H__
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_DECLARE_FINAL_TYPE (WpConfigPolicy, wp_config_policy, WP, CONFIG_POLICY, WpPolicy)
|
||||
|
||||
WpConfigPolicy *wp_config_policy_new (WpConfiguration *config);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
427
modules/module-config-policy/context.c
Normal file
427
modules/module-config-policy/context.c
Normal file
|
|
@ -0,0 +1,427 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2020 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
#include "parser-endpoint-link.h"
|
||||
#include "context.h"
|
||||
|
||||
struct link_info {
|
||||
WpEndpoint *ep;
|
||||
guint32 stream_id;
|
||||
gboolean keep;
|
||||
};
|
||||
|
||||
static void
|
||||
link_info_destroy (gpointer p)
|
||||
{
|
||||
struct link_info *li = p;
|
||||
g_return_if_fail (li);
|
||||
g_clear_object (&li->ep);
|
||||
g_slice_free (struct link_info, li);
|
||||
}
|
||||
|
||||
struct _WpConfigPolicyContext
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
/* Props */
|
||||
GWeakRef core;
|
||||
|
||||
WpObjectManager *sessions_om;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CORE,
|
||||
};
|
||||
|
||||
enum {
|
||||
SIGNAL_LINK_ACTIVATED,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals[N_SIGNALS];
|
||||
|
||||
G_DEFINE_TYPE (WpConfigPolicyContext, wp_config_policy_context,
|
||||
G_TYPE_OBJECT)
|
||||
|
||||
static WpEndpoint *
|
||||
wp_config_policy_context_get_data_target (WpConfigPolicyContext *self,
|
||||
WpSession *session, const struct WpParserEndpointLinkData *data,
|
||||
guint32 *stream_id)
|
||||
{
|
||||
g_autoptr (WpIterator) it = NULL;
|
||||
g_auto (GValue) val = G_VALUE_INIT;
|
||||
WpEndpoint *target = NULL;
|
||||
|
||||
g_return_val_if_fail (session, NULL);
|
||||
|
||||
it = wp_session_iterate_endpoints (session);
|
||||
|
||||
/* If target-endpoint data was defined in the configuration file, find the
|
||||
* matching endpoint based on target-endpoint data */
|
||||
if (data->has_te) {
|
||||
guint highest_prio = 0;
|
||||
while (wp_iterator_next (it, &val)) {
|
||||
WpEndpoint *ep = g_value_get_object (&val);
|
||||
if (wp_parser_endpoint_link_matches_endpoint_data (ep,
|
||||
&data->te.endpoint_data)) {
|
||||
g_autoptr (WpProperties) props = wp_proxy_get_properties (WP_PROXY (ep));
|
||||
const char *priority = wp_properties_get (props, "endpoint.priority");
|
||||
const guint prio = atoi (priority);
|
||||
if (highest_prio <= prio) {
|
||||
highest_prio = prio;
|
||||
target = ep;
|
||||
}
|
||||
}
|
||||
g_value_unset (&val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, use the default session endpoint */
|
||||
else {
|
||||
const char *type_name;
|
||||
switch (data->me.endpoint_data.direction) {
|
||||
case WP_DIRECTION_INPUT:
|
||||
type_name = "wp-session-default-endpoint-audio-source";
|
||||
break;
|
||||
case WP_DIRECTION_OUTPUT:
|
||||
type_name = "wp-session-default-endpoint-audio-sink";
|
||||
break;
|
||||
default:
|
||||
g_warn_if_reached ();
|
||||
return NULL;
|
||||
}
|
||||
while (wp_iterator_next (it, &val)) {
|
||||
WpEndpoint *ep = g_value_get_object (&val);
|
||||
guint def_id = wp_session_get_default_endpoint (session, type_name);
|
||||
if (def_id == wp_proxy_get_bound_id (WP_PROXY (ep))) {
|
||||
target = ep;
|
||||
break;
|
||||
}
|
||||
g_value_unset (&val);
|
||||
}
|
||||
}
|
||||
|
||||
if (!target)
|
||||
return NULL;
|
||||
|
||||
/* Find the stream that matches the data name, otherwise use the first one */
|
||||
if (stream_id) {
|
||||
g_autoptr (WpIterator) stream_it = wp_endpoint_iterate_streams (target);
|
||||
g_auto (GValue) stream_val = G_VALUE_INIT;
|
||||
*stream_id = SPA_ID_INVALID;
|
||||
while (wp_iterator_next (stream_it, &stream_val)) {
|
||||
WpProxy *stream = g_value_get_object (&stream_val);
|
||||
if (g_strcmp0 (wp_endpoint_stream_get_name (WP_ENDPOINT_STREAM (stream)),
|
||||
data->te.stream) == 0) {
|
||||
*stream_id = wp_proxy_get_bound_id (stream);
|
||||
break;
|
||||
}
|
||||
if (*stream_id == SPA_ID_INVALID)
|
||||
*stream_id = wp_proxy_get_bound_id (stream);
|
||||
|
||||
g_value_unset (&stream_val);
|
||||
}
|
||||
}
|
||||
|
||||
return g_object_ref (target);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_add_link_info (WpConfigPolicyContext *self,
|
||||
GHashTable *table, WpSession *session, WpEndpoint *ep)
|
||||
{
|
||||
g_autoptr (WpCore) core = g_weak_ref_get (&self->core);
|
||||
g_autoptr (WpConfiguration) config = wp_configuration_get_instance (core);
|
||||
g_autoptr (WpConfigParser) parser = NULL;
|
||||
const struct WpParserEndpointLinkData *data = NULL;
|
||||
struct link_info *res = NULL;
|
||||
g_autoptr (WpEndpoint) target = NULL;
|
||||
guint32 stream_id = SPA_ID_INVALID;
|
||||
|
||||
/* Get the parser for the endpoint-link extension */
|
||||
parser = wp_configuration_get_parser (config,
|
||||
WP_PARSER_ENDPOINT_LINK_EXTENSION);
|
||||
|
||||
/* Get the matched endpoint data from the parser */
|
||||
data = wp_config_parser_get_matched_data (parser, G_OBJECT (ep));
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
/* Get the target */
|
||||
target = wp_config_policy_context_get_data_target (self, session, data,
|
||||
&stream_id);
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
/* Create the link info */
|
||||
res = g_slice_new0 (struct link_info);
|
||||
res->ep = g_object_ref (ep);
|
||||
res->stream_id = stream_id;
|
||||
res->keep = data->el.keep;
|
||||
|
||||
/* Get the link infos for the target, or create a new one if not found */
|
||||
GPtrArray *link_infos = g_hash_table_lookup (table, target);
|
||||
if (!link_infos) {
|
||||
link_infos = g_ptr_array_new_with_free_func (link_info_destroy);
|
||||
g_ptr_array_add (link_infos, res);
|
||||
g_hash_table_insert (table, g_steal_pointer (&target), link_infos);
|
||||
} else {
|
||||
g_ptr_array_add (link_infos, res);
|
||||
}
|
||||
}
|
||||
|
||||
static gint
|
||||
link_info_compare_func (gconstpointer a, gconstpointer b, gpointer data)
|
||||
{
|
||||
struct link_info *li_a = *(struct link_info *const *)a;
|
||||
struct link_info *li_b = *(struct link_info *const *)b;
|
||||
g_autoptr (WpProperties) props_a = NULL;
|
||||
g_autoptr (WpProperties) props_b = NULL;
|
||||
guint prio_a = 0, prio_b = 0;
|
||||
const char *str = NULL;
|
||||
gint res = 0;
|
||||
|
||||
res = (gint) li_a->keep - (gint) li_b->keep;
|
||||
if (res != 0)
|
||||
return res;
|
||||
|
||||
/* Sort from highest priority to lowest */
|
||||
props_a = wp_proxy_get_properties (WP_PROXY (li_a->ep));
|
||||
str = wp_properties_get (props_a, "endpoint.priority");
|
||||
if (str)
|
||||
prio_a = atoi (str);
|
||||
props_b = wp_proxy_get_properties (WP_PROXY (li_b->ep));
|
||||
str = wp_properties_get (props_b, "endpoint.priority");
|
||||
if (str)
|
||||
prio_b = atoi (str);
|
||||
return prio_b - prio_a;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wp_config_policy_context_handle_pending_link (WpConfigPolicyContext *self,
|
||||
struct link_info *li, WpEndpoint *target)
|
||||
{
|
||||
g_autoptr (WpProperties) props = NULL;
|
||||
const guint32 target_id = wp_proxy_get_bound_id (WP_PROXY (target));
|
||||
|
||||
/* Create the link properties */
|
||||
props = wp_properties_new_empty ();
|
||||
switch (wp_endpoint_get_direction (li->ep)) {
|
||||
case WP_DIRECTION_INPUT:
|
||||
/* Capture */
|
||||
wp_properties_setf (props, "endpoint-link.output.endpoint", "%u", target_id);
|
||||
wp_properties_setf (props, "endpoint-link.output.stream", "%u", li->stream_id);
|
||||
break;
|
||||
case WP_DIRECTION_OUTPUT:
|
||||
/* Playback */
|
||||
wp_properties_setf (props, "endpoint-link.input.endpoint", "%u", target_id);
|
||||
wp_properties_setf (props, "endpoint-link.input.stream", "%u", li->stream_id);
|
||||
break;
|
||||
default:
|
||||
g_return_val_if_reached (FALSE);
|
||||
}
|
||||
|
||||
/* Create the link */
|
||||
wp_endpoint_create_link (li->ep, props);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
links_table_handle_foreach (gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
WpConfigPolicyContext *self = data;
|
||||
WpEndpoint *target = key;
|
||||
GPtrArray *link_infos = value;
|
||||
|
||||
/* Sort the link infos by role and creation time */
|
||||
g_ptr_array_sort_with_data (link_infos, link_info_compare_func, target);
|
||||
|
||||
/* Handle the first endpoint and also the ones with keep=true */
|
||||
for (guint i = 0; i < link_infos->len; i++) {
|
||||
struct link_info *li = g_ptr_array_index (link_infos, i);
|
||||
if (i == 0 || li->keep)
|
||||
wp_config_policy_context_handle_pending_link (self, li, target);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_session_endpoints_changed (WpSession *session, WpConfigPolicyContext *self)
|
||||
{
|
||||
g_autoptr (WpIterator) it = NULL;
|
||||
g_auto (GValue) val = G_VALUE_INIT;
|
||||
|
||||
wp_debug ("endpoints changed");
|
||||
|
||||
/* Create the links table <target, array-of-link-info> */
|
||||
GHashTable *links_table = g_hash_table_new_full (g_direct_hash,
|
||||
g_direct_equal, g_object_unref, (GDestroyNotify) g_ptr_array_unref);
|
||||
|
||||
/* Fill the links table */
|
||||
it = wp_session_iterate_endpoints (session);
|
||||
while (wp_iterator_next (it, &val)) {
|
||||
WpEndpoint *ep = g_value_get_object (&val);
|
||||
wp_config_policy_context_add_link_info (self, links_table, session, ep);
|
||||
g_value_unset (&val);
|
||||
}
|
||||
|
||||
/* Handle the links */
|
||||
g_hash_table_foreach (links_table, links_table_handle_foreach, self);
|
||||
|
||||
/* Clean up */
|
||||
g_clear_pointer (&links_table, g_hash_table_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
on_session_links_changed (WpSession *session, WpConfigPolicyContext *self)
|
||||
{
|
||||
g_autoptr (WpIterator) it = NULL;
|
||||
g_auto (GValue) val = G_VALUE_INIT;
|
||||
const gchar *error = NULL;
|
||||
|
||||
/* Always activate all inactive links */
|
||||
it = wp_session_iterate_links (session);
|
||||
while (wp_iterator_next (it, &val)) {
|
||||
WpEndpointLink *ep_link = g_value_get_object (&val);
|
||||
if (wp_endpoint_link_get_state (ep_link, &error) ==
|
||||
WP_ENDPOINT_LINK_STATE_INACTIVE) {
|
||||
wp_endpoint_link_request_state (ep_link, WP_ENDPOINT_LINK_STATE_ACTIVE);
|
||||
|
||||
/* Emit the link activated signal */
|
||||
g_signal_emit (self, signals[SIGNAL_LINK_ACTIVATED], 0, ep_link);
|
||||
}
|
||||
g_value_unset (&val);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_session_added (WpObjectManager *om, WpProxy *proxy,
|
||||
WpConfigPolicyContext *self)
|
||||
{
|
||||
/* Handle links-changed and endpoints-changed callbacks on all sessions*/
|
||||
g_signal_connect_object (proxy, "endpoints-changed",
|
||||
G_CALLBACK (on_session_endpoints_changed), self, 0);
|
||||
g_signal_connect_object (proxy, "links-changed",
|
||||
G_CALLBACK (on_session_links_changed), self, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_constructed (GObject * object)
|
||||
{
|
||||
WpConfigPolicyContext *self = WP_CONFIG_POLICY_CONTEXT (object);
|
||||
g_autoptr (WpCore) core = g_weak_ref_get (&self->core);
|
||||
g_return_if_fail (core);
|
||||
g_autoptr (WpConfiguration) config = wp_configuration_get_instance (core);
|
||||
g_return_if_fail (config);
|
||||
|
||||
/* Add the endpoint-link parser */
|
||||
wp_configuration_add_extension (config, WP_PARSER_ENDPOINT_LINK_EXTENSION,
|
||||
WP_TYPE_PARSER_ENDPOINT_LINK);
|
||||
|
||||
/* Parse the files */
|
||||
wp_configuration_reload (config, WP_PARSER_ENDPOINT_LINK_EXTENSION);
|
||||
|
||||
/* Install the session object manager */
|
||||
wp_object_manager_add_interest_1 (self->sessions_om, WP_TYPE_SESSION, NULL);
|
||||
wp_object_manager_request_proxy_features (self->sessions_om, WP_TYPE_SESSION,
|
||||
WP_SESSION_FEATURES_STANDARD);
|
||||
g_signal_connect_object (self->sessions_om, "object-added",
|
||||
G_CALLBACK (on_session_added), self, 0);
|
||||
wp_core_install_object_manager (core, self->sessions_om);
|
||||
|
||||
G_OBJECT_CLASS (wp_config_policy_context_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpConfigPolicyContext *self = WP_CONFIG_POLICY_CONTEXT (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_CORE:
|
||||
g_weak_ref_set (&self->core, g_value_get_object (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpConfigPolicyContext *self = WP_CONFIG_POLICY_CONTEXT (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_CORE:
|
||||
g_value_take_object (value, g_weak_ref_get (&self->core));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_finalize (GObject *object)
|
||||
{
|
||||
WpConfigPolicyContext *self = WP_CONFIG_POLICY_CONTEXT (object);
|
||||
|
||||
g_autoptr (WpCore) core = g_weak_ref_get (&self->core);
|
||||
if (core) {
|
||||
g_autoptr (WpConfiguration) config = wp_configuration_get_instance (core);
|
||||
wp_configuration_remove_extension (config, WP_PARSER_ENDPOINT_LINK_EXTENSION);
|
||||
}
|
||||
g_weak_ref_clear (&self->core);
|
||||
|
||||
g_clear_object (&self->sessions_om);
|
||||
|
||||
G_OBJECT_CLASS (wp_config_policy_context_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_init (WpConfigPolicyContext *self)
|
||||
{
|
||||
self->sessions_om = wp_object_manager_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_class_init (WpConfigPolicyContextClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
|
||||
object_class->constructed = wp_config_policy_context_constructed;
|
||||
object_class->finalize = wp_config_policy_context_finalize;
|
||||
object_class->set_property = wp_config_policy_context_set_property;
|
||||
object_class->get_property = wp_config_policy_context_get_property;
|
||||
|
||||
/* Properties */
|
||||
g_object_class_install_property (object_class, PROP_CORE,
|
||||
g_param_spec_object ("core", "core", "The wireplumber core",
|
||||
WP_TYPE_CORE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/* Signals */
|
||||
signals[SIGNAL_LINK_ACTIVATED] = g_signal_new ("link-activated",
|
||||
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, WP_TYPE_ENDPOINT_LINK);
|
||||
}
|
||||
|
||||
WpConfigPolicyContext *
|
||||
wp_config_policy_context_new (WpCore *core)
|
||||
{
|
||||
return g_object_new (wp_config_policy_context_get_type (),
|
||||
"core", core,
|
||||
NULL);
|
||||
}
|
||||
24
modules/module-config-policy/context.h
Normal file
24
modules/module-config-policy/context.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2020 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __WIREPLUMBER_CONFIG_POLICY_CONTEXT_H__
|
||||
#define __WIREPLUMBER_CONFIG_POLICY_CONTEXT_H__
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define WP_TYPE_CONFIG_POLICY_CONTEXT (wp_config_policy_context_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (WpConfigPolicyContext, wp_config_policy_context,
|
||||
WP, CONFIG_POLICY_CONTEXT, GObject);
|
||||
|
||||
WpConfigPolicyContext * wp_config_policy_context_new (WpCore *core);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
@ -12,21 +12,8 @@
|
|||
|
||||
#include "parser-endpoint-link.h"
|
||||
|
||||
static gboolean
|
||||
wildcard_match (const char *pattern, const char *str)
|
||||
{
|
||||
if(*pattern == '\0' && *str == '\0')
|
||||
return TRUE;
|
||||
if(*pattern == '?' || *pattern == *str)
|
||||
return wildcard_match (pattern+1, str + 1);
|
||||
if(*pattern == '*')
|
||||
return wildcard_match (pattern + 1, str) ||
|
||||
wildcard_match (pattern, str + 1);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
wp_parser_endpoint_link_matches_endpoint_data (WpBaseEndpoint *ep,
|
||||
wp_parser_endpoint_link_matches_endpoint_data (WpEndpoint *ep,
|
||||
const struct WpParserEndpointLinkEndpointData *data)
|
||||
{
|
||||
g_autoptr (WpProperties) props = NULL;
|
||||
|
|
@ -34,24 +21,19 @@ wp_parser_endpoint_link_matches_endpoint_data (WpBaseEndpoint *ep,
|
|||
g_return_val_if_fail (ep, FALSE);
|
||||
g_return_val_if_fail (data, FALSE);
|
||||
|
||||
props = wp_base_endpoint_get_properties (ep);
|
||||
g_return_val_if_fail (props, FALSE);
|
||||
|
||||
/* Name */
|
||||
if (data->name &&
|
||||
!wildcard_match (data->name, wp_base_endpoint_get_name (ep)))
|
||||
!g_pattern_match_simple (data->name, wp_endpoint_get_name (ep)))
|
||||
return FALSE;
|
||||
|
||||
/* Media Class */
|
||||
if (data->media_class &&
|
||||
g_strcmp0 (wp_base_endpoint_get_media_class (ep), data->media_class) != 0)
|
||||
return FALSE;
|
||||
|
||||
/* Direction */
|
||||
if (wp_base_endpoint_get_direction (ep) != data->direction)
|
||||
g_strcmp0 (wp_endpoint_get_media_class (ep), data->media_class) != 0)
|
||||
return FALSE;
|
||||
|
||||
/* Properties */
|
||||
props = wp_proxy_get_properties (WP_PROXY (ep));
|
||||
g_return_val_if_fail (props, FALSE);
|
||||
if (!wp_properties_matches (props, data->props))
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -123,37 +105,23 @@ parse_properties (WpTomlTable *table, const char *name)
|
|||
return props;
|
||||
}
|
||||
|
||||
static guint
|
||||
parse_endpoint_direction (const char *direction)
|
||||
{
|
||||
if (g_strcmp0 (direction, "sink") == 0)
|
||||
return PW_DIRECTION_INPUT;
|
||||
else if (g_strcmp0 (direction, "source") == 0)
|
||||
return PW_DIRECTION_OUTPUT;
|
||||
|
||||
g_return_val_if_reached (PW_DIRECTION_INPUT);
|
||||
}
|
||||
|
||||
static struct WpParserEndpointLinkData *
|
||||
wp_parser_endpoint_link_data_new (const gchar *location)
|
||||
{
|
||||
g_autoptr (WpTomlFile) file = NULL;
|
||||
g_autoptr (WpTomlTable) table = NULL, me = NULL, te = NULL, el = NULL;
|
||||
struct WpParserEndpointLinkData *res = NULL;
|
||||
g_autofree char *direction = NULL;
|
||||
|
||||
/* File format:
|
||||
* ------------
|
||||
* [match-endpoint]
|
||||
* name (string)
|
||||
* media_class (string)
|
||||
* direction (string)
|
||||
* properties (WpProperties)
|
||||
*
|
||||
* [target-endpoint]
|
||||
* name (string)
|
||||
* media_class (string)
|
||||
* direction (string)
|
||||
* properties (WpProperties)
|
||||
* stream (string)
|
||||
*
|
||||
|
|
@ -189,12 +157,6 @@ wp_parser_endpoint_link_data_new (const gchar *location)
|
|||
res->me.endpoint_data.media_class =
|
||||
wp_toml_table_get_string (me, "media_class");
|
||||
|
||||
/* Get the direction from the match endpoint table */
|
||||
direction = wp_toml_table_get_string (me, "direction");
|
||||
if (!direction)
|
||||
goto error;
|
||||
res->me.endpoint_data.direction = parse_endpoint_direction (direction);
|
||||
|
||||
/* Get the match endpoint properties (Optional) */
|
||||
res->me.endpoint_data.props = parse_properties (me, "properties");
|
||||
|
||||
|
|
@ -211,10 +173,6 @@ wp_parser_endpoint_link_data_new (const gchar *location)
|
|||
res->te.endpoint_data.media_class =
|
||||
wp_toml_table_get_string (te, "media_class");
|
||||
|
||||
/* Set the direction to the match endpoint's reverse one */
|
||||
res->te.endpoint_data.direction =
|
||||
pw_direction_reverse (res->me.endpoint_data.direction);
|
||||
|
||||
/* Get the target endpoint properties (Optional) */
|
||||
res->te.endpoint_data.props = parse_properties (te, "properties");
|
||||
|
||||
|
|
@ -276,7 +234,7 @@ static gconstpointer
|
|||
wp_parser_endpoint_link_get_matched_data (WpConfigParser *parser, gpointer data)
|
||||
{
|
||||
WpParserEndpointLink *self = WP_PARSER_ENDPOINT_LINK (parser);
|
||||
WpBaseEndpoint *ep = WP_BASE_ENDPOINT (data);
|
||||
WpEndpoint *ep = WP_ENDPOINT (data);
|
||||
const struct WpParserEndpointLinkData *d = NULL;
|
||||
|
||||
/* Find the first data that matches endpoint */
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ struct WpParserEndpointLinkData {
|
|||
};
|
||||
|
||||
/* Helpers */
|
||||
gboolean wp_parser_endpoint_link_matches_endpoint_data (WpBaseEndpoint *ep,
|
||||
gboolean wp_parser_endpoint_link_matches_endpoint_data (WpEndpoint *ep,
|
||||
const struct WpParserEndpointLinkEndpointData *data);
|
||||
|
||||
#define WP_TYPE_PARSER_ENDPOINT_LINK (wp_parser_endpoint_link_get_type ())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
[match-endpoint]
|
||||
direction = "sink"
|
||||
media_class = "Stream/Input/Audio"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Audio/Source"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
[match-endpoint]
|
||||
direction = "sink"
|
||||
media_class = "Stream/Input/Video"
|
||||
|
||||
[target-endpoint]
|
||||
direction = "output"
|
||||
media_class = "Video/Source"
|
||||
|
||||
[endpoint-link]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
[match-endpoint]
|
||||
direction = "source"
|
||||
media_class = "Stream/Output/Audio"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Audio/Sink"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
[match-endpoint]
|
||||
direction = "source"
|
||||
media_class = "Stream/Output/Video"
|
||||
|
||||
[target-endpoint]
|
||||
direction = "sink"
|
||||
media_class = "Video/Sink"
|
||||
|
||||
[endpoint-link]
|
||||
|
|
|
|||
|
|
@ -7,372 +7,239 @@
|
|||
*/
|
||||
|
||||
#include "../common/base-test-fixture.h"
|
||||
#include "config-policy/context.h"
|
||||
#include "../../modules/module-config-policy/context.h"
|
||||
|
||||
typedef struct {
|
||||
WpBaseTestFixture base;
|
||||
} TestConfigPolicyFixture;
|
||||
WpSession *session;
|
||||
} TestFixture;
|
||||
|
||||
static WpSessionItem *
|
||||
load_item (TestFixture * f, const gchar * factory, const gchar * media_class)
|
||||
{
|
||||
g_autoptr (WpNode) node = NULL;
|
||||
g_autoptr (WpSessionItem) item = NULL;
|
||||
g_auto (GVariantBuilder) b = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
|
||||
|
||||
/* create item */
|
||||
|
||||
item = wp_session_item_make (f->base.core, "si-simple-node-endpoint");
|
||||
g_assert_nonnull (item);
|
||||
|
||||
node = wp_node_new_from_factory (f->base.core,
|
||||
"spa-node-factory",
|
||||
wp_properties_new (
|
||||
"factory.name", factory,
|
||||
"node.name", factory,
|
||||
NULL));
|
||||
g_assert_nonnull (node);
|
||||
|
||||
wp_proxy_augment (WP_PROXY (node), WP_PROXY_FEATURES_STANDARD, NULL,
|
||||
(GAsyncReadyCallback) test_proxy_augment_finish_cb, f);
|
||||
g_main_loop_run (f->base.loop);
|
||||
|
||||
/* configure */
|
||||
|
||||
g_variant_builder_add (&b, "{sv}", "node",
|
||||
g_variant_new_uint64 ((guint64) node));
|
||||
g_variant_builder_add (&b, "{sv}", "media-class",
|
||||
g_variant_new_string (media_class));
|
||||
g_assert_true (wp_session_item_configure (item, g_variant_builder_end (&b)));
|
||||
|
||||
/* activate */
|
||||
|
||||
wp_session_item_activate (item,
|
||||
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
|
||||
g_main_loop_run (f->base.loop);
|
||||
|
||||
/* export */
|
||||
|
||||
wp_session_item_export (item, f->session,
|
||||
(GAsyncReadyCallback) test_si_export_finish_cb, f);
|
||||
g_main_loop_run (f->base.loop);
|
||||
|
||||
return g_steal_pointer (&item);
|
||||
}
|
||||
|
||||
static WpSessionItem *
|
||||
load_adapter_item (TestFixture * f, const gchar * factory,
|
||||
const gchar * media_class, guint num_streams)
|
||||
{
|
||||
g_autoptr (WpNode) node = NULL;
|
||||
g_autoptr (WpSessionItem) adapter = NULL;
|
||||
g_autoptr (WpSessionItem) item = NULL;
|
||||
|
||||
/* create item */
|
||||
|
||||
adapter = wp_session_item_make (f->base.core, "si-adapter");
|
||||
g_assert_nonnull (adapter);
|
||||
item = wp_session_item_make (f->base.core, "si-audio-softdsp-endpoint");
|
||||
g_assert_nonnull (item);
|
||||
|
||||
node = wp_node_new_from_factory (f->base.core,
|
||||
"adapter",
|
||||
wp_properties_new (
|
||||
"factory.name", factory,
|
||||
"node.name", factory,
|
||||
NULL));
|
||||
g_assert_nonnull (node);
|
||||
|
||||
wp_proxy_augment (WP_PROXY (node), WP_PROXY_FEATURES_STANDARD, NULL,
|
||||
(GAsyncReadyCallback) test_proxy_augment_finish_cb, f);
|
||||
g_main_loop_run (f->base.loop);
|
||||
|
||||
/* configure adapter */
|
||||
|
||||
{
|
||||
g_auto (GVariantBuilder) b =
|
||||
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
|
||||
g_variant_builder_add (&b, "{sv}", "node",
|
||||
g_variant_new_uint64 ((guint64) node));
|
||||
g_variant_builder_add (&b, "{sv}", "media-class",
|
||||
g_variant_new_string (media_class));
|
||||
g_assert_true (wp_session_item_configure (adapter, g_variant_builder_end (&b)));
|
||||
}
|
||||
|
||||
/* configure 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)));
|
||||
}
|
||||
|
||||
/* add the streams */
|
||||
|
||||
for (guint i = 0; i < num_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_true (wp_session_bin_add (WP_SESSION_BIN (item),
|
||||
g_steal_pointer (&stream)));
|
||||
}
|
||||
|
||||
/* activate */
|
||||
|
||||
wp_session_item_activate (item,
|
||||
(GAsyncReadyCallback) test_si_activate_finish_cb, f);
|
||||
g_main_loop_run (f->base.loop);
|
||||
|
||||
/* export */
|
||||
|
||||
wp_session_item_export (item, f->session,
|
||||
(GAsyncReadyCallback) test_si_export_finish_cb, f);
|
||||
g_main_loop_run (f->base.loop);
|
||||
|
||||
return g_steal_pointer (&item);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
config_policy_setup (TestConfigPolicyFixture *self, gconstpointer user_data)
|
||||
config_policy_setup (TestFixture *f, gconstpointer user_data)
|
||||
{
|
||||
wp_base_test_fixture_setup (&self->base, 0);
|
||||
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_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_assert_nonnull (pw_context_load_module (f->base.server.context,
|
||||
"libpipewire-module-link-factory", NULL, NULL));
|
||||
}
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
WpModule *module = wp_module_load (f->base.core, "C",
|
||||
"libwireplumber-module-si-simple-node-endpoint", NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (module);
|
||||
module = wp_module_load (f->base.core, "C",
|
||||
"libwireplumber-module-si-adapter", NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (module);
|
||||
module = wp_module_load (f->base.core, "C",
|
||||
"libwireplumber-module-si-convert", NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (module);
|
||||
module = wp_module_load (f->base.core, "C",
|
||||
"libwireplumber-module-si-audio-softdsp-endpoint", NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (module);
|
||||
module = wp_module_load (f->base.core, "C",
|
||||
"libwireplumber-module-si-standard-link", NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (module);
|
||||
}
|
||||
|
||||
g_assert_nonnull (
|
||||
f->session = WP_SESSION (wp_impl_session_new (f->base.core)));
|
||||
wp_impl_session_set_property (WP_IMPL_SESSION (f->session),
|
||||
"session.name", "audio");
|
||||
wp_proxy_augment (WP_PROXY (f->session), WP_SESSION_FEATURES_STANDARD, NULL,
|
||||
(GAsyncReadyCallback) test_proxy_augment_finish_cb, f);
|
||||
g_main_loop_run (f->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
config_policy_teardown (TestConfigPolicyFixture *self, gconstpointer user_data)
|
||||
config_policy_teardown (TestFixture *f, gconstpointer user_data)
|
||||
{
|
||||
wp_base_test_fixture_teardown (&self->base);
|
||||
g_clear_object (&f->session);
|
||||
wp_base_test_fixture_teardown (&f->base);
|
||||
}
|
||||
|
||||
static void
|
||||
playback (TestConfigPolicyFixture *f, gconstpointer data)
|
||||
on_link_activated (WpConfigPolicyContext *ctx, WpEndpointLink *ep_link,
|
||||
TestFixture *f)
|
||||
{
|
||||
g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
|
||||
f->base.core, f->base.loop, "config-policy/config-playback");
|
||||
WpBaseEndpointLink *link = NULL;
|
||||
g_autoptr (WpBaseEndpoint) src = NULL;
|
||||
g_autoptr (WpBaseEndpoint) sink = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep1 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep2 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep3 = NULL;
|
||||
|
||||
/* Create the device endpoint */
|
||||
ep1 = wp_config_policy_context_add_endpoint (ctx, "ep1", "Fake/Sink",
|
||||
PW_DIRECTION_INPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep1);
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep1));
|
||||
|
||||
/* Create the first client endpoint */
|
||||
ep2 = wp_config_policy_context_add_endpoint (ctx, "ep2", "Stream/Output/Fake",
|
||||
PW_DIRECTION_OUTPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep2);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep2));
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep1));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep2), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep2 == src);
|
||||
g_assert_true (ep1 == sink);
|
||||
|
||||
/* Create the second client endpoint */
|
||||
ep3 = wp_config_policy_context_add_endpoint (ctx, "ep3", "Stream/Output/Fake",
|
||||
PW_DIRECTION_OUTPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep2);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep3));
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep1));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep3), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep3 == src);
|
||||
g_assert_true (ep1 == sink);
|
||||
|
||||
/* Make sure ep2 is unlinked after ep3 was linked */
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep2));
|
||||
|
||||
/* Remove the client endpoints */
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep2);
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep3);
|
||||
g_assert_nonnull (ep_link);
|
||||
g_main_loop_quit (f->base.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
capture (TestConfigPolicyFixture *f, gconstpointer data)
|
||||
playback (TestFixture *f, gconstpointer data)
|
||||
{
|
||||
g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
|
||||
f->base.core, f->base.loop, "config-policy/config-capture");
|
||||
WpBaseEndpointLink *link = NULL;
|
||||
g_autoptr (WpBaseEndpoint) src = NULL;
|
||||
g_autoptr (WpBaseEndpoint) sink = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep1 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep2 = NULL;
|
||||
/* Set the configuration path */
|
||||
g_autoptr (WpConfiguration) config = wp_configuration_get_instance (f->base.core);
|
||||
g_assert_nonnull (config);
|
||||
wp_configuration_add_path (config, "config-policy/playback");
|
||||
|
||||
/* Create the device endpoint */
|
||||
ep1 = wp_config_policy_context_add_endpoint (ctx, "ep1", "Fake/Source",
|
||||
PW_DIRECTION_OUTPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep1);
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep1));
|
||||
/* Create the policy context and handle the done callback */
|
||||
g_autoptr (WpConfigPolicyContext) ctx =
|
||||
wp_config_policy_context_new (f->base.core);
|
||||
g_assert_nonnull (ctx);
|
||||
g_signal_connect (ctx, "link-activated", (GCallback) on_link_activated, f);
|
||||
|
||||
/* Create the client endpoint */
|
||||
ep2 = wp_config_policy_context_add_endpoint (ctx, "ep2", "Stream/Input/Fake",
|
||||
PW_DIRECTION_INPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep2);
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep2), 0);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep2));
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep1));
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep1 == src);
|
||||
g_assert_true (ep2 == sink);
|
||||
|
||||
/* Remove the client endpoint */
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep2);
|
||||
}
|
||||
|
||||
static void
|
||||
playback_capture (TestConfigPolicyFixture *f, gconstpointer data)
|
||||
{
|
||||
g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
|
||||
f->base.core, f->base.loop, "config-policy/config-playback-capture");
|
||||
WpBaseEndpointLink *link = NULL;
|
||||
g_autoptr (WpBaseEndpoint) src = NULL;
|
||||
g_autoptr (WpBaseEndpoint) sink = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep1 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep2 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep3 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep4 = NULL;
|
||||
|
||||
/* Create the device endpoints */
|
||||
ep1 = wp_config_policy_context_add_endpoint (ctx, "ep1", "Fake/Sink",
|
||||
PW_DIRECTION_INPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep1);
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep1));
|
||||
ep2 = wp_config_policy_context_add_endpoint (ctx, "ep2", "Fake/Source",
|
||||
PW_DIRECTION_OUTPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep2);
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep2));
|
||||
|
||||
/* Create the playback client endpoint */
|
||||
ep3 = wp_config_policy_context_add_endpoint (ctx, "ep3", "Stream/Output/Fake",
|
||||
PW_DIRECTION_OUTPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep3);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep3));
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep1));
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep2));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep3), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep3 == src);
|
||||
g_assert_true (ep1 == sink);
|
||||
|
||||
/* Create the capture client endpoint */
|
||||
ep4 = wp_config_policy_context_add_endpoint (ctx, "ep4", "Stream/Input/Fake",
|
||||
PW_DIRECTION_INPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep4);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep4));
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep2));
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep3));
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep1));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep4), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep2 == src);
|
||||
g_assert_true (ep4 == sink);
|
||||
|
||||
/* Remove the client endpoints */
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep4);
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep3);
|
||||
}
|
||||
|
||||
static void
|
||||
playback_priority (TestConfigPolicyFixture *f, gconstpointer data)
|
||||
{
|
||||
g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
|
||||
f->base.core, f->base.loop, "config-policy/config-playback-priority");
|
||||
WpBaseEndpointLink *link = NULL;
|
||||
g_autoptr (WpBaseEndpoint) src = NULL;
|
||||
g_autoptr (WpBaseEndpoint) sink = NULL;
|
||||
g_autoptr (WpBaseEndpoint) dev = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep1 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep2 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep3 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep4 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep5 = NULL;
|
||||
|
||||
/* Create the device endpoint with 4 streams */
|
||||
dev = wp_config_policy_context_add_endpoint (ctx, "dev", "Fake/Sink",
|
||||
PW_DIRECTION_INPUT, NULL, NULL, 4);
|
||||
g_assert_nonnull (dev);
|
||||
g_assert_false (wp_base_endpoint_is_linked (dev));
|
||||
|
||||
/* Create the client endpoint for steam 2 (priority 2) and make sure it
|
||||
* is linked */
|
||||
ep2 = wp_config_policy_context_add_endpoint (ctx, "ep_for_stream_2",
|
||||
"Stream/Output/Fake", PW_DIRECTION_OUTPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep2);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep2));
|
||||
g_assert_true (wp_base_endpoint_is_linked (dev));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep2), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep2 == src);
|
||||
g_assert_true (dev == sink);
|
||||
|
||||
/* Create the client endpoint for steam 1 (priority 1) and make sure it
|
||||
* is not linked */
|
||||
ep1 = wp_config_policy_context_add_endpoint (ctx, "ep_for_stream_1",
|
||||
"Stream/Output/Fake", PW_DIRECTION_OUTPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep1);
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep1));
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep2));
|
||||
g_assert_true (wp_base_endpoint_is_linked (dev));
|
||||
|
||||
/* Create the client endpoint for steam 3 (priority 3) and make sure it
|
||||
* is linked */
|
||||
ep3 = wp_config_policy_context_add_endpoint (ctx, "ep_for_stream_3",
|
||||
"Stream/Output/Fake", PW_DIRECTION_OUTPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep3);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep3));
|
||||
g_assert_true (wp_base_endpoint_is_linked (dev));
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep1));
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep2));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep3), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep3 == src);
|
||||
g_assert_true (dev == sink);
|
||||
|
||||
/* Remove ep2 and ep1 */
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep2);
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep1);
|
||||
|
||||
/* Create the client endpoint with role "1" (priority 1) and make sure it
|
||||
* is not linked */
|
||||
ep4 = wp_config_policy_context_add_endpoint (ctx, "ep_with_role",
|
||||
"Stream/Output/Fake", PW_DIRECTION_OUTPUT, NULL, "1", 0);
|
||||
g_assert_nonnull (ep4);
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep4));
|
||||
|
||||
/* Create the client endpoint with role "3" (priority 3) and make sure it
|
||||
* is linked (last one wins) */
|
||||
ep5 = wp_config_policy_context_add_endpoint (ctx, "ep_with_role",
|
||||
"Stream/Output/Fake", PW_DIRECTION_OUTPUT, NULL, "3", 0);
|
||||
g_assert_nonnull (ep5);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep5));
|
||||
g_assert_true (wp_base_endpoint_is_linked (dev));
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep4));
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep3));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep5), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep5 == src);
|
||||
g_assert_true (dev == sink);
|
||||
|
||||
/* Remove ep4, ep5 and ep3 */
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep4);
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep5);
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep3);
|
||||
}
|
||||
|
||||
static void
|
||||
playback_keep (TestConfigPolicyFixture *f, gconstpointer data)
|
||||
{
|
||||
g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
|
||||
f->base.core, f->base.loop, "config-policy/config-playback-keep");
|
||||
WpBaseEndpointLink *link = NULL;
|
||||
g_autoptr (WpBaseEndpoint) src = NULL;
|
||||
g_autoptr (WpBaseEndpoint) sink = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep1 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep2 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep3 = NULL;
|
||||
|
||||
/* Create the device endpoint */
|
||||
ep1 = wp_config_policy_context_add_endpoint (ctx, "ep1", "Fake/Sink",
|
||||
PW_DIRECTION_INPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep1);
|
||||
g_assert_false (wp_base_endpoint_is_linked (ep1));
|
||||
|
||||
/* Create the first client endpoint */
|
||||
ep2 = wp_config_policy_context_add_endpoint (ctx, "ep2", "Stream/Output/Fake",
|
||||
PW_DIRECTION_OUTPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep2);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep2));
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep1));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep2), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep2 == src);
|
||||
g_assert_true (ep1 == sink);
|
||||
|
||||
/* Create the second client endpoint */
|
||||
ep3 = wp_config_policy_context_add_endpoint (ctx, "ep3", "Stream/Output/Fake",
|
||||
PW_DIRECTION_OUTPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep2);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep3));
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep1));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep3), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep3 == src);
|
||||
g_assert_true (ep1 == sink);
|
||||
|
||||
/* Make sure ep2 is still linked after ep3 was linked */
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep2));
|
||||
|
||||
/* Remove the client endpoints */
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep2);
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep3);
|
||||
}
|
||||
|
||||
static void
|
||||
playback_role (TestConfigPolicyFixture *f, gconstpointer data)
|
||||
{
|
||||
g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
|
||||
f->base.core, f->base.loop, "config-policy/config-playback-role");
|
||||
WpBaseEndpointLink *link = NULL;
|
||||
g_autoptr (WpBaseEndpoint) src = NULL;
|
||||
g_autoptr (WpBaseEndpoint) sink = NULL;
|
||||
g_autoptr (WpBaseEndpoint) dev = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep1 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep2 = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep3 = NULL;
|
||||
|
||||
/* Create the device with 2 roles: "0" with id 0, and "1" with id 1 */
|
||||
dev = wp_config_policy_context_add_endpoint (ctx, "dev", "Fake/Sink",
|
||||
PW_DIRECTION_INPUT, NULL, NULL, 2);
|
||||
g_assert_nonnull (dev);
|
||||
g_assert_false (wp_base_endpoint_is_linked (dev));
|
||||
|
||||
/* Create the first client endpoint with role "0" and make sure the role
|
||||
* defined in the configuration file which is "1" is used */
|
||||
ep1 = wp_config_policy_context_add_endpoint (ctx, "ep1", "Stream/Output/Fake",
|
||||
PW_DIRECTION_OUTPUT, NULL, "0", 0);
|
||||
g_assert_nonnull (ep1);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep1));
|
||||
g_assert_true (wp_base_endpoint_is_linked (dev));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep1), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep1 == src);
|
||||
g_assert_true (dev == sink);
|
||||
g_assert_true (
|
||||
WP_STREAM_ID_NONE == wp_base_endpoint_link_get_source_stream (link));
|
||||
g_assert_true (1 == wp_base_endpoint_link_get_sink_stream (link));
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep1);
|
||||
|
||||
/* Create the second client endpoint with role "1" and make sure it uses it
|
||||
* because there is none defined in the configuration file */
|
||||
ep2 = wp_config_policy_context_add_endpoint (ctx, "ep2", "Stream/Output/Fake",
|
||||
PW_DIRECTION_OUTPUT, NULL, "1", 0);
|
||||
g_assert_nonnull (ep2);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep2));
|
||||
g_assert_true (wp_base_endpoint_is_linked (dev));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep2), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep2 == src);
|
||||
g_assert_true (dev == sink);
|
||||
g_assert_true (
|
||||
WP_STREAM_ID_NONE == wp_base_endpoint_link_get_source_stream (link));
|
||||
g_assert_true (1 == wp_base_endpoint_link_get_sink_stream (link));
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep2);
|
||||
|
||||
/* Create the third client endpoint without role and make sure it uses the
|
||||
* lowest priority on from the streams file because the endpoint-link file
|
||||
* does not have any either */
|
||||
ep3 = wp_config_policy_context_add_endpoint (ctx, "ep3", "Stream/Output/Fake",
|
||||
PW_DIRECTION_OUTPUT, NULL, NULL, 0);
|
||||
g_assert_nonnull (ep3);
|
||||
g_assert_true (wp_base_endpoint_is_linked (ep3));
|
||||
g_assert_true (wp_base_endpoint_is_linked (dev));
|
||||
link = g_ptr_array_index (wp_base_endpoint_get_links (ep3), 0);
|
||||
src = wp_base_endpoint_link_get_source_endpoint (link);
|
||||
sink = wp_base_endpoint_link_get_sink_endpoint (link);
|
||||
g_assert_true (ep3 == src);
|
||||
g_assert_true (dev == sink);
|
||||
g_assert_true (
|
||||
WP_STREAM_ID_NONE == wp_base_endpoint_link_get_source_stream (link));
|
||||
g_assert_true (0 == wp_base_endpoint_link_get_sink_stream (link));
|
||||
wp_config_policy_context_remove_endpoint (ctx, ep3);
|
||||
/* Create the items and make sure a link is created */
|
||||
g_autoptr (WpSessionItem) sink = load_item (f, "fakesink", "Audio/Sink");
|
||||
g_assert_nonnull (sink);
|
||||
g_autoptr (WpSessionItem) source = load_adapter_item (f, "audiotestsrc",
|
||||
"Audio/Source", 2);
|
||||
g_assert_nonnull (source);
|
||||
g_main_loop_run (f->base.loop);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -381,18 +248,8 @@ main (int argc, char *argv[])
|
|||
g_test_init (&argc, &argv, NULL);
|
||||
wp_init (WP_INIT_ALL);
|
||||
|
||||
g_test_add ("/modules/config-policy/playback", TestConfigPolicyFixture,
|
||||
g_test_add ("/modules/config-policy/playback", TestFixture,
|
||||
NULL, config_policy_setup, playback, config_policy_teardown);
|
||||
g_test_add ("/modules/config-policy/capture", TestConfigPolicyFixture,
|
||||
NULL, config_policy_setup, capture, config_policy_teardown);
|
||||
g_test_add ("/modules/config-policy/playback-capture", TestConfigPolicyFixture,
|
||||
NULL, config_policy_setup, playback_capture, config_policy_teardown);
|
||||
g_test_add ("/modules/config-policy/playback-priority", TestConfigPolicyFixture,
|
||||
NULL, config_policy_setup, playback_priority, config_policy_teardown);
|
||||
g_test_add ("/modules/config-policy/playback-keep", TestConfigPolicyFixture,
|
||||
NULL, config_policy_setup, playback_keep, config_policy_teardown);
|
||||
g_test_add ("/modules/config-policy/playback-role", TestConfigPolicyFixture,
|
||||
NULL, config_policy_setup, playback_role, config_policy_teardown);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
[match-endpoint]
|
||||
direction = "sink"
|
||||
media_class = "Stream/Input/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Source"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
[match-endpoint]
|
||||
direction = "sink"
|
||||
media_class = "Stream/Input/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Source"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
[match-endpoint]
|
||||
direction = "source"
|
||||
media_class = "Stream/Output/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Sink"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
[match-endpoint]
|
||||
direction = "source"
|
||||
media_class = "Stream/Output/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Sink"
|
||||
|
||||
[endpoint-link]
|
||||
keep = true
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
[match-endpoint]
|
||||
direction = "source"
|
||||
name = "ep_for_stream_1"
|
||||
media_class = "Stream/Output/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Sink"
|
||||
stream = "1"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
[match-endpoint]
|
||||
direction = "source"
|
||||
name = "ep_for_stream_2"
|
||||
media_class = "Stream/Output/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Sink"
|
||||
stream = "2"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
[match-endpoint]
|
||||
direction = "source"
|
||||
name = "ep_for_stream_3"
|
||||
media_class = "Stream/Output/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Sink"
|
||||
stream = "3"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
[match-endpoint]
|
||||
direction = "source"
|
||||
name = "ep_with_role"
|
||||
media_class = "Stream/Output/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Sink"
|
||||
streams = "default.streams"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
[match-endpoint]
|
||||
name = "ep1"
|
||||
direction = "source"
|
||||
media_class = "Stream/Output/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Sink"
|
||||
stream = "1"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
[match-endpoint]
|
||||
name = "ep2"
|
||||
direction = "source"
|
||||
media_class = "Stream/Output/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Sink"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
[match-endpoint]
|
||||
name = "ep3"
|
||||
direction = "source"
|
||||
media_class = "Stream/Output/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Sink"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
[match-endpoint]
|
||||
direction = "source"
|
||||
media_class = "Stream/Output/Fake"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Fake/Sink"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
#include "context.h"
|
||||
#include "endpoint-fake.h"
|
||||
#include "endpoint-link-fake.h"
|
||||
#include "../../../modules/module-config-policy/parser-endpoint-link.h"
|
||||
#include "../../../modules/module-config-policy/config-policy.h"
|
||||
|
||||
struct _WpConfigPolicyContext
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
/* Props */
|
||||
GWeakRef core;
|
||||
GMainLoop *loop;
|
||||
char *config_path;
|
||||
|
||||
WpConfigPolicy *policy;
|
||||
GWeakRef last_endpoint;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CORE,
|
||||
PROP_LOOP,
|
||||
PROP_CONFIG_PATH,
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (WpConfigPolicyContext, wp_config_policy_context, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
on_done (WpConfigPolicyContext *self)
|
||||
{
|
||||
g_return_if_fail (self->loop);
|
||||
g_main_loop_quit (self->loop);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_constructed (GObject *object)
|
||||
{
|
||||
WpConfigPolicyContext *self = WP_CONFIG_POLICY_CONTEXT (object);
|
||||
g_autoptr (WpCore) core = g_weak_ref_get (&self->core);
|
||||
g_return_if_fail (core);
|
||||
|
||||
/* Register the endpoint link fake factory */
|
||||
wp_factory_new (core, WP_FAKE_ENDPOINT_LINK_FACTORY_NAME,
|
||||
wp_fake_endpoint_link_factory);
|
||||
|
||||
/* Set the configuration path */
|
||||
g_autoptr (WpConfiguration) config = wp_configuration_get_instance (core);
|
||||
wp_configuration_add_path (config, self->config_path);
|
||||
|
||||
/* Register the config policy */
|
||||
self->policy = wp_config_policy_new (config);
|
||||
wp_policy_register (WP_POLICY (self->policy), core);
|
||||
|
||||
/* Handle the done signal */
|
||||
g_signal_connect_object (self->policy, "done", (GCallback) on_done, self,
|
||||
G_CONNECT_SWAPPED);
|
||||
|
||||
G_OBJECT_CLASS (wp_config_policy_context_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpConfigPolicyContext *self = WP_CONFIG_POLICY_CONTEXT (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_CORE:
|
||||
g_weak_ref_set (&self->core, g_value_get_object (value));
|
||||
break;
|
||||
case PROP_LOOP:
|
||||
self->loop = g_value_get_pointer (value);
|
||||
break;
|
||||
case PROP_CONFIG_PATH:
|
||||
self->config_path = g_value_dup_string (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpConfigPolicyContext *self = WP_CONFIG_POLICY_CONTEXT (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_CORE:
|
||||
g_value_take_object (value, g_weak_ref_get (&self->core));
|
||||
break;
|
||||
case PROP_LOOP:
|
||||
g_value_set_pointer (value, self->loop);
|
||||
break;
|
||||
case PROP_CONFIG_PATH:
|
||||
g_value_set_string (value, self->config_path);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_finalize (GObject * object)
|
||||
{
|
||||
WpConfigPolicyContext *self = WP_CONFIG_POLICY_CONTEXT (object);
|
||||
|
||||
g_weak_ref_clear (&self->last_endpoint);
|
||||
|
||||
if (self->policy)
|
||||
wp_policy_unregister (WP_POLICY (self->policy));
|
||||
g_clear_object (&self->policy);
|
||||
|
||||
self->loop = NULL;
|
||||
g_weak_ref_clear (&self->core);
|
||||
|
||||
G_OBJECT_CLASS (wp_config_policy_context_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_init (WpConfigPolicyContext * self)
|
||||
{
|
||||
g_weak_ref_init (&self->core, NULL);
|
||||
self->loop = NULL;
|
||||
|
||||
g_weak_ref_init (&self->last_endpoint, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_config_policy_context_class_init (WpConfigPolicyContextClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
|
||||
object_class->constructed = wp_config_policy_context_constructed;
|
||||
object_class->finalize = wp_config_policy_context_finalize;
|
||||
object_class->set_property = wp_config_policy_context_set_property;
|
||||
object_class->get_property = wp_config_policy_context_get_property;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_CORE,
|
||||
g_param_spec_object ("core", "core", "The wireplumber core", WP_TYPE_CORE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_LOOP,
|
||||
g_param_spec_pointer ("loop", "loop", "The main loop where pipewire runs",
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_CONFIG_PATH,
|
||||
g_param_spec_string ("config-path", "config-path",
|
||||
"The config-path of the context", NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
WpConfigPolicyContext *
|
||||
wp_config_policy_context_new (WpCore *core, GMainLoop *loop,
|
||||
const char *config_path)
|
||||
{
|
||||
return g_object_new (wp_config_policy_context_get_type (),
|
||||
"core", core,
|
||||
"loop", loop,
|
||||
"config-path", config_path,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
on_endpoint_created (GObject *initable, GAsyncResult *res, gpointer data)
|
||||
{
|
||||
WpConfigPolicyContext *self = data;
|
||||
GError *error = NULL;
|
||||
g_autoptr (WpBaseEndpoint) ep = NULL;
|
||||
|
||||
ep = wp_base_endpoint_new_finish (initable, res, &error);
|
||||
g_return_if_fail (!error);
|
||||
g_return_if_fail (ep);
|
||||
|
||||
/* Update last endpoint weak ref */
|
||||
g_weak_ref_set (&self->last_endpoint, ep);
|
||||
|
||||
/* Register the endpoint */
|
||||
wp_base_endpoint_register (ep);
|
||||
}
|
||||
|
||||
WpBaseEndpoint *
|
||||
wp_config_policy_context_add_endpoint (WpConfigPolicyContext *self,
|
||||
const char *name, const char *media_class, guint direction,
|
||||
WpProperties *props, const char *role, guint streams)
|
||||
{
|
||||
g_autoptr (WpCore) core = g_weak_ref_get (&self->core);
|
||||
g_return_val_if_fail (core, NULL);
|
||||
|
||||
wp_fake_endpoint_new_async (core, name, media_class, direction, props, role,
|
||||
streams, on_endpoint_created, self);
|
||||
|
||||
g_main_loop_run (self->loop);
|
||||
return g_weak_ref_get(&self->last_endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
wp_config_policy_context_remove_endpoint (WpConfigPolicyContext *self,
|
||||
WpBaseEndpoint *ep)
|
||||
{
|
||||
g_return_if_fail (ep);
|
||||
|
||||
wp_base_endpoint_unregister (ep);
|
||||
g_main_loop_run (self->loop);
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __WIREPLUMBER_CONFIG_POLICY_CONTEXT_H__
|
||||
#define __WIREPLUMBER_CONFIG_POLICY_CONTEXT_H__
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
static const guint CONFIG_POLICY_CONTEXT_ID_NONE = G_MAXUINT;
|
||||
|
||||
G_DECLARE_FINAL_TYPE (WpConfigPolicyContext, wp_config_policy_context, WP,
|
||||
CONFIG_POLICY_CONTEXT, GObject);
|
||||
|
||||
WpConfigPolicyContext *wp_config_policy_context_new (WpCore *core,
|
||||
GMainLoop *loop, const char *config_path);
|
||||
WpBaseEndpoint *wp_config_policy_context_add_endpoint (WpConfigPolicyContext *self,
|
||||
const char *name, const char *media_class, guint direction,
|
||||
WpProperties *props, const char *role, guint streams);
|
||||
void wp_config_policy_context_remove_endpoint (WpConfigPolicyContext *self,
|
||||
WpBaseEndpoint *ep);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
@ -1,253 +0,0 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
#include "endpoint-fake.h"
|
||||
#include "endpoint-link-fake.h"
|
||||
|
||||
struct _WpFakeEndpoint
|
||||
{
|
||||
WpBaseEndpoint parent;
|
||||
GTask *init_task;
|
||||
guint id;
|
||||
|
||||
/* Props */
|
||||
WpProperties *props;
|
||||
char *role;
|
||||
guint streams;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PROPS,
|
||||
PROP_ROLE,
|
||||
PROP_STREAMS,
|
||||
};
|
||||
|
||||
static GAsyncInitableIface *wp_fake_endpoint_parent_interface = NULL;
|
||||
static void wp_fake_endpoint_async_initable_init (gpointer iface,
|
||||
gpointer iface_data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (WpFakeEndpoint, wp_fake_endpoint, WP_TYPE_BASE_ENDPOINT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
|
||||
wp_fake_endpoint_async_initable_init))
|
||||
|
||||
static WpProperties *
|
||||
wp_fake_endpoint_get_properties (WpBaseEndpoint * ep)
|
||||
{
|
||||
WpFakeEndpoint *self = WP_FAKE_ENDPOINT (ep);
|
||||
return wp_properties_ref (self->props);
|
||||
}
|
||||
|
||||
static const char *
|
||||
wp_fake_endpoint_get_role (WpBaseEndpoint * ep)
|
||||
{
|
||||
WpFakeEndpoint *self = WP_FAKE_ENDPOINT (ep);
|
||||
return self->role;
|
||||
}
|
||||
|
||||
static guint32
|
||||
wp_fake_endpoint_get_global_id (WpBaseEndpoint * ep)
|
||||
{
|
||||
WpFakeEndpoint *self = WP_FAKE_ENDPOINT (ep);
|
||||
return self->id;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wp_fake_endpoint_prepare_link (WpBaseEndpoint * ep, guint32 stream_id,
|
||||
WpBaseEndpointLink * link, GVariant ** properties, GError ** error)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_begin_fade (WpBaseEndpoint * ep, guint32 stream_id,
|
||||
guint duration, gfloat step, guint direction, guint type,
|
||||
GCancellable * cancellable, GAsyncReadyCallback callback, gpointer data)
|
||||
{
|
||||
g_autoptr (GTask) task = g_task_new (ep, cancellable, callback, data);
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static const char *
|
||||
wp_fake_endpoint_get_endpoint_link_factory (WpBaseEndpoint * ep)
|
||||
{
|
||||
return WP_FAKE_ENDPOINT_LINK_FACTORY_NAME;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_constructed (GObject * object)
|
||||
{
|
||||
WpFakeEndpoint *self = WP_FAKE_ENDPOINT (object);
|
||||
GVariantDict d;
|
||||
|
||||
for (guint i = 0; i < self->streams; i++) {
|
||||
g_autofree gchar *name = g_strdup_printf ("%u", i);
|
||||
g_variant_dict_init (&d, NULL);
|
||||
g_variant_dict_insert (&d, "id", "u", i);
|
||||
g_variant_dict_insert (&d, "name", "s", name);
|
||||
g_variant_dict_insert (&d, "priority", "u", i);
|
||||
wp_base_endpoint_register_stream (WP_BASE_ENDPOINT (self), g_variant_dict_end (&d));
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (wp_fake_endpoint_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpFakeEndpoint *self = WP_FAKE_ENDPOINT (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_PROPS:
|
||||
g_clear_pointer (&self->props, wp_properties_unref);
|
||||
self->props = g_value_dup_boxed (value);
|
||||
if (!self->props)
|
||||
self->props = wp_properties_new_empty ();
|
||||
break;
|
||||
case PROP_ROLE:
|
||||
g_clear_pointer (&self->role, g_free);
|
||||
self->role = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_STREAMS:
|
||||
self->streams = g_value_get_uint (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpFakeEndpoint *self = WP_FAKE_ENDPOINT (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_PROPS:
|
||||
g_value_take_boxed (value, self->props);
|
||||
break;
|
||||
case PROP_ROLE:
|
||||
g_value_set_string (value, self->role);
|
||||
break;
|
||||
case PROP_STREAMS:
|
||||
g_value_set_uint (value, self->streams);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_finalize (GObject * object)
|
||||
{
|
||||
WpFakeEndpoint *self = WP_FAKE_ENDPOINT (object);
|
||||
g_clear_pointer (&self->props, wp_properties_unref);
|
||||
G_OBJECT_CLASS (wp_fake_endpoint_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wp_fake_endpoint_finish_creation (gpointer d)
|
||||
{
|
||||
WpFakeEndpoint *self = d;
|
||||
|
||||
g_task_return_boolean (self->init_task, TRUE);
|
||||
g_clear_object (&self->init_task);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_init_async (GAsyncInitable *initable, int io_priority,
|
||||
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
|
||||
{
|
||||
WpFakeEndpoint *self = WP_FAKE_ENDPOINT (initable);
|
||||
|
||||
self->init_task = g_task_new (initable, cancellable, callback, data);
|
||||
|
||||
wp_fake_endpoint_parent_interface->init_async (initable, io_priority,
|
||||
cancellable, callback, data);
|
||||
|
||||
g_autoptr (WpCore) core = wp_base_endpoint_get_core (WP_BASE_ENDPOINT(self));
|
||||
g_return_if_fail (core);
|
||||
|
||||
wp_core_idle_add (core, NULL, wp_fake_endpoint_finish_creation, self, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_async_initable_init (gpointer iface, gpointer iface_data)
|
||||
{
|
||||
GAsyncInitableIface *ai_iface = iface;
|
||||
wp_fake_endpoint_parent_interface = g_type_interface_peek_parent (iface);
|
||||
ai_iface->init_async = wp_fake_endpoint_init_async;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_init (WpFakeEndpoint * self)
|
||||
{
|
||||
static guint id = 0;
|
||||
self->id = id++;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_class_init (WpFakeEndpointClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
WpBaseEndpointClass *endpoint_class = (WpBaseEndpointClass *) klass;
|
||||
|
||||
object_class->constructed = wp_fake_endpoint_constructed;
|
||||
object_class->finalize = wp_fake_endpoint_finalize;
|
||||
object_class->set_property = wp_fake_endpoint_set_property;
|
||||
object_class->get_property = wp_fake_endpoint_get_property;
|
||||
|
||||
endpoint_class->get_properties = wp_fake_endpoint_get_properties;
|
||||
endpoint_class->get_role = wp_fake_endpoint_get_role;
|
||||
endpoint_class->get_global_id = wp_fake_endpoint_get_global_id;
|
||||
endpoint_class->prepare_link = wp_fake_endpoint_prepare_link;
|
||||
endpoint_class->begin_fade = wp_fake_endpoint_begin_fade;
|
||||
endpoint_class->get_endpoint_link_factory =
|
||||
wp_fake_endpoint_get_endpoint_link_factory;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PROPS,
|
||||
g_param_spec_boxed ("properties", "properties",
|
||||
"The properties of the fake endpoint", WP_TYPE_PROPERTIES,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ROLE,
|
||||
g_param_spec_string ("role", "role",
|
||||
"The role of the fake endpoint", NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_STREAMS,
|
||||
g_param_spec_uint ("streams", "streams",
|
||||
"The number of streams this endpoint has", 0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
void
|
||||
wp_fake_endpoint_new_async (WpCore *core, const char *name,
|
||||
const char *media_class, guint direction,
|
||||
WpProperties *props, const char *role, guint streams,
|
||||
GAsyncReadyCallback ready, gpointer data)
|
||||
{
|
||||
g_async_initable_new_async (
|
||||
wp_fake_endpoint_get_type (), G_PRIORITY_DEFAULT, NULL, ready, data,
|
||||
"core", core,
|
||||
"name", name,
|
||||
"media-class", media_class,
|
||||
"direction", direction,
|
||||
"priority", 0,
|
||||
"properties", props,
|
||||
"role", role,
|
||||
"streams", streams,
|
||||
NULL);
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __WIREPLUMBER_FAKE_ENDPOINT_H__
|
||||
#define __WIREPLUMBER_FAKE_ENDPOINT_H__
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_DECLARE_FINAL_TYPE (WpFakeEndpoint, wp_fake_endpoint, WP, FAKE_ENDPOINT,
|
||||
WpBaseEndpoint)
|
||||
|
||||
void
|
||||
wp_fake_endpoint_new_async (WpCore *core, const char *name,
|
||||
const char *media_class, guint direction,
|
||||
WpProperties *props, const char *role, guint streams,
|
||||
GAsyncReadyCallback ready, gpointer data);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
#include "endpoint-fake.h"
|
||||
#include "endpoint-link-fake.h"
|
||||
|
||||
struct _WpFakeEndpointLink
|
||||
{
|
||||
WpBaseEndpointLink parent;
|
||||
GTask *init_task;
|
||||
guint id;
|
||||
|
||||
/* Props */
|
||||
GWeakRef core;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CORE
|
||||
};
|
||||
|
||||
static GAsyncInitableIface *wp_fake_endpoint_link_parent_interface = NULL;
|
||||
static void wp_fake_endpoint_link_async_initable_init (gpointer iface,
|
||||
gpointer iface_data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (WpFakeEndpointLink, wp_fake_endpoint_link,
|
||||
WP_TYPE_BASE_ENDPOINT_LINK,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
|
||||
wp_fake_endpoint_link_async_initable_init))
|
||||
|
||||
static gboolean
|
||||
wp_fake_endpoint_link_create (WpBaseEndpointLink * epl, GVariant * src_data,
|
||||
GVariant * sink_data, GError ** error)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_link_destroy (WpBaseEndpointLink * epl)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_link_set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpFakeEndpointLink *self = WP_FAKE_ENDPOINT_LINK (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_CORE:
|
||||
g_weak_ref_set (&self->core, g_value_get_object (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_link_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpFakeEndpointLink *self = WP_FAKE_ENDPOINT_LINK (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_CORE:
|
||||
g_value_take_object (value, g_weak_ref_get (&self->core));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_link_finalize (GObject * object)
|
||||
{
|
||||
WpFakeEndpointLink *self = WP_FAKE_ENDPOINT_LINK (object);
|
||||
g_clear_object (&self->init_task);
|
||||
g_weak_ref_clear (&self->core);
|
||||
G_OBJECT_CLASS (wp_fake_endpoint_link_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wp_fake_endpoint_link_finish_creation (gpointer d)
|
||||
{
|
||||
WpFakeEndpointLink *self = d;
|
||||
|
||||
g_task_return_boolean (self->init_task, TRUE);
|
||||
g_clear_object (&self->init_task);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_link_init_async (GAsyncInitable *initable, int io_priority,
|
||||
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
|
||||
{
|
||||
WpFakeEndpointLink *self = WP_FAKE_ENDPOINT_LINK (initable);
|
||||
|
||||
self->init_task = g_task_new (initable, cancellable, callback, data);
|
||||
|
||||
wp_fake_endpoint_link_parent_interface->init_async (initable,
|
||||
io_priority, cancellable, callback, data);
|
||||
|
||||
g_autoptr (WpCore) core = g_weak_ref_get (&self->core);
|
||||
g_return_if_fail (core);
|
||||
|
||||
wp_core_idle_add (core, NULL, wp_fake_endpoint_link_finish_creation, self, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_link_async_initable_init (gpointer iface,
|
||||
gpointer iface_data)
|
||||
{
|
||||
GAsyncInitableIface *ai_iface = iface;
|
||||
wp_fake_endpoint_link_parent_interface = g_type_interface_peek_parent (iface);
|
||||
ai_iface->init_async = wp_fake_endpoint_link_init_async;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_link_init (WpFakeEndpointLink * self)
|
||||
{
|
||||
static guint id = 0;
|
||||
self->id = id++;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_fake_endpoint_link_class_init (WpFakeEndpointLinkClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
WpBaseEndpointLinkClass *link_class = (WpBaseEndpointLinkClass *) klass;
|
||||
|
||||
object_class->finalize = wp_fake_endpoint_link_finalize;
|
||||
object_class->get_property = wp_fake_endpoint_link_get_property;
|
||||
object_class->set_property = wp_fake_endpoint_link_set_property;
|
||||
|
||||
link_class->create = wp_fake_endpoint_link_create;
|
||||
link_class->destroy = wp_fake_endpoint_link_destroy;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_CORE,
|
||||
g_param_spec_object ("core", "core", "The wireplumber core",
|
||||
WP_TYPE_CORE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
void
|
||||
wp_fake_endpoint_link_factory (WpFactory * factory, GType type,
|
||||
GVariant * properties, GAsyncReadyCallback ready, gpointer data)
|
||||
{
|
||||
g_autoptr (WpCore) core = NULL;
|
||||
guint64 src, sink;
|
||||
guint src_stream, sink_stream;
|
||||
gboolean keep;
|
||||
|
||||
/* Get the Core */
|
||||
core = wp_factory_get_core(factory);
|
||||
g_return_if_fail (core);
|
||||
|
||||
/* Get the properties */
|
||||
if (!g_variant_lookup (properties, "src", "t", &src))
|
||||
return;
|
||||
if (!g_variant_lookup (properties, "src-stream", "u", &src_stream))
|
||||
return;
|
||||
if (!g_variant_lookup (properties, "sink", "t", &sink))
|
||||
return;
|
||||
if (!g_variant_lookup (properties, "sink-stream", "u", &sink_stream))
|
||||
return;
|
||||
if (!g_variant_lookup (properties, "keep", "b", &keep))
|
||||
return;
|
||||
|
||||
/* Create the endpoint link */
|
||||
g_async_initable_new_async (
|
||||
wp_fake_endpoint_link_get_type (), G_PRIORITY_DEFAULT, NULL, ready, data,
|
||||
"src", (gpointer)src,
|
||||
"src-stream", src_stream,
|
||||
"sink", (gpointer)sink,
|
||||
"sink-stream", sink_stream,
|
||||
"keep", keep,
|
||||
"core", core,
|
||||
NULL);
|
||||
}
|
||||
|
||||
guint
|
||||
wp_fake_endpoint_link_get_id (WpFakeEndpointLink *self)
|
||||
{
|
||||
return self->id;
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __WIREPLUMBER_FAKE_ENDPOINT_LINK_H__
|
||||
#define __WIREPLUMBER_FAKE_ENDPOINT_LINK_H__
|
||||
|
||||
#include <wp/wp.h>
|
||||
|
||||
#define WP_FAKE_ENDPOINT_LINK_FACTORY_NAME "endpoint-link-fake"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_DECLARE_FINAL_TYPE (WpFakeEndpointLink, wp_fake_endpoint_link, WP,
|
||||
FAKE_ENDPOINT_LINK, WpBaseEndpointLink)
|
||||
|
||||
void wp_fake_endpoint_link_factory (WpFactory * factory, GType type,
|
||||
GVariant * properties, GAsyncReadyCallback ready, gpointer data);
|
||||
|
||||
guint wp_fake_endpoint_link_get_id (WpFakeEndpointLink *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
[match-endpoint]
|
||||
media_class = "Audio/Source"
|
||||
|
||||
[target-endpoint]
|
||||
media_class = "Audio/Sink"
|
||||
|
||||
[endpoint-link]
|
||||
keep = false
|
||||
|
|
@ -52,11 +52,8 @@ test(
|
|||
executable('test-config-policy',
|
||||
[
|
||||
'config-policy.c',
|
||||
'config-policy/context.c',
|
||||
'config-policy/endpoint-fake.c',
|
||||
'config-policy/endpoint-link-fake.c',
|
||||
'../../modules/module-config-policy/config-policy.c',
|
||||
'../../modules/module-config-policy/parser-endpoint-link.c'
|
||||
'../../modules/module-config-policy/parser-endpoint-link.c',
|
||||
'../../modules/module-config-policy/context.c',
|
||||
],
|
||||
dependencies: common_deps + [wptoml_dep], c_args: common_args),
|
||||
env: common_env,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue