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:
Wim Taymans 2018-02-07 11:52:55 +01:00
parent 8e89474c7e
commit f9237eb0db
4 changed files with 93 additions and 11 deletions

View file

@ -60,6 +60,8 @@ pw_control_new(struct pw_core *core,
this->param = pw_spa_pod_copy(param);
this->direction = direction;
spa_list_init(&this->inputs);
if (user_data_size > 0)
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)
{
struct impl *impl = SPA_CONTAINER_OF(control, struct impl, this);
struct pw_control *other;
pw_log_debug("control %p: destroy", control);
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);
if (control->port) {
@ -99,9 +111,10 @@ void pw_control_destroy(struct pw_control *control)
pw_log_debug("control %p: free", control);
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)
pw_memblock_free(impl->mem);
}
free(control->param);
@ -135,6 +148,10 @@ int pw_control_link(struct pw_control *control, struct pw_control *other)
other->direction != SPA_DIRECTION_INPUT)
return -EINVAL;
/* input control already has a linked output control */
if (other->output != NULL)
return -EEXIST;
impl = SPA_CONTAINER_OF(control, struct impl, this);
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)
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) {
@ -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:
return res;
}
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;
}

View file

@ -55,6 +55,12 @@ struct pw_control_events {
/** The control is freed */
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 */

View file

@ -352,6 +352,7 @@ static int do_remove_port(struct spa_loop *loop,
void pw_port_destroy(struct pw_port *port)
{
struct pw_node *node = port->node;
struct pw_control *control, *ctemp;
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_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);
spa_hook_list_call(&port->listener_list, struct pw_port_events, free);

View file

@ -418,6 +418,11 @@ struct pw_control {
enum spa_direction direction; /**< the direction */
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;
int32_t size;