From bffcb2e6f17d2c2cf6224d93c34c56342b39288e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 23 Jan 2024 18:08:32 +0100 Subject: [PATCH] pulse-server: implement subscribe in device-restore Add a client that subscribes to the list of subscribers and make the client watch for EnumFormat changes. When a subscribed client sees an EnumFormat change for a sink, emit EVENT to the client. This will send the EVENT to pavucontrol when the supported IEC958 formats change so that it can update the gui. --- .../modules/module-device-restore.c | 158 +++++++++++++++++- 1 file changed, 149 insertions(+), 9 deletions(-) diff --git a/src/modules/module-protocol-pulse/modules/module-device-restore.c b/src/modules/module-protocol-pulse/modules/module-device-restore.c index ddb0e6450..5a8c8d680 100644 --- a/src/modules/module-protocol-pulse/modules/module-device-restore.c +++ b/src/modules/module-protocol-pulse/modules/module-device-restore.c @@ -19,6 +19,15 @@ #define EXT_DEVICE_RESTORE_VERSION 1 +enum { + SUBCOMMAND_TEST, + SUBCOMMAND_SUBSCRIBE, + SUBCOMMAND_EVENT, + SUBCOMMAND_READ_FORMATS_ALL, + SUBCOMMAND_READ_FORMATS, + SUBCOMMAND_SAVE_FORMATS +}; + #include #include #include @@ -38,11 +47,13 @@ #include "../client.h" #include "../collect.h" +#include "../commands.h" #include "../defs.h" #include "../extension.h" #include "../format.h" #include "../manager.h" #include "../message.h" +#include "../operation.h" #include "../reply.h" #include "../volume.h" @@ -59,6 +70,8 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); struct module_device_restore_data { struct module *module; + + struct spa_list subscribed; }; static const struct spa_dict_item module_device_restore_info[] = { @@ -83,11 +96,127 @@ static int do_extension_device_restore_test(struct module *module, struct client return client_queue_message(client, reply); } -static int do_extension_device_restore_subscribe(struct module *module, struct client *client, uint32_t command, uint32_t tag, struct message *m) +struct subscribe { + struct spa_list link; + struct module_device_restore_data *data; + + struct client *client; + struct spa_hook listener; + + struct spa_hook manager_listener; +}; + +static void remove_subscribe(struct subscribe *s) { - return reply_simple_ack(client, tag); + spa_list_remove(&s->link); + spa_hook_remove(&s->listener); + spa_hook_remove(&s->manager_listener); + free(s); } +static void emit_event(struct subscribe *s, uint32_t type, uint32_t idx) +{ + struct client *client = s->client; + struct message *msg = message_alloc(client->impl, -1, 0); + + pw_log_info("[%s] EVENT index:%u name:%s %d/%d", client->name, + s->data->module->index, s->data->module->info->name, type, idx); + + message_put(msg, + TAG_U32, COMMAND_EXTENSION, + TAG_U32, 0, + TAG_U32, s->data->module->index, + TAG_STRING, s->data->module->info->name, + TAG_U32, SUBCOMMAND_EVENT, + TAG_U32, type, + TAG_U32, idx, + TAG_INVALID); + + client_queue_message(client, msg); +} + +static void module_client_disconnect(void *data) +{ + struct subscribe *s = data; + remove_subscribe(s); +} + +static const struct client_events module_client_events = { + VERSION_CLIENT_EVENTS, + .disconnect = module_client_disconnect, +}; + +static void manager_updated(void *data, struct pw_manager_object *object) +{ + struct subscribe *s = data; + uint32_t i; + + if (!pw_manager_object_is_sink(object)) + return; + + for (i = 0; i < object->n_params; i++) { + if (object->params[i].id == SPA_PARAM_EnumFormat && + object->params[i].user != 0) + emit_event(s, DEVICE_TYPE_SINK, object->index); + } +} + +struct pw_manager_events manager_events = { + PW_VERSION_MANAGER_EVENTS, + .added = manager_updated, + .updated = manager_updated, +}; + +static struct subscribe *add_subscribe(struct module_device_restore_data *data, struct client *c) +{ + struct subscribe *s; + s = calloc(1, sizeof(*s)); + if (s == NULL) + return NULL; + s->data = data; + s->client = c; + client_add_listener(c, &s->listener, &module_client_events, s); + spa_list_append(&data->subscribed, &s->link); + + pw_manager_add_listener(c->manager, &s->manager_listener, + &manager_events, s); + return s; +} + +static struct subscribe *find_subscribe(struct module_device_restore_data *data, struct client *c) +{ + struct subscribe *s; + spa_list_for_each(s, &data->subscribed, link) { + if (s->client == c) + return s; + } + return NULL; +} + +static int do_extension_device_restore_subscribe(struct module *module, struct client *client, uint32_t command, uint32_t tag, struct message *m) +{ + struct module_device_restore_data * const d = module->user_data; + int res; + bool enabled; + struct subscribe *s; + + if ((res = message_get(m, + TAG_BOOLEAN, &enabled, + TAG_INVALID)) < 0) + return -EPROTO; + + s = find_subscribe(d, client); + if (enabled) { + if (s == NULL) + s = add_subscribe(d, client); + if (s == NULL) + return -errno; + } else { + if (s != NULL) + remove_subscribe(s); + } + return reply_simple_ack(client, tag); +} struct format_data { struct client *client; @@ -248,7 +377,6 @@ static int set_node_codecs(struct pw_manager_object *o, uint32_t n_codecs, uint3 return 0; } - static int do_extension_device_restore_save_formats(struct module *module, struct client *client, uint32_t command, uint32_t tag, struct message *m) { @@ -318,12 +446,12 @@ static int do_extension_device_restore_save_formats(struct module *module, struc } static const struct extension module_device_restore_extension[] = { - { "TEST", 0, do_extension_device_restore_test, }, - { "SUBSCRIBE", 1, do_extension_device_restore_subscribe, }, - { "EVENT", 2, }, - { "READ_FORMATS_ALL", 3, do_extension_device_restore_read_formats_all, }, - { "READ_FORMATS", 4, do_extension_device_restore_read_formats, }, - { "SAVE_FORMATS", 5, do_extension_device_restore_save_formats, }, + { "TEST", SUBCOMMAND_TEST, do_extension_device_restore_test, }, + { "SUBSCRIBE", SUBCOMMAND_SUBSCRIBE, do_extension_device_restore_subscribe, }, + { "EVENT", SUBCOMMAND_EVENT, }, + { "READ_FORMATS_ALL", SUBCOMMAND_READ_FORMATS_ALL, do_extension_device_restore_read_formats_all, }, + { "READ_FORMATS", SUBCOMMAND_READ_FORMATS, do_extension_device_restore_read_formats, }, + { "SAVE_FORMATS", SUBCOMMAND_SAVE_FORMATS, do_extension_device_restore_save_formats, }, { NULL }, }; @@ -339,6 +467,17 @@ static int module_device_restore_prepare(struct module * const module) static int module_device_restore_load(struct module *module) { + struct module_device_restore_data * const data = module->user_data; + spa_list_init(&data->subscribed); + return 0; +} +static int module_device_restore_unload(struct module *module) +{ + struct module_device_restore_data * const data = module->user_data; + struct subscribe *s; + + spa_list_consume(s, &data->subscribed, link) + remove_subscribe(s); return 0; } @@ -347,6 +486,7 @@ DEFINE_MODULE_INFO(module_device_restore) = { .load_once = true, .prepare = module_device_restore_prepare, .load = module_device_restore_load, + .unload = module_device_restore_unload, .extension = module_device_restore_extension, .properties = &SPA_DICT_INIT_ARRAY(module_device_restore_info), .data_size = sizeof(struct module_device_restore_data),