diff options
-rw-r--r-- | doc/messaging_api.txt | 24 | ||||
-rw-r--r-- | src/modules/bluetooth/module-bluez5-device.c | 47 | ||||
-rw-r--r-- | src/pulsecore/core.c | 22 | ||||
-rw-r--r-- | src/pulsecore/message-handler.c | 18 | ||||
-rw-r--r-- | src/pulsecore/message-handler.h | 3 | ||||
-rw-r--r-- | src/utils/pactl.c | 48 |
6 files changed, 93 insertions, 69 deletions
diff --git a/doc/messaging_api.txt b/doc/messaging_api.txt index e0a921da4..18c5fd818 100644 --- a/doc/messaging_api.txt +++ b/doc/messaging_api.txt @@ -4,26 +4,18 @@ The message API allows any object within pulseaudio to register a message handler. A message handler is a function that can be called by clients using PA_COMMAND_SEND_OBJECT_MESSAGE. A message consists at least of an object path and a message command, both specified as strings. Additional parameters can -be specified using a single string, but are not mandatory. The message handler -returns an error number as defined in def.h and also returns a string in -the "response" variable. If the string is not empty it consists of elements. -Curly braces are used to separate elements. Each element can itself contain -further elements. For example consider a message that returns multiple elements -which each contain an integer and an array of float. A response string would -look like that: -{{Integer} {{1st float} {2nd float} ...}}{...} -Any characters that are not enclosed in curly braces are ignored (all characters -between { and {, between } and } and between } and {). The same syntax is used -to specify message parameters. The reference further down lists available messages, -their parameters and return values. If a return value is enclosed in {}, this -means that multiple elements of the same type may be returned. +be specified using a single string in JSON format, but are not mandatory. -For string parameters that contain curly braces or backslashes, those characters -must be escaped by adding a "\" before them. +The message handler returns an error number as defined in def.h and also returns +a string in the "response" variable. Non-empty response will be in JSON format. + +The reference further down lists available messages, their parameters +and return values. Reference: Object path: /core Message: list-handlers Parameters: None -Return value: {{{Handler name} {Description}} ...} +Return value: JSON array of handler description objects + [{"name":"Handler name","description":"Description"} ...] diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index 108b2923a..66e6c1d6c 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -27,6 +27,7 @@ #include <arpa/inet.h> +#include <pulse/json.h> #include <pulse/rtclock.h> #include <pulse/timeval.h> #include <pulse/utf8.h> @@ -2458,7 +2459,7 @@ static char *list_codecs(struct userdata *u) { const pa_a2dp_codec_capabilities *a2dp_capabilities; const pa_a2dp_codec_id *key; pa_hashmap *a2dp_endpoints; - pa_message_params *param; + pa_json_encoder *encoder; unsigned int i; bool is_a2dp_sink; void *state; @@ -2467,9 +2468,9 @@ static char *list_codecs(struct userdata *u) { a2dp_endpoints = is_a2dp_sink ? u->device->a2dp_sink_endpoints : u->device->a2dp_source_endpoints; - param = pa_message_params_new(); + encoder = pa_json_encoder_new(); - pa_message_params_begin_list(param); + pa_json_encoder_begin_element_array(encoder); PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, a2dp_endpoints, state) { for (i = 0; i < pa_bluetooth_a2dp_codec_count(); i++) { @@ -2479,23 +2480,23 @@ static char *list_codecs(struct userdata *u) { if (memcmp(key, &a2dp_codec->id, sizeof(pa_a2dp_codec_id)) == 0) { if (a2dp_codec->can_be_supported(is_a2dp_sink)) { - pa_message_params_begin_list(param); + pa_json_encoder_begin_element_object(encoder); - pa_message_params_write_string(param, a2dp_codec->name); - pa_message_params_write_string(param, a2dp_codec->description); + pa_json_encoder_add_member_string(encoder, "name", a2dp_codec->name); + pa_json_encoder_add_member_string(encoder, "description", a2dp_codec->description); - pa_message_params_end_list(param); + pa_json_encoder_end_object(encoder); } } } } - pa_message_params_end_list(param); + pa_json_encoder_end_array(encoder); - return pa_message_params_to_string_free(param); + return pa_json_encoder_to_string_free(encoder); } -static int bluez5_device_message_handler(const char *object_path, const char *message, char *message_parameters, char **response, void *userdata) { +static int bluez5_device_message_handler(const char *object_path, const char *message, const pa_json_object *parameters, char **response, void *userdata) { char *message_handler_path; pa_hashmap *capabilities_hashmap; pa_bluetooth_profile_t profile; @@ -2503,8 +2504,6 @@ static int bluez5_device_message_handler(const char *object_path, const char *me const char *codec_name; struct userdata *u; bool is_a2dp_sink; - void *state = NULL; - int err; pa_assert(u = (struct userdata *)userdata); pa_assert(message); @@ -2539,9 +2538,17 @@ static int bluez5_device_message_handler(const char *object_path, const char *me } if (pa_streq(message, "switch-codec")) { - err = pa_message_params_read_string(message_parameters, &codec_name, &state); - if (err < 0) - return err; + if (!parameters) { + pa_log_info("Codec switching operation requires codec name string parameter"); + return -PA_ERR_INVALID; + } + + if (pa_json_object_get_type(parameters) != PA_JSON_TYPE_STRING) { + pa_log_info("Codec name object parameter must be a string"); + return -PA_ERR_INVALID; + } + + codec_name = pa_json_object_get_string(parameters); if (u->a2dp_codec && pa_streq(codec_name, u->a2dp_codec->name)) { pa_log_info("Requested codec is currently selected codec"); @@ -2599,15 +2606,13 @@ static int bluez5_device_message_handler(const char *object_path, const char *me *response = list_codecs(u); return PA_OK; } else if (pa_streq(message, "get-codec")) { - pa_message_params *param; - param = pa_message_params_new(); + pa_json_encoder *encoder; + encoder = pa_json_encoder_new(); if (u->a2dp_codec) - pa_message_params_write_string(param, u->a2dp_codec->name); - else - pa_message_params_write_string(param, "none"); + pa_json_encoder_add_element_string(encoder, u->a2dp_codec->name); - *response = pa_message_params_to_string_free(param); + *response = pa_json_encoder_to_string_free(encoder); return PA_OK; } diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 8b830199f..b1ee4bb8b 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -66,29 +66,27 @@ static void core_free(pa_object *o); /* Returns a list of handlers. */ static char *message_handler_list(pa_core *c) { - pa_message_params *param; + pa_json_encoder *encoder; void *state = NULL; struct pa_message_handler *handler; - param = pa_message_params_new(); + encoder = pa_json_encoder_new(); - pa_message_params_begin_list(param); + pa_json_encoder_begin_element_array(encoder); PA_HASHMAP_FOREACH(handler, c->message_handlers, state) { - pa_message_params_begin_list(param); + pa_json_encoder_begin_element_object(encoder); - /* object_path cannot contain characters that need escaping, therefore - * pa_message_params_write_raw() can safely be used here. */ - pa_message_params_write_raw(param, handler->object_path, true); - pa_message_params_write_string(param, handler->description); + pa_json_encoder_add_member_string(encoder, "name", handler->object_path); + pa_json_encoder_add_member_string(encoder, "description", handler->description); - pa_message_params_end_list(param); + pa_json_encoder_end_object(encoder); } - pa_message_params_end_list(param); + pa_json_encoder_end_array(encoder); - return pa_message_params_to_string_free(param); + return pa_json_encoder_to_string_free(encoder); } -static int core_message_handler(const char *object_path, const char *message, char *message_parameters, char **response, void *userdata) { +static int core_message_handler(const char *object_path, const char *message, const pa_json_object *parameters, char **response, void *userdata) { pa_core *c; pa_assert(c = (pa_core *) userdata); diff --git a/src/pulsecore/message-handler.c b/src/pulsecore/message-handler.c index 40644554a..89c0b5110 100644 --- a/src/pulsecore/message-handler.c +++ b/src/pulsecore/message-handler.c @@ -105,7 +105,8 @@ void pa_message_handler_unregister(pa_core *c, const char *object_path) { int pa_message_handler_send_message(pa_core *c, const char *object_path, const char *message, const char *message_parameters, char **response) { struct pa_message_handler *handler; int ret; - char *parameter_copy, *path_copy; + char *path_copy; + pa_json_object *parameters = NULL; pa_assert(c); pa_assert(object_path); @@ -125,14 +126,21 @@ int pa_message_handler_send_message(pa_core *c, const char *object_path, const c return -PA_ERR_NOENTITY; } - parameter_copy = pa_xstrdup(message_parameters); + pa_xfree(path_copy); + + if (message_parameters) { + parameters = pa_json_parse(message_parameters); + + if (!parameters) + return -PA_ERR_INVALID; + } /* The handler is expected to return an error code and may also return an error string in response */ - ret = handler->callback(handler->object_path, message, parameter_copy, response, handler->userdata); + ret = handler->callback(handler->object_path, message, parameters, response, handler->userdata); - pa_xfree(parameter_copy); - pa_xfree(path_copy); + if (parameters) + pa_json_object_free(parameters); return ret; } diff --git a/src/pulsecore/message-handler.h b/src/pulsecore/message-handler.h index 38b24e1b2..b42d8c636 100644 --- a/src/pulsecore/message-handler.h +++ b/src/pulsecore/message-handler.h @@ -19,6 +19,7 @@ ***/ #include <pulsecore/core.h> +#include <pulse/json.h> /* Message handler types and functions */ @@ -26,7 +27,7 @@ typedef int (*pa_message_handler_cb_t)( const char *object_path, const char *message, - char *message_parameters, + const pa_json_object *parameters, char **response, void *userdata); diff --git a/src/utils/pactl.c b/src/utils/pactl.c index bc1c5265a..56852bfc0 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -37,6 +37,7 @@ #include <pulse/pulseaudio.h> #include <pulse/message-params.h> #include <pulse/ext-device-restore.h> +#include <pulse/json.h> #include <pulsecore/i18n.h> #include <pulsecore/macro.h> @@ -897,10 +898,10 @@ static void send_message_callback(pa_context *c, int success, char *response, vo } static void list_handlers_callback(pa_context *c, int success, char *response, void *userdata) { - void *state = NULL; - char *handler_list; - char *handler_struct; int err; + pa_json_object *o; + int i; + const pa_json_object *v, *path, *description; if (!success) { pa_log(_("list-handlers message failed: %s"), pa_strerror(pa_context_errno(c))); @@ -908,29 +909,45 @@ static void list_handlers_callback(pa_context *c, int success, char *response, v return; } - if (pa_message_params_read_raw(response, &handler_list, &state) <= 0) { + o = pa_json_parse(response); + + if (!o) { pa_log(_("list-handlers message response could not be parsed correctly")); + pa_json_object_free(o); + quit(1); + return; + } + + if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY) { + pa_log(_("list-handlers message response is not a JSON array")); + pa_json_object_free(o); quit(1); return; } - state = NULL; - while ((err = pa_message_params_read_raw(handler_list, &handler_struct, &state)) > 0) { - void *state2 = NULL; - const char *path; - const char *description; + err = 0; - if (pa_message_params_read_string(handler_struct, &path, &state2) <= 0) { + for (i = 0; i < pa_json_object_get_array_length(o); ++i) { + v = pa_json_object_get_array_member(o, i); + if (pa_json_object_get_type(v) != PA_JSON_TYPE_OBJECT) { + pa_log(_("list-handlers message response array element %d is not a JSON object"), i); err = -1; break; } - if (pa_message_params_read_string(handler_struct, &description, &state2) <= 0) { + + path = pa_json_object_get_object_member(v, "name"); + if (!path || pa_json_object_get_type(path) != PA_JSON_TYPE_STRING) { + err = -1; + break; + } + description = pa_json_object_get_object_member(v, "description"); + if (!description || pa_json_object_get_type(description) != PA_JSON_TYPE_STRING) { err = -1; break; } if (short_list_format) - printf("%s\n", path); + printf("%s\n", pa_json_object_get_string(path)); else { if (nl) printf("\n"); @@ -938,17 +955,20 @@ static void list_handlers_callback(pa_context *c, int success, char *response, v printf("Message Handler %s\n" "\tDescription: %s\n", - path, - description); + pa_json_object_get_string(path), + pa_json_object_get_string(description)); } } if (err < 0) { pa_log(_("list-handlers message response could not be parsed correctly")); + pa_json_object_free(o); quit(1); return; } + pa_json_object_free(o); + complete_action(); } |