mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
port: simplify states
Remove the mix states, we can get rid of them when: The format is the same for all mixer ports. Set the existing format on new mixer ports. When the first format is set, the port becomes READY. When all mixer ports are cleared the port goes back to CONFIGURE. Only output ports allocate and manage buffers, input ports share the buffers of the peer output port on the link.
This commit is contained in:
parent
412c7f4cee
commit
dcbe94c55a
5 changed files with 157 additions and 189 deletions
|
|
@ -704,7 +704,7 @@ client_node_port_set_param(void *object,
|
|||
}
|
||||
}
|
||||
|
||||
res = pw_port_set_param(port, SPA_ID_INVALID, id, flags, param);
|
||||
res = pw_port_set_param(port, id, flags, param);
|
||||
if (res < 0) {
|
||||
pw_proxy_error(proxy, res, "can't set port param: %s", spa_strerror(res));
|
||||
goto done;
|
||||
|
|
@ -934,7 +934,6 @@ client_node_port_set_io(void *object,
|
|||
return res;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int link_signal_func(void *user_data)
|
||||
{
|
||||
struct link *link = user_data;
|
||||
|
|
@ -944,7 +943,6 @@ static int link_signal_func(void *user_data)
|
|||
pw_log_warn("link %p: write failed %m", link);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
client_node_set_activation(void *object,
|
||||
|
|
@ -984,7 +982,6 @@ client_node_set_activation(void *object,
|
|||
}
|
||||
pw_log_debug("node %p: set activation %d", node, node_id);
|
||||
|
||||
#if 0
|
||||
if (ptr) {
|
||||
struct link *link;
|
||||
link = pw_array_add(&data->links, sizeof(struct link));
|
||||
|
|
@ -993,11 +990,13 @@ client_node_set_activation(void *object,
|
|||
link->link.signal = link_signal_func;
|
||||
link->link.signal_data = link;
|
||||
spa_graph_link_add(&node->rt.root, &link->activation->state[0], &link->link);
|
||||
link->link.state->required--;
|
||||
pw_log_debug("node %p: required %d, pending %d", node,
|
||||
link->link.state->required,
|
||||
link->link.state->pending);
|
||||
} else {
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -152,37 +152,42 @@ static void pw_link_update_state(struct pw_link *link, enum pw_link_state state,
|
|||
|
||||
static void complete_ready(void *obj, void *data, int res, uint32_t id)
|
||||
{
|
||||
struct pw_port_mix *mix = data;
|
||||
struct pw_link *this = data;
|
||||
struct pw_port_mix *mix = obj == this->input->node ? &this->rt.in_mix : &this->rt.out_mix;
|
||||
struct pw_port *port = mix->p;
|
||||
|
||||
if (SPA_RESULT_IS_OK(res)) {
|
||||
pw_port_mix_update_state(port, mix, PW_PORT_STATE_READY);
|
||||
pw_port_update_state(port, PW_PORT_STATE_READY);
|
||||
pw_log_debug("port %p: state READY", port);
|
||||
} else {
|
||||
pw_port_mix_update_state(port, mix, PW_PORT_STATE_ERROR);
|
||||
pw_port_update_state(port, PW_PORT_STATE_ERROR);
|
||||
pw_log_warn("port %p: failed to go to READY", port);
|
||||
}
|
||||
if (this->input->state >= PW_PORT_STATE_READY &&
|
||||
this->output->state >= PW_PORT_STATE_READY)
|
||||
pw_link_update_state(this, PW_LINK_STATE_ALLOCATING, NULL);
|
||||
}
|
||||
|
||||
static void complete_paused(void *obj, void *data, int res, uint32_t id)
|
||||
{
|
||||
struct pw_port_mix *mix = data;
|
||||
struct pw_link *this = data;
|
||||
struct pw_port_mix *mix = obj == this->input->node ? &this->rt.in_mix : &this->rt.out_mix;
|
||||
struct pw_port *port = mix->p;
|
||||
|
||||
if (SPA_RESULT_IS_OK(res)) {
|
||||
pw_port_mix_update_state(port, mix, PW_PORT_STATE_PAUSED);
|
||||
pw_port_update_state(port, PW_PORT_STATE_PAUSED);
|
||||
pw_log_debug("port %p: state PAUSED", port);
|
||||
} else {
|
||||
pw_port_mix_update_state(port, mix, PW_PORT_STATE_ERROR);
|
||||
pw_port_update_state(port, PW_PORT_STATE_ERROR);
|
||||
pw_log_warn("port %p: failed to go to PAUSED", port);
|
||||
}
|
||||
if (this->input->state >= PW_PORT_STATE_PAUSED &&
|
||||
this->output->state >= PW_PORT_STATE_PAUSED)
|
||||
pw_link_update_state(this, PW_LINK_STATE_PAUSED, NULL);
|
||||
|
||||
}
|
||||
|
||||
static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_state)
|
||||
static int do_negotiate(struct pw_link *this)
|
||||
{
|
||||
struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
|
||||
int res = -EIO, res2;
|
||||
|
|
@ -194,14 +199,20 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st
|
|||
uint8_t buffer[4096];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
||||
uint32_t index;
|
||||
uint32_t in_mix_state, out_mix_state;
|
||||
uint32_t in_state, out_state;
|
||||
|
||||
in_mix_state = this->rt.in_mix.state;
|
||||
out_mix_state = this->rt.out_mix.state;
|
||||
if (this->info.state >= PW_LINK_STATE_NEGOTIATING)
|
||||
return 0;
|
||||
|
||||
pw_log_debug("in_state:%d out_state:%d", in_mix_state, out_mix_state);
|
||||
input = this->input;
|
||||
output = this->output;
|
||||
|
||||
if (in_mix_state != PW_PORT_STATE_CONFIGURE && out_mix_state != PW_PORT_STATE_CONFIGURE)
|
||||
in_state = input->state;
|
||||
out_state = output->state;
|
||||
|
||||
pw_log_debug("link %p: in_state:%d out_state:%d", this, in_state, out_state);
|
||||
|
||||
if (in_state != PW_PORT_STATE_CONFIGURE && out_state != PW_PORT_STATE_CONFIGURE)
|
||||
return 0;
|
||||
|
||||
pw_link_update_state(this, PW_LINK_STATE_NEGOTIATING, NULL);
|
||||
|
|
@ -212,9 +223,6 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st
|
|||
if ((res = pw_core_find_format(this->core, output, input, NULL, 0, NULL, &format, &b, &error)) < 0)
|
||||
goto error;
|
||||
|
||||
in_state = input->state;
|
||||
out_state = output->state;
|
||||
|
||||
format = spa_pod_copy(format);
|
||||
spa_pod_fixate(format);
|
||||
|
||||
|
|
@ -277,6 +285,11 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st
|
|||
}
|
||||
if (current == NULL || spa_pod_compare(current, format) != 0) {
|
||||
pw_log_debug("link %p: input format change, renegotiate", this);
|
||||
if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) {
|
||||
if (current)
|
||||
spa_debug_pod(2, NULL, current);
|
||||
spa_debug_pod(2, NULL, format);
|
||||
}
|
||||
pw_node_set_state(input->node, PW_NODE_STATE_SUSPENDED);
|
||||
in_state = PW_PORT_STATE_CONFIGURE;
|
||||
}
|
||||
|
|
@ -290,10 +303,9 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st
|
|||
if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG))
|
||||
spa_debug_format(2, NULL, format);
|
||||
|
||||
if (out_mix_state == PW_PORT_STATE_CONFIGURE) {
|
||||
pw_log_debug("link %p: doing set format on output mix", this);
|
||||
if (out_state == PW_PORT_STATE_CONFIGURE) {
|
||||
pw_log_debug("link %p: doing set format on output", this);
|
||||
if ((res = pw_port_set_param(output,
|
||||
this->rt.out_mix.port.port_id,
|
||||
SPA_PARAM_Format, SPA_NODE_PARAM_FLAG_NEAREST,
|
||||
format)) < 0) {
|
||||
asprintf(&error, "error set output format: %d (%s)", res, spa_strerror(res));
|
||||
|
|
@ -301,14 +313,15 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st
|
|||
}
|
||||
if (SPA_RESULT_IS_ASYNC(res)) {
|
||||
res = spa_node_sync(output->node->node, res),
|
||||
pw_work_queue_add(impl->work, output->node, res, complete_ready,
|
||||
&this->rt.out_mix);
|
||||
pw_work_queue_add(impl->work, output->node, res,
|
||||
complete_ready, this);
|
||||
} else {
|
||||
complete_ready(output->node, this, res, 0);
|
||||
}
|
||||
}
|
||||
if (in_mix_state == PW_PORT_STATE_CONFIGURE) {
|
||||
pw_log_debug("link %p: doing set format on input mix", this);
|
||||
if (in_state == PW_PORT_STATE_CONFIGURE) {
|
||||
pw_log_debug("link %p: doing set format on input", this);
|
||||
if ((res2 = pw_port_set_param(input,
|
||||
this->rt.in_mix.port.port_id,
|
||||
SPA_PARAM_Format, SPA_NODE_PARAM_FLAG_NEAREST,
|
||||
format)) < 0) {
|
||||
asprintf(&error, "error set input format: %d (%s)", res2, spa_strerror(res2));
|
||||
|
|
@ -316,10 +329,12 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st
|
|||
}
|
||||
if (SPA_RESULT_IS_ASYNC(res2)) {
|
||||
res2 = spa_node_sync(input->node->node, res2),
|
||||
pw_work_queue_add(impl->work, input->node, res2, complete_ready,
|
||||
&this->rt.in_mix);
|
||||
pw_work_queue_add(impl->work, input->node, res2,
|
||||
complete_ready, this);
|
||||
if (res == 0)
|
||||
res = res2;
|
||||
} else {
|
||||
complete_ready(input->node, this, res2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -540,7 +555,7 @@ static int select_io(struct pw_link *this)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_state)
|
||||
static int do_allocation(struct pw_link *this)
|
||||
{
|
||||
struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
|
||||
int res;
|
||||
|
|
@ -548,21 +563,17 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s
|
|||
char *error = NULL;
|
||||
struct pw_port *input, *output;
|
||||
struct allocation allocation = { NULL, };
|
||||
uint32_t in_mix_state, out_mix_state;
|
||||
|
||||
in_mix_state = this->rt.in_mix.state;
|
||||
out_mix_state = this->rt.out_mix.state;
|
||||
|
||||
pw_log_debug("%d %d", in_mix_state, out_mix_state);
|
||||
|
||||
if (in_mix_state != PW_PORT_STATE_READY && out_mix_state != PW_PORT_STATE_READY)
|
||||
if (this->info.state > PW_LINK_STATE_ALLOCATING)
|
||||
return 0;
|
||||
|
||||
pw_link_update_state(this, PW_LINK_STATE_ALLOCATING, NULL);
|
||||
|
||||
input = this->input;
|
||||
output = this->output;
|
||||
|
||||
pw_log_debug("link %p: in_state:%d out_state:%d", this, input->state, output->state);
|
||||
|
||||
pw_link_update_state(this, PW_LINK_STATE_ALLOCATING, NULL);
|
||||
|
||||
pw_log_debug("link %p: doing alloc buffers %p %p", this, output->node, input->node);
|
||||
|
||||
in_flags = input->spa_flags;
|
||||
|
|
@ -582,14 +593,6 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s
|
|||
|
||||
pw_log_debug("link %p: reusing %d output buffers %p", this,
|
||||
allocation.n_buffers, allocation.buffers);
|
||||
} else if (input->allocation.n_buffers && input->mix == NULL) {
|
||||
out_flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
in_flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
|
||||
move_allocation(&input->allocation, &allocation);
|
||||
|
||||
pw_log_debug("link %p: reusing %d input buffers %p", this,
|
||||
allocation.n_buffers, allocation.buffers);
|
||||
} else {
|
||||
struct spa_pod **params, *param;
|
||||
uint8_t buffer[4096];
|
||||
|
|
@ -682,8 +685,10 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s
|
|||
}
|
||||
if (SPA_RESULT_IS_ASYNC(res)) {
|
||||
res = spa_node_sync(output->node->node, res),
|
||||
pw_work_queue_add(impl->work, output->node, res, complete_paused,
|
||||
&this->rt.out_mix);
|
||||
pw_work_queue_add(impl->work, output->node, res,
|
||||
complete_paused, this);
|
||||
} else {
|
||||
complete_paused(output->node, this, res, 0);
|
||||
}
|
||||
|
||||
out_flags &= ~SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
|
|
@ -691,24 +696,6 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s
|
|||
|
||||
pw_log_debug("link %p: allocated %d buffers %p from output port", this,
|
||||
allocation.n_buffers, allocation.buffers);
|
||||
} else if (in_flags & SPA_PORT_FLAG_CAN_ALLOC_BUFFERS) {
|
||||
if ((res = pw_port_alloc_buffers(input,
|
||||
this->rt.in_mix.port.port_id,
|
||||
params, n_params,
|
||||
allocation.buffers,
|
||||
&allocation.n_buffers)) < 0) {
|
||||
asprintf(&error, "error alloc input buffers: %d", res);
|
||||
goto error;
|
||||
}
|
||||
if (SPA_RESULT_IS_ASYNC(res)) {
|
||||
res = spa_node_sync(input->node->node, res),
|
||||
pw_work_queue_add(impl->work, input->node, res, complete_paused,
|
||||
&this->rt.in_mix);
|
||||
}
|
||||
|
||||
in_flags &= ~SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
pw_log_debug("link %p: allocated %d buffers %p from input port", this,
|
||||
allocation.n_buffers, allocation.buffers);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -725,12 +712,12 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s
|
|||
}
|
||||
if (SPA_RESULT_IS_ASYNC(res)) {
|
||||
res = spa_node_sync(output->node->node, res),
|
||||
pw_work_queue_add(impl->work, output->node, res, complete_paused,
|
||||
&this->rt.out_mix);
|
||||
pw_work_queue_add(impl->work, output->node, res,
|
||||
complete_paused, this);
|
||||
} else {
|
||||
complete_paused(output->node, this, res, 0);
|
||||
}
|
||||
|
||||
move_allocation(&allocation, &output->allocation);
|
||||
|
||||
}
|
||||
if (in_flags & SPA_PORT_FLAG_CAN_USE_BUFFERS) {
|
||||
pw_log_debug("link %p: using %d buffers %p on input port", this,
|
||||
|
|
@ -745,8 +732,10 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s
|
|||
}
|
||||
if (SPA_RESULT_IS_ASYNC(res)) {
|
||||
res = spa_node_sync(input->node->node, res),
|
||||
pw_work_queue_add(impl->work, input->node, res, complete_paused,
|
||||
&this->rt.in_mix);
|
||||
pw_work_queue_add(impl->work, input->node, res,
|
||||
complete_paused, this);
|
||||
} else {
|
||||
complete_paused(input->node, this, res, 0);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -817,20 +806,29 @@ static void check_states(void *obj, void *user_data, int res, uint32_t id)
|
|||
struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
|
||||
int in_state, out_state;
|
||||
struct pw_port *input, *output;
|
||||
int in_mix_state, out_mix_state;
|
||||
|
||||
if (this->info.state == PW_LINK_STATE_ERROR)
|
||||
return;
|
||||
|
||||
if (this->info.state == PW_LINK_STATE_PAUSED)
|
||||
return;
|
||||
|
||||
input = this->input;
|
||||
output = this->output;
|
||||
|
||||
if (input == NULL || output == NULL)
|
||||
if (input == NULL || output == NULL) {
|
||||
pw_link_update_state(this, PW_LINK_STATE_ERROR,
|
||||
strdup("link without input or output port"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (input->node->info.state == PW_NODE_STATE_ERROR ||
|
||||
output->node->info.state == PW_NODE_STATE_ERROR)
|
||||
output->node->info.state == PW_NODE_STATE_ERROR) {
|
||||
pw_log_warn("link %p: one of the nodes is in error in:%d out:%d", this,
|
||||
input->node->info.state,
|
||||
output->node->info.state);
|
||||
return;
|
||||
}
|
||||
|
||||
in_state = input->state;
|
||||
out_state = output->state;
|
||||
|
|
@ -838,27 +836,20 @@ static void check_states(void *obj, void *user_data, int res, uint32_t id)
|
|||
pw_log_debug("link %p: input state %d, output state %d", this, in_state, out_state);
|
||||
|
||||
if (in_state == PW_PORT_STATE_ERROR || out_state == PW_PORT_STATE_ERROR) {
|
||||
pw_link_update_state(this, PW_LINK_STATE_ERROR, NULL);
|
||||
pw_link_update_state(this, PW_LINK_STATE_ERROR, strdup("ports are in error"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (PW_PORT_IS_CONTROL(output) && PW_PORT_IS_CONTROL(input)) {
|
||||
pw_port_mix_update_state(input, &this->rt.in_mix, PW_PORT_STATE_PAUSED);
|
||||
pw_port_mix_update_state(output, &this->rt.out_mix, PW_PORT_STATE_PAUSED);
|
||||
}
|
||||
|
||||
in_mix_state = this->rt.in_mix.state;
|
||||
out_mix_state = this->rt.out_mix.state;
|
||||
|
||||
if (in_mix_state == PW_PORT_STATE_PAUSED && out_mix_state == PW_PORT_STATE_PAUSED) {
|
||||
pw_port_update_state(input, PW_PORT_STATE_PAUSED);
|
||||
pw_port_update_state(output, PW_PORT_STATE_PAUSED);
|
||||
pw_link_update_state(this, PW_LINK_STATE_PAUSED, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((res = do_negotiate(this, in_state, out_state)) != 0)
|
||||
if ((res = do_negotiate(this)) != 0)
|
||||
goto exit;
|
||||
|
||||
if ((res = do_allocation(this, in_state, out_state)) != 0)
|
||||
if ((res = do_allocation(this)) != 0)
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
|
|
@ -1036,7 +1027,6 @@ int pw_link_deactivate(struct pw_link *this)
|
|||
pw_log_debug("port %p: input state %d -> %d", this->input,
|
||||
this->input->state, PW_PORT_STATE_PAUSED);
|
||||
}
|
||||
pw_port_mix_update_state(this->input, &this->rt.in_mix, PW_PORT_STATE_CONFIGURE);
|
||||
|
||||
if (output_node->n_used_input_links <= output_node->idle_used_input_links &&
|
||||
output_node->n_used_output_links <= output_node->idle_used_output_links &&
|
||||
|
|
@ -1045,7 +1035,6 @@ int pw_link_deactivate(struct pw_link *this)
|
|||
pw_log_debug("port %p: output state %d -> %d", this->output,
|
||||
this->output->state, PW_PORT_STATE_PAUSED);
|
||||
}
|
||||
pw_port_mix_update_state(this->output, &this->rt.out_mix, PW_PORT_STATE_CONFIGURE);
|
||||
|
||||
pw_link_update_state(this, PW_LINK_STATE_INIT, NULL);
|
||||
|
||||
|
|
@ -1108,18 +1097,20 @@ static void input_node_result(void *data, int seq, int res, const void *result)
|
|||
{
|
||||
struct impl *impl = data;
|
||||
struct pw_node *node = impl->this.input->node;
|
||||
pw_log_debug("link %p: input node %p result %d %d", impl, node, seq, res);
|
||||
if (SPA_RESULT_IS_ASYNC(seq))
|
||||
if (SPA_RESULT_IS_ASYNC(seq)) {
|
||||
pw_log_debug("link %p: input node %p result %d %d", impl, node, seq, res);
|
||||
pw_work_queue_complete(impl->work, node, SPA_RESULT_ASYNC_SEQ(seq), res);
|
||||
}
|
||||
}
|
||||
|
||||
static void output_node_result(void *data, int seq, int res, const void *result)
|
||||
{
|
||||
struct impl *impl = data;
|
||||
struct pw_node *node = impl->this.output->node;
|
||||
pw_log_debug("link %p: output node %p result %d %d", impl, node, seq, res);
|
||||
if (SPA_RESULT_IS_ASYNC(seq))
|
||||
if (SPA_RESULT_IS_ASYNC(seq)) {
|
||||
pw_log_debug("link %p: output node %p result %d %d", impl, node, seq, res);
|
||||
pw_work_queue_complete(impl->work, node, SPA_RESULT_ASYNC_SEQ(seq), res);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_node_events input_node_events = {
|
||||
|
|
|
|||
|
|
@ -224,14 +224,14 @@ static int suspend_node(struct pw_node *this)
|
|||
pw_log_debug("node %p: suspend node", this);
|
||||
|
||||
spa_list_for_each(p, &this->input_ports, link) {
|
||||
if ((res = pw_port_set_param(p, SPA_ID_INVALID, SPA_PARAM_Format, 0, NULL)) < 0)
|
||||
if ((res = pw_port_set_param(p, SPA_PARAM_Format, 0, NULL)) < 0)
|
||||
pw_log_warn("error unset format input: %s", spa_strerror(res));
|
||||
/* force CONFIGURE in case of async */
|
||||
p->state = PW_PORT_STATE_CONFIGURE;
|
||||
}
|
||||
|
||||
spa_list_for_each(p, &this->output_ports, link) {
|
||||
if ((res = pw_port_set_param(p, SPA_ID_INVALID, SPA_PARAM_Format, 0, NULL)) < 0)
|
||||
if ((res = pw_port_set_param(p, SPA_PARAM_Format, 0, NULL)) < 0)
|
||||
pw_log_warn("error unset format output: %s", spa_strerror(res));
|
||||
/* force CONFIGURE in case of async */
|
||||
p->state = PW_PORT_STATE_CONFIGURE;
|
||||
|
|
@ -896,6 +896,7 @@ static int node_ready(void *data, int status)
|
|||
{
|
||||
struct pw_node *node = data;
|
||||
struct pw_node *driver = node->driver_node;
|
||||
struct spa_graph_port *p, *pp;
|
||||
|
||||
pw_log_trace("node %p: ready driver:%d exported:%d %p status:%d", node,
|
||||
node->driver, node->exported, driver, status);
|
||||
|
|
@ -907,9 +908,13 @@ static int node_ready(void *data, int status)
|
|||
|
||||
spa_graph_run(driver->rt.driver);
|
||||
|
||||
if (status == SPA_STATUS_HAVE_BUFFER)
|
||||
spa_graph_node_process(&driver->rt.root);
|
||||
|
||||
if (status == SPA_STATUS_HAVE_BUFFER) {
|
||||
spa_list_for_each(p, &node->rt.node.ports[SPA_DIRECTION_OUTPUT], link) {
|
||||
if ((pp = p->peer) != NULL)
|
||||
spa_node_process((struct spa_node*)pp->node->callbacks_data);
|
||||
}
|
||||
spa_graph_node_trigger(&driver->rt.root);
|
||||
}
|
||||
spa_graph_link_trigger(&driver->rt.driver_link);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,35 +50,6 @@ struct resource_data {
|
|||
|
||||
/** \endcond */
|
||||
|
||||
static inline void adjust_mix_state(struct pw_port *port, enum pw_port_state state, int dir)
|
||||
{
|
||||
switch (state) {
|
||||
case PW_PORT_STATE_CONFIGURE:
|
||||
port->n_mix_configure += dir;
|
||||
break;
|
||||
case PW_PORT_STATE_READY:
|
||||
port->n_mix_ready += dir;
|
||||
break;
|
||||
case PW_PORT_STATE_PAUSED:
|
||||
port->n_mix_paused += dir;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void pw_port_mix_update_state(struct pw_port *port, struct pw_port_mix *mix, enum pw_port_state state)
|
||||
{
|
||||
if (mix && mix->state != state) {
|
||||
adjust_mix_state(port, mix->state, -1);
|
||||
mix->state = state;
|
||||
adjust_mix_state(port, state, 1);
|
||||
pw_log_debug("port %p: mix %d c:%d r:%d p:%d", port, mix->id,
|
||||
port->n_mix_configure, port->n_mix_ready,
|
||||
port->n_mix_paused);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_info_changed(struct pw_port *port)
|
||||
{
|
||||
struct pw_resource *resource;
|
||||
|
|
@ -220,10 +191,9 @@ int pw_port_init_mix(struct pw_port *port, struct pw_port_mix *mix)
|
|||
port->direction, port_id,
|
||||
0);
|
||||
|
||||
mix->p = port;
|
||||
mix->state = PW_PORT_STATE_CONFIGURE;
|
||||
spa_list_append(&port->mix_list, &mix->link);
|
||||
port->n_mix++;
|
||||
adjust_mix_state(port, mix->state, 1);
|
||||
mix->p = port;
|
||||
|
||||
if (port->mix->add_port)
|
||||
port->mix->add_port(port->mix, port->direction, port_id, NULL);
|
||||
|
|
@ -231,6 +201,23 @@ int pw_port_init_mix(struct pw_port *port, struct pw_port_mix *mix)
|
|||
if (pi && pi->init_mix)
|
||||
res = pi->init_mix(port->implementation_data, mix);
|
||||
|
||||
/* set the same format on the mixer as on the port if any */
|
||||
if (port->mix->enum_params && port->mix->set_param) {
|
||||
uint32_t idx = 0;
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod_builder b;
|
||||
struct spa_pod *param;
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
if (spa_node_port_enum_params_sync(port->mix,
|
||||
pw_direction_reverse(port->direction), 0,
|
||||
SPA_PARAM_Format, &idx, NULL, ¶m, &b) == 1) {
|
||||
spa_node_port_set_param(port->mix,
|
||||
port->direction, port_id,
|
||||
SPA_PARAM_Format, 0, param);
|
||||
}
|
||||
}
|
||||
|
||||
pw_log_debug("port %p: init mix %d.%d io %p", port,
|
||||
port->port_id, mix->port.port_id, mix->io);
|
||||
|
||||
|
|
@ -245,7 +232,7 @@ int pw_port_release_mix(struct pw_port *port, struct pw_port_mix *mix)
|
|||
const struct pw_port_implementation *pi = port->implementation;
|
||||
|
||||
pw_map_remove(&port->mix_port_map, port_id);
|
||||
adjust_mix_state(port, mix->state, -1);
|
||||
spa_list_remove(&mix->link);
|
||||
port->n_mix--;
|
||||
|
||||
if (pi && pi->release_mix)
|
||||
|
|
@ -339,6 +326,7 @@ struct pw_port *pw_port_new(enum pw_direction direction,
|
|||
this->info.props = &this->properties->dict;
|
||||
|
||||
spa_list_init(&this->links);
|
||||
spa_list_init(&this->mix_list);
|
||||
spa_list_init(&this->control_list[0]);
|
||||
spa_list_init(&this->control_list[1]);
|
||||
|
||||
|
|
@ -913,55 +901,48 @@ int pw_port_is_linked(struct pw_port *port)
|
|||
}
|
||||
|
||||
SPA_EXPORT
|
||||
int pw_port_set_param(struct pw_port *port, uint32_t mix_id, uint32_t id, uint32_t flags,
|
||||
int pw_port_set_param(struct pw_port *port, uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
{
|
||||
int res = 0;
|
||||
struct pw_node *node = port->node;
|
||||
struct pw_port_mix *mix = NULL;
|
||||
|
||||
if (mix_id != SPA_ID_INVALID)
|
||||
mix = pw_map_lookup(&port->mix_port_map, mix_id);
|
||||
pw_log_debug("port %p: %d set param %d %p", port, port->state, id, param);
|
||||
|
||||
if (mix != NULL && port->mix->port_set_param != NULL) {
|
||||
struct spa_graph_port *p = &mix->port;
|
||||
/* set the parameters on all ports of the mixer node if possible */
|
||||
if (port->mix->port_set_param != NULL) {
|
||||
struct pw_port_mix *mix;
|
||||
|
||||
res = spa_node_port_set_param(port->mix,
|
||||
p->direction, p->port_id,
|
||||
id, flags, param);
|
||||
|
||||
pw_log_debug("port %p: %d set param on mix %d:%d.%d %s: %d (%s)", port, port->state,
|
||||
port->direction, port->port_id, p->port_id,
|
||||
spa_debug_type_find_name(spa_type_param, id), res, spa_strerror(res));
|
||||
if (res < 0)
|
||||
goto done;
|
||||
|
||||
if (port->state == PW_PORT_STATE_CONFIGURE) {
|
||||
spa_list_for_each(mix, &port->mix_list, link) {
|
||||
spa_node_port_set_param(port->mix,
|
||||
pw_direction_reverse(p->direction), 0,
|
||||
id, flags, param);
|
||||
mix->port.direction, mix->port.port_id,
|
||||
id, flags, param);
|
||||
}
|
||||
}
|
||||
if (port->state == PW_PORT_STATE_CONFIGURE || param == NULL) {
|
||||
res = spa_node_port_set_param(node->node, port->direction, port->port_id, id, flags, param);
|
||||
pw_log_debug("port %p: %d set param on node %d:%d %s: %d (%s)", port, port->state,
|
||||
port->direction, port->port_id,
|
||||
spa_debug_type_find_name(spa_type_param, id), res, spa_strerror(res));
|
||||
spa_node_port_set_param(port->mix,
|
||||
pw_direction_reverse(port->direction), 0,
|
||||
id, flags, param);
|
||||
}
|
||||
|
||||
done:
|
||||
/* then set parameter on node */
|
||||
res = spa_node_port_set_param(node->node,
|
||||
port->direction, port->port_id,
|
||||
id, flags, param);
|
||||
|
||||
pw_log_debug("port %p: %d set param on node %d:%d %s: %d (%s)", port, port->state,
|
||||
port->direction, port->port_id,
|
||||
spa_debug_type_find_name(spa_type_param, id), res, spa_strerror(res));
|
||||
|
||||
if (id == SPA_PARAM_Format) {
|
||||
pw_log_debug("port %p: %d %p %d", port, port->state, param, res);
|
||||
/* setting the format always destroys the negotiated buffers */
|
||||
free_allocation(&port->allocation);
|
||||
port->allocated = false;
|
||||
|
||||
if (param == NULL || res < 0) {
|
||||
free_allocation(&port->allocation);
|
||||
port->allocated = false;
|
||||
pw_port_mix_update_state(port, mix, PW_PORT_STATE_CONFIGURE);
|
||||
if (port->n_mix_configure == port->n_mix)
|
||||
pw_port_update_state(port, PW_PORT_STATE_CONFIGURE);
|
||||
pw_port_update_state(port, PW_PORT_STATE_CONFIGURE);
|
||||
}
|
||||
else if (!SPA_RESULT_IS_ASYNC(res)) {
|
||||
pw_port_mix_update_state(port, mix, PW_PORT_STATE_READY);
|
||||
if (port->state == PW_PORT_STATE_CONFIGURE)
|
||||
pw_port_update_state(port, PW_PORT_STATE_READY);
|
||||
pw_port_update_state(port, PW_PORT_STATE_READY);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
|
@ -985,23 +966,21 @@ int pw_port_use_buffers(struct pw_port *port, uint32_t mix_id,
|
|||
if (n_buffers > 0 && port->state < PW_PORT_STATE_READY)
|
||||
return -EIO;
|
||||
|
||||
if (mix_id != SPA_ID_INVALID &&
|
||||
(mix = pw_map_lookup(&port->mix_port_map, mix_id)) == NULL)
|
||||
if ((mix = pw_map_lookup(&port->mix_port_map, mix_id)) == NULL)
|
||||
return -EIO;
|
||||
|
||||
if (mix && port->mix->port_use_buffers != NULL) {
|
||||
if (port->mix->port_use_buffers != NULL) {
|
||||
struct spa_graph_port *p = &mix->port;
|
||||
res = spa_node_port_use_buffers(port->mix,
|
||||
p->direction, p->port_id, buffers, n_buffers);
|
||||
pw_log_debug("port %p: use buffers on mix: %d (%s)",
|
||||
port, res, spa_strerror(res));
|
||||
}
|
||||
if (n_buffers == 0) {
|
||||
pw_port_mix_update_state(port, mix, PW_PORT_STATE_READY);
|
||||
if (port->n_mix_ready + port->n_mix_configure == port->n_mix)
|
||||
pw_port_update_state(port, PW_PORT_STATE_READY);
|
||||
pw_log_debug("port %p: use buffers on mix: %p %d (%s)",
|
||||
port, port->mix, res, spa_strerror(res));
|
||||
}
|
||||
|
||||
if (n_buffers == 0) {
|
||||
if (port->n_mix == 0)
|
||||
pw_port_update_state(port, PW_PORT_STATE_READY);
|
||||
}
|
||||
if (port->state == PW_PORT_STATE_READY) {
|
||||
if (!SPA_FLAG_CHECK(port->mix_flags, PW_PORT_MIX_FLAG_MIX_ONLY)) {
|
||||
res = spa_node_port_use_buffers(node->node,
|
||||
|
|
@ -1016,9 +995,7 @@ int pw_port_use_buffers(struct pw_port *port, uint32_t mix_id,
|
|||
}
|
||||
|
||||
if (n_buffers > 0 && !SPA_RESULT_IS_ASYNC(res)) {
|
||||
pw_port_mix_update_state(port, mix, PW_PORT_STATE_PAUSED);
|
||||
if (port->state == PW_PORT_STATE_READY)
|
||||
pw_port_update_state(port, PW_PORT_STATE_PAUSED);
|
||||
pw_port_update_state(port, PW_PORT_STATE_PAUSED);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
@ -1039,7 +1016,7 @@ int pw_port_alloc_buffers(struct pw_port *port, uint32_t mix_id,
|
|||
if ((mix = pw_map_lookup(&port->mix_port_map, mix_id)) == NULL)
|
||||
return -EIO;
|
||||
|
||||
if (port->mix->port_use_buffers) {
|
||||
if (port->mix->port_alloc_buffers) {
|
||||
struct spa_graph_port *p = &mix->port;
|
||||
res = spa_node_port_alloc_buffers(port->mix, p->direction, p->port_id,
|
||||
params, n_params,
|
||||
|
|
@ -1066,12 +1043,10 @@ int pw_port_alloc_buffers(struct pw_port *port, uint32_t mix_id,
|
|||
}
|
||||
|
||||
if (*n_buffers == 0) {
|
||||
pw_port_mix_update_state(port, mix, PW_PORT_STATE_READY);
|
||||
if (port->n_mix_ready + port->n_mix_configure == port->n_mix)
|
||||
if (port->n_mix == 0)
|
||||
pw_port_update_state(port, PW_PORT_STATE_READY);
|
||||
}
|
||||
else if (!SPA_RESULT_IS_ASYNC(res)) {
|
||||
pw_port_mix_update_state(port, mix, PW_PORT_STATE_PAUSED);
|
||||
pw_port_update_state(port, PW_PORT_STATE_PAUSED);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -392,11 +392,11 @@ struct pw_node {
|
|||
};
|
||||
|
||||
struct pw_port_mix {
|
||||
struct spa_list link;
|
||||
struct pw_port *p;
|
||||
struct spa_graph_port port;
|
||||
struct spa_io_buffers *io;
|
||||
uint32_t id;
|
||||
enum pw_port_state state; /**< state of the port */
|
||||
};
|
||||
|
||||
struct pw_port_implementation {
|
||||
|
|
@ -464,11 +464,9 @@ struct pw_port {
|
|||
|
||||
int allocated:1; /**< if buffers are allocated */
|
||||
|
||||
struct spa_list mix_list; /**< list of \ref pw_port_mix */
|
||||
struct pw_map mix_port_map; /**< map from port_id from mixer */
|
||||
uint32_t n_mix;
|
||||
uint32_t n_mix_configure;
|
||||
uint32_t n_mix_ready;
|
||||
uint32_t n_mix_paused;
|
||||
|
||||
struct {
|
||||
struct spa_io_buffers io; /**< io area of the port */
|
||||
|
|
@ -772,7 +770,7 @@ int pw_port_is_linked(struct pw_port *port);
|
|||
|
||||
/** Set a param on a port \memberof pw_port, use SPA_ID_INVALID for mix_id to set
|
||||
* the param on all mix ports */
|
||||
int pw_port_set_param(struct pw_port *port, uint32_t mix_id,
|
||||
int pw_port_set_param(struct pw_port *port,
|
||||
uint32_t id, uint32_t flags, const struct spa_pod *param);
|
||||
|
||||
/** Use buffers on a port \memberof pw_port */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue