diff --git a/src/modules/module-client-node/remote-node.c b/src/modules/module-client-node/remote-node.c index a86a8084b..63263e657 100644 --- a/src/modules/module-client-node/remote-node.c +++ b/src/modules/module-client-node/remote-node.c @@ -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; } diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 355f05218..ae2c91d39 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -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 = { diff --git a/src/pipewire/node.c b/src/pipewire/node.c index ac603e229..6441ee5ef 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -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; } diff --git a/src/pipewire/port.c b/src/pipewire/port.c index ea8de3515..50e4e3b9f 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -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); } diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 3ae975a07..c6c189c8f 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -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 */