[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