From 0a27040c9a07c2b1a81fc0960ec0ee69b399069d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 13 Dec 2018 12:04:02 +0100 Subject: [PATCH] port: keep track of mix port states Keep track of the state of the mixer ports and update the port state accordingly. This avoids clearing the format or buffers on the port when mixers are still busy. --- src/pipewire/link.c | 24 ++++++------- src/pipewire/port.c | 80 ++++++++++++++++++++++++++++++------------ src/pipewire/private.h | 7 ++++ 3 files changed, 77 insertions(+), 34 deletions(-) diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 679cb1b04..d51ff8e87 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -152,12 +152,12 @@ static void complete_ready(void *obj, void *data, int res, uint32_t id) struct pw_port *port = mix->p; if (SPA_RESULT_IS_OK(res)) { - port->state = PW_PORT_STATE_READY; - mix->state = PW_PORT_STATE_READY; + 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 { - port->state = PW_PORT_STATE_ERROR; - mix->state = PW_PORT_STATE_ERROR; + 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); } } @@ -168,12 +168,12 @@ static void complete_paused(void *obj, void *data, int res, uint32_t id) struct pw_port *port = mix->p; if (SPA_RESULT_IS_OK(res)) { - port->state = PW_PORT_STATE_PAUSED; - mix->state = PW_PORT_STATE_PAUSED; + 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 { - port->state = PW_PORT_STATE_ERROR; - mix->state = PW_PORT_STATE_ERROR; + 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); } } @@ -937,8 +937,8 @@ static int check_states(struct pw_link *this, void *user_data, int res) } if (PW_PORT_IS_CONTROL(output) && PW_PORT_IS_CONTROL(input)) { - this->rt.in_mix.state = PW_PORT_STATE_PAUSED; - this->rt.out_mix.state = PW_PORT_STATE_PAUSED; + 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; @@ -1152,7 +1152,7 @@ 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); } - this->rt.in_mix.state = PW_PORT_STATE_CONFIGURE; + 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 && @@ -1161,7 +1161,7 @@ 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); } - this->rt.out_mix.state = PW_PORT_STATE_CONFIGURE; + 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); diff --git a/src/pipewire/port.c b/src/pipewire/port.c index 797b3b6dd..f5056c0c7 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -46,11 +46,37 @@ struct resource_data { /** \endcond */ - -static void port_update_state(struct pw_port *port, struct pw_port_mix *mix, enum pw_port_state state) +static inline void adjust_mix_state(struct pw_port *port, enum pw_port_state state, int dir) { - if (mix) + 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); + } +} + +void pw_port_update_state(struct pw_port *port, enum pw_port_state state) +{ if (port->state != state) { pw_log(state == PW_PORT_STATE_ERROR ? SPA_LOG_LEVEL_ERROR : SPA_LOG_LEVEL_DEBUG, @@ -156,8 +182,11 @@ int pw_port_init_mix(struct pw_port *port, struct pw_port_mix *mix) spa_graph_port_init(&mix->port, port->direction, port_id, 0); + mix->p = port; mix->state = PW_PORT_STATE_CONFIGURE; + port->n_mix++; + adjust_mix_state(port, mix->state, 1); if (port->mix->add_port) port->mix->add_port(port->mix, port->direction, port_id); @@ -177,6 +206,8 @@ 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); + port->n_mix--; if (pi && pi->release_mix) res = pi->release_mix(port->implementation_data, mix); @@ -592,7 +623,7 @@ int pw_port_add(struct pw_port *port, struct pw_node *node) pw_loop_invoke(node->data_loop, do_add_port, SPA_ID_INVALID, NULL, 0, false, port); if (port->state <= PW_PORT_STATE_INIT) - port_update_state(port, NULL, PW_PORT_STATE_CONFIGURE); + pw_port_update_state(port, PW_PORT_STATE_CONFIGURE); pw_node_events_port_added(node, port); @@ -848,13 +879,14 @@ int pw_port_set_param(struct pw_port *port, uint32_t mix_id, uint32_t id, uint32 if (param == NULL || res < 0) { free_allocation(&port->allocation); port->allocated = false; - port_update_state(port, mix, PW_PORT_STATE_CONFIGURE); + 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); } 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) - port_update_state(port, mix, PW_PORT_STATE_READY); - else if (mix) - mix->state = PW_PORT_STATE_READY; + pw_port_update_state(port, PW_PORT_STATE_READY); } } return res; @@ -888,8 +920,13 @@ int pw_port_use_buffers(struct pw_port *port, uint32_t mix_id, 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); + } - if (port->state == PW_PORT_STATE_READY || n_buffers == 0) { + 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, port->direction, port->port_id, buffers, n_buffers); @@ -902,16 +939,10 @@ int pw_port_use_buffers(struct pw_port *port, uint32_t mix_id, res = pi->use_buffers(port->implementation_data, buffers, n_buffers); } - if (res < 0) - n_buffers = 0; - - if (n_buffers == 0) - port_update_state(port, mix, PW_PORT_STATE_READY); - else if (!SPA_RESULT_IS_ASYNC(res)) { + 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) - port_update_state(port, mix, PW_PORT_STATE_PAUSED); - else if (mix) - mix->state = PW_PORT_STATE_PAUSED; + pw_port_update_state(port, PW_PORT_STATE_PAUSED); } return res; } @@ -957,10 +988,15 @@ int pw_port_alloc_buffers(struct pw_port *port, uint32_t mix_id, port->allocated = true; } - if (*n_buffers == 0) - port_update_state(port, mix, PW_PORT_STATE_READY); - else if (!SPA_RESULT_IS_ASYNC(res)) - port_update_state(port, mix, PW_PORT_STATE_PAUSED); + 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); + } + 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); + } return res; } diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 0b81d22fc..873270dc7 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -445,6 +445,10 @@ struct pw_port { #define PW_PORT_MIX_FLAG_MIX_ONLY (1<<1) /**< only negotiate mix ports */ uint32_t mix_flags; /**< flags for the mixing */ 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 */ @@ -693,6 +697,9 @@ int pw_port_add(struct pw_port *port, struct pw_node *node); int pw_port_init_mix(struct pw_port *port, struct pw_port_mix *mix); int pw_port_release_mix(struct pw_port *port, struct pw_port_mix *mix); +void pw_port_mix_update_state(struct pw_port *port, struct pw_port_mix *mix, enum pw_port_state state); +void pw_port_update_state(struct pw_port *port, enum pw_port_state state); + /** Unlink a port \memberof pw_port */ void pw_port_unlink(struct pw_port *port);