Implement PW_TYPE_INTERFACE_Metadata
This commit is contained in:
@@ -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',
|
||||
|
353
lib/wp/metadata.c
Normal file
353
lib/wp/metadata.c
Normal file
@@ -0,0 +1,353 @@
|
||||
/* 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);
|
||||
}
|
45
lib/wp/metadata.h
Normal file
45
lib/wp/metadata.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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',
|
||||
[
|
||||
|
65
modules/module-metadata-settings.c
Normal file
65
modules/module-metadata-settings.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/* 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));
|
||||
}
|
@@ -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
|
||||
|
Reference in New Issue
Block a user