1
Fork 0

jack: handle concurrent jack_port_get_buffer()

Ardour calls jack_port_get_buffer() from multiple threads. For audio
buffers this will result in mixing the input samples into the target
buffer and there is no window for having a corrupt buffer.

For MIDI, there is a problem because we need to convert from and to
PipeWire MIDI and while we do that from multiple threads, the midi
buffer can be incomplete or corrupt.

Fix this by building the intermediate POD to a thread-local scratch area
and then copy it to the target buffer. If this is done from multiple
threads there is no moment where incomplete data can be seen in the
target buffer.

Make the complete midi-scratch buffer thread_local so that we also avoid
a race when converting midi data from a foreign port.

When we write into the scratch buffer when mixing and converting input
midi data, we also avoid a race there.

Fixes #3632
This commit is contained in:
Wim Taymans 2023-11-22 16:08:01 +01:00
parent 72323dcaf3
commit 3376b96f2a
1 changed files with 11 additions and 7 deletions

View File

@ -9,6 +9,7 @@
#include <sys/mman.h>
#include <regex.h>
#include <math.h>
#include <threads.h>
#include <jack/jack.h>
#include <jack/intclient.h>
@ -111,7 +112,7 @@ static struct globals globals;
static bool mlock_warned = false;
#define MIDI_SCRATCH_FRAMES 8192
static float midi_scratch[MIDI_SCRATCH_FRAMES];
static thread_local float midi_scratch[MIDI_SCRATCH_FRAMES];
#define OBJECT_CHUNK 8
@ -1535,9 +1536,14 @@ static inline void process_empty(struct port *p, uint32_t frames)
{
struct buffer *b;
ptr = get_buffer_output(p, c->max_frames, 1, &b);
if (SPA_LIKELY(ptr != NULL))
if (SPA_LIKELY(ptr != NULL)) {
/* first build the complete pod in scratch memory, then copy it
* to the target buffer. This makes it possible for multiple threads
* to do this concurrently */
b->datas[0].chunk->size = convert_from_midi(src,
ptr, c->max_frames * sizeof(float));
midi_scratch, MIDI_SCRATCH_FRAMES * sizeof(float));
memcpy(ptr, midi_scratch, b->datas[0].chunk->size);
}
break;
}
default:
@ -5201,12 +5207,10 @@ static void *get_buffer_input_float(struct port *p, jack_nframes_t frames)
static void *get_buffer_input_midi(struct port *p, jack_nframes_t frames)
{
struct mix *mix;
void *ptr = p->emptyptr;
void *ptr = midi_scratch;
struct spa_pod_sequence *seq[MAX_MIX];
uint32_t n_seq = 0;
jack_midi_clear_buffer(ptr);
spa_list_for_each(mix, &p->mix, port_link) {
struct spa_data *d;
struct buffer *b;
@ -5232,8 +5236,8 @@ static void *get_buffer_input_midi(struct port *p, jack_nframes_t frames)
if (n_seq == MAX_MIX)
break;
}
midi_init_buffer(ptr, MIDI_SCRATCH_FRAMES);
convert_to_midi(seq, n_seq, ptr, p->client->fix_midi_events);
return ptr;
}