jack: pause processing until callback is emited

Change the buffer_size and sample_rate when we are sure the proces
callback is not running.

Delay process callback until we have called the buffer_size or
samplerate callback. Otherwise the jack application might be called with
the new buffer_size/sample_rate before the callback has been called.
This commit is contained in:
Wim Taymans 2021-09-11 13:07:10 +02:00
parent 966fbd5a21
commit 6dde4ea1aa

View file

@ -736,19 +736,24 @@ void jack_get_version(int *major_ptr, int *minor_ptr, int *micro_ptr, int *proto
*proto_ptr = 0; *proto_ptr = 0;
} }
#define do_callback(c,callback,...) \ #define do_callback_expr(c,expr,callback,...) \
({ \ ({ \
if (c->callback && c->active) { \ if (c->callback && c->active) { \
pw_thread_loop_unlock(c->context.loop); \ pw_thread_loop_unlock(c->context.loop); \
if (c->locked_process) \ if (c->locked_process) \
pthread_mutex_lock(&c->rt_lock); \ pthread_mutex_lock(&c->rt_lock); \
(expr); \
c->callback(__VA_ARGS__); \ c->callback(__VA_ARGS__); \
if (c->locked_process) \ if (c->locked_process) \
pthread_mutex_unlock(&c->rt_lock); \ pthread_mutex_unlock(&c->rt_lock); \
pw_thread_loop_lock(c->context.loop); \ pw_thread_loop_lock(c->context.loop); \
} else { \
(expr); \
} \ } \
}) })
#define do_callback(c,callback,...) do_callback_expr(c,{},callback,__VA_ARGS__)
#define do_rt_callback_res(c,callback,...) \ #define do_rt_callback_res(c,callback,...) \
({ \ ({ \
int res = 0; \ int res = 0; \
@ -1158,20 +1163,20 @@ do_buffer_frames(struct spa_loop *loop,
{ {
uint32_t buffer_frames = *((uint32_t*)data); uint32_t buffer_frames = *((uint32_t*)data);
struct client *c = user_data; struct client *c = user_data;
do_callback(c, bufsize_callback, buffer_frames, c->bufsize_arg); do_callback_expr(c, c->buffer_frames = buffer_frames, bufsize_callback, buffer_frames, c->bufsize_arg);
return 0; return 0;
} }
static inline void check_buffer_frames(struct client *c, struct spa_io_position *pos, bool emit) static inline int check_buffer_frames(struct client *c, struct spa_io_position *pos, bool emit)
{ {
uint32_t buffer_frames = pos->clock.duration; uint32_t buffer_frames = pos->clock.duration;
if (SPA_UNLIKELY(buffer_frames != c->buffer_frames)) { if (SPA_UNLIKELY(buffer_frames != c->buffer_frames)) {
pw_log_info(NAME" %p: bufferframes %d", c, buffer_frames); pw_log_info(NAME" %p: bufferframes %d", c, buffer_frames);
c->buffer_frames = buffer_frames;
if (emit) if (emit)
pw_loop_invoke(c->context.l, do_buffer_frames, 0, pw_loop_invoke(c->context.l, do_buffer_frames, 0,
&buffer_frames, sizeof(buffer_frames), false, c); &buffer_frames, sizeof(buffer_frames), false, c);
} }
return c->buffer_frames == buffer_frames;
} }
static int static int
@ -1180,19 +1185,19 @@ do_sample_rate(struct spa_loop *loop,
{ {
struct client *c = user_data; struct client *c = user_data;
uint32_t sample_rate = *((uint32_t*)data); uint32_t sample_rate = *((uint32_t*)data);
do_callback(c, srate_callback, sample_rate, c->srate_arg); do_callback_expr(c, c->sample_rate = sample_rate, srate_callback, sample_rate, c->srate_arg);
return 0; return 0;
} }
static inline void check_sample_rate(struct client *c, struct spa_io_position *pos) static inline int check_sample_rate(struct client *c, struct spa_io_position *pos)
{ {
uint32_t sample_rate = pos->clock.rate.denom; uint32_t sample_rate = pos->clock.rate.denom;
if (SPA_UNLIKELY(sample_rate != c->sample_rate)) { if (SPA_UNLIKELY(sample_rate != c->sample_rate)) {
pw_log_info(NAME" %p: sample_rate %d", c, sample_rate); pw_log_info(NAME" %p: sample_rate %d", c, sample_rate);
c->sample_rate = sample_rate;
pw_loop_invoke(c->context.l, do_sample_rate, 0, pw_loop_invoke(c->context.l, do_sample_rate, 0,
&sample_rate, sizeof(sample_rate), false, c); &sample_rate, sizeof(sample_rate), false, c);
} }
return c->sample_rate == sample_rate;
} }
static inline uint32_t cycle_run(struct client *c) static inline uint32_t cycle_run(struct client *c)
@ -1232,8 +1237,10 @@ static inline uint32_t cycle_run(struct client *c)
return 0; return 0;
} }
check_buffer_frames(c, pos, true); if (check_buffer_frames(c, pos, true) == 0)
check_sample_rate(c, pos); return 0;
if (check_sample_rate(c, pos) == 0)
return 0;
if (SPA_LIKELY(driver)) { if (SPA_LIKELY(driver)) {
c->jack_state = position_to_jack(driver, &c->jack_position); c->jack_state = position_to_jack(driver, &c->jack_position);
@ -1357,6 +1364,7 @@ on_rtsocket_condition(void *data, int fd, uint32_t mask)
buffer_frames = cycle_run(c); buffer_frames = cycle_run(c);
if (buffer_frames > 0)
status = do_rt_callback_res(c, process_callback, buffer_frames, c->process_arg); status = do_rt_callback_res(c, process_callback, buffer_frames, c->process_arg);
cycle_signal(c, status); cycle_signal(c, status);