string availability_group
uint32 type
+## v35, implemented by >= 15.0
+
+Added new command for communication with objects.
+
+PA_COMMAND_SEND_OBJECT_MESSAGE:
+sends a message to an object identified by an object path
+
+parameters:
+ string object_path - unique path identifying the object
+ string message - message name
+ string message_parameters - additional parameters if required (may be
+ NULL, which should be treated the same as an
+ empty string)
+
+The command returns a string, which may be empty or NULL (NULL should be
+treated the same as an empty 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.
AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
AC_SUBST(PA_API_VERSION, 12)
-AC_SUBST(PA_PROTOCOL_VERSION, 34)
+AC_SUBST(PA_PROTOCOL_VERSION, 35)
# The stable ABI for client applications, for the version info x:y:z
# always will hold x=z
pa_version_major_minor = pa_version_major + '.' + pa_version_minor
pa_api_version = 12
-pa_protocol_version = 34
+pa_protocol_version = 35
# The stable ABI for client applications, for the version info x:y:z
# always will hold x=z
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;
return o;
}
+
+/** Object response string processing **/
+
+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 = 1;
+
+ 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 = 0;
+ response = "";
+ } else if (pa_tagstruct_gets(t, &response) < 0 ||
+ !pa_tagstruct_eof(t)) {
+ pa_context_fail(o->context, PA_ERR_PROTOCOL);
+ goto finish;
+ }
+
+ if (!response)
+ response = "";
+
+ 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 *object_path, 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, object_path);
+ 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;
+}
* 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
/** @} */
+/** @{ \name Messages */
+
+/** Callback prototype for pa_context_send_message_to_object() \since 15.0 */
+typedef void (*pa_context_string_cb_t)(pa_context *c, int success, const char *response, void *userdata);
+
+/** Send a message to an object that registered a message handler. \since 15.0 */
+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 */
/** Stores information about clients. Please note that this structure
* BOTH DIRECTIONS */
PA_COMMAND_REGISTER_MEMFD_SHMID,
+ /* Supported since protocol v34 (14.0) */
+ PA_COMMAND_SEND_OBJECT_MESSAGE,
+
PA_COMMAND_MAX
};
/* Supported since protocol v31 (9.0) */
/* BOTH DIRECTIONS */
[PA_COMMAND_REGISTER_MEMFD_SHMID] = "REGISTER_MEMFD_SHMID",
+
+ /* Supported since protocol v35 (15.0) */
+ [PA_COMMAND_SEND_OBJECT_MESSAGE] = "SEND_OBJECT_MESSAGE",
};
#endif
#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>
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 *object_path = 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, &object_path) < 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, object_path != NULL, tag, PA_ERR_INVALID);
+ CHECK_VALIDITY(c->pstream, pa_utf8_valid(object_path), tag, PA_ERR_INVALID);
+ CHECK_VALIDITY(c->pstream, message != NULL, tag, PA_ERR_INVALID);
+ CHECK_VALIDITY(c->pstream, pa_utf8_valid(message), tag, PA_ERR_INVALID);
+ if (message_parameters)
+ CHECK_VALIDITY(c->pstream, pa_utf8_valid(message_parameters), tag, PA_ERR_INVALID);
+
+ client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
+ pa_log_debug("Client %s sent message %s to path %s", client_name, message, object_path);
+ if (message_parameters)
+ pa_log_debug("Message parameters: %s", message_parameters);
+
+ ret = pa_message_handler_send_message(c->protocol->core, object_path, message, message_parameters, &response);
+
+ if (ret < 0) {
+ pa_pstream_send_error(c->pstream, tag, -ret);
+ return;
+ }
+
+ reply = reply_new(tag);
+ pa_tagstruct_puts(reply, 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;
[PA_COMMAND_REGISTER_MEMFD_SHMID] = command_register_memfd_shmid,
+ [PA_COMMAND_SEND_OBJECT_MESSAGE] = command_send_object_message,
+
[PA_COMMAND_EXTENSION] = command_extension
};