Skip to content
Snippets Groups Projects
Commit 65b4562f authored by raghu447's avatar raghu447
Browse files

Implement PW_TYPE_INTERFACE_Metadata

parent a73e46e2
No related branches found
No related tags found
No related merge requests found
......@@ -10,6 +10,7 @@ wp_lib_sources = files(
'error.c',
'iterator.c',
'link.c',
'metadata.c',
'module.c',
'node.c',
'object-interest.c',
......@@ -43,6 +44,7 @@ wp_lib_headers = files(
'error.h',
'iterator.h',
'link.h',
'metadata.h',
'module.h',
'node.h',
'object-interest.h',
......
/* WirePlumber
*
* Copyright © 2019-2020 Collabora Ltd.
* @author Raghavendra Rao <raghavendra.rao@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
/**
* SECTION: WpMetadata
*
* The #WpMetadata class allows accessing the properties and methods of
* Pipewire Jack metadata object (`struct pw_metadata`).
*
*/
#define G_LOG_DOMAIN "wp-metadata"
#include "metadata.h"
#include "spa-type.h"
#include "spa-pod.h"
#include "debug.h"
#include "private.h"
#include "error.h"
#include "wpenums.h"
#include <pipewire/pipewire.h>
#include <pipewire/array.h>
#include <pipewire/extensions/metadata.h>
#include <spa/pod/builder.h>
#include <spa/pod/parser.h>
#include <spa/pod/filter.h>
/* WpMetadata */
typedef struct _WpMetadataPrivate WpMetadataPrivate;
struct _WpMetadataPrivate
{
struct pw_metadata *iface;
struct spa_hook listener;
struct spa_hook_list hooks;
struct pw_properties *properties;
struct pw_array metadata;
struct pw_proxy *proxy;
};
G_DEFINE_TYPE_WITH_PRIVATE (WpMetadata, wp_metadata, WP_TYPE_PROXY)
static void
wp_metadata_init (WpMetadata * self)
{
}
static void
wp_metadata_finalize (GObject * object)
{
G_OBJECT_CLASS (wp_metadata_parent_class)->finalize (object);
}
static void
wp_metadata_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
{
WpMetadata *self = WP_METADATA (proxy);
WpMetadataPrivate *priv = wp_metadata_get_instance_private (self);
priv->iface = (struct pw_metadata *) pw_proxy;
}
static void
wp_metadata_class_init (WpMetadataClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpProxyClass *proxy_class = (WpProxyClass *) klass;
object_class->finalize = wp_metadata_finalize;
proxy_class->pw_iface_type = PW_TYPE_INTERFACE_Metadata;
proxy_class->pw_iface_version = PW_VERSION_METADATA;
proxy_class->pw_proxy_created = wp_metadata_pw_proxy_created;
}
/* WpImplMetadata */
typedef struct _WpImplMetadata WpImplMetadata;
struct _WpImplMetadata
{
WpMetadata parent;
struct spa_interface iface;
struct spa_hook_list hooks;
gboolean subscribed;
};
G_DEFINE_TYPE (WpImplMetadata, wp_impl_metadata, WP_TYPE_METADATA)
#define pw_metadata_emit(hooks,method,version,...) \
spa_hook_list_call_simple(hooks, struct pw_metadata_events, \
method, version, ##__VA_ARGS__)
#define pw_metadata_emit_property(hooks,...) \
pw_metadata_emit(hooks,property, 0, ##__VA_ARGS__)
struct item {
uint32_t subject;
char *key;
char *type;
char *value;
};
static void
clear_item(struct item *item)
{
free(item->key);
free(item->type);
free(item->value);
spa_zero(*item);
}
static void
set_item(struct item *item, uint32_t subject, const char *key,
const char *type, const char *value)
{
item->subject = subject;
item->key = strdup(key);
item->type = strdup(type);
item->value = strdup(value);
}
static void
emit_properties(WpImplMetadata *self,
const struct spa_dict *dict)
{
struct item *item;
WpMetadataPrivate *priv = wp_metadata_get_instance_private (WP_METADATA (self));
pw_array_for_each(item, &priv->metadata) {
wp_info_object (self, "metadata : %d %s %s %s",
item->subject, item->key, item->type, item->value);
pw_metadata_emit_property(&priv->hooks,
item->subject,
item->key,
item->type,
item->value);
}
}
static int
impl_add_listener(void *object,
struct spa_hook *listener,
const struct pw_metadata_events *events,
void *data)
{
WpImplMetadata *self = WP_IMPL_METADATA (object);
WpMetadataPrivate *priv = wp_metadata_get_instance_private (WP_METADATA (self));
struct spa_hook_list save;
spa_hook_list_isolate (&priv->hooks, &save, listener, events, data);
emit_properties(self, &priv->properties->dict);
spa_hook_list_join (&priv->hooks, &save);
return 0;
}
static struct item *
find_item(WpImplMetadata *self, uint32_t subject, const char *key)
{
struct item *item;
WpMetadataPrivate *priv = wp_metadata_get_instance_private (WP_METADATA (self));
pw_array_for_each(item, &priv->metadata) {
if (item->subject == subject && (key == NULL ||
!strcmp(item->key, key))) {
return item;
}
}
return NULL;
}
static int
clear_subjects(WpImplMetadata *self, uint32_t subject)
{
struct item *item;
uint32_t removed = 0;
WpMetadataPrivate *priv = wp_metadata_get_instance_private (WP_METADATA (self));
while (true) {
item = find_item(self, subject, NULL);
if (item == NULL)
break;
wp_debug_object (self, "remove id:%d key:%s", subject, item->key);
clear_item(item);
pw_array_remove(&priv->metadata, item);
removed++;
}
if (removed > 0)
pw_metadata_emit_property(&priv->hooks, subject, NULL, NULL, NULL);
return 0;
}
static void
clear_items(WpImplMetadata *self)
{
struct item *item;
WpMetadataPrivate *priv = wp_metadata_get_instance_private (WP_METADATA (self));
pw_array_consume(item, &priv->metadata)
clear_subjects(self, item->subject);
pw_array_reset(&priv->metadata);
}
static int
impl_set_property(void *object, uint32_t subject, const char *key,
const char *type, const char *value)
{
WpImplMetadata *self = WP_IMPL_METADATA (object);
WpMetadataPrivate *priv;
struct item *item = NULL;
g_return_val_if_fail (WP_IS_IMPL_METADATA (self), -1);
priv = wp_metadata_get_instance_private (WP_METADATA (self));
if (key == NULL)
return clear_subjects(self, subject);
item = find_item(self, subject, key);
if (item == NULL) {
if (value == NULL)
return 0;
item = pw_array_add(&priv->metadata, sizeof(*item));
if (item == NULL)
return -errno;
} else {
clear_item(item);
}
if (value != NULL) {
if (type == NULL)
type = "string";
set_item(item, subject, key, type, value);
wp_debug_object (self, "%p: add id:%d key:%s type:%s value:%s", self,
subject, key, type, value);
} else {
type = NULL;
pw_array_remove(&priv->metadata, item);
wp_debug_object(self, "%p: remove id:%d key:%s", self, subject, key);
}
pw_metadata_emit_property(&priv->hooks, subject, key, type, value);
return 0;
}
static int
impl_clear(void *object)
{
WpImplMetadata *self = WP_IMPL_METADATA (object);
WpMetadataPrivate *priv = wp_metadata_get_instance_private (WP_METADATA (self));
clear_items(self);
pw_array_clear(&priv->metadata);
pw_properties_free(priv->properties);
return 0;
}
static const struct pw_metadata_methods impl_metadata = {
PW_VERSION_METADATA_METHODS,
.add_listener = impl_add_listener,
.set_property = impl_set_property,
.clear = impl_clear,
};
static void
wp_impl_metadata_init (WpImplMetadata * self)
{
WpMetadataPrivate *priv = wp_metadata_get_instance_private (WP_METADATA (self));
self->iface = SPA_INTERFACE_INIT (
PW_TYPE_INTERFACE_Metadata,
PW_VERSION_METADATA,
&impl_metadata, self);
spa_hook_list_init (&priv->hooks);
priv->iface = (struct pw_metadata *) &self->iface;
priv->properties = pw_properties_new(NULL, NULL);
pw_array_init(&priv->metadata, 4096);
}
static void
wp_impl_metadata_finalize (GObject * object)
{
G_OBJECT_CLASS (wp_impl_metadata_parent_class)->finalize (object);
}
static void
wp_impl_metadata_augment (WpProxy * proxy, WpProxyFeatures features)
{
WpImplMetadata *self = WP_IMPL_METADATA (proxy);
WpMetadataPrivate *priv = wp_metadata_get_instance_private (WP_METADATA (self));
/* PW_PROXY depends on BOUND */
if (features & WP_PROXY_FEATURE_PW_PROXY)
features |= WP_PROXY_FEATURE_BOUND;
if (features & WP_PROXY_FEATURE_BOUND) {
g_autoptr (WpCore) core = wp_proxy_get_core (proxy);
struct pw_core *pw_core = wp_core_get_pw_core (core);
/* no pw_core -> we are not connected */
if (!pw_core) {
wp_proxy_augment_error (proxy, g_error_new (WP_DOMAIN_LIBRARY,
WP_LIBRARY_ERROR_OPERATION_FAILED,
"The WirePlumber core is not connected; "
"object cannot be exported to PipeWire"));
wp_critical(G_LOG_DOMAIN "metadata : FAIL - Exiting %s",__FUNCTION__);
return;
}
wp_proxy_set_pw_proxy (proxy, pw_core_export (pw_core,
PW_TYPE_INTERFACE_Metadata,
&priv->properties->dict,
priv->iface, 0));
}
}
static void
wp_impl_metadata_class_init (WpImplMetadataClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpProxyClass *proxy_class = (WpProxyClass *) klass;
object_class->finalize = wp_impl_metadata_finalize;
proxy_class->augment = wp_impl_metadata_augment;
proxy_class->enum_params = NULL;
proxy_class->subscribe_params = NULL;
proxy_class->pw_proxy_created = NULL;
}
WpImplMetadata *
wp_impl_metadata_new (WpCore * core)
{
g_return_val_if_fail (WP_IS_CORE (core), NULL);
return g_object_new (WP_TYPE_IMPL_METADATA,
"core", core,
NULL);
}
/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author Raghavendra Rao <raghavendra.rao@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#ifndef __WIREPLUMBER_METADATA_H__
#define __WIREPLUMBER_METADATA_H__
#include "proxy.h"
G_BEGIN_DECLS
#define WP_METADATA_FEATURES_STANDARD \
(WP_PROXY_FEATURES_STANDARD)
/**
* WP_TYPE_METADATA:
*
* The #WpMetadata #GType
*/
#define WP_TYPE_METADATA (wp_metadata_get_type ())
WP_API
G_DECLARE_DERIVABLE_TYPE (WpMetadata, wp_metadata, WP, METADATA, WpProxy)
struct _WpMetadataClass
{
WpProxyClass parent_class;
};
/**
* WP_TYPE_IMPL_MEATADATA:
*
* The #WpImplMetadata #GType
*/
#define WP_TYPE_IMPL_METADATA (wp_impl_metadata_get_type ())
WP_API
G_DECLARE_FINAL_TYPE (WpImplMetadata, wp_impl_metadata, WP, IMPL_METADATA, WpMetadata)
WP_API
WpImplMetadata * wp_impl_metadata_new (WpCore * core);
G_END_DECLS
#endif
......@@ -80,6 +80,7 @@ wp_init (WpInitFlags flags)
g_type_ensure (WP_TYPE_ENDPOINT_LINK);
g_type_ensure (WP_TYPE_ENDPOINT_STREAM);
g_type_ensure (WP_TYPE_LINK);
g_type_ensure (WP_TYPE_METADATA);
g_type_ensure (WP_TYPE_NODE);
g_type_ensure (WP_TYPE_PORT);
g_type_ensure (WP_TYPE_SESSION);
......
......@@ -20,6 +20,7 @@
#include "error.h"
#include "iterator.h"
#include "link.h"
#include "metadata.h"
#include "module.h"
#include "node.h"
#include "object-interest.h"
......
......@@ -20,6 +20,17 @@ reserve_device_interface_src = gnome.gdbus_codegen('reserve-device-interface',
namespace : 'Wp'
)
shared_library(
'wireplumber-module-metadata-settings',
[
'module-metadata-settings.c',
],
c_args : [common_c_args, '-DG_LOG_DOMAIN="m-metadata"'],
install : true,
install_dir : wireplumber_module_dir,
dependencies : [wp_dep, pipewire_dep],
)
shared_library(
'wireplumber-module-monitor',
[
......
/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author Raghavendra Rao <raghavendra.rao@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include <pipewire/pipewire.h>
struct _WpMetadataSettings
{
WpPlugin parent;
WpImplMetadata *metadata;
};
G_DECLARE_FINAL_TYPE (WpMetadataSettings, wp_metadata_settings,
WP, METADATA_SETTINGS, WpPlugin)
G_DEFINE_TYPE (WpMetadataSettings, wp_metadata_settings, WP_TYPE_PLUGIN)
static void
wp_metadata_settings_init (WpMetadataSettings * self)
{
}
static void
wp_metadata_settings_activate (WpPlugin * plugin)
{
WpMetadataSettings * self = WP_METADATA_SETTINGS (plugin);
g_autoptr (WpCore) core = wp_plugin_get_core (plugin);
g_return_if_fail (core);
self->metadata = wp_impl_metadata_new(core);
wp_proxy_augment (WP_PROXY(self->metadata),
WP_METADATA_FEATURES_STANDARD, NULL,
NULL, self);
}
static void
wp_metadata_settings_deactivate (WpPlugin * plugin)
{
WpMetadataSettings * self = WP_METADATA_SETTINGS (plugin);
g_clear_object (&self->metadata);
}
static void
wp_metadata_settings_class_init (WpMetadataSettingsClass * klass)
{
WpPluginClass *plugin_class = (WpPluginClass *) klass;
plugin_class->activate = wp_metadata_settings_activate;
plugin_class->deactivate = wp_metadata_settings_deactivate;
}
WP_PLUGIN_EXPORT void
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
{
wp_plugin_register (g_object_new (wp_metadata_settings_get_type (),
"module", module,
NULL));
}
\ No newline at end of file
......@@ -73,3 +73,6 @@ load-module C libwireplumber-module-config-endpoint
# Implements linking clients to devices based on TOML configuration files
load-module C libwireplumber-module-config-policy
# Activates metadata module
load-module C libwireplumber-module-metadata-settings
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