mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
jack: improve midi buffer handling
nframes in the midi buffer should be set to the current cycle buffer_size and it should restrict the timestamps that can be set on the midi events. Keep the last max_frames around in a globals so that we can use it to set the midi buffer to the default size. Return NULL when we do jack_port_get_buffer() with larger nframes than the current cycle buffer_size, just like JACK. Otherwise this could result in a crash when we try to mix more than the available buffer space. Check and reset the midi buffer better. Check if the MAGIC is still ok. jack_midi_reset_buffer() should restore the MAGIC and other values.
This commit is contained in:
parent
ca4f9d4989
commit
7a9dfc188a
1 changed files with 42 additions and 29 deletions
|
|
@ -110,6 +110,7 @@ struct globals {
|
||||||
struct pw_array descriptions;
|
struct pw_array descriptions;
|
||||||
struct spa_list free_objects;
|
struct spa_list free_objects;
|
||||||
struct spa_thread_utils *thread_utils;
|
struct spa_thread_utils *thread_utils;
|
||||||
|
uint32_t max_frames;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct globals globals;
|
static struct globals globals;
|
||||||
|
|
@ -2585,18 +2586,18 @@ static int client_node_port_set_param(void *data,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void midi_init_buffer(void *data, uint32_t max_frames)
|
static void midi_init_buffer(void *data, uint32_t max_frames, uint32_t nframes)
|
||||||
{
|
{
|
||||||
struct midi_buffer *mb = data;
|
struct midi_buffer *mb = data;
|
||||||
mb->magic = MIDI_BUFFER_MAGIC;
|
mb->magic = MIDI_BUFFER_MAGIC;
|
||||||
mb->buffer_size = max_frames * sizeof(float);
|
mb->buffer_size = max_frames * sizeof(float);
|
||||||
mb->nframes = max_frames;
|
mb->nframes = nframes;
|
||||||
mb->write_pos = 0;
|
mb->write_pos = 0;
|
||||||
mb->event_count = 0;
|
mb->event_count = 0;
|
||||||
mb->lost_events = 0;
|
mb->lost_events = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *init_buffer(struct port *p)
|
static inline void *init_buffer(struct port *p, uint32_t nframes)
|
||||||
{
|
{
|
||||||
struct client *c = p->client;
|
struct client *c = p->client;
|
||||||
void *data = p->emptyptr;
|
void *data = p->emptyptr;
|
||||||
|
|
@ -2605,8 +2606,9 @@ static inline void *init_buffer(struct port *p)
|
||||||
|
|
||||||
if (p->object->port.type_id == TYPE_ID_MIDI) {
|
if (p->object->port.type_id == TYPE_ID_MIDI) {
|
||||||
struct midi_buffer *mb = data;
|
struct midi_buffer *mb = data;
|
||||||
midi_init_buffer(data, c->max_frames);
|
midi_init_buffer(data, c->max_frames, nframes);
|
||||||
pw_log_debug("port %p: init midi buffer size:%d", p, mb->buffer_size);
|
pw_log_debug("port %p: init midi buffer size:%d frames:%d", p,
|
||||||
|
mb->buffer_size, nframes);
|
||||||
} else
|
} else
|
||||||
memset(data, 0, c->max_frames * sizeof(float));
|
memset(data, 0, c->max_frames * sizeof(float));
|
||||||
|
|
||||||
|
|
@ -3883,7 +3885,7 @@ jack_client_t * jack_client_open (const char *client_name,
|
||||||
goto no_props;
|
goto no_props;
|
||||||
client->context.nl = pw_thread_loop_get_loop(client->context.notify);
|
client->context.nl = pw_thread_loop_get_loop(client->context.notify);
|
||||||
|
|
||||||
client->max_frames = client->context.context->settings.clock_quantum_limit;
|
globals.max_frames = client->max_frames = client->context.context->settings.clock_quantum_limit;
|
||||||
|
|
||||||
client->notify_source = pw_loop_add_event(client->context.nl,
|
client->notify_source = pw_loop_add_event(client->context.nl,
|
||||||
on_notify_event, client);
|
on_notify_event, client);
|
||||||
|
|
@ -5026,7 +5028,7 @@ jack_port_t * jack_port_register (jack_client_t *client,
|
||||||
strcpy(o->port.name, name);
|
strcpy(o->port.name, name);
|
||||||
o->port.type_id = type_id;
|
o->port.type_id = type_id;
|
||||||
|
|
||||||
init_buffer(p);
|
init_buffer(p, c->max_frames);
|
||||||
|
|
||||||
if (direction == SPA_DIRECTION_INPUT) {
|
if (direction == SPA_DIRECTION_INPUT) {
|
||||||
switch (type_id) {
|
switch (type_id) {
|
||||||
|
|
@ -5260,7 +5262,7 @@ static void *get_buffer_input_float(struct port *p, jack_nframes_t frames)
|
||||||
p->zeroed = false;
|
p->zeroed = false;
|
||||||
}
|
}
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
ptr = init_buffer(p);
|
ptr = init_buffer(p, frames);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5297,7 +5299,7 @@ static void *get_buffer_input_midi(struct port *p, jack_nframes_t frames)
|
||||||
if (n_seq == MAX_MIX)
|
if (n_seq == MAX_MIX)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
midi_init_buffer(mb, MIDI_SCRATCH_FRAMES);
|
midi_init_buffer(mb, MIDI_SCRATCH_FRAMES, frames);
|
||||||
/* first convert to a thread local scratch buffer, then memcpy into
|
/* first convert to a thread local scratch buffer, then memcpy into
|
||||||
* the per port buffer. This makes it possible to call this function concurrently
|
* the per port buffer. This makes it possible to call this function concurrently
|
||||||
* but also have different pointers per port */
|
* but also have different pointers per port */
|
||||||
|
|
@ -5335,7 +5337,7 @@ static void *get_buffer_output_empty(struct port *p, jack_nframes_t frames)
|
||||||
|
|
||||||
static void *get_buffer_input_empty(struct port *p, jack_nframes_t frames)
|
static void *get_buffer_input_empty(struct port *p, jack_nframes_t frames)
|
||||||
{
|
{
|
||||||
return init_buffer(p);
|
return init_buffer(p, frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPA_EXPORT
|
SPA_EXPORT
|
||||||
|
|
@ -5344,17 +5346,22 @@ void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames)
|
||||||
struct object *o = port_to_object(port);
|
struct object *o = port_to_object(port);
|
||||||
struct port *p = NULL;
|
struct port *p = NULL;
|
||||||
void *ptr = NULL;
|
void *ptr = NULL;
|
||||||
|
struct client *c;
|
||||||
|
|
||||||
return_val_if_fail(o != NULL, NULL);
|
return_val_if_fail(o != NULL, NULL);
|
||||||
|
|
||||||
if (o->type != INTERFACE_Port || o->client == NULL)
|
c = o->client;
|
||||||
|
if (o->type != INTERFACE_Port || c == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (frames > c->max_frames)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if ((p = o->port.port) == NULL) {
|
if ((p = o->port.port) == NULL) {
|
||||||
struct mix *mix;
|
struct mix *mix;
|
||||||
struct buffer *b;
|
struct buffer *b;
|
||||||
|
|
||||||
if ((mix = find_mix_peer(o->client, o->id)) == NULL)
|
if ((mix = find_mix_peer(c, o->id)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
pw_log_trace("peer mix: %p %d", mix, mix->peer_id);
|
pw_log_trace("peer mix: %p %d", mix, mix->peer_id);
|
||||||
|
|
@ -5368,7 +5375,7 @@ void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames)
|
||||||
void *pod;
|
void *pod;
|
||||||
|
|
||||||
ptr = midi_scratch;
|
ptr = midi_scratch;
|
||||||
midi_init_buffer(ptr, MIDI_SCRATCH_FRAMES);
|
midi_init_buffer(ptr, MIDI_SCRATCH_FRAMES, frames);
|
||||||
|
|
||||||
d = &b->datas[0];
|
d = &b->datas[0];
|
||||||
if ((pod = spa_pod_from_data(d->data, d->maxsize,
|
if ((pod = spa_pod_from_data(d->data, d->maxsize,
|
||||||
|
|
@ -5377,7 +5384,7 @@ void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames)
|
||||||
if (!spa_pod_is_sequence(pod))
|
if (!spa_pod_is_sequence(pod))
|
||||||
goto done;
|
goto done;
|
||||||
seq[0] = pod;
|
seq[0] = pod;
|
||||||
convert_to_midi(seq, 1, ptr, o->client->fix_midi_events);
|
convert_to_midi(seq, 1, ptr, c->fix_midi_events);
|
||||||
} else {
|
} else {
|
||||||
ptr = get_buffer_data(b, frames);
|
ptr = get_buffer_data(b, frames);
|
||||||
}
|
}
|
||||||
|
|
@ -5385,7 +5392,7 @@ void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames)
|
||||||
ptr = p->get_buffer(p, frames);
|
ptr = p->get_buffer(p, frames);
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
pw_log_trace_fp("%p: port %p buffer %p", o->client, p, ptr);
|
pw_log_trace_fp("%p: port:%p buffer:%p frames:%d", c, p, ptr, frames);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7115,8 +7122,8 @@ int jack_midi_event_get(jack_midi_event_t *event,
|
||||||
{
|
{
|
||||||
struct midi_buffer *mb = port_buffer;
|
struct midi_buffer *mb = port_buffer;
|
||||||
struct midi_event *ev = SPA_PTROFF(mb, sizeof(*mb), struct midi_event);
|
struct midi_event *ev = SPA_PTROFF(mb, sizeof(*mb), struct midi_event);
|
||||||
return_val_if_fail(mb != NULL, -EINVAL);
|
if (mb == NULL || mb->magic != MIDI_BUFFER_MAGIC)
|
||||||
return_val_if_fail(ev != NULL, -EINVAL);
|
return -EINVAL;
|
||||||
if (event_index >= mb->event_count)
|
if (event_index >= mb->event_count)
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
ev += event_index;
|
ev += event_index;
|
||||||
|
|
@ -7130,7 +7137,8 @@ SPA_EXPORT
|
||||||
void jack_midi_clear_buffer(void *port_buffer)
|
void jack_midi_clear_buffer(void *port_buffer)
|
||||||
{
|
{
|
||||||
struct midi_buffer *mb = port_buffer;
|
struct midi_buffer *mb = port_buffer;
|
||||||
return_if_fail(mb != NULL);
|
if (mb == NULL || mb->magic != MIDI_BUFFER_MAGIC)
|
||||||
|
return;
|
||||||
mb->event_count = 0;
|
mb->event_count = 0;
|
||||||
mb->write_pos = 0;
|
mb->write_pos = 0;
|
||||||
mb->lost_events = 0;
|
mb->lost_events = 0;
|
||||||
|
|
@ -7139,7 +7147,7 @@ void jack_midi_clear_buffer(void *port_buffer)
|
||||||
SPA_EXPORT
|
SPA_EXPORT
|
||||||
void jack_midi_reset_buffer(void *port_buffer)
|
void jack_midi_reset_buffer(void *port_buffer)
|
||||||
{
|
{
|
||||||
jack_midi_clear_buffer(port_buffer);
|
midi_init_buffer(port_buffer, globals.max_frames, globals.max_frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPA_EXPORT
|
SPA_EXPORT
|
||||||
|
|
@ -7148,7 +7156,8 @@ size_t jack_midi_max_event_size(void* port_buffer)
|
||||||
struct midi_buffer *mb = port_buffer;
|
struct midi_buffer *mb = port_buffer;
|
||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
|
|
||||||
return_val_if_fail(mb != NULL, 0);
|
if (mb == NULL || mb->magic != MIDI_BUFFER_MAGIC)
|
||||||
|
return 0;
|
||||||
|
|
||||||
buffer_size = mb->buffer_size;
|
buffer_size = mb->buffer_size;
|
||||||
|
|
||||||
|
|
@ -7174,18 +7183,21 @@ jack_midi_data_t* jack_midi_event_reserve(void *port_buffer,
|
||||||
size_t data_size)
|
size_t data_size)
|
||||||
{
|
{
|
||||||
struct midi_buffer *mb = port_buffer;
|
struct midi_buffer *mb = port_buffer;
|
||||||
struct midi_event *events = SPA_PTROFF(mb, sizeof(*mb), struct midi_event);
|
struct midi_event *events;
|
||||||
size_t buffer_size;
|
|
||||||
|
|
||||||
return_val_if_fail(mb != NULL, NULL);
|
|
||||||
|
|
||||||
buffer_size = mb->buffer_size;
|
|
||||||
|
|
||||||
|
if (SPA_UNLIKELY(mb == NULL)) {
|
||||||
|
pw_log_warn("port buffer is NULL");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (SPA_UNLIKELY(mb->magic != MIDI_BUFFER_MAGIC)) {
|
||||||
|
pw_log_warn("port buffer is invalid");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if (SPA_UNLIKELY(time >= mb->nframes)) {
|
if (SPA_UNLIKELY(time >= mb->nframes)) {
|
||||||
pw_log_warn("midi %p: time:%d frames:%d", port_buffer, time, mb->nframes);
|
pw_log_warn("midi %p: time:%d frames:%d", port_buffer, time, mb->nframes);
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
events = SPA_PTROFF(mb, sizeof(*mb), struct midi_event);
|
||||||
if (SPA_UNLIKELY(mb->event_count > 0 && time < events[mb->event_count - 1].time)) {
|
if (SPA_UNLIKELY(mb->event_count > 0 && time < events[mb->event_count - 1].time)) {
|
||||||
pw_log_warn("midi %p: time:%d ev:%d", port_buffer, time, mb->event_count);
|
pw_log_warn("midi %p: time:%d ev:%d", port_buffer, time, mb->event_count);
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
@ -7208,7 +7220,7 @@ jack_midi_data_t* jack_midi_event_reserve(void *port_buffer,
|
||||||
res = ev->inline_data;
|
res = ev->inline_data;
|
||||||
} else {
|
} else {
|
||||||
mb->write_pos += data_size;
|
mb->write_pos += data_size;
|
||||||
ev->byte_offset = buffer_size - 1 - mb->write_pos;
|
ev->byte_offset = mb->buffer_size - 1 - mb->write_pos;
|
||||||
res = SPA_PTROFF(mb, ev->byte_offset, uint8_t);
|
res = SPA_PTROFF(mb, ev->byte_offset, uint8_t);
|
||||||
}
|
}
|
||||||
mb->event_count += 1;
|
mb->event_count += 1;
|
||||||
|
|
@ -7232,7 +7244,8 @@ SPA_EXPORT
|
||||||
uint32_t jack_midi_get_lost_event_count(void *port_buffer)
|
uint32_t jack_midi_get_lost_event_count(void *port_buffer)
|
||||||
{
|
{
|
||||||
struct midi_buffer *mb = port_buffer;
|
struct midi_buffer *mb = port_buffer;
|
||||||
return_val_if_fail(mb != NULL, 0);
|
if (mb == NULL || mb->magic != MIDI_BUFFER_MAGIC)
|
||||||
|
return 0;
|
||||||
return mb->lost_events;
|
return mb->lost_events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue