mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									bcaf7cd722
								
							
						
					
					
						commit
						6f6dc8b63e
					
				
					 2 changed files with 57 additions and 39 deletions
				
			
		| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue