mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-26 07:58:03 -04:00
spa: Add a varlink client support library
This commit is contained in:
parent
8b8241d6e3
commit
7caf86eaa6
6 changed files with 1069 additions and 0 deletions
|
|
@ -27,6 +27,17 @@ if find.found()
|
|||
endforeach
|
||||
endif
|
||||
|
||||
utils = [
|
||||
['varlink-call', []],
|
||||
]
|
||||
|
||||
foreach a : utils
|
||||
executable('spa-' + a[0], a[0] + '.c',
|
||||
dependencies : [ spa_dep, dl_lib, pthread_lib, mathlib ] + a[1],
|
||||
include_directories : [configinc],
|
||||
)
|
||||
endforeach
|
||||
|
||||
benchmark_apps = [
|
||||
['stress-ringbuffer', []],
|
||||
['benchmark-pod', []],
|
||||
|
|
|
|||
260
spa/tests/varlink-call.c
Normal file
260
spa/tests/varlink-call.c
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
/* Spa */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2026 Arun Raghavan */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <spa/support/log.h>
|
||||
#include <spa/support/loop.h>
|
||||
#include <spa/support/plugin.h>
|
||||
#include <spa/support/varlink.h>
|
||||
#include <spa/utils/dict.h>
|
||||
#include <spa/utils/hook.h>
|
||||
#include <spa/utils/names.h>
|
||||
#include <spa/utils/json-core.h>
|
||||
#include <spa/utils/result.h>
|
||||
#include <time.h>
|
||||
|
||||
struct data {
|
||||
const char *plugin_dir;
|
||||
|
||||
struct spa_support support[16];
|
||||
uint32_t n_support;
|
||||
struct spa_log *log;
|
||||
struct spa_loop *loop;
|
||||
struct spa_loop_control *loop_control;
|
||||
struct spa_loop_utils *loop_utils;
|
||||
struct spa_system *system;
|
||||
|
||||
struct spa_varlink *varlink;
|
||||
struct spa_varlink_client *client;
|
||||
struct spa_hook listener;
|
||||
|
||||
bool running;
|
||||
};
|
||||
|
||||
static int load_handle(struct data *data, struct spa_handle **handle, const
|
||||
char *lib, const char *name, struct spa_dict *info)
|
||||
{
|
||||
int res;
|
||||
void *hnd;
|
||||
spa_handle_factory_enum_func_t enum_func;
|
||||
uint32_t i;
|
||||
char *path;
|
||||
|
||||
if ((path = spa_aprintf("%s/%s", data->plugin_dir, lib)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
hnd = dlopen(path, RTLD_NOW);
|
||||
free(path);
|
||||
|
||||
if (hnd == NULL) {
|
||||
printf("can't load %s: %s\n", lib, dlerror());
|
||||
return -ENOENT;
|
||||
}
|
||||
if ((enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
|
||||
printf("can't find enum function\n");
|
||||
res = -ENOENT;
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
||||
for (i = 0;;) {
|
||||
const struct spa_handle_factory *factory;
|
||||
|
||||
if ((res = enum_func(&factory, &i)) <= 0) {
|
||||
if (res != 0)
|
||||
printf("can't enumerate factories: %s\n", spa_strerror(res));
|
||||
break;
|
||||
}
|
||||
if (factory->version < 1)
|
||||
continue;
|
||||
if (!spa_streq(factory->name, name))
|
||||
continue;
|
||||
|
||||
*handle = calloc(1, spa_handle_factory_get_size(factory, NULL));
|
||||
if ((res = spa_handle_factory_init(factory, *handle,
|
||||
info, data->support,
|
||||
data->n_support)) < 0) {
|
||||
printf("can't make factory instance: %d\n", res);
|
||||
goto exit_cleanup;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -EBADF;
|
||||
|
||||
exit_cleanup:
|
||||
dlclose(hnd);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int init(struct data *data)
|
||||
{
|
||||
struct spa_handle *handle;
|
||||
struct spa_dict_item items[1];
|
||||
struct spa_dict info;
|
||||
const char *str;
|
||||
void *iface;
|
||||
int res;
|
||||
|
||||
if ((str = getenv("SPA_PLUGIN_DIR")) == NULL)
|
||||
str = PLUGINDIR;
|
||||
data->plugin_dir = str;
|
||||
|
||||
/* enable the debug messages in SPA */
|
||||
items[0] = SPA_DICT_ITEM_INIT(SPA_KEY_LOG_TIMESTAMP, "true");
|
||||
info = SPA_DICT_ARRAY(items);
|
||||
if ((res = load_handle(data, &handle, "support/libspa-support.so",
|
||||
SPA_NAME_SUPPORT_LOG, &info)) < 0)
|
||||
return res;
|
||||
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Log, &iface)) < 0) {
|
||||
printf("can't get System interface %d\n", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
data->log = iface;
|
||||
data->support[data->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_Log, data->log);
|
||||
|
||||
if ((str = getenv("SPA_DEBUG")))
|
||||
data->log->level = atoi(str);
|
||||
|
||||
/* load and set support system */
|
||||
if ((res = load_handle(data, &handle,
|
||||
"support/libspa-support.so",
|
||||
SPA_NAME_SUPPORT_SYSTEM, NULL)) < 0)
|
||||
return res;
|
||||
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_System, &iface)) < 0) {
|
||||
printf("can't get System interface %d\n", res);
|
||||
return res;
|
||||
}
|
||||
data->system = iface;
|
||||
data->support[data->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_System, data->system);
|
||||
data->support[data->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_DataSystem, data->system);
|
||||
|
||||
/* load and set support loop and loop control */
|
||||
if ((res = load_handle(data, &handle,
|
||||
"support/libspa-support.so",
|
||||
SPA_NAME_SUPPORT_LOOP, NULL)) < 0)
|
||||
return res;
|
||||
|
||||
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Loop, &iface)) < 0) {
|
||||
printf("can't get interface %d\n", res);
|
||||
return res;
|
||||
}
|
||||
data->loop = iface;
|
||||
data->support[data->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_Loop, data->loop);
|
||||
data->support[data->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_DataLoop, data->loop);
|
||||
|
||||
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_LoopControl, &iface)) < 0) {
|
||||
printf("can't get interface %d\n", res);
|
||||
return res;
|
||||
}
|
||||
data->loop_control = iface;
|
||||
data->support[data->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_LoopControl, data->loop_control);
|
||||
|
||||
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_LoopUtils, &iface)) < 0) {
|
||||
printf("can't get interface %d\n", res);
|
||||
return res;
|
||||
}
|
||||
data->loop_utils = iface;
|
||||
data->support[data->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_LoopUtils, data->loop_utils);
|
||||
|
||||
/* load varlink */
|
||||
if ((res = load_handle(data, &handle,
|
||||
"support/libspa-varlink.so",
|
||||
SPA_NAME_SUPPORT_VARLINK, NULL)) < 0)
|
||||
return res;
|
||||
|
||||
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Varlink, &iface)) < 0) {
|
||||
printf("can't get interface %d\n", res);
|
||||
return res;
|
||||
}
|
||||
data->varlink = iface;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
on_reply(void *userdata, const char *params, const char *error, size_t len, bool continues)
|
||||
{
|
||||
struct data *data = userdata;
|
||||
|
||||
if (params) {
|
||||
printf("Got reply: params: %.*s, continues: %s\n",
|
||||
(int) len, params, continues ? "true" : "false");
|
||||
} else {
|
||||
printf("Got reply: error: %.*s\n", (int) len, error);
|
||||
}
|
||||
|
||||
data->running = false;
|
||||
}
|
||||
|
||||
static void on_disconnect(void *userdata)
|
||||
{
|
||||
struct data *data = userdata;
|
||||
printf("Disconnected\n");
|
||||
data->running = false;
|
||||
}
|
||||
|
||||
static void on_destroy(void *userdata)
|
||||
{
|
||||
printf("Destroyed\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct data data = { 0 };
|
||||
struct spa_varlink_client_events events = {
|
||||
.disconnect = on_disconnect,
|
||||
.destroy = on_destroy,
|
||||
};
|
||||
int res;
|
||||
bool sync = true;
|
||||
|
||||
if (argc < 4 || argc > 5) {
|
||||
printf("usage: %s <socket> <method> <parameters> <sync: 1|0>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = init(&data);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
if (argc == 5)
|
||||
sync = argv[4][0] == '1';
|
||||
|
||||
data.running = true;
|
||||
|
||||
data.client = spa_varlink_connect(data.varlink, argv[1]);
|
||||
if (data.client == NULL) {
|
||||
printf("Could not connect to socket: %s\n", spa_strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
spa_varlink_client_add_listener(data.client, &data.listener, &events, &data);
|
||||
|
||||
if (sync) {
|
||||
char *reply;
|
||||
res = spa_varlink_client_call_sync(data.client, argv[2], argv[3], &reply);
|
||||
if (res < 0) {
|
||||
printf("Call failed: %s\n", spa_strerror(res));
|
||||
return -1;
|
||||
}
|
||||
printf("Got reply (%d): %s\n", res, reply);
|
||||
} else {
|
||||
res = spa_varlink_client_call(data.client, argv[2], argv[3], false, false, on_reply, &data);
|
||||
if (res < 0) {
|
||||
printf("Could not connect to socket: %s\n", spa_strerror(res));
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (data.running) {
|
||||
spa_loop_control_iterate(data.loop_control, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
spa_varlink_client_destroy(data.client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue