mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05: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