core: add message handler

This patch adds a small message handler to the core which enables
clients to list available handlers via the list-handlers message.
Command: pacmd send-message /core list-handlers
pactl can be used with the same parameters.

The patch also introduces a convention for the return string.
It consists of a list of elements where curly braces are used
to separate elements. Each element can itself contain further
elements. For example consider a message that returns multiple
elements which each contain an integer and an array of float.
A response string would look like that:
{{Integer} {{1st float} {2nd float} ...}}{...}

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/51>
This commit is contained in:
Georg Chini 2020-01-14 11:00:20 +01:00 committed by Tanu Kaskinen
parent 68f2f1395d
commit 5c0ab52145
3 changed files with 84 additions and 6 deletions

View File

@ -6,10 +6,19 @@ PA_COMMAND_SEND_OBJECT_MESSAGE. A message consists at least of an object path
and a message command, both specified as strings. Additional parameters can
be specified using a single string, but are not mandatory. The message handler
returns an error number as defined in def.h and also returns a string in
the "response" variable. The following reference lists available messages,
their parameters and return values.
the "response" variable. If the string is not empty it consists of elements.
Curly braces are used to separate elements. Each element can itself contain
further elements. For example consider a message that returns multiple elements
which each contain an integer and an array of float. A response string would
look like that:
{{Integer} {{1st float} {2nd float} ...}}{...}
Any characters that are not enclosed in curly braces are ignored (all characters
between { and {, between } and } and between } and {). The same syntax is used
to specify message parameters. The following reference lists available messages,
their parameters and return values. If a return value is enclosed in {}, this
means that multiple elements of the same type may be returned.
Recipient:
Message:
Parameters:
Return value:
Object path: /core
Message: list-handlers
Parameters: None
Return value: {{{Handler name} {Description}} ...}

View File

@ -33,11 +33,13 @@
#include <pulsecore/module.h>
#include <pulsecore/core-rtclock.h>
#include <pulsecore/core-util.h>
#include <pulsecore/message-handler.h>
#include <pulsecore/core-scache.h>
#include <pulsecore/core-subscribe.h>
#include <pulsecore/random.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/strbuf.h>
#include "core.h"
@ -61,6 +63,45 @@ static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t o
static void core_free(pa_object *o);
/* Returns a list of handlers. */
static char *message_handler_list(pa_core *c) {
pa_strbuf *buf;
void *state = NULL;
struct pa_message_handler *handler;
buf = pa_strbuf_new();
pa_strbuf_putc(buf, '{');
PA_HASHMAP_FOREACH(handler, c->message_handlers, state) {
pa_strbuf_putc(buf, '{');
pa_strbuf_printf(buf, "{%s} {", handler->object_path);
if (handler->description)
pa_strbuf_puts(buf, handler->description);
pa_strbuf_puts(buf, "}}");
}
pa_strbuf_putc(buf, '}');
return pa_strbuf_to_string_free(buf);
}
static int core_message_handler(const char *object_path, const char *message, const char *message_parameters, char **response, void *userdata) {
pa_core *c;
pa_assert(c = (pa_core *) userdata);
pa_assert(message);
pa_assert(response);
pa_assert(pa_safe_streq(object_path, "/core"));
if (pa_streq(message, "list-handlers")) {
*response = message_handler_list(c);
return PA_OK;
}
return -PA_ERR_NOTIMPLEMENTED;
}
pa_core* pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t shm_size) {
pa_core* c;
pa_mempool *pool;
@ -105,6 +146,8 @@ pa_core* pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t
c->shared = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
c->message_handlers = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
pa_message_handler_register(c, "/core", "Core message handler", core_message_handler, (void *) c);
c->default_source = NULL;
c->default_sink = NULL;
@ -202,6 +245,8 @@ static void core_free(pa_object *o) {
pa_assert(pa_hashmap_isempty(c->shared));
pa_hashmap_free(c->shared);
pa_message_handler_unregister(c, "/core");
pa_assert(pa_hashmap_isempty(c->message_handlers));
pa_hashmap_free(c->message_handlers);

View File

@ -31,6 +31,20 @@
#include "message-handler.h"
/* Check if a string does not contain control characters. Currently these are
* only "{" and "}". */
static bool string_is_valid(const char *test_string) {
uint32_t i;
for (i = 0; test_string[i]; i++) {
if (test_string[i] == '{' ||
test_string[i] == '}')
return false;
}
return true;
}
/* Message handler functions */
/* Register message handler for the specified object. object_path must be a unique name starting with "/". */
@ -45,6 +59,11 @@ void pa_message_handler_register(pa_core *c, const char *object_path, const char
/* Ensure that the object path is not empty and starts with "/". */
pa_assert(object_path[0] == '/');
/* Ensure that object path and description are valid strings */
pa_assert(string_is_valid(object_path));
if (description)
pa_assert(string_is_valid(description));
handler = pa_xnew0(struct pa_message_handler, 1);
handler->userdata = userdata;
handler->callback = cb;
@ -97,6 +116,11 @@ int pa_message_handler_set_description(pa_core *c, const char *object_path, cons
if (!(handler = pa_hashmap_get(c->message_handlers, object_path)))
return -PA_ERR_NOENTITY;
if (description) {
if (!string_is_valid(description))
return -PA_ERR_INVALID;
}
pa_xfree(handler->description);
handler->description = pa_xstrdup(description);