mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	stream: fix introspection of linked device
This commit is contained in:
		
							parent
							
								
									3cfbdc750a
								
							
						
					
					
						commit
						71d87c589d
					
				
					 4 changed files with 165 additions and 35 deletions
				
			
		| 
						 | 
					@ -86,6 +86,16 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name)
 | 
				
			||||||
	return pa_context_new_with_proplist(mainloop, name, NULL);
 | 
						return pa_context_new_with_proplist(mainloop, name, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct global *pa_context_find_global(pa_context *c, uint32_t id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct global *g;
 | 
				
			||||||
 | 
						spa_list_for_each(g, &c->globals, link) {
 | 
				
			||||||
 | 
							if (g->id == id)
 | 
				
			||||||
 | 
								return g;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int set_mask(pa_context *c, struct global *g)
 | 
					static int set_mask(pa_context *c, struct global *g)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *str;
 | 
						const char *str;
 | 
				
			||||||
| 
						 | 
					@ -100,10 +110,24 @@ static int set_mask(pa_context *c, struct global *g)
 | 
				
			||||||
			g->mask = PA_SUBSCRIPTION_MASK_SINK;
 | 
								g->mask = PA_SUBSCRIPTION_MASK_SINK;
 | 
				
			||||||
			g->event = PA_SUBSCRIPTION_EVENT_SINK;
 | 
								g->event = PA_SUBSCRIPTION_EVENT_SINK;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							else if (strcmp(str, "Audio/DSP/Playback") == 0) {
 | 
				
			||||||
 | 
								if ((str = pw_properties_get(g->props, "node.session")) == NULL)
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								g->mask = PA_SUBSCRIPTION_MASK_DSP_SINK;
 | 
				
			||||||
 | 
								g->dsp_info.session = pa_context_find_global(c,
 | 
				
			||||||
 | 
										pw_properties_parse_int(str));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else if (strcmp(str, "Audio/Source") == 0) {
 | 
							else if (strcmp(str, "Audio/Source") == 0) {
 | 
				
			||||||
			g->mask = PA_SUBSCRIPTION_MASK_SOURCE;
 | 
								g->mask = PA_SUBSCRIPTION_MASK_SOURCE;
 | 
				
			||||||
			g->event = PA_SUBSCRIPTION_EVENT_SOURCE;
 | 
								g->event = PA_SUBSCRIPTION_EVENT_SOURCE;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							else if (strcmp(str, "Audio/DSP/Capture") == 0) {
 | 
				
			||||||
 | 
								if ((str = pw_properties_get(g->props, "node.session")) == NULL)
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								g->mask = PA_SUBSCRIPTION_MASK_DSP_SOURCE;
 | 
				
			||||||
 | 
								g->dsp_info.session = pa_context_find_global(c,
 | 
				
			||||||
 | 
										pw_properties_parse_int(str));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else if (strcmp(str, "Stream/Output/Audio") == 0) {
 | 
							else if (strcmp(str, "Stream/Output/Audio") == 0) {
 | 
				
			||||||
			g->mask = PA_SUBSCRIPTION_MASK_SINK_INPUT;
 | 
								g->mask = PA_SUBSCRIPTION_MASK_SINK_INPUT;
 | 
				
			||||||
			g->event = PA_SUBSCRIPTION_EVENT_SINK_INPUT;
 | 
								g->event = PA_SUBSCRIPTION_EVENT_SINK_INPUT;
 | 
				
			||||||
| 
						 | 
					@ -112,8 +136,6 @@ static int set_mask(pa_context *c, struct global *g)
 | 
				
			||||||
			g->mask = PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT;
 | 
								g->mask = PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT;
 | 
				
			||||||
			g->event = PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT;
 | 
								g->event = PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (g->type == c->t->module) {
 | 
						else if (g->type == c->t->module) {
 | 
				
			||||||
		g->mask = PA_SUBSCRIPTION_MASK_MODULE;
 | 
							g->mask = PA_SUBSCRIPTION_MASK_MODULE;
 | 
				
			||||||
| 
						 | 
					@ -123,6 +145,23 @@ static int set_mask(pa_context *c, struct global *g)
 | 
				
			||||||
		g->mask = PA_SUBSCRIPTION_MASK_CLIENT;
 | 
							g->mask = PA_SUBSCRIPTION_MASK_CLIENT;
 | 
				
			||||||
		g->event = PA_SUBSCRIPTION_EVENT_CLIENT;
 | 
							g->event = PA_SUBSCRIPTION_EVENT_CLIENT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						else if (g->type == c->t->port) {
 | 
				
			||||||
 | 
							pw_log_debug("found port %d", g->id);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (g->type == c->t->link) {
 | 
				
			||||||
 | 
					                if ((str = pw_properties_get(g->props, "link.output")) == NULL)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							g->link_info.src = pa_context_find_global(c, pw_properties_parse_int(str));
 | 
				
			||||||
 | 
					                if ((str = pw_properties_get(g->props, "link.input")) == NULL)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							g->link_info.dst = pa_context_find_global(c, pw_properties_parse_int(str));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (g->link_info.src == NULL || g->link_info.dst == NULL)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pw_log_debug("link %d->%d", g->link_info.src->parent_id,
 | 
				
			||||||
 | 
									g->link_info.dst->parent_id);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,6 +185,7 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id,
 | 
				
			||||||
	if (set_mask(c, g) == 0)
 | 
						if (set_mask(c, g) == 0)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug("mask %d/%d", g->mask, g->event);
 | 
				
			||||||
	spa_list_append(&c->globals, &g->link);
 | 
						spa_list_append(&c->globals, &g->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (c->subscribe_mask & g->mask) {
 | 
						if (c->subscribe_mask & g->mask) {
 | 
				
			||||||
| 
						 | 
					@ -157,16 +197,6 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct global *pa_context_find_global(pa_context *c, uint32_t id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct global *g;
 | 
					 | 
				
			||||||
	spa_list_for_each(g, &c->globals, link) {
 | 
					 | 
				
			||||||
		if (g->id == id)
 | 
					 | 
				
			||||||
			return g;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void registry_event_global_remove(void *object, uint32_t id)
 | 
					static void registry_event_global_remove(void *object, uint32_t id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pa_context *c = object;
 | 
						pa_context *c = object;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -190,6 +190,10 @@ struct pa_mainloop {
 | 
				
			||||||
	int n_events;
 | 
						int n_events;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PA_SUBSCRIPTION_MASK_DSP_SINK	0x1000U
 | 
				
			||||||
 | 
					#define PA_SUBSCRIPTION_MASK_DSP_SOURCE	0x2000U
 | 
				
			||||||
 | 
					#define PA_SUBSCRIPTION_MASK_DSP	(PA_SUBSCRIPTION_MASK_DSP_SINK | PA_SUBSCRIPTION_MASK_DSP_SOURCE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct global {
 | 
					struct global {
 | 
				
			||||||
	struct spa_list link;
 | 
						struct spa_list link;
 | 
				
			||||||
	uint32_t id;
 | 
						uint32_t id;
 | 
				
			||||||
| 
						 | 
					@ -206,6 +210,17 @@ struct global {
 | 
				
			||||||
	struct pw_proxy *proxy;
 | 
						struct pw_proxy *proxy;
 | 
				
			||||||
	struct spa_hook proxy_listener;
 | 
						struct spa_hook proxy_listener;
 | 
				
			||||||
        struct spa_hook proxy_proxy_listener;
 | 
					        struct spa_hook proxy_proxy_listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* for links */
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								struct global *src;
 | 
				
			||||||
 | 
								struct global *dst;
 | 
				
			||||||
 | 
							} link_info;
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								struct global *session;
 | 
				
			||||||
 | 
							} dsp_info;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pa_context {
 | 
					struct pa_context {
 | 
				
			||||||
| 
						 | 
					@ -333,6 +348,7 @@ struct pa_stream {
 | 
				
			||||||
	struct pw_buffer *dequeued[MAX_BUFFERS];
 | 
						struct pw_buffer *dequeued[MAX_BUFFERS];
 | 
				
			||||||
	struct spa_ringbuffer dequeued_ring;
 | 
						struct spa_ringbuffer dequeued_ring;
 | 
				
			||||||
	size_t dequeued_size;
 | 
						size_t dequeued_size;
 | 
				
			||||||
 | 
						size_t maxsize;
 | 
				
			||||||
	struct spa_list pending;
 | 
						struct spa_list pending;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_buffer *buffer;
 | 
						struct pw_buffer *buffer;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,6 +130,7 @@ static void sink_callback(struct sink_data *d)
 | 
				
			||||||
	spa_zero(i);
 | 
						spa_zero(i);
 | 
				
			||||||
	i.index = g->id;
 | 
						i.index = g->id;
 | 
				
			||||||
	i.name = info->name;
 | 
						i.name = info->name;
 | 
				
			||||||
 | 
						i.description = info->name;
 | 
				
			||||||
	i.proplist = pa_proplist_new_dict(info->props);
 | 
						i.proplist = pa_proplist_new_dict(info->props);
 | 
				
			||||||
	i.owner_module = g->parent_id;
 | 
						i.owner_module = g->parent_id;
 | 
				
			||||||
	i.base_volume = PA_VOLUME_NORM;
 | 
						i.base_volume = PA_VOLUME_NORM;
 | 
				
			||||||
| 
						 | 
					@ -339,6 +340,7 @@ static void source_info(pa_operation *o, void *userdata)
 | 
				
			||||||
	struct source_data *d = userdata;
 | 
						struct source_data *d = userdata;
 | 
				
			||||||
	source_callback(d);
 | 
						source_callback(d);
 | 
				
			||||||
	d->cb(d->context, NULL, 1, d->userdata);
 | 
						d->cb(d->context, NULL, 1, d->userdata);
 | 
				
			||||||
 | 
						pa_operation_done(o);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata)
 | 
					pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata)
 | 
				
			||||||
| 
						 | 
					@ -388,6 +390,7 @@ static void source_info_list(pa_operation *o, void *userdata)
 | 
				
			||||||
		source_callback(d);
 | 
							source_callback(d);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d->cb(c, NULL, 1, d->userdata);
 | 
						d->cb(c, NULL, 1, d->userdata);
 | 
				
			||||||
 | 
						pa_operation_done(o);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata)
 | 
					pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata)
 | 
				
			||||||
| 
						 | 
					@ -493,6 +496,7 @@ static void module_info(pa_operation *o, void *userdata)
 | 
				
			||||||
	struct module_data *d = userdata;
 | 
						struct module_data *d = userdata;
 | 
				
			||||||
	module_callback(d);
 | 
						module_callback(d);
 | 
				
			||||||
	d->cb(d->context, NULL, 1, d->userdata);
 | 
						d->cb(d->context, NULL, 1, d->userdata);
 | 
				
			||||||
 | 
						pa_operation_done(o);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata)
 | 
					pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata)
 | 
				
			||||||
| 
						 | 
					@ -537,6 +541,7 @@ static void module_info_list(pa_operation *o, void *userdata)
 | 
				
			||||||
		module_callback(d);
 | 
							module_callback(d);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d->cb(c, NULL, 1, d->userdata);
 | 
						d->cb(c, NULL, 1, d->userdata);
 | 
				
			||||||
 | 
						pa_operation_done(o);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata)
 | 
					pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata)
 | 
				
			||||||
| 
						 | 
					@ -601,6 +606,7 @@ static void client_info(pa_operation *o, void *userdata)
 | 
				
			||||||
	struct client_data *d = userdata;
 | 
						struct client_data *d = userdata;
 | 
				
			||||||
	client_callback(d);
 | 
						client_callback(d);
 | 
				
			||||||
	d->cb(d->context, NULL, 1, d->userdata);
 | 
						d->cb(d->context, NULL, 1, d->userdata);
 | 
				
			||||||
 | 
						pa_operation_done(o);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata)
 | 
					pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata)
 | 
				
			||||||
| 
						 | 
					@ -645,6 +651,7 @@ static void client_info_list(pa_operation *o, void *userdata)
 | 
				
			||||||
		client_callback(d);
 | 
							client_callback(d);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d->cb(c, NULL, 1, d->userdata);
 | 
						d->cb(c, NULL, 1, d->userdata);
 | 
				
			||||||
 | 
						pa_operation_done(o);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata)
 | 
					pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata)
 | 
				
			||||||
| 
						 | 
					@ -717,14 +724,27 @@ struct sink_input_data {
 | 
				
			||||||
	struct global *global;
 | 
						struct global *global;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static pa_stream *find_stream(pa_context *c, uint32_t idx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pa_stream *s;
 | 
				
			||||||
 | 
						spa_list_for_each(s, &c->streams, link) {
 | 
				
			||||||
 | 
							if (pw_stream_get_node_id(s->stream) == idx)
 | 
				
			||||||
 | 
								return s;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void sink_input_callback(struct sink_input_data *d)
 | 
					static void sink_input_callback(struct sink_input_data *d)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct global *g = d->global;
 | 
						struct global *g = d->global;
 | 
				
			||||||
	struct pw_node_info *info = g->info;
 | 
						struct pw_node_info *info = g->info;
 | 
				
			||||||
	pa_sink_input_info i;
 | 
						pa_sink_input_info i;
 | 
				
			||||||
	pa_format_info ii[1];
 | 
						pa_format_info ii[1];
 | 
				
			||||||
 | 
						pa_stream *s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug("index %d", g->id);
 | 
						pw_log_debug("index %d", g->id);
 | 
				
			||||||
 | 
						s = find_stream(d->context, g->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_zero(i);
 | 
						spa_zero(i);
 | 
				
			||||||
	i.index = g->id;
 | 
						i.index = g->id;
 | 
				
			||||||
	i.name = info->name;
 | 
						i.name = info->name;
 | 
				
			||||||
| 
						 | 
					@ -740,7 +760,11 @@ static void sink_input_callback(struct sink_input_data *d)
 | 
				
			||||||
	i.has_volume = true;
 | 
						i.has_volume = true;
 | 
				
			||||||
	i.volume_writable = true;
 | 
						i.volume_writable = true;
 | 
				
			||||||
	i.volume.channels = 1;
 | 
						i.volume.channels = 1;
 | 
				
			||||||
	i.volume.values[0] = PA_VOLUME_NORM;
 | 
						if (s)
 | 
				
			||||||
 | 
							i.volume.values[0] = s->volume * PA_VOLUME_NORM;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							i.volume.values[0] = PA_VOLUME_NORM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	d->cb(d->context, &i, 0, d->userdata);
 | 
						d->cb(d->context, &i, 0, d->userdata);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -749,6 +773,7 @@ static void sink_input_info(pa_operation *o, void *userdata)
 | 
				
			||||||
	struct sink_input_data *d = userdata;
 | 
						struct sink_input_data *d = userdata;
 | 
				
			||||||
	sink_input_callback(d);
 | 
						sink_input_callback(d);
 | 
				
			||||||
	d->cb(d->context, NULL, 1, d->userdata);
 | 
						d->cb(d->context, NULL, 1, d->userdata);
 | 
				
			||||||
 | 
						pa_operation_done(o);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata)
 | 
					pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata)
 | 
				
			||||||
| 
						 | 
					@ -792,6 +817,7 @@ static void sink_input_info_list(pa_operation *o, void *userdata)
 | 
				
			||||||
		sink_input_callback(d);
 | 
							sink_input_callback(d);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d->cb(c, NULL, 1, d->userdata);
 | 
						d->cb(c, NULL, 1, d->userdata);
 | 
				
			||||||
 | 
						pa_operation_done(o);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata)
 | 
					pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata)
 | 
				
			||||||
| 
						 | 
					@ -826,16 +852,6 @@ pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, u
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static pa_stream *find_stream(pa_context *c, uint32_t idx)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	pa_stream *s;
 | 
					 | 
				
			||||||
	spa_list_for_each(s, &c->streams, link) {
 | 
					 | 
				
			||||||
		if (pw_stream_get_node_id(s->stream) == idx)
 | 
					 | 
				
			||||||
			return s;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct success_ack {
 | 
					struct success_ack {
 | 
				
			||||||
	pa_context_success_cb_t cb;
 | 
						pa_context_success_cb_t cb;
 | 
				
			||||||
	void *userdata;
 | 
						void *userdata;
 | 
				
			||||||
| 
						 | 
					@ -845,9 +861,9 @@ static void on_success(pa_operation *o, void *userdata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct success_ack *d = userdata;
 | 
						struct success_ack *d = userdata;
 | 
				
			||||||
	pa_context *c = o->context;
 | 
						pa_context *c = o->context;
 | 
				
			||||||
	pa_operation_done(o);
 | 
					 | 
				
			||||||
	if (d->cb)
 | 
						if (d->cb)
 | 
				
			||||||
		d->cb(c, PA_OK, d->userdata);
 | 
							d->cb(c, PA_OK, d->userdata);
 | 
				
			||||||
 | 
						pa_operation_done(o);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata)
 | 
					pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										90
									
								
								src/stream.c
									
										
									
									
									
								
							
							
						
						
									
										90
									
								
								src/stream.c
									
										
									
									
									
								
							| 
						 | 
					@ -96,10 +96,70 @@ static int dequeue_buffer(pa_stream *s)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dump_buffer_attr(pa_stream *s, pa_buffer_attr *attr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pw_log_info("stream %p: maxlength: %u", s, attr->maxlength);
 | 
				
			||||||
 | 
						pw_log_info("stream %p: tlength: %u", s, attr->tlength);
 | 
				
			||||||
 | 
						pw_log_info("stream %p: minreq: %u", s, attr->minreq);
 | 
				
			||||||
 | 
						pw_log_info("stream %p: prebuf: %u", s, attr->prebuf);
 | 
				
			||||||
 | 
						pw_log_info("stream %p: fragsize: %u", s, attr->fragsize);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void configure_buffers(pa_stream *s)
 | 
					static void configure_buffers(pa_stream *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	s->buffer_attr.maxlength = 65536;
 | 
						s->buffer_attr.maxlength = s->maxsize;
 | 
				
			||||||
	s->buffer_attr.prebuf = s->buffer_attr.minreq;
 | 
						s->buffer_attr.prebuf = s->buffer_attr.minreq;
 | 
				
			||||||
 | 
						s->buffer_attr.fragsize = s->buffer_attr.minreq;
 | 
				
			||||||
 | 
						dump_buffer_attr(s, &s->buffer_attr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct global *find_linked(pa_stream *s, uint32_t idx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct global *g, *f;
 | 
				
			||||||
 | 
						pa_context *c = s->context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_list_for_each(g, &c->globals, link) {
 | 
				
			||||||
 | 
							if (g->type != c->t->link)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pw_log_debug("%d %d %d", idx,
 | 
				
			||||||
 | 
									g->link_info.src->parent_id,
 | 
				
			||||||
 | 
									g->link_info.dst->parent_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (g->link_info.src->parent_id == idx)
 | 
				
			||||||
 | 
								f = pa_context_find_global(c, g->link_info.dst->parent_id);
 | 
				
			||||||
 | 
							else if (g->link_info.dst->parent_id == idx)
 | 
				
			||||||
 | 
								f = pa_context_find_global(c, g->link_info.src->parent_id);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (f == NULL)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (f->mask & PA_SUBSCRIPTION_MASK_DSP) {
 | 
				
			||||||
 | 
								f = f->dsp_info.session;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return f;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void configure_device(pa_stream *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct global *g;
 | 
				
			||||||
 | 
						const char *str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						g = find_linked(s, pa_stream_get_index(s));
 | 
				
			||||||
 | 
						if (g == NULL) {
 | 
				
			||||||
 | 
							s->device_index = PA_INVALID_INDEX;
 | 
				
			||||||
 | 
							s->device_name = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							s->device_index = g->id;
 | 
				
			||||||
 | 
							if ((str = pw_properties_get(g->props, "node.name")) == NULL)
 | 
				
			||||||
 | 
								s->device_name = strdup("unknown");
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								s->device_name = strdup(str);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pw_log_debug("linked to %d '%s'", s->device_index, s->device_name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void stream_state_changed(void *data, enum pw_stream_state old,
 | 
					static void stream_state_changed(void *data, enum pw_stream_state old,
 | 
				
			||||||
| 
						 | 
					@ -122,6 +182,7 @@ static void stream_state_changed(void *data, enum pw_stream_state old,
 | 
				
			||||||
	case PW_STREAM_STATE_READY:
 | 
						case PW_STREAM_STATE_READY:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PW_STREAM_STATE_PAUSED:
 | 
						case PW_STREAM_STATE_PAUSED:
 | 
				
			||||||
 | 
							configure_device(s);
 | 
				
			||||||
		configure_buffers(s);
 | 
							configure_buffers(s);
 | 
				
			||||||
		pa_stream_set_state(s, PA_STREAM_READY);
 | 
							pa_stream_set_state(s, PA_STREAM_READY);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -219,14 +280,9 @@ static void patch_buffer_attr(pa_stream *s, pa_buffer_attr *attr, pa_stream_flag
 | 
				
			||||||
	if (attr->fragsize == (uint32_t) -1)
 | 
						if (attr->fragsize == (uint32_t) -1)
 | 
				
			||||||
		attr->fragsize = attr->tlength; /* Pass data to the app only when the buffer is filled up once */
 | 
							attr->fragsize = attr->tlength; /* Pass data to the app only when the buffer is filled up once */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("stream %p: maxlength: %u", s, attr->maxlength);
 | 
						dump_buffer_attr(s, attr);
 | 
				
			||||||
	pw_log_info("stream %p: tlength: %u", s, attr->tlength);
 | 
					 | 
				
			||||||
	pw_log_info("stream %p: minreq: %u", s, attr->minreq);
 | 
					 | 
				
			||||||
	pw_log_info("stream %p: prebuf: %u", s, attr->prebuf);
 | 
					 | 
				
			||||||
	pw_log_info("stream %p: fragsize: %u", s, attr->fragsize);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
static void stream_format_changed(void *data, const struct spa_pod *format)
 | 
					static void stream_format_changed(void *data, const struct spa_pod *format)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pa_stream *s = data;
 | 
						pa_stream *s = data;
 | 
				
			||||||
| 
						 | 
					@ -271,6 +327,17 @@ static void stream_format_changed(void *data, const struct spa_pod *format)
 | 
				
			||||||
	pw_stream_finish_format(s->stream, res, params, n_params);
 | 
						pw_stream_finish_format(s->stream, res, params, n_params);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void stream_add_buffer(void *data, struct pw_buffer *buffer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pa_stream *s = data;
 | 
				
			||||||
 | 
						s->maxsize += buffer->buffer->datas[0].maxsize;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void stream_remove_buffer(void *data, struct pw_buffer *buffer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pa_stream *s = data;
 | 
				
			||||||
 | 
						s->maxsize -= buffer->buffer->datas[0].maxsize;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void stream_process(void *data)
 | 
					static void stream_process(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pa_stream *s = data;
 | 
						pa_stream *s = data;
 | 
				
			||||||
| 
						 | 
					@ -295,6 +362,8 @@ static const struct pw_stream_events stream_events =
 | 
				
			||||||
	PW_VERSION_STREAM_EVENTS,
 | 
						PW_VERSION_STREAM_EVENTS,
 | 
				
			||||||
	.state_changed = stream_state_changed,
 | 
						.state_changed = stream_state_changed,
 | 
				
			||||||
	.format_changed = stream_format_changed,
 | 
						.format_changed = stream_format_changed,
 | 
				
			||||||
 | 
						.add_buffer = stream_add_buffer,
 | 
				
			||||||
 | 
						.remove_buffer = stream_remove_buffer,
 | 
				
			||||||
	.process = stream_process,
 | 
						.process = stream_process,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -378,9 +447,7 @@ pa_stream* stream_new(pa_context *c, const char *name,
 | 
				
			||||||
	s->buffer_attr.fragsize = (uint32_t) -1;
 | 
						s->buffer_attr.fragsize = (uint32_t) -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s->device_index = PA_INVALID_INDEX;
 | 
						s->device_index = PA_INVALID_INDEX;
 | 
				
			||||||
 | 
						s->device_name = NULL;
 | 
				
			||||||
	s->device_index = 0;
 | 
					 | 
				
			||||||
	s->device_name = strdup("unknown");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_ringbuffer_init(&s->dequeued_ring);
 | 
						spa_ringbuffer_init(&s->dequeued_ring);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -479,6 +546,7 @@ void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pa_stream_ref(s);
 | 
						pa_stream_ref(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug("stream %p: state %d -> %d", s, s->state, st);
 | 
				
			||||||
	s->state = st;
 | 
						s->state = st;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (s->state_callback)
 | 
						if (s->state_callback)
 | 
				
			||||||
| 
						 | 
					@ -1279,7 +1347,7 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec)
 | 
				
			||||||
	if (r_usec)
 | 
						if (r_usec)
 | 
				
			||||||
		*r_usec = res;
 | 
							*r_usec = res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug("stream %p: %ld %ld %ld %ld %d/%d %ld", s, now, t.now, delay, t.ticks, t.rate.num, t.rate.denom, res);
 | 
						pw_log_trace("stream %p: %ld %ld %ld %ld %d/%d %ld", s, now, t.now, delay, t.ticks, t.rate.num, t.rate.denom, res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue