summaryrefslogtreecommitdiffstats
path: root/src/modules/module-protocol-pulse/message-handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/module-protocol-pulse/message-handler.c')
-rw-r--r--src/modules/module-protocol-pulse/message-handler.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/modules/module-protocol-pulse/message-handler.c b/src/modules/module-protocol-pulse/message-handler.c
new file mode 100644
index 0000000..8763ea7
--- /dev/null
+++ b/src/modules/module-protocol-pulse/message-handler.c
@@ -0,0 +1,143 @@
+#include <stdint.h>
+
+#include <regex.h>
+
+#include <spa/param/props.h>
+#include <spa/pod/builder.h>
+#include <spa/pod/pod.h>
+#include <spa/utils/defs.h>
+#include <spa/utils/json.h>
+#include <spa/utils/string.h>
+
+#include <pipewire/pipewire.h>
+
+#include "collect.h"
+#include "log.h"
+#include "manager.h"
+#include "message-handler.h"
+
+static int bluez_card_object_message_handler(struct pw_manager *m, struct pw_manager_object *o, const char *message, const char *params, char **response)
+{
+ struct transport_codec_info codecs[64];
+ uint32_t n_codecs, active;
+
+ pw_log_debug(": bluez-card %p object message:'%s' params:'%s'", o, message, params);
+
+ n_codecs = collect_transport_codec_info(o, codecs, SPA_N_ELEMENTS(codecs), &active);
+
+ if (n_codecs == 0)
+ return -EINVAL;
+
+ if (spa_streq(message, "switch-codec")) {
+ char codec[256];
+ struct spa_json it;
+ char buf[1024];
+ struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
+ struct spa_pod_frame f[1];
+ struct spa_pod *param;
+ uint32_t codec_id = SPA_ID_INVALID;
+
+ /* Parse args */
+ if (params == NULL)
+ return -EINVAL;
+
+ spa_json_init(&it, params, strlen(params));
+ if (spa_json_get_string(&it, codec, sizeof(codec)) <= 0)
+ return -EINVAL;
+
+ codec_id = atoi(codec);
+
+ /* Switch codec */
+ spa_pod_builder_push_object(&b, &f[0],
+ SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
+ spa_pod_builder_add(&b,
+ SPA_PROP_bluetoothAudioCodec, SPA_POD_Id(codec_id), 0);
+ param = spa_pod_builder_pop(&b, &f[0]);
+
+ pw_device_set_param((struct pw_device *)o->proxy,
+ SPA_PARAM_Props, 0, param);
+ return 0;
+ } else if (spa_streq(message, "list-codecs")) {
+ uint32_t i;
+ FILE *r;
+ size_t size;
+ bool first = true;
+
+ r = open_memstream(response, &size);
+ if (r == NULL)
+ return -errno;
+
+ fputc('[', r);
+ for (i = 0; i < n_codecs; ++i) {
+ const char *desc = codecs[i].description;
+ fprintf(r, "%s{\"name\":\"%d\",\"description\":\"%s\"}",
+ first ? "" : ",",
+ (int)codecs[i].id, desc ? desc : "Unknown");
+ first = false;
+ }
+ fputc(']', r);
+
+ return fclose(r) ? -errno : 0;
+ } else if (spa_streq(message, "get-codec")) {
+ if (active == SPA_ID_INVALID)
+ *response = strdup("null");
+ else
+ *response = spa_aprintf("\"%d\"", (int)codecs[active].id);
+ return *response ? 0 : -ENOMEM;
+ }
+
+ return -ENOSYS;
+}
+
+static int core_object_message_handler(struct pw_manager *m, struct pw_manager_object *o, const char *message, const char *params, char **response)
+{
+ pw_log_debug(": core %p object message:'%s' params:'%s'", o, message, params);
+
+ if (spa_streq(message, "list-handlers")) {
+ FILE *r;
+ size_t size;
+ bool first = true;
+
+ r = open_memstream(response, &size);
+ if (r == NULL)
+ return -errno;
+
+ fputc('[', r);
+ spa_list_for_each(o, &m->object_list, link) {
+ if (o->message_object_path) {
+ fprintf(r, "%s{\"name\":\"%s\",\"description\":\"%s\"}",
+ first ? "" : ",",
+ o->message_object_path, o->type);
+ first = false;
+ }
+ }
+ fputc(']', r);
+ return fclose(r) ? -errno : 0;
+ }
+
+ return -ENOSYS;
+}
+
+void register_object_message_handlers(struct pw_manager_object *o)
+{
+ const char *str;
+
+ if (o->id == PW_ID_CORE) {
+ free(o->message_object_path);
+ o->message_object_path = strdup("/core");
+ o->message_handler = core_object_message_handler;
+ return;
+ }
+
+ if (pw_manager_object_is_card(o) && o->props != NULL &&
+ (str = pw_properties_get(o->props, PW_KEY_DEVICE_API)) != NULL &&
+ spa_streq(str, "bluez5")) {
+ str = pw_properties_get(o->props, PW_KEY_DEVICE_NAME);
+ if (str) {
+ free(o->message_object_path);
+ o->message_object_path = spa_aprintf("/card/%s/bluez", str);
+ o->message_handler = bluez_card_object_message_handler;
+ }
+ return;
+ }
+}