mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-08 10:28:03 +02:00
lib: add new WpPolicy class and basic policy management functionality
This commit is contained in:
parent
18f3e764c0
commit
25d70c5446
6 changed files with 408 additions and 0 deletions
|
|
@ -219,3 +219,4 @@ G_DEFINE_QUARK (pw-remote, wp_global_pw_remote)
|
|||
G_DEFINE_QUARK (endpoint, wp_global_endpoint)
|
||||
G_DEFINE_QUARK (factory, wp_global_factory)
|
||||
G_DEFINE_QUARK (module, wp_global_module)
|
||||
G_DEFINE_QUARK (policy-manager, wp_global_policy_manager)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ GQuark wp_global_factory_quark (void);
|
|||
#define WP_GLOBAL_MODULE (wp_global_module_quark ())
|
||||
GQuark wp_global_module_quark (void);
|
||||
|
||||
#define WP_GLOBAL_POLICY_MANAGER (wp_global_policy_manager_quark ())
|
||||
GQuark wp_global_policy_manager_quark (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ wp_lib_sources = [
|
|||
'error.c',
|
||||
'factory.c',
|
||||
'module.c',
|
||||
'policy.c',
|
||||
]
|
||||
|
||||
wp_lib_headers = [
|
||||
|
|
@ -12,6 +13,7 @@ wp_lib_headers = [
|
|||
'error.h',
|
||||
'factory.h',
|
||||
'module.h',
|
||||
'policy.h',
|
||||
'wp.h',
|
||||
]
|
||||
|
||||
|
|
|
|||
335
lib/wp/policy.c
Normal file
335
lib/wp/policy.c
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "policy.h"
|
||||
|
||||
/* WpPolicyManager */
|
||||
|
||||
struct _WpPolicyManager
|
||||
{
|
||||
GObject parent;
|
||||
GList *policies;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (WpPolicyManager, wp_policy_manager, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
wp_policy_manager_init (WpPolicyManager *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wp_policy_manager_finalize (GObject *object)
|
||||
{
|
||||
WpPolicyManager *self = WP_POLICY_MANAGER (object);
|
||||
|
||||
g_list_free_full (self->policies, g_object_unref);
|
||||
|
||||
G_OBJECT_CLASS (wp_policy_manager_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_policy_manager_class_init (WpPolicyManagerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
|
||||
object_class->finalize = wp_policy_manager_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
policy_mgr_endpoint_added (WpCore *core, GQuark key, WpEndpoint *ep,
|
||||
WpPolicyManager *self)
|
||||
{
|
||||
GList *l;
|
||||
WpPolicy *p;
|
||||
gboolean handled = FALSE;
|
||||
|
||||
for (l = g_list_first (self->policies); l; l = g_list_next (l)) {
|
||||
p = WP_POLICY (l->data);
|
||||
|
||||
if (WP_POLICY_GET_CLASS (p)->endpoint_added)
|
||||
WP_POLICY_GET_CLASS (p)->endpoint_added (p, ep);
|
||||
|
||||
if (!handled && WP_POLICY_GET_CLASS (p)->handle_endpoint)
|
||||
handled = WP_POLICY_GET_CLASS (p)->handle_endpoint (p, ep);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
policy_mgr_endpoint_removed (WpCore *core, GQuark key, WpEndpoint *ep,
|
||||
WpPolicyManager *self)
|
||||
{
|
||||
GList *l;
|
||||
WpPolicy *p;
|
||||
|
||||
for (l = g_list_first (self->policies); l; l = g_list_next (l)) {
|
||||
p = WP_POLICY (l->data);
|
||||
|
||||
if (WP_POLICY_GET_CLASS (p)->endpoint_removed)
|
||||
WP_POLICY_GET_CLASS (p)->endpoint_removed (p, ep);
|
||||
}
|
||||
}
|
||||
|
||||
static WpPolicyManager *
|
||||
wp_policy_manager_new (WpCore *core)
|
||||
{
|
||||
WpPolicyManager *mgr = g_object_new (WP_TYPE_POLICY_MANAGER, NULL);
|
||||
|
||||
g_signal_connect_object (core, "global-added::endpoint",
|
||||
(GCallback) policy_mgr_endpoint_added, mgr, 0);
|
||||
g_signal_connect_object (core, "global-removed::endpoint",
|
||||
(GCallback) policy_mgr_endpoint_removed, mgr, 0);
|
||||
|
||||
wp_core_register_global (core, WP_GLOBAL_POLICY_MANAGER, mgr,
|
||||
g_object_unref);
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
/* WpPolicy */
|
||||
|
||||
/**
|
||||
* WpPolicyClass::endpoint_added:
|
||||
* @self: the policy
|
||||
* @ep: the endpoint
|
||||
*
|
||||
* Called when a new endpoint has been added.
|
||||
* This is only informative, to be used for internal bookeeping purposes.
|
||||
* No action should be taken to do something with this endpoint.
|
||||
*/
|
||||
|
||||
/**
|
||||
* WpPolicyClass::endpoint_removed:
|
||||
* @self: the policy
|
||||
* @ep: the endpoint
|
||||
*
|
||||
* Called when an endpoint has been removed.
|
||||
* This is only informative, to be used for internal bookeeping purposes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* WpPolicyClass::handle_endpoint:
|
||||
* @self: the policy
|
||||
* @ep: the endpoint
|
||||
*
|
||||
* Called when a new endpoint has been added.
|
||||
* The policy is meant to decide if this endpoint needs to be linked
|
||||
* somewhere and if so, create the link.
|
||||
* This will only be called if no other higher-ranked policy has already
|
||||
* handled this endpoint.
|
||||
*
|
||||
* Returns: TRUE if this policy did handle the endpoint, FALSE to let some
|
||||
* lower-ranked policy to try
|
||||
*/
|
||||
|
||||
/**
|
||||
* WpPolicyClass::find_endpoint:
|
||||
* @self: the policy
|
||||
* @props: properties of the lookup
|
||||
* @stream_id: (out): the relevant stream id of the returned endpoint
|
||||
*
|
||||
* Called to locate an endpoint with a specific set of properties,
|
||||
* which may be used to implement decision making when multiple endpoints
|
||||
* can match.
|
||||
*
|
||||
* The most notorious use case of this function is to locate a target
|
||||
* device endpoint in order to link a client one.
|
||||
*
|
||||
* @props is expected to be a dictionary (a{sv}) GVariant with keys that
|
||||
* describe the situation. Some of these keys can be:
|
||||
* * "action" (s): Currently the value can be "link" or "mixer". "link" is
|
||||
* to find a target for linking a client. "mixer" is to find a target
|
||||
* to modify mixer controls.
|
||||
* * "media.role" (s): the role of the media stream, as defined in pipewire
|
||||
* * "media.class" (s): the media class that the returned endpoint is supposed
|
||||
* to have (policy is free to ignore this)
|
||||
* * "target.properties" (a{sv}): the properties of the other endpoint in case
|
||||
* the action is "link"
|
||||
*
|
||||
* @stream_id is to be set to the stream id of the returned endpoint that
|
||||
* the policy wants to be used for this action.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): the found endpoint, or NULL
|
||||
*/
|
||||
|
||||
typedef struct _WpPolicyPrivate WpPolicyPrivate;
|
||||
struct _WpPolicyPrivate
|
||||
{
|
||||
guint32 rank;
|
||||
WpCore *core;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_RANK
|
||||
};
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpPolicy, wp_policy, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
wp_policy_init (WpPolicy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wp_policy_set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpPolicyPrivate *priv = wp_policy_get_instance_private (WP_POLICY (object));
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_RANK:
|
||||
priv->rank = g_value_get_uint (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_policy_get_property (GObject * object, guint property_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
WpPolicyPrivate *priv = wp_policy_get_instance_private (WP_POLICY (object));
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_RANK:
|
||||
g_value_set_uint (value, priv->rank);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
wp_policy_class_init (WpPolicyClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
|
||||
object_class->set_property = wp_policy_set_property;
|
||||
object_class->get_property = wp_policy_get_property;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_RANK,
|
||||
g_param_spec_uint ("rank", "rank", "The rank of the policy",
|
||||
0, G_MAXINT32, WP_POLICY_RANK_UPSTREAM,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
guint32
|
||||
wp_policy_get_rank (WpPolicy *self)
|
||||
{
|
||||
WpPolicyPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (WP_IS_POLICY (self), 0);
|
||||
|
||||
priv = wp_policy_get_instance_private (self);
|
||||
return priv->rank;
|
||||
}
|
||||
|
||||
WpCore *
|
||||
wp_policy_get_core (WpPolicy *self)
|
||||
{
|
||||
WpPolicyPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (WP_IS_POLICY (self), NULL);
|
||||
|
||||
priv = wp_policy_get_instance_private (self);
|
||||
return priv->core ? g_object_ref (priv->core) : NULL;
|
||||
}
|
||||
|
||||
static gint
|
||||
compare_ranks (const WpPolicy * a, const WpPolicy * b)
|
||||
{
|
||||
WpPolicyPrivate *a_priv = wp_policy_get_instance_private ((WpPolicy *) a);
|
||||
WpPolicyPrivate *b_priv = wp_policy_get_instance_private ((WpPolicy *) b);
|
||||
return (gint) b_priv->rank - (gint) a_priv->rank;
|
||||
}
|
||||
|
||||
void
|
||||
wp_policy_register (WpPolicy *self, WpCore *core)
|
||||
{
|
||||
WpPolicyManager *mgr;
|
||||
WpPolicyPrivate *priv;
|
||||
|
||||
g_return_if_fail (WP_IS_POLICY (self));
|
||||
g_return_if_fail (WP_IS_CORE (core));
|
||||
|
||||
mgr = wp_core_get_global (core, WP_GLOBAL_POLICY_MANAGER);
|
||||
if (G_UNLIKELY (!mgr))
|
||||
mgr = wp_policy_manager_new (core);
|
||||
|
||||
mgr->policies = g_list_insert_sorted (mgr->policies, g_object_ref (self),
|
||||
(GCompareFunc) compare_ranks);
|
||||
|
||||
priv = wp_policy_get_instance_private (self);
|
||||
priv->core = core;
|
||||
}
|
||||
|
||||
void
|
||||
wp_policy_unregister (WpPolicy *self)
|
||||
{
|
||||
WpPolicyManager *mgr;
|
||||
WpPolicyPrivate *priv;
|
||||
|
||||
g_return_if_fail (WP_IS_POLICY (self));
|
||||
|
||||
priv = wp_policy_get_instance_private (self);
|
||||
|
||||
if (priv->core) {
|
||||
mgr = wp_core_get_global (priv->core, WP_GLOBAL_POLICY_MANAGER);
|
||||
if (G_UNLIKELY (!mgr)) {
|
||||
g_critical ("WpPolicy:%p seems registered, but the policy manager "
|
||||
"is absent", self);
|
||||
return;
|
||||
}
|
||||
|
||||
mgr->policies = g_list_remove (mgr->policies, self);
|
||||
g_object_unref (self);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_policy_find_endpoint:
|
||||
* @core: the #WpCore
|
||||
* @props: properties of the lookup
|
||||
* @stream_id: (out): the relevant stream id of the returned endpoint
|
||||
*
|
||||
* Calls #WpPolicyClass::find_endpoint on all policies, in order, until
|
||||
* it finds a suitable endpoint.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): the found endpoint, or NULL
|
||||
*/
|
||||
WpEndpoint *
|
||||
wp_policy_find_endpoint (WpCore *core, GVariant *props,
|
||||
guint32 *stream_id)
|
||||
{
|
||||
WpPolicyManager *mgr;
|
||||
GList *l;
|
||||
WpPolicy *p;
|
||||
WpEndpoint * ret;
|
||||
|
||||
g_return_val_if_fail (WP_IS_CORE (core), NULL);
|
||||
g_return_val_if_fail (g_variant_is_of_type (props, G_VARIANT_TYPE_VARDICT), NULL);
|
||||
g_return_val_if_fail (stream_id != NULL, NULL);
|
||||
|
||||
mgr = wp_core_get_global (core, WP_GLOBAL_POLICY_MANAGER);
|
||||
if (mgr) {
|
||||
for (l = g_list_first (mgr->policies); l; l = g_list_next (l)) {
|
||||
p = WP_POLICY (l->data);
|
||||
|
||||
if (WP_POLICY_GET_CLASS (p)->find_endpoint &&
|
||||
(ret = WP_POLICY_GET_CLASS (p)->find_endpoint (p, props, stream_id)))
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
66
lib/wp/policy.h
Normal file
66
lib/wp/policy.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __WIREPLUMBER_POLICY_H__
|
||||
#define __WIREPLUMBER_POLICY_H__
|
||||
|
||||
#include "endpoint.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* WpPolicyRank:
|
||||
* @WP_POLICY_RANK_UPSTREAM: should only be used inside WirePlumber
|
||||
* @WP_POLICY_RANK_PLATFORM: policies provided by the platform
|
||||
* @WP_POLICY_RANK_VENDOR: policies provided by hardware vendors
|
||||
*
|
||||
* The rank of a policy is an unsigned integer that can take an arbitrary
|
||||
* value from 0 to G_MAXINT32 (0x7fffffff). On invocation, policies ranked
|
||||
* with a higher number are tried first, which is how one can implement
|
||||
* overrides. This enum provides default values for certain kinds of policies.
|
||||
* Feel free to add/substract numbers to these constants in order to make a
|
||||
* hierarchy, if you are implementing multiple different policies that need to
|
||||
* be tried in a certain order.
|
||||
*/
|
||||
typedef enum {
|
||||
WP_POLICY_RANK_UPSTREAM = 1,
|
||||
WP_POLICY_RANK_PLATFORM = 128,
|
||||
WP_POLICY_RANK_VENDOR = 256,
|
||||
} WpPolicyRank;
|
||||
|
||||
#define WP_TYPE_POLICY_MANAGER (wp_policy_manager_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (WpPolicyManager, wp_policy_manager, WP, POLICY_MANAGER, GObject)
|
||||
|
||||
#define WP_TYPE_POLICY (wp_policy_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (WpPolicy, wp_policy, WP, POLICY, GObject)
|
||||
|
||||
struct _WpPolicyClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*endpoint_added) (WpPolicy *self, WpEndpoint *ep);
|
||||
void (*endpoint_removed) (WpPolicy *self, WpEndpoint *ep);
|
||||
|
||||
gboolean (*handle_endpoint) (WpPolicy *self, WpEndpoint *ep);
|
||||
|
||||
WpEndpoint * (*find_endpoint) (WpPolicy *self, GVariant *props,
|
||||
guint32 *stream_id);
|
||||
};
|
||||
|
||||
guint32 wp_policy_get_rank (WpPolicy *self);
|
||||
WpCore *wp_policy_get_core (WpPolicy *self);
|
||||
|
||||
void wp_policy_register (WpPolicy *self, WpCore *core);
|
||||
void wp_policy_unregister (WpPolicy *self);
|
||||
|
||||
WpEndpoint * wp_policy_find_endpoint (WpCore *core, GVariant *props,
|
||||
guint32 *stream_id);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
@ -11,3 +11,4 @@
|
|||
#include "error.h"
|
||||
#include "factory.h"
|
||||
#include "module.h"
|
||||
#include "policy.h"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue