LADI
/
spa
1
Fork 0
spa/spa/tools/spa-inspect.c

300 lines
7.4 KiB
C

/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
#include <spa/support/plugin.h>
#include <spa/support/log-impl.h>
#include <spa/support/loop.h>
#include <spa/utils/result.h>
#include <spa/utils/string.h>
#include <spa/node/node.h>
#include <spa/node/utils.h>
#include <spa/pod/parser.h>
#include <spa/param/param.h>
#include <spa/param/format.h>
#include <spa/debug/dict.h>
#include <spa/debug/pod.h>
#include <spa/debug/format.h>
#include <spa/debug/types.h>
static SPA_LOG_IMPL(default_log);
struct data {
struct spa_support support[4];
uint32_t n_support;
struct spa_log *log;
struct spa_loop loop;
struct spa_node *node;
struct spa_hook listener;
};
static void print_param(void *data, int seq, int res, uint32_t type, const void *result)
{
switch (type) {
case SPA_RESULT_TYPE_NODE_PARAMS:
{
const struct spa_result_node_params *r = result;
if (spa_pod_is_object_type(r->param, SPA_TYPE_OBJECT_Format))
spa_debug_format(16, NULL, r->param);
else
spa_debug_pod(16, NULL, r->param);
break;
}
default:
break;
}
}
static void
inspect_node_params(struct data *data, struct spa_node *node,
uint32_t n_params, struct spa_param_info *params)
{
int res;
uint32_t i;
struct spa_hook listener;
static const struct spa_node_events node_events = {
SPA_VERSION_NODE_EVENTS,
.result = print_param,
};
for (i = 0; i < n_params; i++) {
printf("enumerating: %s:\n", spa_debug_type_find_name(spa_type_param, params[i].id));
if (!SPA_FLAG_IS_SET(params[i].flags, SPA_PARAM_INFO_READ))
continue;
spa_zero(listener);
spa_node_add_listener(node, &listener, &node_events, data);
res = spa_node_enum_params(node, 0, params[i].id, 0, UINT32_MAX, NULL);
spa_hook_remove(&listener);
if (res != 0) {
printf("error enum_params %d: %s", params[i].id, spa_strerror(res));
break;
}
}
}
static void
inspect_port_params(struct data *data, struct spa_node *node,
enum spa_direction direction, uint32_t port_id,
uint32_t n_params, struct spa_param_info *params)
{
int res;
uint32_t i;
struct spa_hook listener;
static const struct spa_node_events node_events = {
SPA_VERSION_NODE_EVENTS,
.result = print_param,
};
for (i = 0; i < n_params; i++) {
printf("param: %s: flags %c%c\n",
spa_debug_type_find_name(spa_type_param, params[i].id),
params[i].flags & SPA_PARAM_INFO_READ ? 'r' : '-',
params[i].flags & SPA_PARAM_INFO_WRITE ? 'w' : '-');
if (!SPA_FLAG_IS_SET(params[i].flags, SPA_PARAM_INFO_READ))
continue;
printf("values:\n");
spa_zero(listener);
spa_node_add_listener(node, &listener, &node_events, data);
res = spa_node_port_enum_params(node, 0,
direction, port_id,
params[i].id, 0, UINT32_MAX,
NULL);
spa_hook_remove(&listener);
if (res != 0) {
printf("error port_enum_params %d: %s", params[i].id, spa_strerror(res));
break;
}
}
}
static void node_info(void *_data, const struct spa_node_info *info)
{
struct data *data = _data;
printf("node info: %08"PRIx64"\n", info->change_mask);
printf("max input ports: %u\n", info->max_input_ports);
printf("max output ports: %u\n", info->max_output_ports);
if (info->change_mask & SPA_NODE_CHANGE_MASK_PROPS) {
printf("node properties:\n");
spa_debug_dict(2, info->props);
}
if (info->change_mask & SPA_NODE_CHANGE_MASK_PARAMS) {
inspect_node_params(data, data->node, info->n_params, info->params);
}
}
static void node_port_info(void *_data, enum spa_direction direction, uint32_t id,
const struct spa_port_info *info)
{
struct data *data = _data;
printf(" %s port: %08x",
direction == SPA_DIRECTION_INPUT ? "input" : "output",
id);
if (info == NULL) {
printf(" removed\n");
}
else {
printf(" info:\n");
if (info->change_mask & SPA_PORT_CHANGE_MASK_PROPS) {
printf("port properties:\n");
spa_debug_dict(2, info->props);
}
if (info->change_mask & SPA_PORT_CHANGE_MASK_PARAMS) {
inspect_port_params(data, data->node, direction, id,
info->n_params, info->params);
}
}
}
static const struct spa_node_events node_events =
{
SPA_VERSION_NODE_EVENTS,
.info = node_info,
.port_info = node_port_info,
};
static void inspect_node(struct data *data, struct spa_node *node)
{
data->node = node;
spa_node_add_listener(node, &data->listener, &node_events, data);
spa_hook_remove(&data->listener);
}
static void inspect_factory(struct data *data, const struct spa_handle_factory *factory)
{
int res;
struct spa_handle *handle;
void *interface;
const struct spa_interface_info *info;
uint32_t index;
printf("factory version:\t\t%d\n", factory->version);
printf("factory name:\t\t'%s'\n", factory->name);
if (factory->version < 1) {
printf("\tno further info for version %d < 1\n", factory->version);
return;
}
printf("factory info:\n");
if (factory->info)
spa_debug_dict(2, factory->info);
else
printf(" none\n");
printf("factory interfaces:\n");
for (index = 0;;) {
if ((res = spa_handle_factory_enum_interface_info(factory, &info, &index)) <= 0) {
if (res != 0)
printf("error spa_handle_factory_enum_interface_info: %s",
spa_strerror(res));
break;
}
printf(" interface: '%s'\n", info->type);
}
handle = calloc(1, spa_handle_factory_get_size(factory, NULL));
if ((res =
spa_handle_factory_init(factory, handle, NULL, data->support, data->n_support)) < 0) {
printf("can't make factory instance: %d\n", res);
goto out;
}
printf("factory instance:\n");
for (index = 0;;) {
if ((res = spa_handle_factory_enum_interface_info(factory, &info, &index)) <= 0) {
if (res != 0)
printf("error spa_handle_factory_enum_interface_info: %s",
spa_strerror(res));
break;
}
printf(" interface: '%s'\n", info->type);
if ((res = spa_handle_get_interface(handle, info->type, &interface)) < 0) {
printf("can't get interface: %s: %d\n", info->type, res);
continue;
}
if (spa_streq(info->type, SPA_TYPE_INTERFACE_Node))
inspect_node(data, interface);
else
printf("skipping unknown interface\n");
}
if ((res = spa_handle_clear(handle)) < 0)
printf("failed to clear handle: %s\n", spa_strerror(res));
out:
free(handle);
}
static const struct spa_loop_methods impl_loop = {
SPA_VERSION_LOOP_METHODS,
};
int main(int argc, char *argv[])
{
struct data data = { 0 };
int res;
void *handle;
spa_handle_factory_enum_func_t enum_func;
uint32_t index;
const char *str;
if (argc < 2) {
printf("usage: %s <plugin.so>\n", argv[0]);
return -1;
}
data.log = &default_log.log;
data.loop.iface = SPA_INTERFACE_INIT(
SPA_TYPE_INTERFACE_Loop,
SPA_VERSION_LOOP,
&impl_loop, &data);
if ((str = getenv("SPA_DEBUG")))
data.log->level = atoi(str);
data.support[0] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_Log, data.log);
data.support[1] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_Loop, &data.loop);
data.support[2] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_DataLoop, &data.loop);
data.n_support = 3;
if ((handle = dlopen(argv[1], RTLD_NOW)) == NULL) {
printf("can't load %s\n", argv[1]);
return -1;
}
if ((enum_func = dlsym(handle, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
printf("can't find function\n");
return -1;
}
for (index = 0;;) {
const struct spa_handle_factory *factory;
if ((res = enum_func(&factory, &index)) <= 0) {
if (res != 0)
printf("error enum_func: %s", spa_strerror(res));
break;
}
inspect_factory(&data, factory);
}
return 0;
}