[pulseaudio-discuss] [PATCH 2/6] protocol-native: add message sending capability

Georg Chini georg at chini.tk
Sat Aug 19 15:48:02 UTC 2017


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                        |  7 +++++
 configure.ac                    |  2 +-
 src/map-file                    |  1 +
 src/pulse/introspect.c          | 59 +++++++++++++++++++++++++++++++++++++++++
 src/pulse/introspect.h          |  7 +++++
 src/pulsecore/native-common.h   |  2 ++
 src/pulsecore/pdispatch.c       |  2 ++
 src/pulsecore/protocol-native.c | 46 ++++++++++++++++++++++++++++++++
 8 files changed, 125 insertions(+), 1 deletion(-)

diff --git a/PROTOCOL b/PROTOCOL
index 546998b7..ccd3cd2c 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -420,6 +420,13 @@ memfd support only to 10.0+ clients.
 
 Check commit 451d1d676237c81 for further details.
 
+## v33, implemented by > 11.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
+
 #### 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 77b5ff5d..e28755b0 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..4e78c1f9 100644
--- a/src/map-file
+++ b/src/map-file
@@ -118,6 +118,7 @@ pa_context_suspend_sink_by_name;
 pa_context_suspend_source_by_index;
 pa_context_suspend_source_by_name;
 pa_context_unload_module;
+pa_context_send_message_to_object;
 pa_context_unref;
 pa_cvolume_avg;
 pa_cvolume_avg_mask;
diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
index 510d784a..f23ff932 100644
--- a/src/pulse/introspect.c
+++ b/src/pulse/introspect.c
@@ -2184,3 +2184,62 @@ 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;
+
+    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;
+
+        response = NULL;
+    } else if (pa_tagstruct_gets(t, &response) ||
+               !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, 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..e78f6665 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -423,6 +423,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, const char *response, void *userdata);
+
 /** 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);
 
@@ -438,6 +441,10 @@ pa_operation* pa_context_load_module(pa_context *c, const char*name, const char
 /** Unload a module. */
 pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata);
 
+/** Send a message to an object. This does not only apply to modules but to any 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);
+
 /** @} */
 
 /** @{ \name Clients */
diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h
index 70338b9f..c24dd666 100644
--- a/src/pulsecore/native-common.h
+++ b/src/pulsecore/native-common.h
@@ -187,6 +187,8 @@ enum {
      * BOTH DIRECTIONS */
     PA_COMMAND_REGISTER_MEMFD_SHMID,
 
+    PA_COMMAND_SEND_OBJECT_MESSAGE,
+
     PA_COMMAND_MAX
 };
 
diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c
index ab632a5a..52970f58 100644
--- a/src/pulsecore/pdispatch.c
+++ b/src/pulsecore/pdispatch.c
@@ -199,6 +199,8 @@ static const char *command_names[PA_COMMAND_MAX] = {
     /* Supported since protocol v31 (9.0) */
     /* BOTH DIRECTIONS */
     [PA_COMMAND_REGISTER_MEMFD_SHMID] = "REGISTER_MEMFD_SHMID",
+
+    [PA_COMMAND_SEND_OBJECT_MESSAGE] = "SEND_OBJECT_MESSAGE",
 };
 
 #endif
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 866e2c64..6a09fd8b 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/core-messages.h>
 #include <pulsecore/log.h>
 #include <pulsecore/mem.h>
 #include <pulsecore/strlist.h>
@@ -4685,6 +4686,49 @@ 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;
+    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);
+    CHECK_VALIDITY(c->pstream, message != NULL, tag, PA_ERR_INVALID);
+
+    ret = pa_core_send_message(c->protocol->core, recipient_name, message, message_parameters, &response);
+
+    if (ret == PA_CORE_SEND_NO_RECIPIENT) {
+        pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
+        return;
+
+    } else if (ret == PA_CORE_SEND_FAILURE) {
+        pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
+        return;
+    }
+
+    reply = reply_new(tag);
+    pa_tagstruct_puts(reply, (const char *)response);
+    pa_xfree(response);
+
+    pa_pstream_send_tagstruct(c->pstream, reply);
+}
+
 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
     uint32_t idx = PA_INVALID_INDEX;
@@ -4936,6 +4980,8 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
 
     [PA_COMMAND_REGISTER_MEMFD_SHMID] = command_register_memfd_shmid,
 
+    [PA_COMMAND_SEND_OBJECT_MESSAGE] = command_send_object_message,
+
     [PA_COMMAND_EXTENSION] = command_extension
 };
 
-- 
2.11.0



More information about the pulseaudio-discuss mailing list