diff options
Diffstat (limited to '')
-rw-r--r-- | src/pipewire/introspect.c | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/src/pipewire/introspect.c b/src/pipewire/introspect.c new file mode 100644 index 0000000..e52ef28 --- /dev/null +++ b/src/pipewire/introspect.c @@ -0,0 +1,590 @@ +/* PipeWire + * + * Copyright © 2018 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 <string.h> + +#include <spa/pod/builder.h> + +#include "pipewire/pipewire.h" + +#include "pipewire/core.h" + +SPA_EXPORT +const char *pw_node_state_as_string(enum pw_node_state state) +{ + switch (state) { + case PW_NODE_STATE_ERROR: + return "error"; + case PW_NODE_STATE_CREATING: + return "creating"; + case PW_NODE_STATE_SUSPENDED: + return "suspended"; + case PW_NODE_STATE_IDLE: + return "idle"; + case PW_NODE_STATE_RUNNING: + return "running"; + } + return "invalid-state"; +} + +SPA_EXPORT +const char *pw_direction_as_string(enum pw_direction direction) +{ + switch (direction) { + case PW_DIRECTION_INPUT: + return "input"; + case PW_DIRECTION_OUTPUT: + return "output"; + } + return "invalid"; +} + +SPA_EXPORT +const char *pw_link_state_as_string(enum pw_link_state state) +{ + switch (state) { + case PW_LINK_STATE_ERROR: + return "error"; + case PW_LINK_STATE_UNLINKED: + return "unlinked"; + case PW_LINK_STATE_INIT: + return "init"; + case PW_LINK_STATE_NEGOTIATING: + return "negotiating"; + case PW_LINK_STATE_ALLOCATING: + return "allocating"; + case PW_LINK_STATE_PAUSED: + return "paused"; + case PW_LINK_STATE_ACTIVE: + return "active"; + } + return "invalid-state"; +} + +static void pw_spa_dict_destroy(struct spa_dict *dict) +{ + const struct spa_dict_item *item; + + spa_dict_for_each(item, dict) { + free((void *) item->key); + free((void *) item->value); + } + free((void*)dict->items); + free(dict); +} + +static struct spa_dict *pw_spa_dict_copy(struct spa_dict *dict) +{ + struct spa_dict *copy; + struct spa_dict_item *items; + uint32_t i; + + if (dict == NULL) + return NULL; + + copy = calloc(1, sizeof(struct spa_dict)); + if (copy == NULL) + goto no_mem; + copy->items = items = calloc(dict->n_items, sizeof(struct spa_dict_item)); + if (copy->items == NULL) + goto no_items; + copy->n_items = dict->n_items; + + for (i = 0; i < dict->n_items; i++) { + items[i].key = strdup(dict->items[i].key); + items[i].value = dict->items[i].value ? strdup(dict->items[i].value) : NULL; + } + return copy; + + no_items: + free(copy); + no_mem: + return NULL; +} + +SPA_EXPORT +struct pw_core_info *pw_core_info_merge(struct pw_core_info *info, + const struct pw_core_info *update, bool reset) +{ + if (update == NULL) + return info; + + if (info == NULL) { + info = calloc(1, sizeof(struct pw_core_info)); + if (info == NULL) + return NULL; + + info->id = update->id; + info->cookie = update->cookie; + info->user_name = update->user_name ? strdup(update->user_name) : NULL; + info->host_name = update->host_name ? strdup(update->host_name) : NULL; + info->version = update->version ? strdup(update->version) : NULL; + info->name = update->name ? strdup(update->name) : NULL; + } + if (reset) + info->change_mask = 0; + info->change_mask |= update->change_mask; + + if (update->change_mask & PW_CORE_CHANGE_MASK_PROPS) { + if (info->props) + pw_spa_dict_destroy(info->props); + info->props = pw_spa_dict_copy(update->props); + } + return info; +} + +SPA_EXPORT +struct pw_core_info *pw_core_info_update(struct pw_core_info *info, + const struct pw_core_info *update) +{ + return pw_core_info_merge(info, update, true); +} + +SPA_EXPORT +void pw_core_info_free(struct pw_core_info *info) +{ + free((void *) info->user_name); + free((void *) info->host_name); + free((void *) info->version); + free((void *) info->name); + if (info->props) + pw_spa_dict_destroy(info->props); + free(info); +} + +SPA_EXPORT +struct pw_node_info *pw_node_info_merge(struct pw_node_info *info, + const struct pw_node_info *update, bool reset) +{ + if (update == NULL) + return info; + + if (info == NULL) { + info = calloc(1, sizeof(struct pw_node_info)); + if (info == NULL) + return NULL; + + info->id = update->id; + info->max_input_ports = update->max_input_ports; + info->max_output_ports = update->max_output_ports; + } + if (reset) + info->change_mask = 0; + info->change_mask |= update->change_mask; + + if (update->change_mask & PW_NODE_CHANGE_MASK_INPUT_PORTS) { + info->n_input_ports = update->n_input_ports; + } + if (update->change_mask & PW_NODE_CHANGE_MASK_OUTPUT_PORTS) { + info->n_output_ports = update->n_output_ports; + } + if (update->change_mask & PW_NODE_CHANGE_MASK_STATE) { + info->state = update->state; + free((void *) info->error); + info->error = update->error ? strdup(update->error) : NULL; + } + if (update->change_mask & PW_NODE_CHANGE_MASK_PROPS) { + if (info->props) + pw_spa_dict_destroy(info->props); + info->props = pw_spa_dict_copy(update->props); + } + if (update->change_mask & PW_NODE_CHANGE_MASK_PARAMS) { + uint32_t i, n_params = update->n_params; + void *np; + + np = pw_reallocarray(info->params, n_params, sizeof(struct spa_param_info)); + if (np == NULL) { + free(info->params); + info->params = NULL; + info->n_params = n_params = 0; + } + info->params = np; + + for (i = 0; i < SPA_MIN(info->n_params, n_params); i++) { + info->params[i].id = update->params[i].id; + if (reset) + info->params[i].user = 0; + if (info->params[i].flags != update->params[i].flags) { + info->params[i].flags = update->params[i].flags; + info->params[i].user++; + } + } + info->n_params = n_params; + for (; i < info->n_params; i++) { + info->params[i].id = update->params[i].id; + info->params[i].flags = update->params[i].flags; + info->params[i].user = 1; + } + } + return info; +} + +SPA_EXPORT +struct pw_node_info *pw_node_info_update(struct pw_node_info *info, + const struct pw_node_info *update) +{ + return pw_node_info_merge(info, update, true); +} + +SPA_EXPORT +void pw_node_info_free(struct pw_node_info *info) +{ + free((void *) info->error); + if (info->props) + pw_spa_dict_destroy(info->props); + free((void *) info->params); + free(info); +} + +SPA_EXPORT +struct pw_port_info *pw_port_info_merge(struct pw_port_info *info, + const struct pw_port_info *update, bool reset) +{ + + if (update == NULL) + return info; + + if (info == NULL) { + info = calloc(1, sizeof(struct pw_port_info)); + if (info == NULL) + return NULL; + + info->id = update->id; + info->direction = update->direction; + } + if (reset) + info->change_mask = 0; + info->change_mask |= update->change_mask; + + if (update->change_mask & PW_PORT_CHANGE_MASK_PROPS) { + if (info->props) + pw_spa_dict_destroy(info->props); + info->props = pw_spa_dict_copy(update->props); + } + if (update->change_mask & PW_PORT_CHANGE_MASK_PARAMS) { + uint32_t i, n_params = update->n_params; + void *np; + + np = pw_reallocarray(info->params, n_params, sizeof(struct spa_param_info)); + if (np == NULL) { + free(info->params); + info->params = NULL; + info->n_params = n_params = 0; + } + info->params = np; + + for (i = 0; i < SPA_MIN(info->n_params, n_params); i++) { + info->params[i].id = update->params[i].id; + if (reset) + info->params[i].user = 0; + if (info->params[i].flags != update->params[i].flags) { + info->params[i].flags = update->params[i].flags; + info->params[i].user++; + } + } + info->n_params = n_params; + for (; i < info->n_params; i++) { + info->params[i].id = update->params[i].id; + info->params[i].flags = update->params[i].flags; + info->params[i].user = 1; + } + } + return info; +} + +SPA_EXPORT +struct pw_port_info *pw_port_info_update(struct pw_port_info *info, + const struct pw_port_info *update) +{ + return pw_port_info_merge(info, update, true); +} + +SPA_EXPORT +void pw_port_info_free(struct pw_port_info *info) +{ + if (info->props) + pw_spa_dict_destroy(info->props); + free((void *) info->params); + free(info); +} + +SPA_EXPORT +struct pw_factory_info *pw_factory_info_merge(struct pw_factory_info *info, + const struct pw_factory_info *update, bool reset) +{ + if (update == NULL) + return info; + + if (info == NULL) { + info = calloc(1, sizeof(struct pw_factory_info)); + if (info == NULL) + return NULL; + + info->id = update->id; + info->name = update->name ? strdup(update->name) : NULL; + info->type = update->type ? strdup(update->type) : NULL; + info->version = update->version; + } + if (reset) + info->change_mask = 0; + info->change_mask |= update->change_mask; + + if (update->change_mask & PW_FACTORY_CHANGE_MASK_PROPS) { + if (info->props) + pw_spa_dict_destroy(info->props); + info->props = pw_spa_dict_copy(update->props); + } + return info; +} + +SPA_EXPORT +struct pw_factory_info *pw_factory_info_update(struct pw_factory_info *info, + const struct pw_factory_info *update) +{ + return pw_factory_info_merge(info, update, true); +} + +SPA_EXPORT +void pw_factory_info_free(struct pw_factory_info *info) +{ + free((void *) info->name); + free((void *) info->type); + if (info->props) + pw_spa_dict_destroy(info->props); + free(info); +} + +SPA_EXPORT +struct pw_module_info *pw_module_info_merge(struct pw_module_info *info, + const struct pw_module_info *update, bool reset) +{ + if (update == NULL) + return info; + + if (info == NULL) { + info = calloc(1, sizeof(struct pw_module_info)); + if (info == NULL) + return NULL; + + info->id = update->id; + info->name = update->name ? strdup(update->name) : NULL; + info->filename = update->filename ? strdup(update->filename) : NULL; + info->args = update->args ? strdup(update->args) : NULL; + } + if (reset) + info->change_mask = 0; + info->change_mask |= update->change_mask; + + if (update->change_mask & PW_MODULE_CHANGE_MASK_PROPS) { + if (info->props) + pw_spa_dict_destroy(info->props); + info->props = pw_spa_dict_copy(update->props); + } + return info; +} + +SPA_EXPORT +struct pw_module_info *pw_module_info_update(struct pw_module_info *info, + const struct pw_module_info *update) +{ + return pw_module_info_merge(info, update, true); +} + +SPA_EXPORT +void pw_module_info_free(struct pw_module_info *info) +{ + free((void *) info->name); + free((void *) info->filename); + free((void *) info->args); + if (info->props) + pw_spa_dict_destroy(info->props); + free(info); +} + +SPA_EXPORT +struct pw_device_info *pw_device_info_merge(struct pw_device_info *info, + const struct pw_device_info *update, bool reset) +{ + if (update == NULL) + return info; + + if (info == NULL) { + info = calloc(1, sizeof(struct pw_device_info)); + if (info == NULL) + return NULL; + + info->id = update->id; + } + if (reset) + info->change_mask = 0; + info->change_mask |= update->change_mask; + + if (update->change_mask & PW_DEVICE_CHANGE_MASK_PROPS) { + if (info->props) + pw_spa_dict_destroy(info->props); + info->props = pw_spa_dict_copy(update->props); + } + if (update->change_mask & PW_DEVICE_CHANGE_MASK_PARAMS) { + uint32_t i, n_params = update->n_params; + void *np; + + np = pw_reallocarray(info->params, n_params, sizeof(struct spa_param_info)); + if (np == NULL) { + free(info->params); + info->params = NULL; + info->n_params = n_params = 0; + } + info->params = np; + + for (i = 0; i < SPA_MIN(info->n_params, n_params); i++) { + info->params[i].id = update->params[i].id; + if (reset) + info->params[i].user = 0; + if (info->params[i].flags != update->params[i].flags) { + info->params[i].flags = update->params[i].flags; + info->params[i].user++; + } + } + info->n_params = n_params; + for (; i < info->n_params; i++) { + info->params[i].id = update->params[i].id; + info->params[i].flags = update->params[i].flags; + info->params[i].user = 1; + } + } + return info; +} + +SPA_EXPORT +struct pw_device_info *pw_device_info_update(struct pw_device_info *info, + const struct pw_device_info *update) +{ + return pw_device_info_merge(info, update, true); +} + +SPA_EXPORT +void pw_device_info_free(struct pw_device_info *info) +{ + if (info->props) + pw_spa_dict_destroy(info->props); + free((void *) info->params); + free(info); +} + +SPA_EXPORT +struct pw_client_info *pw_client_info_merge(struct pw_client_info *info, + const struct pw_client_info *update, bool reset) +{ + if (update == NULL) + return info; + + if (info == NULL) { + info = calloc(1, sizeof(struct pw_client_info)); + if (info == NULL) + return NULL; + + info->id = update->id; + } + if (reset) + info->change_mask = 0; + info->change_mask |= update->change_mask; + + if (update->change_mask & PW_CLIENT_CHANGE_MASK_PROPS) { + if (info->props) + pw_spa_dict_destroy(info->props); + info->props = pw_spa_dict_copy(update->props); + } + return info; +} + +SPA_EXPORT +struct pw_client_info *pw_client_info_update(struct pw_client_info *info, + const struct pw_client_info *update) +{ + return pw_client_info_merge(info, update, true); +} + +SPA_EXPORT +void pw_client_info_free(struct pw_client_info *info) +{ + if (info->props) + pw_spa_dict_destroy(info->props); + free(info); +} + +SPA_EXPORT +struct pw_link_info *pw_link_info_merge(struct pw_link_info *info, + const struct pw_link_info *update, bool reset) +{ + if (update == NULL) + return info; + + if (info == NULL) { + info = calloc(1, sizeof(struct pw_link_info)); + if (info == NULL) + return NULL; + + info->id = update->id; + info->output_node_id = update->output_node_id; + info->output_port_id = update->output_port_id; + info->input_node_id = update->input_node_id; + info->input_port_id = update->input_port_id; + } + if (reset) + info->change_mask = 0; + info->change_mask |= update->change_mask; + + if (update->change_mask & PW_LINK_CHANGE_MASK_STATE) { + info->state = update->state; + free((void *) info->error); + info->error = update->error ? strdup(update->error) : NULL; + } + if (update->change_mask & PW_LINK_CHANGE_MASK_FORMAT) { + free(info->format); + info->format = update->format ? spa_pod_copy(update->format) : NULL; + } + if (update->change_mask & PW_LINK_CHANGE_MASK_PROPS) { + if (info->props) + pw_spa_dict_destroy(info->props); + info->props = pw_spa_dict_copy(update->props); + } + return info; +} + +SPA_EXPORT +struct pw_link_info *pw_link_info_update(struct pw_link_info *info, + const struct pw_link_info *update) +{ + return pw_link_info_merge(info, update, true); +} + +SPA_EXPORT +void pw_link_info_free(struct pw_link_info *info) +{ + free((void *) info->error); + free(info->format); + if (info->props) + pw_spa_dict_destroy(info->props); + free(info); +} |