mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	control: keep track of linked controls
Keep track of what controls are linked together. Clean up links on destroy. Implement unlink, reset io area. Add events for control link/unlink
This commit is contained in:
		
							parent
							
								
									8e89474c7e
								
							
						
					
					
						commit
						f9237eb0db
					
				
					 4 changed files with 93 additions and 11 deletions
				
			
		| 
						 | 
					@ -60,6 +60,8 @@ pw_control_new(struct pw_core *core,
 | 
				
			||||||
	this->param = pw_spa_pod_copy(param);
 | 
						this->param = pw_spa_pod_copy(param);
 | 
				
			||||||
	this->direction = direction;
 | 
						this->direction = direction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_list_init(&this->inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (user_data_size > 0)
 | 
					        if (user_data_size > 0)
 | 
				
			||||||
		this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void);
 | 
							this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,11 +85,21 @@ pw_control_new(struct pw_core *core,
 | 
				
			||||||
void pw_control_destroy(struct pw_control *control)
 | 
					void pw_control_destroy(struct pw_control *control)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = SPA_CONTAINER_OF(control, struct impl, this);
 | 
						struct impl *impl = SPA_CONTAINER_OF(control, struct impl, this);
 | 
				
			||||||
 | 
						struct pw_control *other;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug("control %p: destroy", control);
 | 
						pw_log_debug("control %p: destroy", control);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_hook_list_call(&control->listener_list, struct pw_control_events, destroy);
 | 
						spa_hook_list_call(&control->listener_list, struct pw_control_events, destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (control->direction == SPA_DIRECTION_OUTPUT) {
 | 
				
			||||||
 | 
							spa_list_for_each(other, &control->inputs, inputs_link)
 | 
				
			||||||
 | 
								pw_control_unlink(control, other);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							if (control->output)
 | 
				
			||||||
 | 
								pw_control_unlink(control->output, control);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_list_remove(&control->link);
 | 
						spa_list_remove(&control->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (control->port) {
 | 
						if (control->port) {
 | 
				
			||||||
| 
						 | 
					@ -99,9 +111,10 @@ void pw_control_destroy(struct pw_control *control)
 | 
				
			||||||
	pw_log_debug("control %p: free", control);
 | 
						pw_log_debug("control %p: free", control);
 | 
				
			||||||
	spa_hook_list_call(&control->listener_list, struct pw_control_events, free);
 | 
						spa_hook_list_call(&control->listener_list, struct pw_control_events, free);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (control->direction == SPA_DIRECTION_OUTPUT)
 | 
						if (control->direction == SPA_DIRECTION_OUTPUT) {
 | 
				
			||||||
		if (impl->mem)
 | 
							if (impl->mem)
 | 
				
			||||||
			pw_memblock_free(impl->mem);
 | 
								pw_memblock_free(impl->mem);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(control->param);
 | 
						free(control->param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,6 +148,10 @@ int pw_control_link(struct pw_control *control, struct pw_control *other)
 | 
				
			||||||
	    other->direction != SPA_DIRECTION_INPUT)
 | 
						    other->direction != SPA_DIRECTION_INPUT)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* input control already has a linked output control */
 | 
				
			||||||
 | 
						if (other->output != NULL)
 | 
				
			||||||
 | 
							return -EEXIST;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl = SPA_CONTAINER_OF(control, struct impl, this);
 | 
						impl = SPA_CONTAINER_OF(control, struct impl, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug("control %p: link to %p", control, other);
 | 
						pw_log_debug("control %p: link to %p", control, other);
 | 
				
			||||||
| 
						 | 
					@ -147,15 +164,6 @@ int pw_control_link(struct pw_control *control, struct pw_control *other)
 | 
				
			||||||
					     &impl->mem)) < 0)
 | 
										     &impl->mem)) < 0)
 | 
				
			||||||
			goto exit;
 | 
								goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (control->port) {
 | 
					 | 
				
			||||||
			struct pw_port *port = control->port;
 | 
					 | 
				
			||||||
			if ((res = spa_node_port_set_io(port->node->node,
 | 
					 | 
				
			||||||
					     port->direction, port->port_id,
 | 
					 | 
				
			||||||
					     control->id,
 | 
					 | 
				
			||||||
					     impl->mem->ptr, control->size)) < 0) {
 | 
					 | 
				
			||||||
				goto exit;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (other->port) {
 | 
						if (other->port) {
 | 
				
			||||||
| 
						 | 
					@ -168,11 +176,68 @@ int pw_control_link(struct pw_control *control, struct pw_control *other)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (spa_list_is_empty(&control->inputs)) {
 | 
				
			||||||
 | 
							if (control->port) {
 | 
				
			||||||
 | 
								struct pw_port *port = control->port;
 | 
				
			||||||
 | 
								if ((res = spa_node_port_set_io(port->node->node,
 | 
				
			||||||
 | 
										     port->direction, port->port_id,
 | 
				
			||||||
 | 
										     control->id,
 | 
				
			||||||
 | 
										     impl->mem->ptr, control->size)) < 0) {
 | 
				
			||||||
 | 
									goto exit;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						other->output = control;
 | 
				
			||||||
 | 
						spa_list_append(&control->inputs, &other->inputs_link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_hook_list_call(&control->listener_list, struct pw_control_events, linked, other);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     exit:
 | 
					     exit:
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pw_control_unlink(struct pw_control *control, struct pw_control *other)
 | 
					int pw_control_unlink(struct pw_control *control, struct pw_control *other)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return -ENOTSUP;
 | 
						int res = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (control->direction == SPA_DIRECTION_INPUT) {
 | 
				
			||||||
 | 
							struct pw_control *tmp = control;
 | 
				
			||||||
 | 
							control = other;
 | 
				
			||||||
 | 
							other = tmp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (control->direction != SPA_DIRECTION_OUTPUT ||
 | 
				
			||||||
 | 
						    other->direction != SPA_DIRECTION_INPUT)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (other->output != control)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug("control %p: unlink from %p", control, other);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						other->output = NULL;
 | 
				
			||||||
 | 
						spa_list_remove(&other->inputs_link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (spa_list_is_empty(&control->inputs)) {
 | 
				
			||||||
 | 
							struct pw_port *port = control->port;
 | 
				
			||||||
 | 
							if ((res = spa_node_port_set_io(port->node->node,
 | 
				
			||||||
 | 
									     port->direction, port->port_id,
 | 
				
			||||||
 | 
									     control->id, NULL, 0)) < 0) {
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (other->port) {
 | 
				
			||||||
 | 
							struct pw_port *port = other->port;
 | 
				
			||||||
 | 
							if ((res = spa_node_port_set_io(port->node->node,
 | 
				
			||||||
 | 
									     port->direction, port->port_id,
 | 
				
			||||||
 | 
									     other->id, NULL, 0)) < 0) {
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_hook_list_call(&control->listener_list, struct pw_control_events, unlinked, other);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      exit:
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,6 +55,12 @@ struct pw_control_events {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** The control is freed */
 | 
						/** The control is freed */
 | 
				
			||||||
	void (*free) (void *data);
 | 
						void (*free) (void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** control is linked to another control */
 | 
				
			||||||
 | 
						void (*linked) (void *data, struct pw_control *other);
 | 
				
			||||||
 | 
						/** control is unlinked from another control */
 | 
				
			||||||
 | 
						void (*unlinked) (void *data, struct pw_control *other);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Get the control parent port or NULL when not set */
 | 
					/** Get the control parent port or NULL when not set */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -352,6 +352,7 @@ static int do_remove_port(struct spa_loop *loop,
 | 
				
			||||||
void pw_port_destroy(struct pw_port *port)
 | 
					void pw_port_destroy(struct pw_port *port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_node *node = port->node;
 | 
						struct pw_node *node = port->node;
 | 
				
			||||||
 | 
						struct pw_control *control, *ctemp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug("port %p: destroy", port);
 | 
						pw_log_debug("port %p: destroy", port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -374,6 +375,11 @@ void pw_port_destroy(struct pw_port *port)
 | 
				
			||||||
		spa_hook_list_call(&node->listener_list, struct pw_node_events, port_removed, port);
 | 
							spa_hook_list_call(&node->listener_list, struct pw_node_events, port_removed, port);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_list_for_each_safe(control, ctemp, &port->control_list[0], port_link)
 | 
				
			||||||
 | 
							pw_control_destroy(control);
 | 
				
			||||||
 | 
						spa_list_for_each_safe(control, ctemp, &port->control_list[1], port_link)
 | 
				
			||||||
 | 
							pw_control_destroy(control);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug("port %p: free", port);
 | 
						pw_log_debug("port %p: free", port);
 | 
				
			||||||
	spa_hook_list_call(&port->listener_list, struct pw_port_events, free);
 | 
						spa_hook_list_call(&port->listener_list, struct pw_port_events, free);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -418,6 +418,11 @@ struct pw_control {
 | 
				
			||||||
	enum spa_direction direction;	/**< the direction */
 | 
						enum spa_direction direction;	/**< the direction */
 | 
				
			||||||
	struct spa_pod *param;		/**< control params */
 | 
						struct spa_pod *param;		/**< control params */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct pw_control *output;	/**< pointer to linked output control */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct spa_list inputs;		/**< list of linked input controls */
 | 
				
			||||||
 | 
						struct spa_list inputs_link;	/**< link in linked input control */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t id;
 | 
						uint32_t id;
 | 
				
			||||||
	int32_t size;
 | 
						int32_t size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue