From 6f6dc8b63ee5c17393b9966edbfce6e6a8358169 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 5 Oct 2020 12:13:07 +0200 Subject: [PATCH] pulse: set stream READY after it is linked Wait until we have linked the stream to a device or stream before we emit the READY state. This is what pulseaudio expects. Remove stream_index from disconnecting stream so that we don't accidentally use it again. It is possible that we already created a new stream with the same id before the old stream could complete the disconnect. --- pipewire-pulseaudio/src/context.c | 52 +++++++++++++++++++++++++++++-- pipewire-pulseaudio/src/stream.c | 44 +++++--------------------- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/pipewire-pulseaudio/src/context.c b/pipewire-pulseaudio/src/context.c index 227cf376d..771f8f3a9 100644 --- a/pipewire-pulseaudio/src/context.c +++ b/pipewire-pulseaudio/src/context.c @@ -1209,6 +1209,36 @@ static const struct pw_proxy_events proxy_events = { .destroy = proxy_destroy, }; +static void configure_device(pa_stream *s, struct global *g) +{ + const char *str; + uint32_t old = s->device_index; + + if (s->direction == PA_STREAM_RECORD) { + if (g->mask == (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) { + s->device_index = g->node_info.monitor; + } + else + s->device_index = g->id; + } else { + s->device_index = g->id; + } + + free(s->device_name); + if ((str = pw_properties_get(g->props, PW_KEY_NODE_NAME)) == NULL) + s->device_name = strdup("unknown"); + else + s->device_name = strdup(str); + + pw_log_debug("stream %p: linked to %d '%s'", s, s->device_index, s->device_name); + + if (s->state == PA_STREAM_CREATING) + pa_stream_set_state(s, PA_STREAM_READY); + + if (old != SPA_ID_INVALID && old != s->device_index && s->moved_callback) + s->moved_callback(s, s->moved_userdata); +} + static void update_link(pa_context *c, uint32_t src_node_id, uint32_t dst_node_id) { struct global *s, *d; @@ -1219,16 +1249,32 @@ static void update_link(pa_context *c, uint32_t src_node_id, uint32_t dst_node_i if (s == NULL || d == NULL) return; - if ((s->mask & (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) && + if (s->stream && s->stream->direct_on_input == dst_node_id) { + pw_log_debug("node %d linked to stream %d %p (%d)", + src_node_id, dst_node_id, s->stream, s->stream->state); + if (s->stream->state == PA_STREAM_CREATING) + pa_stream_set_state(s->stream, PA_STREAM_READY); + } + else if (d->stream && d->stream->direct_on_input == src_node_id) { + pw_log_debug("node %d linked to stream %d %p (%d)", + dst_node_id, src_node_id, d->stream, d->stream->state); + if (d->stream->state == PA_STREAM_CREATING) + pa_stream_set_state(d->stream, PA_STREAM_READY); + } + else if ((s->mask & (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) && (d->mask & (PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT))) { pw_log_debug("node %d linked to device %d", dst_node_id, src_node_id); d->node_info.device_index = src_node_id; + if (d->stream) + configure_device(d->stream, s); if (!d->init) emit_event(c, d, PA_SUBSCRIPTION_EVENT_CHANGE); } else if ((s->mask & (PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT)) && (d->mask & (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE))) { pw_log_debug("node %d linked to device %d", src_node_id, dst_node_id); s->node_info.device_index = dst_node_id; + if (s->stream) + configure_device(s->stream, d); if (!s->init) emit_event(c, s, PA_SUBSCRIPTION_EVENT_CHANGE); } @@ -1288,8 +1334,10 @@ static int set_mask(pa_context *c, struct global *g) g->event = PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT; } g->stream = pa_context_find_stream(c, g->id); - if (g->stream) + if (g->stream) { + pw_log_debug("global stream %p", g->stream); g->stream->global = g; + } if ((str = pw_properties_get(g->props, PW_KEY_CLIENT_ID)) != NULL) g->node_info.client_id = atoi(str); diff --git a/pipewire-pulseaudio/src/stream.c b/pipewire-pulseaudio/src/stream.c index e276066fb..3b23f87ab 100644 --- a/pipewire-pulseaudio/src/stream.c +++ b/pipewire-pulseaudio/src/stream.c @@ -52,43 +52,12 @@ static void dump_buffer_attr(pa_stream *s, pa_buffer_attr *attr) pw_log_debug("stream %p: fragsize: %u", s, attr->fragsize); } -static void configure_device(pa_stream *s) -{ - struct global *g; - const char *str; - uint32_t old = s->device_index; - - g = pa_context_find_linked(s->context, pa_stream_get_index(s)); - if (g == NULL) { - s->device_index = PA_INVALID_INDEX; - s->device_name = NULL; - } else { - if (s->direction == PA_STREAM_RECORD) { - if (g->mask == (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) - s->device_index = g->node_info.monitor; - else - s->device_index = g->id; - } - else { - s->device_index = g->id; - } - - free(s->device_name); - if ((str = pw_properties_get(g->props, PW_KEY_NODE_NAME)) == NULL) - s->device_name = strdup("unknown"); - else - s->device_name = strdup(str); - } - pw_log_debug("stream %p: linked to %d '%s'", s, s->device_index, s->device_name); - - if (old != s->device_index && s->moved_callback) - s->moved_callback(s, s->moved_userdata); -} - static void stream_destroy(void *data) { pa_stream *s = data; s->stream = NULL; + if (s->global) + s->global->stream = NULL; } static void stream_state_changed(void *data, enum pw_stream_state old, @@ -125,8 +94,6 @@ static void stream_state_changed(void *data, enum pw_stream_state old, } break; case PW_STREAM_STATE_STREAMING: - configure_device(s); - pa_stream_set_state(s, PA_STREAM_READY); if (s->suspended) { s->suspended = false; if (!c->disconnect && s->started_callback) @@ -608,7 +575,8 @@ static pa_stream* stream_new(pa_context *c, const char *name, else pa_channel_map_init(&s->channel_map); - pw_log_debug("channel map: %p %s", map, pa_channel_map_snprint(str, sizeof(str), &s->channel_map)); + pw_log_debug("stream %p: channel map: %p %s", s, + map, pa_channel_map_snprint(str, sizeof(str), &s->channel_map)); s->n_formats = 0; if (formats) { @@ -681,7 +649,6 @@ static void stream_unlink(pa_stream *s) if (s->stream) pw_stream_set_active(s->stream, false); - s->stream_index = PA_INVALID_INDEX; s->context = NULL; pa_stream_unref(s); } @@ -1106,6 +1073,7 @@ int pa_stream_disconnect(pa_stream *s) pa_stream_ref(s); s->disconnecting = true; + s->stream_index = PA_INVALID_INDEX; pw_stream_disconnect(s->stream); o = pa_operation_new(c, s, on_disconnected, 0); @@ -1968,6 +1936,7 @@ int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx) PA_CHECK_VALIDITY(s->context, sink_input_idx != PA_INVALID_INDEX, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); + pw_log_debug("stream %p: Set monitor stream %u", s, sink_input_idx); s->direct_on_input = sink_input_idx; return 0; } @@ -1978,6 +1947,7 @@ uint32_t pa_stream_get_monitor_stream(PA_CONST pa_stream *s) spa_assert(s); spa_assert(s->refcount >= 1); + pw_log_debug("stream %p: get monitor stream %u", s, s->direct_on_input); PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direct_on_input != PA_INVALID_INDEX, PA_ERR_BADSTATE, PA_INVALID_INDEX);