mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-09 10:58:05 +02:00
lib: implement plugin mechanism and a basic proxy object
This commit is contained in:
parent
a50bb17ed6
commit
6f6e2b0e3e
7 changed files with 1004 additions and 0 deletions
|
|
@ -2,12 +2,18 @@ wp_lib_sources = [
|
|||
'error.c',
|
||||
'interface-impl.c',
|
||||
'object.c',
|
||||
'plugin-registry.c',
|
||||
'plugin.c',
|
||||
'proxy.c',
|
||||
]
|
||||
|
||||
wp_lib_headers = [
|
||||
'error.h',
|
||||
'interface-impl.h',
|
||||
'object.h',
|
||||
'plugin-registry.h',
|
||||
'plugin.h',
|
||||
'proxy.h',
|
||||
]
|
||||
|
||||
enums = gnome.mkenums_simple('wpenums', sources: wp_lib_headers)
|
||||
|
|
|
|||
223
lib/wp/plugin-registry.c
Normal file
223
lib/wp/plugin-registry.c
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "plugin-registry.h"
|
||||
#include "plugin.h"
|
||||
|
||||
typedef struct {
|
||||
gsize block_size;
|
||||
const WpPluginMetadata *metadata;
|
||||
WpPlugin *instance;
|
||||
} PluginData;
|
||||
|
||||
struct _WpPluginRegistry
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
GList *plugins;
|
||||
GStringChunk *metadata_strings;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (WpPluginRegistry, wp_plugin_registry, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
wp_plugin_registry_init (WpPluginRegistry * self)
|
||||
{
|
||||
self->metadata_strings = g_string_chunk_new (200);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_plugin_registry_dispose (GObject * object)
|
||||
{
|
||||
WpPluginRegistry *self = WP_PLUGIN_REGISTRY (object);
|
||||
GList *list;
|
||||
PluginData *plugin_data;
|
||||
|
||||
for (list = self->plugins; list != NULL; list = g_list_next (list)) {
|
||||
plugin_data = list->data;
|
||||
g_clear_object (&plugin_data->instance);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (wp_plugin_registry_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
plugin_data_free (PluginData *data)
|
||||
{
|
||||
g_slice_free1 (data->block_size, data);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_plugin_registry_finalize (GObject * object)
|
||||
{
|
||||
WpPluginRegistry *self = WP_PLUGIN_REGISTRY (object);
|
||||
|
||||
g_list_free_full (self->plugins, (GDestroyNotify) plugin_data_free);
|
||||
g_string_chunk_free (self->metadata_strings);
|
||||
|
||||
G_OBJECT_CLASS (wp_plugin_registry_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_plugin_registry_class_init (WpPluginRegistryClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
object_class->dispose = wp_plugin_registry_dispose;
|
||||
object_class->finalize = wp_plugin_registry_finalize;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_plugin_registry_new: (constructor)
|
||||
*
|
||||
* Create a new registry.
|
||||
*/
|
||||
WpPluginRegistry *
|
||||
wp_plugin_registry_new (void)
|
||||
{
|
||||
return g_object_new (wp_plugin_registry_get_type (), NULL);
|
||||
}
|
||||
|
||||
static gint
|
||||
compare_ranks (const WpPluginMetadata * a, const WpPluginMetadata * b)
|
||||
{
|
||||
return (gint) b->rank - (gint) a->rank;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_plugin_registry_register_with_metadata: (skip)
|
||||
* @metadata: the metadata
|
||||
* @metadata_size: the sizeof (@metadata), to allow ABI-compatible future
|
||||
* expansion of the structure
|
||||
*
|
||||
* Registers a plugin in the registry.
|
||||
* This method is used internally by WP_PLUGIN_REGISTER().
|
||||
* Avoid using it directly.
|
||||
*/
|
||||
void
|
||||
wp_plugin_registry_register_with_metadata (WpPluginRegistry * self,
|
||||
const WpPluginMetadata * metadata,
|
||||
gsize metadata_size)
|
||||
{
|
||||
PluginData *data;
|
||||
|
||||
g_return_if_fail (WP_IS_PLUGIN_REGISTRY (self));
|
||||
g_return_if_fail (metadata_size == sizeof (WpPluginMetadata));
|
||||
g_return_if_fail (g_type_is_a (metadata->gtype, wp_plugin_get_type ()));
|
||||
g_return_if_fail (metadata->name != NULL);
|
||||
g_return_if_fail (metadata->description != NULL);
|
||||
g_return_if_fail (metadata->author != NULL);
|
||||
g_return_if_fail (metadata->license != NULL);
|
||||
g_return_if_fail (metadata->version != NULL);
|
||||
g_return_if_fail (metadata->origin != NULL);
|
||||
|
||||
data = g_slice_alloc (sizeof (PluginData));
|
||||
data->block_size = sizeof (PluginData);
|
||||
data->metadata = metadata;
|
||||
data->instance = NULL;
|
||||
|
||||
self->plugins = g_list_insert_sorted (self->plugins, data,
|
||||
(GCompareFunc) compare_ranks);
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_plugin_registry_register: (method)
|
||||
* @plugin_type: the #GType of the #WpPlugin subclass
|
||||
* @rank: the rank of the plugin
|
||||
* @name: the name of the plugin
|
||||
* @description: plugin description
|
||||
* @author: author <email@domain>, author2 <email@domain>
|
||||
* @license: a SPDX license ID or "Proprietary"
|
||||
* @version: the version of the plugin
|
||||
* @origin: URL or short reference of where this plugin came from
|
||||
*
|
||||
* Registers a plugin in the registry.
|
||||
* This method creates a dynamically allocated #WpPluginMetadata and is meant
|
||||
* to be used by bindings that have no way of representing #WpPluginMetadata.
|
||||
* In C/C++, you should use WP_PLUGIN_REGISTER()
|
||||
*/
|
||||
void
|
||||
wp_plugin_registry_register (WpPluginRegistry * self,
|
||||
GType plugin_type,
|
||||
guint16 rank,
|
||||
const gchar *name,
|
||||
const gchar *description,
|
||||
const gchar *author,
|
||||
const gchar *license,
|
||||
const gchar *version,
|
||||
const gchar *origin)
|
||||
{
|
||||
PluginData *data;
|
||||
WpPluginMetadata *metadata;
|
||||
|
||||
g_return_if_fail (WP_IS_PLUGIN_REGISTRY (self));
|
||||
g_return_if_fail (g_type_is_a (plugin_type, wp_plugin_get_type ()));
|
||||
g_return_if_fail (name != NULL);
|
||||
g_return_if_fail (description != NULL);
|
||||
g_return_if_fail (author != NULL);
|
||||
g_return_if_fail (license != NULL);
|
||||
g_return_if_fail (version != NULL);
|
||||
g_return_if_fail (origin != NULL);
|
||||
|
||||
data = g_slice_alloc (sizeof (PluginData) + sizeof (WpPluginMetadata));
|
||||
data->block_size = sizeof (PluginData) + sizeof (WpPluginMetadata);
|
||||
|
||||
metadata = (WpPluginMetadata *) ((guint8 *) data) + sizeof (PluginData);
|
||||
metadata->gtype = plugin_type;
|
||||
metadata->rank = rank;
|
||||
metadata->name = g_string_chunk_insert (self->metadata_strings, name);
|
||||
metadata->description = g_string_chunk_insert (self->metadata_strings,
|
||||
description);
|
||||
metadata->author = g_string_chunk_insert (self->metadata_strings, author);
|
||||
metadata->license = g_string_chunk_insert (self->metadata_strings, license);
|
||||
metadata->version = g_string_chunk_insert (self->metadata_strings, version);
|
||||
metadata->origin = g_string_chunk_insert (self->metadata_strings, origin);
|
||||
|
||||
data->metadata = metadata;
|
||||
data->instance = NULL;
|
||||
|
||||
self->plugins = g_list_insert_sorted (self->plugins, data,
|
||||
(GCompareFunc) compare_ranks);
|
||||
}
|
||||
|
||||
static inline void
|
||||
make_plugin (WpPluginRegistry * self, PluginData * plugin_data)
|
||||
{
|
||||
plugin_data->instance = g_object_new (plugin_data->metadata->gtype,
|
||||
"registry", self, "metadata", plugin_data->metadata, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* WpPluginFunc: (skip)
|
||||
*/
|
||||
|
||||
/**
|
||||
* wp_plugin_registry_invoke_internal: (skip)
|
||||
* @self: the registry
|
||||
* @func: a vfunc invocation function of #WpPlugin
|
||||
* @data: data to pass to @func
|
||||
*
|
||||
* Used internally only.
|
||||
*/
|
||||
gboolean
|
||||
wp_plugin_registry_invoke_internal (WpPluginRegistry * self, WpPluginFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
GList *list;
|
||||
PluginData *plugin_data;
|
||||
|
||||
for (list = self->plugins; list != NULL; list = g_list_next (list)) {
|
||||
plugin_data = list->data;
|
||||
if (!plugin_data->instance)
|
||||
make_plugin (self, plugin_data);
|
||||
|
||||
if (func (plugin_data->instance, data))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
53
lib/wp/plugin-registry.h
Normal file
53
lib/wp/plugin-registry.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef __WP_PLUGIN_REGISTRY_H__
|
||||
#define __WP_PLUGIN_REGISTRY_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* declared in plugin.h */
|
||||
typedef struct _WpPluginMetadata WpPluginMetadata;
|
||||
|
||||
G_DECLARE_FINAL_TYPE (WpPluginRegistry, wp_plugin_registry, WP, PLUGIN_REGISTRY, GObject)
|
||||
|
||||
WpPluginRegistry * wp_plugin_registry_new (void);
|
||||
|
||||
void wp_plugin_registry_register_with_metadata (WpPluginRegistry * self,
|
||||
const WpPluginMetadata * metadata,
|
||||
gsize metadata_size);
|
||||
|
||||
void wp_plugin_registry_register (WpPluginRegistry * self,
|
||||
GType plugin_type,
|
||||
guint16 rank,
|
||||
const gchar *name,
|
||||
const gchar *description,
|
||||
const gchar *author,
|
||||
const gchar *license,
|
||||
const gchar *version,
|
||||
const gchar *origin);
|
||||
|
||||
|
||||
typedef gboolean (*WpPluginFunc) (gpointer plugin, gpointer data);
|
||||
gboolean wp_plugin_registry_invoke_internal (WpPluginRegistry * self,
|
||||
WpPluginFunc func, gpointer data);
|
||||
|
||||
#define wp_plugin_registry_invoke(r, func, data) \
|
||||
G_STMT_START \
|
||||
if (!(0 ? func ((WpPlugin *) NULL, data) : \
|
||||
wp_plugin_registry_invoke_internal (r, (WpPluginFunc) func, \
|
||||
(gpointer) data))) { \
|
||||
g_warning ("No plugin handled invocation to " ##func); \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
262
lib/wp/plugin.c
Normal file
262
lib/wp/plugin.c
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_RANK,
|
||||
PROP_NAME,
|
||||
PROP_DESCRIPTION,
|
||||
PROP_AUTHOR,
|
||||
PROP_LICENSE,
|
||||
PROP_VERSION,
|
||||
PROP_ORIGIN,
|
||||
PROP_REGISTRY,
|
||||
PROP_METADATA,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
WpPluginRegistry *registry;
|
||||
const WpPluginMetadata *metadata;
|
||||
} WpPluginPrivate;
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpPlugin, wp_plugin, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
wp_plugin_init (WpPlugin * self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wp_plugin_dispose (GObject * object)
|
||||
{
|
||||
WpPlugin *plugin = WP_PLUGIN (object);
|
||||
WpPluginPrivate *priv = wp_plugin_get_instance_private (plugin);
|
||||
|
||||
g_clear_object (&priv->registry);
|
||||
|
||||
G_OBJECT_CLASS (wp_plugin_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_plugin_set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpPlugin *plugin = WP_PLUGIN (object);
|
||||
WpPluginPrivate *priv = wp_plugin_get_instance_private (plugin);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_REGISTRY:
|
||||
priv->registry = g_value_get_object (value);
|
||||
break;
|
||||
case PROP_METADATA:
|
||||
priv->metadata = g_value_get_pointer (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_plugin_get_property (GObject * object, guint property_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
WpPlugin *plugin = WP_PLUGIN (object);
|
||||
WpPluginPrivate *priv = wp_plugin_get_instance_private (plugin);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_RANK:
|
||||
g_value_set_uint (value, priv->metadata->rank);
|
||||
break;
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, priv->metadata->name);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
g_value_set_string (value, priv->metadata->description);
|
||||
break;
|
||||
case PROP_AUTHOR:
|
||||
g_value_set_string (value, priv->metadata->author);
|
||||
break;
|
||||
case PROP_LICENSE:
|
||||
g_value_set_string (value, priv->metadata->license);
|
||||
break;
|
||||
case PROP_VERSION:
|
||||
g_value_set_string (value, priv->metadata->version);
|
||||
break;
|
||||
case PROP_ORIGIN:
|
||||
g_value_set_string (value, priv->metadata->origin);
|
||||
break;
|
||||
case PROP_REGISTRY:
|
||||
g_value_set_object (value, priv->registry);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
default_handle_pw_proxy (WpPlugin * self, WpProxy * proxy)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_plugin_class_init (WpPluginClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
|
||||
klass->handle_pw_proxy = default_handle_pw_proxy;
|
||||
|
||||
object_class->dispose = wp_plugin_dispose;
|
||||
object_class->get_property = wp_plugin_get_property;
|
||||
object_class->set_property = wp_plugin_set_property;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_RANK,
|
||||
g_param_spec_uint ("rank", "Rank", "The plugin rank", 0, G_MAXUINT, 0,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_NAME,
|
||||
g_param_spec_string ("name", "Name", "The plugin's name", NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_DESCRIPTION,
|
||||
g_param_spec_string ("description", "Description",
|
||||
"The plugin's description", NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_AUTHOR,
|
||||
g_param_spec_string ("author", "Author", "The plugin's author", NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_LICENSE,
|
||||
g_param_spec_string ("license", "License", "The plugin's license", NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_VERSION,
|
||||
g_param_spec_string ("version", "Version", "The plugin's version", NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ORIGIN,
|
||||
g_param_spec_string ("origin", "Origin", "The plugin's origin", NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_REGISTRY,
|
||||
g_param_spec_object ("registry", "Registry",
|
||||
"The WpPluginRegistry that owns this plugin",
|
||||
wp_plugin_registry_get_type (),
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_METADATA,
|
||||
g_param_spec_pointer ("metadata", "metadata", "metadata",
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_PRIVATE));
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_plugin_handle_pw_proxy: (virtual handle_pw_proxy)
|
||||
*/
|
||||
gboolean
|
||||
wp_plugin_handle_pw_proxy (WpPlugin * self, WpProxy * proxy)
|
||||
{
|
||||
if (WP_PLUGIN_GET_CLASS (self)->handle_pw_proxy)
|
||||
return WP_PLUGIN_GET_CLASS (self)->handle_pw_proxy (self, proxy);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_plugin_handle_pw_device: (virtual handle_pw_device)
|
||||
*/
|
||||
gboolean
|
||||
wp_plugin_handle_pw_device (WpPlugin * self, WpProxy * proxy)
|
||||
{
|
||||
if (WP_PLUGIN_GET_CLASS (self)->handle_pw_device)
|
||||
return WP_PLUGIN_GET_CLASS (self)->handle_pw_device (self, proxy);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_plugin_handle_pw_device_node: (virtual handle_pw_device_node)
|
||||
*/
|
||||
gboolean
|
||||
wp_plugin_handle_pw_device_node (WpPlugin * self, WpProxy * proxy)
|
||||
{
|
||||
if (WP_PLUGIN_GET_CLASS (self)->handle_pw_device_node)
|
||||
return WP_PLUGIN_GET_CLASS (self)->handle_pw_device_node (self, proxy);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_plugin_handle_pw_client: (virtual handle_pw_client)
|
||||
*/
|
||||
gboolean
|
||||
wp_plugin_handle_pw_client (WpPlugin * self, WpProxy * proxy)
|
||||
{
|
||||
if (WP_PLUGIN_GET_CLASS (self)->handle_pw_client)
|
||||
return WP_PLUGIN_GET_CLASS (self)->handle_pw_client (self, proxy);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_plugin_handle_pw_client_node: (virtual handle_pw_client_node)
|
||||
*/
|
||||
gboolean
|
||||
wp_plugin_handle_pw_client_node (WpPlugin * self, WpProxy * proxy)
|
||||
{
|
||||
if (WP_PLUGIN_GET_CLASS (self)->handle_pw_client_node)
|
||||
return WP_PLUGIN_GET_CLASS (self)->handle_pw_client_node (self, proxy);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_plugin_provide_interfaces: (virtual provide_interfaces)
|
||||
*/
|
||||
gboolean
|
||||
wp_plugin_provide_interfaces (WpPlugin * self, WpObject * object)
|
||||
{
|
||||
if (WP_PLUGIN_GET_CLASS (self)->provide_interfaces)
|
||||
return WP_PLUGIN_GET_CLASS (self)->provide_interfaces (self, object);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_plugin_get_registry: (method)
|
||||
* @self: the plugin
|
||||
*
|
||||
* Returns: (transfer full): the registry where this plugin is registered
|
||||
*/
|
||||
WpPluginRegistry *
|
||||
wp_plugin_get_registry (WpPlugin * self)
|
||||
{
|
||||
WpPluginPrivate *priv = wp_plugin_get_instance_private (self);
|
||||
g_object_ref (priv->registry);
|
||||
return priv->registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_plugin_get_metadata: (skip)
|
||||
* @self: the plugin
|
||||
*
|
||||
* This is intended for C/C++ only. Use the #WpPlugin properties in bindings.
|
||||
*
|
||||
* Returns: the metadata structure associated with this plugin
|
||||
*/
|
||||
const WpPluginMetadata *
|
||||
wp_plugin_get_metadata (WpPlugin * self)
|
||||
{
|
||||
WpPluginPrivate *priv = wp_plugin_get_instance_private (self);
|
||||
return priv->metadata;
|
||||
}
|
||||
258
lib/wp/plugin.h
Normal file
258
lib/wp/plugin.h
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef __WP_PLUGIN_H__
|
||||
#define __WP_PLUGIN_H__
|
||||
|
||||
#include "object.h"
|
||||
#include "proxy.h"
|
||||
#include "plugin-registry.h"
|
||||
|
||||
#include <gmodule.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* WpPluginRank:
|
||||
* @WP_PLUGIN_RANK_UPSTREAM: should only be used inside WirePlumber
|
||||
* @WP_PLUGIN_RANK_PLATFORM_OVERRIDE: plugins provided by the platform,
|
||||
* possibly to provide a platform-specific policy
|
||||
* @WP_PLUGIN_RANK_VENDOR_OVERRIDE: plugins provided by hardware vendors
|
||||
* to provide hardware-specific device handling and/or policies
|
||||
*
|
||||
* The rank of a plugin is an unsigned integer that can take an arbitrary
|
||||
* value. On invocation, plugins ranked with a higher number are tried first,
|
||||
* which is how one can implement overrides. This enum provides default
|
||||
* values for certain kinds of plugins. Feel free to add/substract numbers
|
||||
* to these constants in order to make a hierarchy, if you are implementing
|
||||
* multiple different plugins that need to be tried in a certain order.
|
||||
*/
|
||||
typedef enum {
|
||||
WP_PLUGIN_RANK_UPSTREAM = 0,
|
||||
WP_PLUGIN_RANK_PLATFORM_OVERRIDE = 128,
|
||||
WP_PLUGIN_RANK_VENDOR_OVERRIDE = 256,
|
||||
} WpPluginRank;
|
||||
|
||||
/**
|
||||
* WpPluginMetadata: (skip)
|
||||
* @gtype: the #GType of the plugin
|
||||
* @rank: the rank of the plugin
|
||||
* @name: the name of the plugin
|
||||
* @description: plugin description
|
||||
* @author: author <email@domain>, author2 <email@domain>
|
||||
* @license: a SPDX license ID or "Proprietary"
|
||||
* @version: the version of the plugin
|
||||
* @origin: URL or short reference of where this plugin came from
|
||||
*
|
||||
* Metadata for registering a plugin (for the C API).
|
||||
* You should normally never need to use this directly.
|
||||
* Use WP_PLUGIN_DEFINE() instead.
|
||||
*/
|
||||
struct _WpPluginMetadata
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
GType gtype;
|
||||
guint rank;
|
||||
};
|
||||
gpointer _unused_for_alignment[2];
|
||||
};
|
||||
const gchar *name;
|
||||
const gchar *description;
|
||||
const gchar *author;
|
||||
const gchar *license;
|
||||
const gchar *version;
|
||||
const gchar *origin;
|
||||
};
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (WpPlugin, wp_plugin, WP, PLUGIN, GObject)
|
||||
|
||||
struct _WpPluginClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
/**
|
||||
* handle_pw_proxy:
|
||||
* @self: the plugin
|
||||
* @proxy: (transfer none): the proxy
|
||||
*
|
||||
* This method is called for every new proxy that appears in PipeWire.
|
||||
* The default implementation will inspect the proxy type and will dispatch
|
||||
* the call to one of the specialized methods available below.
|
||||
* Override only for very special cases.
|
||||
*/
|
||||
gboolean (*handle_pw_proxy) (WpPlugin * self, WpProxy * proxy);
|
||||
|
||||
/**
|
||||
* handle_pw_device:
|
||||
* @self: the plugin
|
||||
* @proxy: (transfer none): the device proxy
|
||||
*
|
||||
* This method is called for every new PipeWire proxy of type
|
||||
* `PipeWire:Interface:Device`. The implementation is expected to create
|
||||
* a new #WpDevice and register it with the #WpDeviceManager.
|
||||
*
|
||||
* The default implementation returns FALSE.
|
||||
* Override if you are implementing custom device management.
|
||||
*
|
||||
* Returns: TRUE if the device was handled, FALSE otherwise.
|
||||
*/
|
||||
gboolean (*handle_pw_device) (WpPlugin * self, WpProxy * proxy);
|
||||
|
||||
/**
|
||||
* handle_pw_device_node:
|
||||
* @self: the plugin
|
||||
* @proxy: (transfer none): the node proxy
|
||||
*
|
||||
* This method is called for every new PipeWire proxy of type
|
||||
* `PipeWire:Interface:Node` whose parent proxy is a
|
||||
* `PipeWire:Interface:Device`.
|
||||
*
|
||||
* The default implementation returns FALSE.
|
||||
* Override if you are implementing custom device management.
|
||||
*
|
||||
* Returns: TRUE if the node was handled, FALSE otherwise.
|
||||
*/
|
||||
gboolean (*handle_pw_device_node) (WpPlugin * self, WpProxy * proxy);
|
||||
|
||||
/**
|
||||
* handle_pw_client:
|
||||
* @self: the plugin
|
||||
* @proxy: (transfer none): the client proxy
|
||||
*
|
||||
* This method is called for every new PipeWire proxy of type
|
||||
* `PipeWire:Interface:Client`. The implementation is expected to update
|
||||
* the client's permissions, if necessary.
|
||||
*
|
||||
* The default implementation returns FALSE.
|
||||
* Override if you are implementing custom policy management.
|
||||
*
|
||||
* Returns: TRUE if the client was handled, FALSE otherwise.
|
||||
*/
|
||||
gboolean (*handle_pw_client) (WpPlugin * self, WpProxy * proxy);
|
||||
|
||||
/**
|
||||
* handle_pw_client_node:
|
||||
* @self: the plugin
|
||||
* @proxy: (transfer none): the node proxy
|
||||
*
|
||||
* This method is called for every new PipeWire proxy of type
|
||||
* `PipeWire:Interface:Node` whose parent proxy is a
|
||||
* `PipeWire:Interface:Client`. The implementation is expected to create
|
||||
* a new #WpStream in some #WpSession.
|
||||
*
|
||||
* The default implementation returns FALSE.
|
||||
* Override if you are implementing custom policy management.
|
||||
*
|
||||
* Returns: TRUE if the node was handled, FALSE otherwise.
|
||||
*/
|
||||
gboolean (*handle_pw_client_node) (WpPlugin * self, WpProxy * proxy);
|
||||
|
||||
/**
|
||||
* provide_interfaces:
|
||||
* @self: the plugin
|
||||
* @object: (transfer none): a #WpObject
|
||||
*
|
||||
* This method is called for every new #WpObject created in WirePlumber.
|
||||
* The implementation is expected to attach any interface implementations
|
||||
* that it can provide for this kind of object, if necessary, only if
|
||||
* these interfaces have not already been attached on the @object.
|
||||
*
|
||||
* The default implementation returns FALSE.
|
||||
* Override if you are providing custom interface implementations for objects.
|
||||
*
|
||||
* Returns: TRUE if the node was handled, FALSE otherwise.
|
||||
*/
|
||||
gboolean (*provide_interfaces) (WpPlugin * self, WpObject * object);
|
||||
};
|
||||
|
||||
gboolean wp_plugin_handle_pw_proxy (WpPlugin * self, WpProxy * proxy);
|
||||
gboolean wp_plugin_handle_pw_device (WpPlugin * self, WpProxy * proxy);
|
||||
gboolean wp_plugin_handle_pw_device_node (WpPlugin * self, WpProxy * proxy);
|
||||
gboolean wp_plugin_handle_pw_client (WpPlugin * self, WpProxy * proxy);
|
||||
gboolean wp_plugin_handle_pw_client_node (WpPlugin * self, WpProxy * proxy);
|
||||
gboolean wp_plugin_provide_interfaces (WpPlugin * self, WpObject * object);
|
||||
|
||||
WpPluginRegistry * wp_plugin_get_registry (WpPlugin * self);
|
||||
const WpPluginMetadata * wp_plugin_get_metadata (WpPlugin * self);
|
||||
|
||||
|
||||
/**
|
||||
* WP_MODULE_INIT_SYMBOL: (skip)
|
||||
*
|
||||
* The linker symbol that serves as an entry point in modules
|
||||
*/
|
||||
#define WP_MODULE_INIT_SYMBOL wireplumber__module_init
|
||||
|
||||
/**
|
||||
* WP_MODULE_DEFINE: (skip)
|
||||
*
|
||||
* A convenience macro to register modules in C/C++.
|
||||
* A module can contain multiple plugins, which are meant to be registered
|
||||
* with WP_PLUGIN_REGISTER in the place of @plugin_reg
|
||||
*
|
||||
* Example usage:
|
||||
* |[
|
||||
* WP_MODULE_DEFINE (
|
||||
* WP_PLUGIN_REGISTER (
|
||||
* MY_PLUGIN_TYPE,
|
||||
* WP_PLUGIN_RANK_PLATFORM_OVERRIDE,
|
||||
* "myplugin",
|
||||
* "A custom policy plugin for Awesome Platform",
|
||||
* "George Kiagiadakis <george.kiagiadakis@collabora.com>",
|
||||
* "LGPL-2.1-or-later",
|
||||
* "3.0.1",
|
||||
* "https://awesome-platform.example"
|
||||
* );
|
||||
* WP_PLUGIN_REGISTER (
|
||||
* SECONDARY_PLUGIN_TYPE,
|
||||
* WP_PLUGIN_RANK_PLATFORM_OVERRIDE - 1,
|
||||
* "secondaryplugin",
|
||||
* "A secondary policy plugin for Awesome Platform",
|
||||
* "George Kiagiadakis <george.kiagiadakis@collabora.com>",
|
||||
* "LGPL-2.1-or-later",
|
||||
* "3.0.1",
|
||||
* "https://awesome-platform.example"
|
||||
* );
|
||||
* )
|
||||
* ]|
|
||||
*/
|
||||
#define WP_MODULE_DEFINE(plugin_reg) \
|
||||
G_MODULE_EXPORT void \
|
||||
WP_MODULE_INIT_SYMBOL (WpPluginRegistry * registry) \
|
||||
{ \
|
||||
plugin_reg; \
|
||||
}
|
||||
|
||||
/**
|
||||
* WP_PLUGIN_REGISTER: (skip)
|
||||
*
|
||||
* A convenience macro to register plugins in C/C++.
|
||||
* See WP_MODULE_DEFINE() for a usage example.
|
||||
* See wp_plugin_registry_register() for a description of the parameters.
|
||||
*/
|
||||
#define WP_PLUGIN_REGISTER(gtype_, rank_, name_, description_, author_, license_, version_, origin_) \
|
||||
G_STMT_START \
|
||||
static const WpPluginMetadata plugin_metadata = { \
|
||||
.gtype = gtype_, \
|
||||
.rank = rank_, \
|
||||
.name = name_, \
|
||||
.description = description_, \
|
||||
.author = author_, \
|
||||
.license = license_, \
|
||||
.version = version_, \
|
||||
.origin = origin_ \
|
||||
}; \
|
||||
wp_plugin_registry_register_with_metadata (registry, &plugin_metadata, \
|
||||
sizeof (plugin_metadata)); \
|
||||
G_STMT_END
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
175
lib/wp/proxy.c
Normal file
175
lib/wp/proxy.c
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "proxy.h"
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
struct _WpProxy
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
struct pw_proxy *proxy;
|
||||
guint32 id;
|
||||
guint32 parent_id;
|
||||
guint32 type;
|
||||
const gchar *type_string;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PROXY,
|
||||
PROP_ID,
|
||||
PROP_PARENT_ID,
|
||||
PROP_SPA_TYPE,
|
||||
PROP_SPA_TYPE_STRING,
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (WpProxy, wp_proxy, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
wp_proxy_init (WpProxy * self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_constructed (GObject * object)
|
||||
{
|
||||
WpProxy *self = WP_PROXY (object);
|
||||
const struct spa_type_info *info = pw_type_info ();
|
||||
|
||||
while (info->type) {
|
||||
if (info->type == self->type) {
|
||||
self->type_string = info->name;
|
||||
break;
|
||||
}
|
||||
info++;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (wp_proxy_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_finalize (GObject * object)
|
||||
{
|
||||
WpProxy *self = WP_PROXY (object);
|
||||
|
||||
G_OBJECT_CLASS (wp_proxy_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
WpProxy *self = WP_PROXY (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_PROXY:
|
||||
self->proxy = g_value_get_pointer (value);
|
||||
break;
|
||||
case PROP_ID:
|
||||
self->id = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_PARENT_ID:
|
||||
self->parent_id = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_SPA_TYPE:
|
||||
self->type = g_value_get_uint (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_get_property (GObject * object, guint property_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
WpProxy *self = WP_PROXY (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_PROXY:
|
||||
g_value_set_pointer (value, self->proxy);
|
||||
break;
|
||||
case PROP_ID:
|
||||
g_value_set_uint (value, self->id);
|
||||
break;
|
||||
case PROP_PARENT_ID:
|
||||
g_value_set_uint (value, self->parent_id);
|
||||
break;
|
||||
case PROP_SPA_TYPE:
|
||||
g_value_set_uint (value, self->type);
|
||||
break;
|
||||
case PROP_SPA_TYPE_STRING:
|
||||
g_value_set_string (value, wp_proxy_get_spa_type_string (self));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_class_init (WpProxyClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
|
||||
object_class->constructed = wp_proxy_constructed;
|
||||
object_class->finalize = wp_proxy_finalize;
|
||||
object_class->get_property = wp_proxy_get_property;
|
||||
object_class->set_property = wp_proxy_set_property;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PROXY,
|
||||
g_param_spec_pointer ("proxy", "proxy",
|
||||
"The underlying struct pw_proxy *",
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ID,
|
||||
g_param_spec_uint ("id", "id",
|
||||
"The global ID of the object", 0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PARENT_ID,
|
||||
g_param_spec_uint ("parent-id", "parent-id",
|
||||
"The global ID of the parent object", 0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SPA_TYPE,
|
||||
g_param_spec_uint ("spa-type", "spa-type",
|
||||
"The SPA type of the object", 0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SPA_TYPE_STRING,
|
||||
g_param_spec_string ("spa-type-string", "spa-type-string",
|
||||
"The string representation of the SPA type of the object", NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
guint32
|
||||
wp_proxy_get_id (WpProxy * self)
|
||||
{
|
||||
return self->id;
|
||||
}
|
||||
|
||||
guint32
|
||||
wp_proxy_get_parent_id (WpProxy * self)
|
||||
{
|
||||
return self->parent_id;
|
||||
}
|
||||
|
||||
guint32
|
||||
wp_proxy_get_spa_type (WpProxy * self)
|
||||
{
|
||||
return self->type;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
wp_proxy_get_spa_type_string (WpProxy * self)
|
||||
{
|
||||
return self->type_string;
|
||||
}
|
||||
27
lib/wp/proxy.h
Normal file
27
lib/wp/proxy.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef __WP_PROXY_H__
|
||||
#define __WP_PROXY_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct pw_proxy;
|
||||
|
||||
G_DECLARE_FINAL_TYPE (WpProxy, wp_proxy, WP, PROXY, GObject)
|
||||
|
||||
guint32 wp_proxy_get_id (WpProxy * self);
|
||||
guint32 wp_proxy_get_parent_id (WpProxy * self);
|
||||
guint32 wp_proxy_get_spa_type (WpProxy * self);
|
||||
const gchar * wp_proxy_get_spa_type_string (WpProxy * self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Reference in a new issue