diff --git a/src/examples/media-session/metadata.c b/src/examples/media-session/metadata.c new file mode 100644 index 000000000..72fce95cc --- /dev/null +++ b/src/examples/media-session/metadata.c @@ -0,0 +1,204 @@ +/* Metadata API + * + * Copyright © 2019 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include + +#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); +} + +struct sm_metadata { + struct pw_metadata impl; + + struct spa_hook_list hooks; + + struct pw_properties *properties; + + struct pw_array metadata; +}; + +static void emit_properties(struct sm_metadata *this, const struct spa_dict *dict) +{ + struct item *item; + pw_array_for_each(item, &this->metadata) { + pw_metadata_emit_property(&this->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) +{ + struct sm_metadata *this = object; + struct spa_hook_list save; + + spa_return_val_if_fail(this != NULL, -EINVAL); + spa_return_val_if_fail(events != NULL, -EINVAL); + + spa_hook_list_isolate(&this->hooks, &save, listener, events, data); + + emit_properties(this, &this->properties->dict); + + spa_hook_list_join(&this->hooks, &save); + + return 0; +} + +static struct item *find_item(struct sm_metadata *this, uint32_t subject, const char *key) +{ + struct item *item; + + pw_array_for_each(item, &this->metadata) { + if (item->subject == subject && !strcmp(item->key, key)) + return item; + } + return NULL; +} + +static void clear_items(struct sm_metadata *this) +{ + struct item *item; + + pw_array_for_each(item, &this->metadata) + clear_item(item); + + pw_array_reset(&this->metadata); +} + +static int impl_set_property(void *object, + uint32_t subject, + const char *key, + const char *type, + const char *value) +{ + struct sm_metadata *this = object; + struct item *item = NULL; + + if (key == NULL) + return -EINVAL; + + item = find_item(this, subject, key); + if (item == NULL) { + if (value == NULL) + return 0; + item = pw_array_add(&this->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); + pw_log_debug(NAME" %p: add id:%d key:%s type:%s value:%s", this, + subject, key, type, value); + } else { + type = NULL; + pw_array_remove(&this->metadata, item); + pw_log_debug(NAME" %p: remove id:%d key:%s", this, subject, key); + } + + + pw_metadata_emit_property(&this->hooks, + subject, key, type, value); + return 0; +} + +static int impl_clear(void *object) +{ + struct sm_metadata *this = object; + clear_items(this); + return 0; +} + +struct pw_metadata_methods impl_metadata = { + PW_VERSION_METADATA_METHODS, + .add_listener = impl_add_listener, + .set_property = impl_set_property, + .clear = impl_clear, +}; + +struct sm_metadata * +sm_metadata_new(struct pw_properties *props) +{ + struct sm_metadata *md; + + if (props == NULL) + props = pw_properties_new(NULL, NULL); + if (props == NULL) + return NULL; + + md = calloc(1, sizeof(*md)); + md->properties = props; + pw_array_init(&md->metadata, 4096); + + md->impl.iface = SPA_INTERFACE_INIT( + PW_TYPE_INTERFACE_Metadata, + PW_VERSION_METADATA, + &impl_metadata, md); + spa_hook_list_init(&md->hooks); + + return md; +} + +void sm_metadata_destroy(struct sm_metadata *this) +{ + clear_items(this); + pw_array_clear(&this->metadata); + pw_properties_free(this->properties); + free(this); +} diff --git a/src/extensions/metadata.h b/src/extensions/metadata.h new file mode 100644 index 000000000..2ca8098fc --- /dev/null +++ b/src/extensions/metadata.h @@ -0,0 +1,100 @@ +/* PipeWire + * + * Copyright © 2019 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef PIPEWIRE_EXT_METADATA_H +#define PIPEWIRE_EXT_METADATA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct pw_metadata { struct spa_interface iface; }; + +#define PW_VERSION_METADATA 3 + +#define PW_EXTENSION_MODULE_METADATA PIPEWIRE_MODULE_PREFIX "module-metadata" + +#define PW_METADATA_EVENT_PROPERTY 0 +#define PW_METADATA_EVENT_NUM 1 + +/** \ref pw_metadata events */ +struct pw_metadata_events { +#define PW_VERSION_METADATA_EVENTS 0 + uint32_t version; + + int (*property) (void *object, + uint32_t subject, + const char *key, + const char *type, + const char *value); +}; + +#define PW_METADATA_METHOD_ADD_LISTENER 0 +#define PW_METADATA_METHOD_SET_PROPERTY 1 +#define PW_METADATA_METHOD_CLEAR 2 +#define PW_METADATA_METHOD_NUM 3 + +/** \ref pw_metadata methods */ +struct pw_metadata_methods { +#define PW_VERSION_METADATA_METHODS 0 + uint32_t version; + + int (*add_listener) (void *object, + struct spa_hook *listener, + const struct pw_metadata_events *events, + void *data); + + int (*set_property) (void *object, + uint32_t subject, + const char *key, + const char *type, + const char *value); + + int (*clear) (void *object); +}; + + +#define pw_metadata_method(o,method,version,...) \ +({ \ + int _res = -ENOTSUP; \ + struct pw_metadata *_p = o; \ + spa_interface_call_res(&_p->iface, \ + struct pw_metadata_methods, _res, \ + method, version, ##__VA_ARGS__); \ + _res; \ +}) + +#define pw_metadata_add_listener(c,...) pw_metadata_method(c,add_listener,0,__VA_ARGS__) +#define pw_metadata_set_property(c,...) pw_metadata_method(c,set_property,0,__VA_ARGS__) +#define pw_metadata_clear(c) pw_metadata_method(c,clear,0) + +#define PW_KEY_METADATA_NAME "metadata.name" + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* PIPEWIRE_EXT_METADATA_H */