jack: emit latency notify when buffer_frames changes

When the buffer frames change, make sure we emit a latency recalculation
even if we don't have a buffer_size callback.

Remove the unused GRAPH notify.

Protect ringbuffer writes to the notify queue with a lock because we
can't know what thread they execute in.

Make a new TOTAL_LATENCY notify type to trigger a complete latency
recalculation.
This commit is contained in:
Wim Taymans 2023-08-23 17:28:24 +02:00
parent d08d05629b
commit 88e4a69765

View file

@ -86,12 +86,12 @@ struct notify {
#define NOTIFY_TYPE_REGISTRATION ((1<<4)) #define NOTIFY_TYPE_REGISTRATION ((1<<4))
#define NOTIFY_TYPE_PORTREGISTRATION ((2<<4)|NOTIFY_ACTIVE_FLAG) #define NOTIFY_TYPE_PORTREGISTRATION ((2<<4)|NOTIFY_ACTIVE_FLAG)
#define NOTIFY_TYPE_CONNECT ((3<<4)|NOTIFY_ACTIVE_FLAG) #define NOTIFY_TYPE_CONNECT ((3<<4)|NOTIFY_ACTIVE_FLAG)
#define NOTIFY_TYPE_GRAPH ((4<<4)|NOTIFY_ACTIVE_FLAG) #define NOTIFY_TYPE_BUFFER_FRAMES ((4<<4)|NOTIFY_ACTIVE_FLAG)
#define NOTIFY_TYPE_BUFFER_FRAMES ((5<<4)|NOTIFY_ACTIVE_FLAG) #define NOTIFY_TYPE_SAMPLE_RATE ((5<<4)|NOTIFY_ACTIVE_FLAG)
#define NOTIFY_TYPE_SAMPLE_RATE ((6<<4)|NOTIFY_ACTIVE_FLAG) #define NOTIFY_TYPE_FREEWHEEL ((6<<4)|NOTIFY_ACTIVE_FLAG)
#define NOTIFY_TYPE_FREEWHEEL ((7<<4)|NOTIFY_ACTIVE_FLAG) #define NOTIFY_TYPE_SHUTDOWN ((7<<4)|NOTIFY_ACTIVE_FLAG)
#define NOTIFY_TYPE_SHUTDOWN ((8<<4)|NOTIFY_ACTIVE_FLAG) #define NOTIFY_TYPE_LATENCY ((8<<4)|NOTIFY_ACTIVE_FLAG)
#define NOTIFY_TYPE_LATENCY ((9<<4)|NOTIFY_ACTIVE_FLAG) #define NOTIFY_TYPE_TOTAL_LATENCY ((9<<4)|NOTIFY_ACTIVE_FLAG)
int type; int type;
struct object *object; struct object *object;
int arg1; int arg1;
@ -901,12 +901,6 @@ jack_get_version_string(void)
return name; return name;
} }
static void recompute_latencies(struct client *c)
{
do_callback(c, latency_callback, c->active, JackCaptureLatency, c->latency_arg);
do_callback(c, latency_callback, c->active, JackPlaybackLatency, c->latency_arg);
}
#define freeze_callbacks(c) \ #define freeze_callbacks(c) \
({ \ ({ \
(c)->frozen_callbacks++; \ (c)->frozen_callbacks++; \
@ -929,7 +923,7 @@ static void emit_callbacks(struct client *c)
int32_t avail; int32_t avail;
uint32_t index; uint32_t index;
struct notify *notify; struct notify *notify;
bool do_graph = false; bool do_graph = false, do_recompute_capture = false, do_recompute_playback = false;
if (c->frozen_callbacks != 0 || !c->pending_callbacks) if (c->frozen_callbacks != 0 || !c->pending_callbacks)
return; return;
@ -982,10 +976,7 @@ static void emit_callbacks(struct client *c)
c->connect_arg); c->connect_arg);
do_graph = true; do_graph = true;
break; do_recompute_capture = do_recompute_playback = true;
case NOTIFY_TYPE_GRAPH:
pw_log_debug("%p: graph", c);
do_graph = true;
break; break;
case NOTIFY_TYPE_BUFFER_FRAMES: case NOTIFY_TYPE_BUFFER_FRAMES:
pw_log_debug("%p: buffer frames %d", c, notify->arg1); pw_log_debug("%p: buffer frames %d", c, notify->arg1);
@ -993,7 +984,7 @@ static void emit_callbacks(struct client *c)
do_callback_expr(c, c->buffer_frames = notify->arg1, do_callback_expr(c, c->buffer_frames = notify->arg1,
bufsize_callback, c->active, bufsize_callback, c->active,
notify->arg1, c->bufsize_arg); notify->arg1, c->bufsize_arg);
recompute_latencies(c); do_recompute_capture = do_recompute_playback = true;
} }
break; break;
case NOTIFY_TYPE_SAMPLE_RATE: case NOTIFY_TYPE_SAMPLE_RATE:
@ -1020,7 +1011,14 @@ static void emit_callbacks(struct client *c)
break; break;
case NOTIFY_TYPE_LATENCY: case NOTIFY_TYPE_LATENCY:
pw_log_debug("%p: latency %d", c, notify->arg1); pw_log_debug("%p: latency %d", c, notify->arg1);
do_callback(c, latency_callback, c->active, notify->arg1, c->latency_arg); if (notify->arg1 == JackCaptureLatency)
do_recompute_capture = true;
else if (notify->arg1 == JackPlaybackLatency)
do_recompute_playback = true;
break;
case NOTIFY_TYPE_TOTAL_LATENCY:
pw_log_debug("%p: total latency", c);
do_recompute_capture = do_recompute_playback = true;
break; break;
default: default:
break; break;
@ -1036,10 +1034,13 @@ static void emit_callbacks(struct client *c)
index += sizeof(struct notify); index += sizeof(struct notify);
spa_ringbuffer_read_update(&c->notify_ring, index); spa_ringbuffer_read_update(&c->notify_ring, index);
} }
if (do_graph) { if (do_recompute_capture)
recompute_latencies(c); do_callback(c, latency_callback, c->active, JackCaptureLatency, c->latency_arg);
if (do_recompute_playback)
do_callback(c, latency_callback, c->active, JackPlaybackLatency, c->latency_arg);
if (do_graph)
do_callback(c, graph_callback, c->active, c->graph_arg); do_callback(c, graph_callback, c->active, c->graph_arg);
}
thaw_callbacks(c); thaw_callbacks(c);
pw_log_debug("%p: leave", c); pw_log_debug("%p: leave", c);
} }
@ -1050,6 +1051,7 @@ static int queue_notify(struct client *c, int type, struct object *o, int arg1,
uint32_t index; uint32_t index;
struct notify *notify; struct notify *notify;
bool emit = false; bool emit = false;
int res = 0;
switch (type) { switch (type) {
case NOTIFY_TYPE_REGISTRATION: case NOTIFY_TYPE_REGISTRATION:
@ -1062,9 +1064,6 @@ static int queue_notify(struct client *c, int type, struct object *o, int arg1,
case NOTIFY_TYPE_CONNECT: case NOTIFY_TYPE_CONNECT:
emit = c->connect_callback != NULL && o != NULL; emit = c->connect_callback != NULL && o != NULL;
break; break;
case NOTIFY_TYPE_GRAPH:
emit = c->graph_callback != NULL || c->latency_callback != NULL;
break;
case NOTIFY_TYPE_BUFFER_FRAMES: case NOTIFY_TYPE_BUFFER_FRAMES:
emit = c->bufsize_callback != NULL; emit = c->bufsize_callback != NULL;
break; break;
@ -1078,6 +1077,7 @@ static int queue_notify(struct client *c, int type, struct object *o, int arg1,
emit = c->info_shutdown_callback != NULL || c->shutdown_callback != NULL; emit = c->info_shutdown_callback != NULL || c->shutdown_callback != NULL;
break; break;
case NOTIFY_TYPE_LATENCY: case NOTIFY_TYPE_LATENCY:
case NOTIFY_TYPE_TOTAL_LATENCY:
emit = c->latency_callback != NULL; emit = c->latency_callback != NULL;
break; break;
default: default:
@ -1086,8 +1086,10 @@ static int queue_notify(struct client *c, int type, struct object *o, int arg1,
if (!emit || ((type & NOTIFY_ACTIVE_FLAG) && !c->active)) { if (!emit || ((type & NOTIFY_ACTIVE_FLAG) && !c->active)) {
switch (type) { switch (type) {
case NOTIFY_TYPE_BUFFER_FRAMES: case NOTIFY_TYPE_BUFFER_FRAMES:
if (!emit) if (!emit) {
c->buffer_frames = arg1; c->buffer_frames = arg1;
queue_notify(c, NOTIFY_TYPE_TOTAL_LATENCY, NULL, 0, NULL);
}
break; break;
case NOTIFY_TYPE_SAMPLE_RATE: case NOTIFY_TYPE_SAMPLE_RATE:
if (!emit) if (!emit)
@ -1100,13 +1102,15 @@ static int queue_notify(struct client *c, int type, struct object *o, int arg1,
o->removing = false; o->removing = false;
free_object(c, o); free_object(c, o);
} }
return 0; return res;
} }
pthread_mutex_lock(&c->context.lock);
filled = spa_ringbuffer_get_write_index(&c->notify_ring, &index); filled = spa_ringbuffer_get_write_index(&c->notify_ring, &index);
if (filled < 0 || filled + sizeof(struct notify) > NOTIFY_BUFFER_SIZE) { if (filled < 0 || filled + sizeof(struct notify) > NOTIFY_BUFFER_SIZE) {
pw_log_warn("%p: notify queue full %d", c, type); pw_log_warn("%p: notify queue full %d", c, type);
return -ENOSPC; res = -ENOSPC;
goto done;
} }
notify = SPA_PTROFF(c->notify_buffer, index & NOTIFY_BUFFER_MASK, struct notify); notify = SPA_PTROFF(c->notify_buffer, index & NOTIFY_BUFFER_MASK, struct notify);
@ -1120,7 +1124,9 @@ static int queue_notify(struct client *c, int type, struct object *o, int arg1,
spa_ringbuffer_write_update(&c->notify_ring, index); spa_ringbuffer_write_update(&c->notify_ring, index);
c->pending_callbacks = true; c->pending_callbacks = true;
check_callbacks(c); check_callbacks(c);
return 0; done:
pthread_mutex_unlock(&c->context.lock);
return res;
} }
static void on_notify_event(void *data, uint64_t count) static void on_notify_event(void *data, uint64_t count)
@ -5860,9 +5866,7 @@ SPA_EXPORT
int jack_recompute_total_latencies (jack_client_t *client) int jack_recompute_total_latencies (jack_client_t *client)
{ {
struct client *c = (struct client *) client; struct client *c = (struct client *) client;
queue_notify(c, NOTIFY_TYPE_LATENCY, NULL, JackCaptureLatency, NULL); return queue_notify(c, NOTIFY_TYPE_TOTAL_LATENCY, NULL, 0, NULL);
queue_notify(c, NOTIFY_TYPE_LATENCY, NULL, JackPlaybackLatency, NULL);
return 0;
} }
static jack_nframes_t port_get_latency (jack_port_t *port) static jack_nframes_t port_get_latency (jack_port_t *port)