jack: improve registration callbacks

Pass the type to the alloc function to make things pretier.

Emit the client added only for the first client and the removed
callback for the last client. Things like pavucontrol will make
many nodes with the same name, which we map to the same client,
only when the last node is gone, we emit the client removed.
This commit is contained in:
Wim Taymans 2021-03-30 12:41:59 +02:00
parent dd6a18d576
commit c50c0b91c5

View file

@ -381,7 +381,7 @@ static void init_port_pool(struct client *c, enum spa_direction direction)
c->n_port_pool[direction] = 0; c->n_port_pool[direction] = 0;
} }
static struct object * alloc_object(struct client *c) static struct object * alloc_object(struct client *c, int type)
{ {
struct object *o; struct object *o;
int i; int i;
@ -394,9 +394,10 @@ static struct object * alloc_object(struct client *c)
spa_list_append(&c->context.free_objects, &o[i].link); spa_list_append(&c->context.free_objects, &o[i].link);
} }
o = spa_list_first(&c->context.free_objects, struct object, link); o = spa_list_first(&c->context.free_objects, struct object, link);
spa_list_remove(&o->link); spa_list_remove(&o->link);
o->client = c; o->client = c;
o->type = type;
return o; return o;
} }
@ -510,8 +511,7 @@ static struct port * alloc_port(struct client *c, enum spa_direction direction)
p = spa_list_first(&c->free_ports[direction], struct port, link); p = spa_list_first(&c->free_ports[direction], struct port, link);
spa_list_remove(&p->link); spa_list_remove(&p->link);
o = alloc_object(c); o = alloc_object(c, INTERFACE_Port);
o->type = INTERFACE_Port;
o->id = SPA_ID_INVALID; o->id = SPA_ID_INVALID;
o->port.node_id = c->node_id; o->port.node_id = c->node_id;
o->port.port_id = p->id; o->port.port_id = p->id;
@ -2161,8 +2161,8 @@ static void registry_event_global(void *data, uint32_t id,
struct client *c = (struct client *) data; struct client *c = (struct client *) data;
struct object *o, *ot, *op; struct object *o, *ot, *op;
const char *str; const char *str;
uint32_t object_type;
size_t size; size_t size;
bool is_first = false;
if (props == NULL) if (props == NULL)
return; return;
@ -2171,8 +2171,7 @@ static void registry_event_global(void *data, uint32_t id,
const char *app, *node_name; const char *app, *node_name;
char tmp[JACK_CLIENT_NAME_SIZE+1]; char tmp[JACK_CLIENT_NAME_SIZE+1];
o = alloc_object(c); o = alloc_object(c, INTERFACE_Node);
object_type = INTERFACE_Node;
if ((str = spa_dict_lookup(props, PW_KEY_CLIENT_ID)) != NULL) if ((str = spa_dict_lookup(props, PW_KEY_CLIENT_ID)) != NULL)
o->node.client_id = atoi(str); o->node.client_id = atoi(str);
@ -2212,11 +2211,13 @@ static void registry_event_global(void *data, uint32_t id,
filter_name(tmp, FILTER_NAME); filter_name(tmp, FILTER_NAME);
ot = find_node(c, tmp); ot = find_node(c, tmp);
if (ot != NULL && o->node.client_id != ot->node.client_id) if (ot != NULL && o->node.client_id != ot->node.client_id) {
snprintf(o->node.name, sizeof(o->node.name), "%.*s-%d", snprintf(o->node.name, sizeof(o->node.name), "%.*s-%d",
(int)(sizeof(tmp)-11), tmp, id); (int)(sizeof(tmp)-11), tmp, id);
else } else {
is_first = ot == NULL;
snprintf(o->node.name, sizeof(o->node.name), "%s", tmp); snprintf(o->node.name, sizeof(o->node.name), "%s", tmp);
}
if ((str = spa_dict_lookup(props, PW_KEY_PRIORITY_DRIVER)) != NULL) if ((str = spa_dict_lookup(props, PW_KEY_PRIORITY_DRIVER)) != NULL)
o->node.priority = pw_properties_parse_int(str); o->node.priority = pw_properties_parse_int(str);
@ -2235,7 +2236,6 @@ static void registry_event_global(void *data, uint32_t id,
bool is_monitor = false; bool is_monitor = false;
char tmp[REAL_JACK_PORT_NAME_SIZE+1]; char tmp[REAL_JACK_PORT_NAME_SIZE+1];
object_type = INTERFACE_Port;
if ((str = spa_dict_lookup(props, PW_KEY_FORMAT_DSP)) == NULL) if ((str = spa_dict_lookup(props, PW_KEY_FORMAT_DSP)) == NULL)
str = "other"; str = "other";
if ((type_id = string_to_type(str)) == SPA_ID_INVALID) if ((type_id = string_to_type(str)) == SPA_ID_INVALID)
@ -2285,7 +2285,7 @@ static void registry_event_global(void *data, uint32_t id,
pw_log_debug(NAME" %p: %s found our port %p", c, tmp, o); pw_log_debug(NAME" %p: %s found our port %p", c, tmp, o);
} }
if (o == NULL) { if (o == NULL) {
o = alloc_object(c); o = alloc_object(c, INTERFACE_Port);
if (o == NULL) if (o == NULL)
goto exit; goto exit;
@ -2339,8 +2339,7 @@ static void registry_event_global(void *data, uint32_t id,
o->port.name, type_id); o->port.name, type_id);
} }
else if (strcmp(type, PW_TYPE_INTERFACE_Link) == 0) { else if (strcmp(type, PW_TYPE_INTERFACE_Link) == 0) {
o = alloc_object(c); o = alloc_object(c, INTERFACE_Link);
object_type = INTERFACE_Link;
pthread_mutex_lock(&c->context.lock); pthread_mutex_lock(&c->context.lock);
spa_list_append(&c->context.links, &o->link); spa_list_append(&c->context.links, &o->link);
@ -2380,7 +2379,6 @@ static void registry_event_global(void *data, uint32_t id,
goto exit; goto exit;
} }
o->type = object_type;
o->id = id; o->id = id;
pthread_mutex_lock(&c->context.lock); pthread_mutex_lock(&c->context.lock);
@ -2394,7 +2392,7 @@ static void registry_event_global(void *data, uint32_t id,
switch (o->type) { switch (o->type) {
case INTERFACE_Node: case INTERFACE_Node:
if (c->registration_callback) if (c->registration_callback && is_first)
c->registration_callback(o->node.name, 1, c->registration_arg); c->registration_callback(o->node.name, 1, c->registration_arg);
break; break;
@ -2421,15 +2419,26 @@ static void registry_event_global_remove(void *object, uint32_t id)
{ {
struct client *c = (struct client *) object; struct client *c = (struct client *) object;
struct object *o; struct object *o;
bool is_last = false;
pw_log_debug(NAME" %p: removed: %u", c, id); pw_log_debug(NAME" %p: removed: %u", c, id);
pthread_mutex_lock(&c->context.lock); pthread_mutex_lock(&c->context.lock);
o = pw_map_lookup(&c->context.globals, id); o = pw_map_lookup(&c->context.globals, id);
if (o != NULL)
spa_list_remove(&o->link);
pthread_mutex_unlock(&c->context.lock); pthread_mutex_unlock(&c->context.lock);
if (o == NULL) if (o == NULL)
return; return;
/* JACK clients expect the objects to hang around after
* they are unregistered. We keep the memory around for that
* reason but reuse it when we can. */
spa_list_append(&c->context.free_objects, &o->link);
if (o->type == INTERFACE_Node)
is_last = find_node(c, o->node.name) == NULL;
pw_thread_loop_unlock(c->context.loop); pw_thread_loop_unlock(c->context.loop);
switch (o->type) { switch (o->type) {
@ -2440,7 +2449,7 @@ static void registry_event_global_remove(void *object, uint32_t id)
if (strcmp(o->node.node_name, c->metadata->default_audio_source) == 0) if (strcmp(o->node.node_name, c->metadata->default_audio_source) == 0)
c->metadata->default_audio_source[0] = '\0'; c->metadata->default_audio_source[0] = '\0';
} }
if (c->registration_callback) if (c->registration_callback && is_last)
c->registration_callback(o->node.name, 0, c->registration_arg); c->registration_callback(o->node.name, 0, c->registration_arg);
break; break;
case INTERFACE_Port: case INTERFACE_Port:
@ -2454,12 +2463,12 @@ static void registry_event_global_remove(void *object, uint32_t id)
} }
pw_thread_loop_lock(c->context.loop); pw_thread_loop_lock(c->context.loop);
/* JACK clients expect the objects to hang around after /* we keep the object available with the id because jack clients
* they are unregistered. We keep them in the map but reuse the * tend to access the objects with it later.
* object when we can *
* pw_map_insert_at(&c->context.globals, id, NULL); * pw_map_insert_at(&c->context.globals, id, NULL);
**/ */
free_object(c, o);
return; return;
} }