[pulseaudio-discuss] [PATCH 1/3] protocol-native: add message sending capability

Georg Chini georg at chini.tk
Fri Aug 4 20:30:00 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 patch "core: add
generic message interface".

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 | 44 ++++++++++++++++++++++++++++++
 8 files changed, 123 insertions(+), 1 deletion(-)

diff --git a/PROTOCOL b/PROTOCOL
index e11aaa01..5cf95364 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -425,6 +425,13 @@ Check commit 451d1d676237c81 for further details.
 Added signal subscription functions. Clients can now subscribe to signals
 that PulseAudio sends.
 
+## v34, 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 e28755b0..011b45eb 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, 33)
+AC_SUBST(PA_PROTOCOL_VERSION, 34)
 
 # 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 d6cc06c1..83301eba 100644
--- a/src/map-file
+++ b/src/map-file
@@ -120,6 +120,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 5b9d5f0c..06c7c576 100644
--- a/src/pulsecore/native-common.h
+++ b/src/pulsecore/native-common.h
@@ -188,6 +188,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 f5aa5a24..22ea90c5 100644
--- a/src/pulsecore/pdispatch.c
+++ b/src/pulsecore/pdispatch.c
@@ -200,6 +200,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 e31562cf..6f6c50f7 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -4707,6 +4707,48 @@ 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;
+    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);
+
+   if (pa_core_message_handler_test(c->protocol->core, recipient_name) != PA_CORE_HANDLER_PUBLIC) {
+       pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
+       return;
+    }
+
+    if (pa_core_send_message(c->protocol->core, recipient_name, message, message_parameters, NULL, &response) != PA_CORE_SEND_OK) {
+        pa_pstream_send_error(c->pstream, tag, 1);
+        pa_xfree(response);
+        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;
@@ -4959,6 +5001,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