jack: handle port registration events for jack clients

The jack client API expects the ports to unregister when a jack client is
deactivated and to register when it is activated. We use pause/resume
for deactivate/activate and don't really destroy the ports.

Track the state of the node (client) and emit port registration when it
changes state. Also make sure we don't emit a port registration when the
node is deactivated.

Fixes #3260
This commit is contained in:
Wim Taymans 2023-08-02 17:30:35 +02:00
parent fac2556404
commit da464853e5

View file

@ -137,6 +137,8 @@ struct object {
char node_name[512]; char node_name[512];
int32_t priority; int32_t priority;
uint32_t client_id; uint32_t client_id;
unsigned is_jack:1;
unsigned is_running:1;
} node; } node;
struct { struct {
uint32_t src; uint32_t src;
@ -3061,6 +3063,35 @@ static const struct pw_proxy_events proxy_events = {
.destroy = proxy_destroy, .destroy = proxy_destroy,
}; };
static void node_info(void *data, const struct pw_node_info *info)
{
struct object *n = data;
struct client *c = n->client;
pw_log_info("DSP node %d state change %s", info->id,
pw_node_state_as_string(info->state));
n->node.is_running = (info->state == PW_NODE_STATE_RUNNING);
if (info->change_mask & PW_NODE_CHANGE_MASK_STATE) {
struct object *p;
spa_list_for_each(p, &c->context.objects, link) {
if (p->type != INTERFACE_Port || p->removed ||
p->port.node_id != info->id)
continue;
if (n->node.is_running)
queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, p, 1, NULL);
else
queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, p, 0, NULL);
}
}
}
static const struct pw_node_events node_events = {
PW_VERSION_NODE,
.info = node_info,
};
static void port_param(void *data, int seq, static void port_param(void *data, int seq,
uint32_t id, uint32_t index, uint32_t next, uint32_t id, uint32_t index, uint32_t next,
const struct spa_pod *param) const struct spa_pod *param)
@ -3105,7 +3136,7 @@ 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;
bool is_first = true; bool do_emit = true;
uint32_t serial; uint32_t serial;
if (props == NULL) if (props == NULL)
@ -3162,7 +3193,7 @@ static void registry_event_global(void *data, uint32_t 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; do_emit = ot == NULL;
snprintf(o->node.name, sizeof(o->node.name), "%s", tmp); snprintf(o->node.name, sizeof(o->node.name), "%s", tmp);
} }
if (id == c->node_id) { if (id == c->node_id) {
@ -3174,9 +3205,21 @@ static void registry_event_global(void *data, uint32_t id,
if ((str = spa_dict_lookup(props, PW_KEY_PRIORITY_SESSION)) != NULL) if ((str = spa_dict_lookup(props, PW_KEY_PRIORITY_SESSION)) != NULL)
o->node.priority = pw_properties_parse_int(str); o->node.priority = pw_properties_parse_int(str);
if ((str = spa_dict_lookup(props, PW_KEY_CLIENT_API)) != NULL)
o->node.is_jack = spa_streq(str, "jack");
pw_log_debug("%p: add node %d", c, id); pw_log_debug("%p: add node %d", c, id);
if (o->node.is_jack) {
o->proxy = pw_registry_bind(c->registry,
id, type, PW_VERSION_NODE, 0);
if (o->proxy) {
pw_proxy_add_listener(o->proxy,
&o->proxy_listener, &proxy_events, o);
pw_proxy_add_object_listener(o->proxy,
&o->object_listener, &node_events, o);
}
}
pthread_mutex_lock(&c->context.lock); pthread_mutex_lock(&c->context.lock);
spa_list_append(&c->context.objects, &o->link); spa_list_append(&c->context.objects, &o->link);
pthread_mutex_unlock(&c->context.lock); pthread_mutex_unlock(&c->context.lock);
@ -3255,6 +3298,8 @@ static void registry_event_global(void *data, uint32_t id,
o->port.latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); o->port.latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
o->port.latency[SPA_DIRECTION_OUTPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); o->port.latency[SPA_DIRECTION_OUTPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT);
do_emit = !ot->node.is_jack || ot->node.is_running;
o->proxy = pw_registry_bind(c->registry, o->proxy = pw_registry_bind(c->registry,
id, type, PW_VERSION_PORT, 0); id, type, PW_VERSION_PORT, 0);
if (o->proxy) { if (o->proxy) {
@ -3409,15 +3454,16 @@ static void registry_event_global(void *data, uint32_t id,
switch (o->type) { switch (o->type) {
case INTERFACE_Node: case INTERFACE_Node:
if (is_first) { pw_log_info("%p: client added \"%s\" emit:%d", c, o->node.name, do_emit);
pw_log_info("%p: client added \"%s\"", c, o->node.name); if (do_emit)
queue_notify(c, NOTIFY_TYPE_REGISTRATION, o, 1, NULL); queue_notify(c, NOTIFY_TYPE_REGISTRATION, o, 1, NULL);
}
break; break;
case INTERFACE_Port: case INTERFACE_Port:
pw_log_info("%p: port added %u/%u \"%s\"", c, o->id, o->serial, o->port.name); pw_log_info("%p: port added %u/%u \"%s\" emit:%d", c, o->id,
queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, o, 1, NULL); o->serial, o->port.name, do_emit);
if (do_emit)
queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, o, 1, NULL);
break; break;
case INTERFACE_Link: case INTERFACE_Link: