Skip to content
Snippets Groups Projects
Commit 6f6e2b0e authored by George Kiagiadakis's avatar George Kiagiadakis
Browse files

lib: implement plugin mechanism and a basic proxy object

parent a50bb17e
No related branches found
No related tags found
No related merge requests found
......@@ -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)
......
/* 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;
}
/* 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
/* 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;
}
/* 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
/* 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;
}
/* 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment