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.
This commit is contained in:
Wim Taymans 2024-01-23 18:08:32 +01:00
parent 979eb0278f
commit bffcb2e6f1

View file

@ -19,6 +19,15 @@
#define EXT_DEVICE_RESTORE_VERSION 1 #define EXT_DEVICE_RESTORE_VERSION 1
enum {
SUBCOMMAND_TEST,
SUBCOMMAND_SUBSCRIBE,
SUBCOMMAND_EVENT,
SUBCOMMAND_READ_FORMATS_ALL,
SUBCOMMAND_READ_FORMATS,
SUBCOMMAND_SAVE_FORMATS
};
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -38,11 +47,13 @@
#include "../client.h" #include "../client.h"
#include "../collect.h" #include "../collect.h"
#include "../commands.h"
#include "../defs.h" #include "../defs.h"
#include "../extension.h" #include "../extension.h"
#include "../format.h" #include "../format.h"
#include "../manager.h" #include "../manager.h"
#include "../message.h" #include "../message.h"
#include "../operation.h"
#include "../reply.h" #include "../reply.h"
#include "../volume.h" #include "../volume.h"
@ -59,6 +70,8 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
struct module_device_restore_data { struct module_device_restore_data {
struct module *module; struct module *module;
struct spa_list subscribed;
}; };
static const struct spa_dict_item module_device_restore_info[] = { 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); 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 format_data {
struct client *client; struct client *client;
@ -248,7 +377,6 @@ static int set_node_codecs(struct pw_manager_object *o, uint32_t n_codecs, uint3
return 0; return 0;
} }
static int do_extension_device_restore_save_formats(struct module *module, struct client *client, static int do_extension_device_restore_save_formats(struct module *module, struct client *client,
uint32_t command, uint32_t tag, struct message *m) 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[] = { static const struct extension module_device_restore_extension[] = {
{ "TEST", 0, do_extension_device_restore_test, }, { "TEST", SUBCOMMAND_TEST, do_extension_device_restore_test, },
{ "SUBSCRIBE", 1, do_extension_device_restore_subscribe, }, { "SUBSCRIBE", SUBCOMMAND_SUBSCRIBE, do_extension_device_restore_subscribe, },
{ "EVENT", 2, }, { "EVENT", SUBCOMMAND_EVENT, },
{ "READ_FORMATS_ALL", 3, do_extension_device_restore_read_formats_all, }, { "READ_FORMATS_ALL", SUBCOMMAND_READ_FORMATS_ALL, do_extension_device_restore_read_formats_all, },
{ "READ_FORMATS", 4, do_extension_device_restore_read_formats, }, { "READ_FORMATS", SUBCOMMAND_READ_FORMATS, do_extension_device_restore_read_formats, },
{ "SAVE_FORMATS", 5, do_extension_device_restore_save_formats, }, { "SAVE_FORMATS", SUBCOMMAND_SAVE_FORMATS, do_extension_device_restore_save_formats, },
{ NULL }, { NULL },
}; };
@ -339,6 +467,17 @@ static int module_device_restore_prepare(struct module * const module)
static int module_device_restore_load(struct module *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; return 0;
} }
@ -347,6 +486,7 @@ DEFINE_MODULE_INFO(module_device_restore) = {
.load_once = true, .load_once = true,
.prepare = module_device_restore_prepare, .prepare = module_device_restore_prepare,
.load = module_device_restore_load, .load = module_device_restore_load,
.unload = module_device_restore_unload,
.extension = module_device_restore_extension, .extension = module_device_restore_extension,
.properties = &SPA_DICT_INIT_ARRAY(module_device_restore_info), .properties = &SPA_DICT_INIT_ARRAY(module_device_restore_info),
.data_size = sizeof(struct module_device_restore_data), .data_size = sizeof(struct module_device_restore_data),