mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-10-29 05:40:27 -04:00 
			
		
		
		
	Add support for mappable buffers in mixer-dsp
This commit is contained in:
		
							parent
							
								
									fe78e80614
								
							
						
					
					
						commit
						df2f36ad8f
					
				
					 2 changed files with 98 additions and 25 deletions
				
			
		|  | @ -3176,6 +3176,7 @@ impl_node_port_use_buffers(void *object, | ||||||
| 	struct impl *this = object; | 	struct impl *this = object; | ||||||
| 	struct port *port; | 	struct port *port; | ||||||
| 	uint32_t i, j, maxsize; | 	uint32_t i, j, maxsize; | ||||||
|  | 	int res; | ||||||
| 
 | 
 | ||||||
| 	spa_return_val_if_fail(this != NULL, -EINVAL); | 	spa_return_val_if_fail(this != NULL, -EINVAL); | ||||||
| 
 | 
 | ||||||
|  | @ -3186,12 +3187,16 @@ impl_node_port_use_buffers(void *object, | ||||||
| 	spa_log_debug(this->log, "%p: use buffers %d on port %d:%d", | 	spa_log_debug(this->log, "%p: use buffers %d on port %d:%d", | ||||||
| 			this, n_buffers, direction, port_id); | 			this, n_buffers, direction, port_id); | ||||||
| 
 | 
 | ||||||
| 	clear_buffers(this, port); | 	if (n_buffers > 0 && !port->have_format) { | ||||||
|  | 		res = -EIO; | ||||||
|  | 		goto error; | ||||||
|  | 	} | ||||||
|  | 	if (n_buffers > MAX_BUFFERS) { | ||||||
|  | 		res = -ENOSPC; | ||||||
|  | 		goto error; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (n_buffers > 0 && !port->have_format) | 	clear_buffers(this, port); | ||||||
| 		return -EIO; |  | ||||||
| 	if (n_buffers > MAX_BUFFERS) |  | ||||||
| 		return -ENOSPC; |  | ||||||
| 
 | 
 | ||||||
| 	maxsize = this->quantum_limit * sizeof(float); | 	maxsize = this->quantum_limit * sizeof(float); | ||||||
| 
 | 
 | ||||||
|  | @ -3200,6 +3205,11 @@ impl_node_port_use_buffers(void *object, | ||||||
| 		uint32_t n_datas = buffers[i]->n_datas; | 		uint32_t n_datas = buffers[i]->n_datas; | ||||||
| 		struct spa_data *d = buffers[i]->datas; | 		struct spa_data *d = buffers[i]->datas; | ||||||
| 
 | 
 | ||||||
|  | 		if (n_datas > MAX_DATAS) { | ||||||
|  | 			res = -ENOSPC; | ||||||
|  | 			goto error; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		b = &port->buffers[i]; | 		b = &port->buffers[i]; | ||||||
| 		b->id = i; | 		b->id = i; | ||||||
| 		b->flags = 0; | 		b->flags = 0; | ||||||
|  | @ -3224,7 +3234,8 @@ impl_node_port_use_buffers(void *object, | ||||||
| 				if (data == MAP_FAILED) { | 				if (data == MAP_FAILED) { | ||||||
| 					spa_log_error(this->log, "%p: mmap failed %d on buffer %d %d %p: %m", | 					spa_log_error(this->log, "%p: mmap failed %d on buffer %d %d %p: %m", | ||||||
| 							this, j, i, d[j].type, data); | 							this, j, i, d[j].type, data); | ||||||
| 					return -EINVAL; | 					res = -EINVAL; | ||||||
|  | 					goto error; | ||||||
| 				} | 				} | ||||||
| 				SPA_FLAG_SET(b->flags, BUFFER_FLAG_MAPPED); | 				SPA_FLAG_SET(b->flags, BUFFER_FLAG_MAPPED); | ||||||
| 				spa_log_debug(this->log, "%p: mmap %d on buffer %d %d %p %p", | 				spa_log_debug(this->log, "%p: mmap %d on buffer %d %d %p %p", | ||||||
|  | @ -3233,7 +3244,8 @@ impl_node_port_use_buffers(void *object, | ||||||
| 			if (data == NULL) { | 			if (data == NULL) { | ||||||
| 				spa_log_error(this->log, "%p: invalid memory %d on buffer %d %d %p", | 				spa_log_error(this->log, "%p: invalid memory %d on buffer %d %d %p", | ||||||
| 						this, j, i, d[j].type, data); | 						this, j, i, d[j].type, data); | ||||||
| 				return -EINVAL; | 				res = -EINVAL; | ||||||
|  | 				goto error; | ||||||
| 			} else if (!SPA_IS_ALIGNED(data, this->max_align)) { | 			} else if (!SPA_IS_ALIGNED(data, this->max_align)) { | ||||||
| 				spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned", | 				spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned", | ||||||
| 						this, j, i); | 						this, j, i); | ||||||
|  | @ -3245,11 +3257,14 @@ impl_node_port_use_buffers(void *object, | ||||||
| 		} | 		} | ||||||
| 		if (direction == SPA_DIRECTION_OUTPUT) | 		if (direction == SPA_DIRECTION_OUTPUT) | ||||||
| 			queue_buffer(this, port, i); | 			queue_buffer(this, port, i); | ||||||
|  | 		port->n_buffers++; | ||||||
| 	} | 	} | ||||||
| 	port->maxsize = maxsize; | 	port->maxsize = maxsize; | ||||||
| 	port->n_buffers = n_buffers; |  | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | error: | ||||||
|  | 	clear_buffers(this, port); | ||||||
|  | 	return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct io_data { | struct io_data { | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
|  | #include <sys/mman.h> | ||||||
| 
 | 
 | ||||||
| #include <spa/support/plugin.h> | #include <spa/support/plugin.h> | ||||||
| #include <spa/support/log.h> | #include <spa/support/log.h> | ||||||
|  | @ -27,6 +28,7 @@ | ||||||
| SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.mixer-dsp"); | SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.mixer-dsp"); | ||||||
| 
 | 
 | ||||||
| #define MAX_BUFFERS	64 | #define MAX_BUFFERS	64 | ||||||
|  | #define MAX_DATAS	SPA_AUDIO_MAX_CHANNELS | ||||||
| #define MAX_PORTS	512 | #define MAX_PORTS	512 | ||||||
| #define MAX_ALIGN	MIX_OPS_MAX_ALIGN | #define MAX_ALIGN	MIX_OPS_MAX_ALIGN | ||||||
| 
 | 
 | ||||||
|  | @ -47,12 +49,15 @@ static void port_props_reset(struct port_props *props) | ||||||
| struct buffer { | struct buffer { | ||||||
| 	uint32_t id; | 	uint32_t id; | ||||||
| #define BUFFER_FLAG_QUEUED	(1 << 0) | #define BUFFER_FLAG_QUEUED	(1 << 0) | ||||||
|  | #define BUFFER_FLAG_MAPPED	(1 << 1) | ||||||
| 	uint32_t flags; | 	uint32_t flags; | ||||||
| 
 | 
 | ||||||
| 	struct spa_list link; | 	struct spa_list link; | ||||||
| 	struct spa_buffer *buffer; | 	struct spa_buffer *buffer; | ||||||
| 	struct spa_meta_header *h; | 	struct spa_meta_header *h; | ||||||
| 	struct spa_buffer buf; | 	struct spa_buffer buf; | ||||||
|  | 
 | ||||||
|  | 	void *datas[MAX_DATAS]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct port { | struct port { | ||||||
|  | @ -450,11 +455,25 @@ next: | ||||||
| 
 | 
 | ||||||
| static int clear_buffers(struct impl *this, struct port *port) | static int clear_buffers(struct impl *this, struct port *port) | ||||||
| { | { | ||||||
| 	if (port->n_buffers > 0) { | 	uint32_t i, j; | ||||||
| 		spa_log_debug(this->log, "%p: clear buffers %p", this, port); | 
 | ||||||
| 		port->n_buffers = 0; | 	spa_log_debug(this->log, "%p: clear buffers %p %d", this, port, port->n_buffers); | ||||||
| 		spa_list_init(&port->queue); | 	for (i = 0; i < port->n_buffers; i++) { | ||||||
|  | 		struct buffer *b = &port->buffers[i]; | ||||||
|  | 		if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_MAPPED)) { | ||||||
|  | 			for (j = 0; j < b->buffer->n_datas; j++) { | ||||||
|  | 				if (b->datas[j]) { | ||||||
|  | 					spa_log_debug(this->log, "%p: unmap buffer %d data %d %p", | ||||||
|  | 							this, i, j, b->datas[j]); | ||||||
|  | 					munmap(b->datas[j], b->buffer->datas[j].maxsize); | ||||||
|  | 					b->datas[j] = NULL; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_MAPPED); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  | 	port->n_buffers = 0; | ||||||
|  | 	spa_list_init(&port->queue); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -581,7 +600,8 @@ impl_node_port_use_buffers(void *object, | ||||||
| { | { | ||||||
| 	struct impl *this = object; | 	struct impl *this = object; | ||||||
| 	struct port *port; | 	struct port *port; | ||||||
| 	uint32_t i; | 	uint32_t i, j; | ||||||
|  | 	int res; | ||||||
| 
 | 
 | ||||||
| 	spa_return_val_if_fail(this != NULL, -EINVAL); | 	spa_return_val_if_fail(this != NULL, -EINVAL); | ||||||
| 
 | 
 | ||||||
|  | @ -594,17 +614,27 @@ impl_node_port_use_buffers(void *object, | ||||||
| 
 | 
 | ||||||
| 	spa_return_val_if_fail(!this->started || port->io == NULL, -EIO); | 	spa_return_val_if_fail(!this->started || port->io == NULL, -EIO); | ||||||
| 
 | 
 | ||||||
| 	clear_buffers(this, port); | 	if (n_buffers > 0 && !port->have_format) { | ||||||
|  | 		res = -EIO; | ||||||
|  | 		goto error; | ||||||
|  | 	} | ||||||
|  | 	if (n_buffers > MAX_BUFFERS) { | ||||||
|  | 		res = -ENOSPC; | ||||||
|  | 		goto error; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (n_buffers > 0 && !port->have_format) | 	clear_buffers(this, port); | ||||||
| 		return -EIO; |  | ||||||
| 	if (n_buffers > MAX_BUFFERS) |  | ||||||
| 		return -ENOSPC; |  | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < n_buffers; i++) { | 	for (i = 0; i < n_buffers; i++) { | ||||||
| 		struct buffer *b; | 		struct buffer *b; | ||||||
|  | 		uint32_t n_datas = buffers[i]->n_datas; | ||||||
| 		struct spa_data *d = buffers[i]->datas; | 		struct spa_data *d = buffers[i]->datas; | ||||||
| 
 | 
 | ||||||
|  | 		if (n_datas > MAX_DATAS) { | ||||||
|  | 			res = -ENOSPC; | ||||||
|  | 			goto error; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		b = &port->buffers[i]; | 		b = &port->buffers[i]; | ||||||
| 		b->buffer = buffers[i]; | 		b->buffer = buffers[i]; | ||||||
| 		b->flags = 0; | 		b->flags = 0; | ||||||
|  | @ -612,23 +642,51 @@ impl_node_port_use_buffers(void *object, | ||||||
| 		b->h = spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h)); | 		b->h = spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h)); | ||||||
| 		b->buf = *buffers[i]; | 		b->buf = *buffers[i]; | ||||||
| 
 | 
 | ||||||
| 		if (d[0].data == NULL) { | 		for (j = 0; j < n_datas; j++) { | ||||||
| 			spa_log_error(this->log, "%p: invalid memory on buffer %d", this, i); | 			void *data = d[j].data; | ||||||
| 			return -EINVAL; | 			if (data == NULL && SPA_FLAG_IS_SET(d[j].flags, SPA_DATA_FLAG_MAPPABLE)) { | ||||||
| 		} | 				int prot = 0; | ||||||
| 		if (!SPA_IS_ALIGNED(d[0].data, this->max_align)) { | 				if (SPA_FLAG_IS_SET(d[j].flags, SPA_DATA_FLAG_READABLE)) | ||||||
| 			spa_log_warn(this->log, "%p: memory on buffer %d not aligned", this, i); | 					prot |= PROT_READ; | ||||||
|  | 				if (SPA_FLAG_IS_SET(d[j].flags, SPA_DATA_FLAG_WRITABLE)) | ||||||
|  | 					prot |= PROT_WRITE; | ||||||
|  | 				data = mmap(NULL, d[j].maxsize, | ||||||
|  | 					prot, MAP_SHARED, d[j].fd, d[j].mapoffset); | ||||||
|  | 				if (data == MAP_FAILED) { | ||||||
|  | 					spa_log_error(this->log, "%p: mmap failed %d on buffer %d %d %p: %m", | ||||||
|  | 							this, j, i, d[j].type, data); | ||||||
|  | 					res = -EINVAL; | ||||||
|  | 					goto error; | ||||||
|  | 				} | ||||||
|  | 				SPA_FLAG_SET(b->flags, BUFFER_FLAG_MAPPED); | ||||||
|  | 				spa_log_debug(this->log, "%p: mmap %d on buffer %d %d %p %p", | ||||||
|  | 							this, j, i, d[j].type, data, b); | ||||||
|  | 			} | ||||||
|  | 			if (data == NULL) { | ||||||
|  | 				spa_log_error(this->log, "%p: invalid memory %d on buffer %d %d %p", | ||||||
|  | 						this, j, i, d[j].type, data); | ||||||
|  | 				res = -EINVAL; | ||||||
|  | 				goto error; | ||||||
|  | 			} else if (!SPA_IS_ALIGNED(data, this->max_align)) { | ||||||
|  | 				spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned", | ||||||
|  | 						this, j, i); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			d[j].data = b->datas[j] = data; | ||||||
| 		} | 		} | ||||||
| 		if (direction == SPA_DIRECTION_OUTPUT) | 		if (direction == SPA_DIRECTION_OUTPUT) | ||||||
| 			queue_buffer(this, port, b); | 			queue_buffer(this, port, b); | ||||||
| 
 | 
 | ||||||
|  | 		port->n_buffers++; | ||||||
| 		spa_log_debug(this->log, "%p: port %d:%d buffer:%d n_data:%d data:%p maxsize:%d", | 		spa_log_debug(this->log, "%p: port %d:%d buffer:%d n_data:%d data:%p maxsize:%d", | ||||||
| 				this, direction, port_id, i, | 				this, direction, port_id, i, | ||||||
| 				buffers[i]->n_datas, d[0].data, d[0].maxsize); | 				buffers[i]->n_datas, d[0].data, d[0].maxsize); | ||||||
| 	} | 	} | ||||||
| 	port->n_buffers = n_buffers; |  | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | error: | ||||||
|  | 	clear_buffers(this, port); | ||||||
|  | 	return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct io_info { | struct io_info { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Gabriel Golfetti
						Gabriel Golfetti