[pulseaudio-discuss] [PATCH 2/5] protocol-native: add message sending capability
Tanu Kaskinen
tanuk at iki.fi
Fri Dec 29 15:06:57 UTC 2017
On Sun, 2017-10-29 at 20:51 +0100, Georg Chini wrote:
> This patch adds the PA_COMMAND_SEND_OBJECT_MESSAGE command to protocol-native
> so that clients can use the messaging feature introduced in the previous patch.
>
> Sending messages can in effect replace the extension system for modules. The
> approach is more flexible than the extension interface because a generic string
> format is used to exchange information. Furthermore the messaging system can be
> used for any object, not only for modules, and is easier to implement than
> extensions.
> ---
> PROTOCOL | 14 ++++++++++
> configure.ac | 2 +-
> src/map-file | 1 +
> src/pulse/introspect.c | 61 +++++++++++++++++++++++++++++++++++++++++
> src/pulse/introspect.h | 16 +++++++++++
> src/pulsecore/native-common.h | 3 ++
> src/pulsecore/pdispatch.c | 3 ++
> src/pulsecore/protocol-native.c | 51 ++++++++++++++++++++++++++++++++++
> 8 files changed, 150 insertions(+), 1 deletion(-)
>
> diff --git a/PROTOCOL b/PROTOCOL
> index 546998b7..b57edea5 100644
> --- a/PROTOCOL
> +++ b/PROTOCOL
> @@ -420,6 +420,20 @@ memfd support only to 10.0+ clients.
>
> Check commit 451d1d676237c81 for further details.
>
> +## v33, implemented by >= 12.0
> +
> +Added new command for communication with objects.
> +
> +PA_COMMAND_SEND_OBJECT_MESSAGE:
> +sends a message to an object that registered a named message handler
> +
> +parameters:
> + const char *recipient_name - name of message handler
> + const char *message - message command
> + const char *message_parameters - additional parameters if required
s/const char */string /
(to be consistent with the v26 section)
> +
> +The command returns a string.
> +
> #### If you just changed the protocol, read this
> ## module-tunnel depends on the sink/source/sink-input/source-input protocol
> ## internals, so if you changed these, you might have broken module-tunnel.
> diff --git a/configure.ac b/configure.ac
> index 0c38fbb5..cd62a477 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -40,7 +40,7 @@ AC_SUBST(PA_MINOR, pa_minor)
> AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
>
> AC_SUBST(PA_API_VERSION, 12)
> -AC_SUBST(PA_PROTOCOL_VERSION, 32)
> +AC_SUBST(PA_PROTOCOL_VERSION, 33)
>
> # The stable ABI for client applications, for the version info x:y:z
> # always will hold y=z
> diff --git a/src/map-file b/src/map-file
> index 93a62b86..9f6181f1 100644
> --- a/src/map-file
> +++ b/src/map-file
> @@ -87,6 +87,7 @@ pa_context_remove_autoload_by_name;
> pa_context_remove_sample;
> pa_context_rttime_new;
> pa_context_rttime_restart;
> +pa_context_send_message_to_object;
> pa_context_set_card_profile_by_index;
> pa_context_set_card_profile_by_name;
> pa_context_set_default_sink;
> diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
> index 510d784a..fb64150b 100644
> --- a/src/pulse/introspect.c
> +++ b/src/pulse/introspect.c
> @@ -2184,3 +2184,64 @@ pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, in
>
> return o;
> }
> +
> +/** Object response string **/
> +
> +static void context_string_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
> + pa_operation *o = userdata;
> + const char *response;
> + int success = 0;
> +
> + pa_assert(pd);
> + pa_assert(o);
> + pa_assert(PA_REFCNT_VALUE(o) >= 1);
> +
> + if (!o->context)
> + goto finish;
> +
> + if (command != PA_COMMAND_REPLY) {
> + if (pa_context_handle_error(o->context, command, t, false) < 0)
> + goto finish;
> +
> + success = -1;
> + response = NULL;
> + } else if (pa_tagstruct_gets(t, &response) < 0 ||
> + !pa_tagstruct_eof(t)) {
> + pa_context_fail(o->context, PA_ERR_PROTOCOL);
> + goto finish;
> + }
> +
> + if (o->callback) {
> + pa_context_string_cb_t cb = (pa_context_string_cb_t) o->callback;
> + cb(o->context, success, response, o->userdata);
> + }
> +
> +finish:
> + pa_operation_done(o);
> + pa_operation_unref(o);
> +}
> +
> +pa_operation* pa_context_send_message_to_object(pa_context *c, const char *recipient_name, const char *message, const char *message_parameters, pa_context_string_cb_t cb, void *userdata) {
> + pa_operation *o;
> + pa_tagstruct *t;
> + uint32_t tag;
> +
> + pa_assert(c);
> + pa_assert(PA_REFCNT_VALUE(c) >= 1);
> +
> + PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
> + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
> +
> + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
> +
> + t = pa_tagstruct_command(c, PA_COMMAND_SEND_OBJECT_MESSAGE, &tag);
> +
> + pa_tagstruct_puts(t, recipient_name);
> + pa_tagstruct_puts(t, message);
> + pa_tagstruct_puts(t, message_parameters);
> +
> + pa_pstream_send_tagstruct(c->pstream, t);
> + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_string_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
> +
> + return o;
> +}
> diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
> index 43389b73..e46e66e0 100644
> --- a/src/pulse/introspect.h
> +++ b/src/pulse/introspect.h
> @@ -204,6 +204,12 @@
> * Server modules can be remotely loaded and unloaded using
> * pa_context_load_module() and pa_context_unload_module().
> *
> + * \subsection message_subsec Messages
> + *
> + * Server objects like sinks, sink inputs or modules can register a message
> + * handler to communicate with clients. A message can be sent to a named
> + * message handler using pa_context_send_message_to_object().
> + *
> * \subsection client_subsec Clients
> *
> * The only operation supported on clients is the possibility of kicking
> @@ -423,6 +429,9 @@ typedef struct pa_module_info {
> /** Callback prototype for pa_context_get_module_info() and friends */
> typedef void (*pa_module_info_cb_t) (pa_context *c, const pa_module_info*i, int eol, void *userdata);
>
> +/** Callback prototype for pa_context_send_message_to_object() */
> +typedef void (*pa_context_string_cb_t)(pa_context *c, int success, const char *response, void *userdata);
> +
This would fit better in the "Messages" section.
> /** Get some information about a module by its index */
> pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata);
>
> @@ -440,6 +449,13 @@ pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_s
>
> /** @} */
>
> +/** @{ \name Messages */
> +
> +/** Send a message to an object that registered a message handler. */
> +pa_operation* pa_context_send_message_to_object(pa_context *c, const char *recipient_name, const char *message, const char *message_parameters, pa_context_string_cb_t cb, void *userdata);
There should be pointer to the message API documentation.
> +
> +/** @} */
> +
> /** @{ \name Clients */
>
> /** Stores information about clients. Please note that this structure
> diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h
> index 70338b9f..5c3cf521 100644
> --- a/src/pulsecore/native-common.h
> +++ b/src/pulsecore/native-common.h
> @@ -187,6 +187,9 @@ enum {
> * BOTH DIRECTIONS */
> PA_COMMAND_REGISTER_MEMFD_SHMID,
>
> + /* Supported since protocol v33 (12.0) */
> + PA_COMMAND_SEND_OBJECT_MESSAGE,
> +
> PA_COMMAND_MAX
> };
>
> diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c
> index ab632a5a..d317a15e 100644
> --- a/src/pulsecore/pdispatch.c
> +++ b/src/pulsecore/pdispatch.c
> @@ -199,6 +199,9 @@ static const char *command_names[PA_COMMAND_MAX] = {
> /* Supported since protocol v31 (9.0) */
> /* BOTH DIRECTIONS */
> [PA_COMMAND_REGISTER_MEMFD_SHMID] = "REGISTER_MEMFD_SHMID",
> +
> + /* Supported since protocol v33 (12.0) */
> + [PA_COMMAND_SEND_OBJECT_MESSAGE] = "SEND_OBJECT_MESSAGE",
> };
>
> #endif
> diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
> index 6ff5ed40..76905207 100644
> --- a/src/pulsecore/protocol-native.c
> +++ b/src/pulsecore/protocol-native.c
> @@ -47,6 +47,7 @@
> #include <pulsecore/namereg.h>
> #include <pulsecore/core-scache.h>
> #include <pulsecore/core-subscribe.h>
> +#include <pulsecore/message-handler.h>
> #include <pulsecore/log.h>
> #include <pulsecore/mem.h>
> #include <pulsecore/strlist.h>
> @@ -4685,6 +4686,54 @@ static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag,
> protocol_error(c);
> }
>
> +/* Send message to an object which registered a handler. Result must be returned as string. */
> +static void command_send_object_message(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
> + pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
> + const char *recipient_name = NULL;
> + const char *message = NULL;
> + const char *message_parameters = NULL;
> + const char *client_name;
> + char *response = NULL;
> + int ret;
> + pa_tagstruct *reply;
> +
> + pa_native_connection_assert_ref(c);
> + pa_assert(t);
> +
> + if (pa_tagstruct_gets(t, &recipient_name) < 0 ||
> + pa_tagstruct_gets(t, &message) < 0 ||
> + pa_tagstruct_gets(t, &message_parameters) < 0 ||
> + !pa_tagstruct_eof(t)) {
> + protocol_error(c);
> + return;
> + }
> +
> + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
> + CHECK_VALIDITY(c->pstream, pa_utf8_valid(recipient_name), tag, PA_ERR_INVALID);
You need to check that recipient_name isn't NULL before calling
pa_utf8_valid().
--
Tanu
https://www.patreon.com/tanuk
More information about the pulseaudio-discuss
mailing list