mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-06-04 03:03:00 -04:00
impl-port: make suspend go from INIT -> CONFIGURE
Bring the port to INIT before going to CONFIGURE when we do the suspend logic. This is to ensure that there always is a state change to emit the state change notification. This was, the link can detect the suspend case and cancel any pending results. One of the problem with suspend is that the state changes on the ports are done from different places; the port and link. This causes issues like: 1. do_negotiate calls pw_port_set_param(Format,..) with the negotiated format. This returns async and the link queues a complete_ready callback. 2. The node is suspended, pw_impl_port_set_param(Format, NULL) is called to clear the port format. This bypasses the link. 3. The reply from step 2 arrives and triggers complete_ready, this brings the port state to READY and the link state to ALLOCATING. 4. The link continues allocating and sets buffers on the port. This then fails because the last format set was NULL. Ideally all port states should be managed in one place and the async port state changes should be kept in the port itself as well but this will need some more work. Fixes #3547
This commit is contained in:
parent
f22932580f
commit
b41d117609
2 changed files with 14 additions and 0 deletions
|
|
@ -1049,15 +1049,28 @@ static void port_state_changed(struct pw_impl_link *this, struct pw_impl_port *p
|
|||
struct pw_impl_port *other, enum pw_impl_port_state old,
|
||||
enum pw_impl_port_state state, const char *error)
|
||||
{
|
||||
struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
|
||||
struct port_info *info;
|
||||
|
||||
pw_log_debug("%p: port %p old:%d -> state:%d prepared:%d preparing:%d",
|
||||
this, port, old, state, this->prepared, this->preparing);
|
||||
|
||||
if (port == impl->output.port)
|
||||
info = &impl->output;
|
||||
else
|
||||
info = &impl->input;
|
||||
|
||||
switch (state) {
|
||||
case PW_IMPL_PORT_STATE_ERROR:
|
||||
link_update_state(this, PW_LINK_STATE_ERROR, -EIO, error ? strdup(error) : NULL);
|
||||
break;
|
||||
case PW_IMPL_PORT_STATE_INIT:
|
||||
case PW_IMPL_PORT_STATE_CONFIGURE:
|
||||
if (old == PW_IMPL_PORT_STATE_INIT) {
|
||||
port_set_busy_id(this, info, SPA_ID_INVALID, SPA_ID_INVALID);
|
||||
pw_work_queue_cancel(impl->work, info, SPA_ID_INVALID);
|
||||
old = PW_IMPL_PORT_STATE_READY;
|
||||
}
|
||||
if (this->prepared || state < old) {
|
||||
this->prepared = this->preparing = false;
|
||||
link_update_state(this, PW_LINK_STATE_INIT, 0, NULL);
|
||||
|
|
|
|||
|
|
@ -1615,6 +1615,7 @@ void pw_impl_port_suspend(struct pw_impl_port *port)
|
|||
int res;
|
||||
if ((res = pw_impl_port_set_param(port, SPA_PARAM_Format, 0, NULL)) < 0)
|
||||
pw_log_warn("%p: error unset format: %s", port, spa_strerror(res));
|
||||
port->state = PW_IMPL_PORT_STATE_INIT;
|
||||
/* force CONFIGURE in case of async, use update_state to
|
||||
* notify links so they can cancel pending work */
|
||||
pw_impl_port_update_state(port, PW_IMPL_PORT_STATE_CONFIGURE, 0, NULL);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue