mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	use endpoint in pulse
This commit is contained in:
		
							parent
							
								
									c9a54112e4
								
							
						
					
					
						commit
						edd011605d
					
				
					 4 changed files with 180 additions and 128 deletions
				
			
		| 
						 | 
					@ -155,8 +155,8 @@ struct global *pa_context_find_linked(pa_context *c, uint32_t idx)
 | 
				
			||||||
		if (g->type != PW_TYPE_INTERFACE_Link)
 | 
							if (g->type != PW_TYPE_INTERFACE_Link)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		src_node_id = g->link_info.src->port_info.node_id;
 | 
							src_node_id = g->link_info.src->stream_info.endpoint_id;
 | 
				
			||||||
		dst_node_id = g->link_info.dst->port_info.node_id;
 | 
							dst_node_id = g->link_info.dst->stream_info.endpoint_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pw_log_debug("context %p: %p %d %d %d", c, g, idx,
 | 
							pw_log_debug("context %p: %p %d %d %d", c, g, idx,
 | 
				
			||||||
				src_node_id, dst_node_id);
 | 
									src_node_id, dst_node_id);
 | 
				
			||||||
| 
						 | 
					@ -185,63 +185,67 @@ static void emit_event(pa_context *c, struct global *g, pa_subscription_event_ty
 | 
				
			||||||
				c->subscribe_userdata);
 | 
									c->subscribe_userdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (g->mask == (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) {
 | 
							if (g->mask == (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) {
 | 
				
			||||||
			pw_log_debug("context %p: obj %d: emit %d:%d", c, g->node_info.monitor,
 | 
								pw_log_debug("context %p: obj %d: emit %d:%d", c, g->stream_info.monitor,
 | 
				
			||||||
					event, PA_SUBSCRIPTION_EVENT_SOURCE);
 | 
										event, PA_SUBSCRIPTION_EVENT_SOURCE);
 | 
				
			||||||
			c->subscribe_callback(c,
 | 
								c->subscribe_callback(c,
 | 
				
			||||||
					event | PA_SUBSCRIPTION_EVENT_SOURCE,
 | 
										event | PA_SUBSCRIPTION_EVENT_SOURCE,
 | 
				
			||||||
					g->node_info.monitor,
 | 
										g->stream_info.monitor,
 | 
				
			||||||
					c->subscribe_userdata);
 | 
										c->subscribe_userdata);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void update_device_props(struct global *g)
 | 
					static void update_endpoint_props(struct global *g)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pa_card_info *i = &g->card_info.info;
 | 
						pa_card_info *i = &g->card_info.info;
 | 
				
			||||||
	const char *s;
 | 
						const char *s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((s = pa_proplist_gets(i->proplist, PW_KEY_DEVICE_ICON_NAME)))
 | 
						if ((s = pa_proplist_gets(i->proplist, PW_KEY_ENDPOINT_ICON_NAME)))
 | 
				
			||||||
		pa_proplist_sets(i->proplist, PA_PROP_DEVICE_ICON_NAME, s);
 | 
							pa_proplist_sets(i->proplist, PA_PROP_DEVICE_ICON_NAME, s);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void device_event_info(void *object, const struct pw_device_info *info)
 | 
					static void endpoint_event_info(void *object, const struct pw_endpoint_info *update)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        struct global *g = object;
 | 
					        struct global *g = object;
 | 
				
			||||||
	pa_card_info *i = &g->card_info.info;
 | 
						pa_card_info *i = &g->card_info.info;
 | 
				
			||||||
	const char *str;
 | 
						const char *str;
 | 
				
			||||||
	uint32_t n;
 | 
						uint32_t n;
 | 
				
			||||||
 | 
						struct pw_endpoint_info *info = g->info;
 | 
				
			||||||
	pw_log_debug("global %p: id:%d change-mask:%"PRIu64, g, g->id, info->change_mask);
 | 
					 | 
				
			||||||
        info = g->info = pw_device_info_update(g->info, info);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i->index = g->id;
 | 
						i->index = g->id;
 | 
				
			||||||
	i->name = info->props ?
 | 
					 | 
				
			||||||
		spa_dict_lookup(info->props, PW_KEY_DEVICE_NAME) : "unknown";
 | 
					 | 
				
			||||||
	str = info->props ? spa_dict_lookup(info->props, PW_KEY_MODULE_ID) : NULL;
 | 
					 | 
				
			||||||
	i->owner_module = str ? (unsigned)atoi(str) : SPA_ID_INVALID;
 | 
					 | 
				
			||||||
	if (info->change_mask & PW_DEVICE_CHANGE_MASK_PROPS) {
 | 
					 | 
				
			||||||
		i->driver = info->props ?
 | 
					 | 
				
			||||||
			spa_dict_lookup(info->props, PW_KEY_DEVICE_API) : NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (i->proplist)
 | 
						pw_log_debug("global %p: id:%d change-mask:%08x", g, g->id, update->change_mask);
 | 
				
			||||||
			pa_proplist_update_dict(i->proplist, info->props);
 | 
						if (!info) {
 | 
				
			||||||
		else {
 | 
							info = g->info = calloc(1, sizeof(*info));
 | 
				
			||||||
			i->proplist = pa_proplist_new_dict(info->props);
 | 
							info->id = update->id;
 | 
				
			||||||
 | 
							info->name = update->name ? strdup(update->name) : NULL;
 | 
				
			||||||
 | 
							info->media_class = update->media_class ? strdup(update->media_class) : NULL;
 | 
				
			||||||
 | 
							info->direction = update->direction;
 | 
				
			||||||
 | 
							info->flags = update->flags;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
		update_device_props(g);
 | 
						info->change_mask = update->change_mask;
 | 
				
			||||||
	}
 | 
						if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_STREAMS)
 | 
				
			||||||
	if (info->change_mask & PW_DEVICE_CHANGE_MASK_PARAMS) {
 | 
							info->n_streams = update->n_streams;
 | 
				
			||||||
 | 
						if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_SESSION)
 | 
				
			||||||
 | 
							info->session_id = update->session_id;
 | 
				
			||||||
 | 
						if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) {
 | 
				
			||||||
 | 
							info->n_params = update->n_params;
 | 
				
			||||||
 | 
							free(info->params);
 | 
				
			||||||
 | 
							info->params = malloc(info->n_params * sizeof(struct spa_param_info));
 | 
				
			||||||
 | 
							memcpy(info->params, update->params,
 | 
				
			||||||
 | 
								info->n_params * sizeof(struct spa_param_info));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (n = 0; n < info->n_params; n++) {
 | 
							for (n = 0; n < info->n_params; n++) {
 | 
				
			||||||
			if (!(info->params[n].flags & SPA_PARAM_INFO_READ))
 | 
								if (!(info->params[n].flags & SPA_PARAM_INFO_READ))
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			switch (info->params[n].id) {
 | 
								switch (info->params[n].id) {
 | 
				
			||||||
			case SPA_PARAM_EnumProfile:
 | 
								case SPA_PARAM_EnumProfile:
 | 
				
			||||||
				pw_device_proxy_enum_params((struct pw_device_proxy*)g->proxy,
 | 
									pw_endpoint_proxy_enum_params((struct pw_endpoint_proxy*)g->proxy,
 | 
				
			||||||
					0, SPA_PARAM_EnumProfile, 0, -1, NULL);
 | 
										0, SPA_PARAM_EnumProfile, 0, -1, NULL);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			case SPA_PARAM_Profile:
 | 
								case SPA_PARAM_Profile:
 | 
				
			||||||
				pw_device_proxy_enum_params((struct pw_device_proxy*)g->proxy,
 | 
									pw_endpoint_proxy_enum_params((struct pw_endpoint_proxy*)g->proxy,
 | 
				
			||||||
					0, SPA_PARAM_Profile, 0, -1, NULL);
 | 
										0, SPA_PARAM_Profile, 0, -1, NULL);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
| 
						 | 
					@ -249,10 +253,31 @@ static void device_event_info(void *object, const struct pw_device_info *info)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) {
 | 
				
			||||||
 | 
							if (info->props)
 | 
				
			||||||
 | 
								pw_properties_free ((struct pw_properties *)info->props);
 | 
				
			||||||
 | 
							info->props =
 | 
				
			||||||
 | 
								(struct spa_dict *) pw_properties_new_dict (update->props);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							i->name = info->props ?
 | 
				
			||||||
 | 
								spa_dict_lookup(info->props, PW_KEY_ENDPOINT_NAME) : "unknown";
 | 
				
			||||||
 | 
							str = info->props ? spa_dict_lookup(info->props, PW_KEY_MODULE_ID) : NULL;
 | 
				
			||||||
 | 
							i->owner_module = str ? (unsigned)atoi(str) : SPA_ID_INVALID;
 | 
				
			||||||
 | 
							i->driver = info->props ?
 | 
				
			||||||
 | 
								spa_dict_lookup(info->props, PW_KEY_DEVICE_API) : "unknown";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (i->proplist)
 | 
				
			||||||
 | 
								pa_proplist_update_dict(i->proplist, info->props);
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								i->proplist = pa_proplist_new_dict(info->props);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							update_endpoint_props(g);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g->pending_seq = pw_proxy_sync(g->proxy, 0);
 | 
						g->pending_seq = pw_proxy_sync(g->proxy, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void device_event_param(void *object, int seq,
 | 
					static void endpoint_event_param(void *object, int seq,
 | 
				
			||||||
		uint32_t id, uint32_t index, uint32_t next,
 | 
							uint32_t id, uint32_t index, uint32_t next,
 | 
				
			||||||
		const struct spa_pod *param)
 | 
							const struct spa_pod *param)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -302,13 +327,13 @@ static void device_event_param(void *object, int seq,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct pw_device_proxy_events device_events = {
 | 
					static const struct pw_endpoint_proxy_events endpoint_events = {
 | 
				
			||||||
	PW_VERSION_DEVICE_PROXY_EVENTS,
 | 
						PW_VERSION_ENDPOINT_PROXY_EVENTS,
 | 
				
			||||||
	.info = device_event_info,
 | 
						.info = endpoint_event_info,
 | 
				
			||||||
	.param = device_event_param,
 | 
						.param = endpoint_event_param,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void device_destroy(void *data)
 | 
					static void endpoint_destroy(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct global *global = data;
 | 
						struct global *global = data;
 | 
				
			||||||
	struct param *p;
 | 
						struct param *p;
 | 
				
			||||||
| 
						 | 
					@ -319,21 +344,41 @@ static void device_destroy(void *data)
 | 
				
			||||||
		spa_list_remove(&p->link);
 | 
							spa_list_remove(&p->link);
 | 
				
			||||||
		free(p);
 | 
							free(p);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (global->info)
 | 
						if (global->info) {
 | 
				
			||||||
		pw_device_info_free(global->info);
 | 
							struct pw_endpoint_info *info = global->info;
 | 
				
			||||||
 | 
							free(info->name);
 | 
				
			||||||
 | 
							free(info->media_class);
 | 
				
			||||||
 | 
							free(info->params);
 | 
				
			||||||
 | 
							if (info->props)
 | 
				
			||||||
 | 
								pw_properties_free ((struct pw_properties *)info->props);
 | 
				
			||||||
 | 
							free(info);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void node_event_info(void *object, const struct pw_node_info *info)
 | 
					static void stream_event_info(void *object, const struct pw_endpoint_stream_info *update)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct global *g = object;
 | 
						struct global *g = object;
 | 
				
			||||||
 | 
						struct pw_endpoint_stream_info *info = g->info;
 | 
				
			||||||
	uint32_t i;
 | 
						uint32_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug("update %d %"PRIu64, g->id, info->change_mask);
 | 
						pw_log_debug("update %d %08x", g->id, update->change_mask);
 | 
				
			||||||
	g->info = pw_node_info_update(g->info, info);
 | 
						if (info == NULL) {
 | 
				
			||||||
 | 
							info = g->info = calloc(1, sizeof(*info));
 | 
				
			||||||
 | 
							info->id = update->id;
 | 
				
			||||||
 | 
							info->endpoint_id = update->endpoint_id;
 | 
				
			||||||
 | 
							info->name = update->name ? strdup(update->name) : NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						info->change_mask = update->change_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS && !g->subscribed) {
 | 
						if (update->change_mask & PW_NODE_CHANGE_MASK_PARAMS && !g->subscribed) {
 | 
				
			||||||
		uint32_t subscribed[32], n_subscribed = 0;
 | 
							uint32_t subscribed[32], n_subscribed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							info->n_params = update->n_params;
 | 
				
			||||||
 | 
							free(info->params);
 | 
				
			||||||
 | 
							info->params = malloc(info->n_params * sizeof(struct spa_param_info));
 | 
				
			||||||
 | 
							memcpy(info->params, update->params,
 | 
				
			||||||
 | 
								info->n_params * sizeof(struct spa_param_info));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 0; i < info->n_params; i++) {
 | 
							for (i = 0; i < info->n_params; i++) {
 | 
				
			||||||
			switch (info->params[i].id) {
 | 
								switch (info->params[i].id) {
 | 
				
			||||||
			case SPA_PARAM_EnumFormat:
 | 
								case SPA_PARAM_EnumFormat:
 | 
				
			||||||
| 
						 | 
					@ -345,11 +390,17 @@ static void node_event_info(void *object, const struct pw_node_info *info)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (n_subscribed > 0) {
 | 
							if (n_subscribed > 0) {
 | 
				
			||||||
			pw_node_proxy_subscribe_params((struct pw_node_proxy*)g->proxy,
 | 
								pw_endpoint_stream_proxy_subscribe_params((struct pw_endpoint_stream_proxy*)g->proxy,
 | 
				
			||||||
					subscribed, n_subscribed);
 | 
										subscribed, n_subscribed);
 | 
				
			||||||
			g->subscribed = true;
 | 
								g->subscribed = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (update->change_mask & PW_ENDPOINT_STREAM_CHANGE_MASK_PROPS) {
 | 
				
			||||||
 | 
							if (info->props)
 | 
				
			||||||
 | 
								pw_properties_free ((struct pw_properties *)info->props);
 | 
				
			||||||
 | 
							info->props =
 | 
				
			||||||
 | 
								(struct spa_dict *) pw_properties_new_dict (update->props);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	g->pending_seq = pw_proxy_sync(g->proxy, 0);
 | 
						g->pending_seq = pw_proxy_sync(g->proxy, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -361,22 +412,22 @@ static void parse_props(struct global *g, const struct spa_pod *param)
 | 
				
			||||||
	SPA_POD_OBJECT_FOREACH(obj, prop) {
 | 
						SPA_POD_OBJECT_FOREACH(obj, prop) {
 | 
				
			||||||
		switch (prop->key) {
 | 
							switch (prop->key) {
 | 
				
			||||||
		case SPA_PROP_volume:
 | 
							case SPA_PROP_volume:
 | 
				
			||||||
			spa_pod_get_float(&prop->value, &g->node_info.volume);
 | 
								spa_pod_get_float(&prop->value, &g->stream_info.volume);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case SPA_PROP_mute:
 | 
							case SPA_PROP_mute:
 | 
				
			||||||
			spa_pod_get_bool(&prop->value, &g->node_info.mute);
 | 
								spa_pod_get_bool(&prop->value, &g->stream_info.mute);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case SPA_PROP_channelVolumes:
 | 
							case SPA_PROP_channelVolumes:
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			uint32_t n_vals;
 | 
								uint32_t n_vals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			n_vals = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
 | 
								n_vals = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
 | 
				
			||||||
					g->node_info.channel_volumes, SPA_AUDIO_MAX_CHANNELS);
 | 
										g->stream_info.channel_volumes, SPA_AUDIO_MAX_CHANNELS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (n_vals != g->node_info.n_channel_volumes) {
 | 
								if (n_vals != g->stream_info.n_channel_volumes) {
 | 
				
			||||||
				emit_event(g->context, g, PA_SUBSCRIPTION_EVENT_REMOVE);
 | 
									emit_event(g->context, g, PA_SUBSCRIPTION_EVENT_REMOVE);
 | 
				
			||||||
				emit_event(g->context, g, PA_SUBSCRIPTION_EVENT_NEW);
 | 
									emit_event(g->context, g, PA_SUBSCRIPTION_EVENT_NEW);
 | 
				
			||||||
				g->node_info.n_channel_volumes = n_vals;
 | 
									g->stream_info.n_channel_volumes = n_vals;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -386,7 +437,7 @@ static void parse_props(struct global *g, const struct spa_pod *param)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void node_event_param(void *object, int seq,
 | 
					static void stream_event_param(void *object, int seq,
 | 
				
			||||||
		uint32_t id, uint32_t index, uint32_t next,
 | 
							uint32_t id, uint32_t index, uint32_t next,
 | 
				
			||||||
		const struct spa_pod *param)
 | 
							const struct spa_pod *param)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -402,17 +453,23 @@ static void node_event_param(void *object, int seq,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct pw_node_proxy_events node_events = {
 | 
					static const struct pw_endpoint_stream_proxy_events stream_events = {
 | 
				
			||||||
	PW_VERSION_NODE_PROXY_EVENTS,
 | 
						PW_VERSION_NODE_PROXY_EVENTS,
 | 
				
			||||||
	.info = node_event_info,
 | 
						.info = stream_event_info,
 | 
				
			||||||
	.param = node_event_param,
 | 
						.param = stream_event_param,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void node_destroy(void *data)
 | 
					static void stream_destroy(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct global *global = data;
 | 
						struct global *global = data;
 | 
				
			||||||
	if (global->info)
 | 
						if (global->info) {
 | 
				
			||||||
		pw_node_info_free(global->info);
 | 
							struct pw_endpoint_stream_info *info = global->info;
 | 
				
			||||||
 | 
							free(info->name);
 | 
				
			||||||
 | 
							free(info->params);
 | 
				
			||||||
 | 
							if (info->props)
 | 
				
			||||||
 | 
								pw_properties_free ((struct pw_properties *)info->props);
 | 
				
			||||||
 | 
							free(info);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void module_event_info(void *object, const struct pw_module_info *info)
 | 
					static void module_event_info(void *object, const struct pw_module_info *info)
 | 
				
			||||||
| 
						 | 
					@ -531,7 +588,7 @@ static int set_mask(pa_context *c, struct global *g)
 | 
				
			||||||
	uint32_t client_version;
 | 
						uint32_t client_version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (g->type) {
 | 
						switch (g->type) {
 | 
				
			||||||
	case PW_TYPE_INTERFACE_Device:
 | 
						case PW_TYPE_INTERFACE_Endpoint:
 | 
				
			||||||
		if (g->props == NULL)
 | 
							if (g->props == NULL)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		if ((str = pw_properties_get(g->props, PW_KEY_MEDIA_CLASS)) == NULL)
 | 
							if ((str = pw_properties_get(g->props, PW_KEY_MEDIA_CLASS)) == NULL)
 | 
				
			||||||
| 
						 | 
					@ -543,21 +600,21 @@ static int set_mask(pa_context *c, struct global *g)
 | 
				
			||||||
		g->mask = PA_SUBSCRIPTION_MASK_CARD;
 | 
							g->mask = PA_SUBSCRIPTION_MASK_CARD;
 | 
				
			||||||
		g->event = PA_SUBSCRIPTION_EVENT_CARD;
 | 
							g->event = PA_SUBSCRIPTION_EVENT_CARD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		events = &device_events;
 | 
							events = &endpoint_events;
 | 
				
			||||||
                client_version = PW_VERSION_DEVICE_PROXY;
 | 
					                client_version = PW_VERSION_ENDPOINT_PROXY;
 | 
				
			||||||
                destroy = device_destroy;
 | 
					                destroy = endpoint_destroy;
 | 
				
			||||||
                spa_list_init(&g->card_info.profiles);
 | 
					                spa_list_init(&g->card_info.profiles);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case PW_TYPE_INTERFACE_Node:
 | 
						case PW_TYPE_INTERFACE_EndpointStream:
 | 
				
			||||||
		if (g->props == NULL)
 | 
							if (g->props == NULL)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((str = pw_properties_get(g->props, PW_KEY_PRIORITY_MASTER)) != NULL)
 | 
							if ((str = pw_properties_get(g->props, PW_KEY_PRIORITY_SESSION)) != NULL)
 | 
				
			||||||
			g->priority_master = pw_properties_parse_int(str);
 | 
								g->priority_session = pw_properties_parse_int(str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((str = pw_properties_get(g->props, PW_KEY_MEDIA_CLASS)) == NULL) {
 | 
							if ((str = pw_properties_get(g->props, PW_KEY_MEDIA_CLASS)) == NULL) {
 | 
				
			||||||
			pw_log_debug("node %d without "PW_KEY_MEDIA_CLASS, g->id);
 | 
								pw_log_warn("node %d without "PW_KEY_MEDIA_CLASS, g->id);
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -565,7 +622,7 @@ static int set_mask(pa_context *c, struct global *g)
 | 
				
			||||||
			pw_log_debug("found sink %d", g->id);
 | 
								pw_log_debug("found sink %d", g->id);
 | 
				
			||||||
			g->mask = PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE;
 | 
								g->mask = PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE;
 | 
				
			||||||
			g->event = PA_SUBSCRIPTION_EVENT_SINK;
 | 
								g->event = PA_SUBSCRIPTION_EVENT_SINK;
 | 
				
			||||||
			g->node_info.monitor = g->id | PA_IDX_FLAG_DSP;
 | 
								g->stream_info.monitor = g->id | PA_IDX_FLAG_DSP;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if (strcmp(str, "Audio/Source") == 0) {
 | 
							else if (strcmp(str, "Audio/Source") == 0) {
 | 
				
			||||||
			pw_log_debug("found source %d", g->id);
 | 
								pw_log_debug("found source %d", g->id);
 | 
				
			||||||
| 
						 | 
					@ -584,13 +641,15 @@ static int set_mask(pa_context *c, struct global *g)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((str = pw_properties_get(g->props, PW_KEY_CLIENT_ID)) != NULL)
 | 
							if ((str = pw_properties_get(g->props, PW_KEY_CLIENT_ID)) != NULL)
 | 
				
			||||||
			g->node_info.client_id = atoi(str);
 | 
								g->stream_info.client_id = atoi(str);
 | 
				
			||||||
 | 
							if ((str = pw_properties_get(g->props, PW_KEY_ENDPOINT_ID)) != NULL)
 | 
				
			||||||
 | 
								g->stream_info.endpoint_id = atoi(str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		events = &node_events;
 | 
							events = &stream_events;
 | 
				
			||||||
                client_version = PW_VERSION_NODE_PROXY;
 | 
					                client_version = PW_VERSION_ENDPOINT_STREAM_PROXY;
 | 
				
			||||||
                destroy = node_destroy;
 | 
					                destroy = stream_destroy;
 | 
				
			||||||
		g->node_info.volume = 1.0;
 | 
							g->stream_info.volume = 1.0;
 | 
				
			||||||
		g->node_info.mute = false;
 | 
							g->stream_info.mute = false;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case PW_TYPE_INTERFACE_Module:
 | 
						case PW_TYPE_INTERFACE_Module:
 | 
				
			||||||
| 
						 | 
					@ -611,13 +670,7 @@ static int set_mask(pa_context *c, struct global *g)
 | 
				
			||||||
                destroy = client_destroy;
 | 
					                destroy = client_destroy;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case PW_TYPE_INTERFACE_Port:
 | 
						case PW_TYPE_INTERFACE_EndpointLink:
 | 
				
			||||||
		if ((str = pw_properties_get(g->props, PW_KEY_NODE_ID)) != NULL)
 | 
					 | 
				
			||||||
			g->port_info.node_id = atoi(str);
 | 
					 | 
				
			||||||
		pw_log_debug("found port %d node %d", g->id, g->port_info.node_id);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case PW_TYPE_INTERFACE_Link:
 | 
					 | 
				
			||||||
                if ((str = pw_properties_get(g->props, PW_KEY_LINK_OUTPUT_PORT)) == NULL)
 | 
					                if ((str = pw_properties_get(g->props, PW_KEY_LINK_OUTPUT_PORT)) == NULL)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		g->link_info.src = pa_context_find_global(c, pw_properties_parse_int(str));
 | 
							g->link_info.src = pa_context_find_global(c, pw_properties_parse_int(str));
 | 
				
			||||||
| 
						 | 
					@ -629,15 +682,15 @@ static int set_mask(pa_context *c, struct global *g)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pw_log_debug("link %d:%d->%d:%d",
 | 
							pw_log_debug("link %d:%d->%d:%d",
 | 
				
			||||||
				g->link_info.src->port_info.node_id,
 | 
									g->link_info.src->stream_info.endpoint_id,
 | 
				
			||||||
				g->link_info.src->id,
 | 
									g->link_info.src->id,
 | 
				
			||||||
				g->link_info.dst->port_info.node_id,
 | 
									g->link_info.dst->stream_info.endpoint_id,
 | 
				
			||||||
				g->link_info.dst->id);
 | 
									g->link_info.dst->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((f = pa_context_find_global(c, g->link_info.src->port_info.node_id)) != NULL &&
 | 
							if ((f = pa_context_find_global(c, g->link_info.src->stream_info.endpoint_id)) != NULL &&
 | 
				
			||||||
		    !f->init)
 | 
							    !f->init)
 | 
				
			||||||
			emit_event(c, f, PA_SUBSCRIPTION_EVENT_CHANGE);
 | 
								emit_event(c, f, PA_SUBSCRIPTION_EVENT_CHANGE);
 | 
				
			||||||
		if ((f = pa_context_find_global(c, g->link_info.dst->port_info.node_id)) != NULL &&
 | 
							if ((f = pa_context_find_global(c, g->link_info.dst->stream_info.endpoint_id)) != NULL &&
 | 
				
			||||||
		    !f->init)
 | 
							    !f->init)
 | 
				
			||||||
			emit_event(c, f, PA_SUBSCRIPTION_EVENT_CHANGE);
 | 
								emit_event(c, f, PA_SUBSCRIPTION_EVENT_CHANGE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -672,7 +725,7 @@ static inline void insert_global(pa_context *c, struct global *global)
 | 
				
			||||||
	struct global *g, *t;
 | 
						struct global *g, *t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_list_for_each_safe(g, t, &c->globals, link) {
 | 
						spa_list_for_each_safe(g, t, &c->globals, link) {
 | 
				
			||||||
		if (g->priority_master < global->priority_master) {
 | 
							if (g->priority_session < global->priority_session) {
 | 
				
			||||||
			g = spa_list_prev(g, link);
 | 
								g = spa_list_prev(g, link);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,7 @@
 | 
				
			||||||
#include <pipewire/utils.h>
 | 
					#include <pipewire/utils.h>
 | 
				
			||||||
#include <pipewire/interfaces.h>
 | 
					#include <pipewire/interfaces.h>
 | 
				
			||||||
#include <pipewire/log.h>
 | 
					#include <pipewire/log.h>
 | 
				
			||||||
 | 
					#include <extensions/session-manager.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Some PulseAudio API added const qualifiers in 13.0 */
 | 
					/* Some PulseAudio API added const qualifiers in 13.0 */
 | 
				
			||||||
#if PA_MAJOR >= 13
 | 
					#if PA_MAJOR >= 13
 | 
				
			||||||
| 
						 | 
					@ -231,7 +232,7 @@ struct global {
 | 
				
			||||||
	pa_subscription_mask_t mask;
 | 
						pa_subscription_mask_t mask;
 | 
				
			||||||
	pa_subscription_event_type_t event;
 | 
						pa_subscription_event_type_t event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int priority_master;
 | 
						int priority_session;
 | 
				
			||||||
	int pending_seq;
 | 
						int pending_seq;
 | 
				
			||||||
	int init:1;
 | 
						int init:1;
 | 
				
			||||||
	int subscribed:1;
 | 
						int subscribed:1;
 | 
				
			||||||
| 
						 | 
					@ -249,7 +250,7 @@ struct global {
 | 
				
			||||||
			struct global *src;
 | 
								struct global *src;
 | 
				
			||||||
			struct global *dst;
 | 
								struct global *dst;
 | 
				
			||||||
		} link_info;
 | 
							} link_info;
 | 
				
			||||||
		/* for sink/source */
 | 
							/* for endpoint stream */
 | 
				
			||||||
		struct {
 | 
							struct {
 | 
				
			||||||
			uint32_t client_id;
 | 
								uint32_t client_id;
 | 
				
			||||||
			uint32_t monitor;
 | 
								uint32_t monitor;
 | 
				
			||||||
| 
						 | 
					@ -257,11 +258,9 @@ struct global {
 | 
				
			||||||
			bool mute;
 | 
								bool mute;
 | 
				
			||||||
			uint32_t n_channel_volumes;
 | 
								uint32_t n_channel_volumes;
 | 
				
			||||||
			float channel_volumes[SPA_AUDIO_MAX_CHANNELS];
 | 
								float channel_volumes[SPA_AUDIO_MAX_CHANNELS];
 | 
				
			||||||
		} node_info;
 | 
								uint32_t endpoint_id;
 | 
				
			||||||
		struct {
 | 
							} stream_info;
 | 
				
			||||||
			uint32_t node_id;
 | 
							/* for endpoints */
 | 
				
			||||||
		} port_info;
 | 
					 | 
				
			||||||
		/* for devices */
 | 
					 | 
				
			||||||
		struct {
 | 
							struct {
 | 
				
			||||||
			struct spa_list profiles;
 | 
								struct spa_list profiles;
 | 
				
			||||||
			uint32_t n_profiles;
 | 
								uint32_t n_profiles;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,7 +90,7 @@ static int wait_globals(pa_context *c, pa_subscription_mask_t mask, pa_operation
 | 
				
			||||||
static void sink_callback(struct sink_data *d)
 | 
					static void sink_callback(struct sink_data *d)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct global *g = d->global;
 | 
						struct global *g = d->global;
 | 
				
			||||||
	struct pw_node_info *info = g->info;
 | 
						struct pw_endpoint_stream_info *info = g->info;
 | 
				
			||||||
	const char *str;
 | 
						const char *str;
 | 
				
			||||||
	uint32_t n;
 | 
						uint32_t n;
 | 
				
			||||||
	pa_sink_info i;
 | 
						pa_sink_info i;
 | 
				
			||||||
| 
						 | 
					@ -102,7 +102,7 @@ static void sink_callback(struct sink_data *d)
 | 
				
			||||||
		i.name = str;
 | 
							i.name = str;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		i.name = "unknown";
 | 
							i.name = "unknown";
 | 
				
			||||||
	pw_log_debug("sink %d %s monitor %d", g->id, i.name, g->node_info.monitor);
 | 
						pw_log_debug("sink %d %s monitor %d", g->id, i.name, g->stream_info.monitor);
 | 
				
			||||||
	i.index = g->id;
 | 
						i.index = g->id;
 | 
				
			||||||
	if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_NODE_DESCRIPTION)))
 | 
						if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_NODE_DESCRIPTION)))
 | 
				
			||||||
		i.description = str;
 | 
							i.description = str;
 | 
				
			||||||
| 
						 | 
					@ -111,17 +111,17 @@ static void sink_callback(struct sink_data *d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i.sample_spec.format = PA_SAMPLE_S16LE;
 | 
						i.sample_spec.format = PA_SAMPLE_S16LE;
 | 
				
			||||||
	i.sample_spec.rate = 44100;
 | 
						i.sample_spec.rate = 44100;
 | 
				
			||||||
	if (g->node_info.n_channel_volumes)
 | 
						if (g->stream_info.n_channel_volumes)
 | 
				
			||||||
		i.sample_spec.channels = g->node_info.n_channel_volumes;
 | 
							i.sample_spec.channels = g->stream_info.n_channel_volumes;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		i.sample_spec.channels = 2;
 | 
							i.sample_spec.channels = 2;
 | 
				
			||||||
	pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
 | 
						pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
 | 
				
			||||||
	i.owner_module = 0;
 | 
						i.owner_module = 0;
 | 
				
			||||||
	i.volume.channels = i.sample_spec.channels;
 | 
						i.volume.channels = i.sample_spec.channels;
 | 
				
			||||||
	for (n = 0; n < i.volume.channels; n++)
 | 
						for (n = 0; n < i.volume.channels; n++)
 | 
				
			||||||
		i.volume.values[n] = g->node_info.volume * g->node_info.channel_volumes[n] * PA_VOLUME_NORM;
 | 
							i.volume.values[n] = g->stream_info.volume * g->stream_info.channel_volumes[n] * PA_VOLUME_NORM;
 | 
				
			||||||
	i.mute = g->node_info.mute;
 | 
						i.mute = g->stream_info.mute;
 | 
				
			||||||
	i.monitor_source = g->node_info.monitor;
 | 
						i.monitor_source = g->stream_info.monitor;
 | 
				
			||||||
	i.monitor_source_name = "unknown";
 | 
						i.monitor_source_name = "unknown";
 | 
				
			||||||
	i.latency = 0;
 | 
						i.latency = 0;
 | 
				
			||||||
	i.driver = "PipeWire";
 | 
						i.driver = "PipeWire";
 | 
				
			||||||
| 
						 | 
					@ -132,7 +132,7 @@ static void sink_callback(struct sink_data *d)
 | 
				
			||||||
	i.proplist = pa_proplist_new_dict(info->props);
 | 
						i.proplist = pa_proplist_new_dict(info->props);
 | 
				
			||||||
	i.configured_latency = 0;
 | 
						i.configured_latency = 0;
 | 
				
			||||||
	i.base_volume = PA_VOLUME_NORM;
 | 
						i.base_volume = PA_VOLUME_NORM;
 | 
				
			||||||
	i.state = node_state_to_sink(info->state);
 | 
						//i.state = node_state_to_sink(info->state);
 | 
				
			||||||
	i.n_volume_steps = PA_VOLUME_NORM+1;
 | 
						i.n_volume_steps = PA_VOLUME_NORM+1;
 | 
				
			||||||
	i.card = PA_INVALID_INDEX;
 | 
						i.card = PA_INVALID_INDEX;
 | 
				
			||||||
	i.n_ports = 0;
 | 
						i.n_ports = 0;
 | 
				
			||||||
| 
						 | 
					@ -297,20 +297,20 @@ static void set_node_volume(pa_context *c, struct global *g, const pa_cvolume *v
 | 
				
			||||||
		vols = channel_volumes;
 | 
							vols = channel_volumes;
 | 
				
			||||||
		n_channel_volumes = volume->channels;
 | 
							n_channel_volumes = volume->channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (n_channel_volumes == g->node_info.n_channel_volumes &&
 | 
							if (n_channel_volumes == g->stream_info.n_channel_volumes &&
 | 
				
			||||||
		    memcmp(g->node_info.channel_volumes, vols, n_channel_volumes * sizeof(float)) == 0 &&
 | 
							    memcmp(g->stream_info.channel_volumes, vols, n_channel_volumes * sizeof(float)) == 0 &&
 | 
				
			||||||
		    mute == g->node_info.mute)
 | 
							    mute == g->stream_info.mute)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		memcpy(g->node_info.channel_volumes, vols, n_channel_volumes * sizeof(float));
 | 
							memcpy(g->stream_info.channel_volumes, vols, n_channel_volumes * sizeof(float));
 | 
				
			||||||
		g->node_info.n_channel_volumes = n_channel_volumes;
 | 
							g->stream_info.n_channel_volumes = n_channel_volumes;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		n_channel_volumes = g->node_info.n_channel_volumes;
 | 
							n_channel_volumes = g->stream_info.n_channel_volumes;
 | 
				
			||||||
		vols = g->node_info.channel_volumes;
 | 
							vols = g->stream_info.channel_volumes;
 | 
				
			||||||
		if (mute == g->node_info.mute)
 | 
							if (mute == g->stream_info.mute)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	g->node_info.mute = mute;
 | 
						g->stream_info.mute = mute;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_node_proxy_set_param((struct pw_node_proxy*)g->proxy,
 | 
						pw_node_proxy_set_param((struct pw_node_proxy*)g->proxy,
 | 
				
			||||||
		SPA_PARAM_Props, 0,
 | 
							SPA_PARAM_Props, 0,
 | 
				
			||||||
| 
						 | 
					@ -345,7 +345,7 @@ pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, c
 | 
				
			||||||
	if (!(g->mask & PA_SUBSCRIPTION_MASK_SINK))
 | 
						if (!(g->mask & PA_SUBSCRIPTION_MASK_SINK))
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_node_volume(c, g, volume, g->node_info.mute);
 | 
						set_node_volume(c, g, volume, g->stream_info.mute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
						o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
				
			||||||
	d = o->userdata;
 | 
						d = o->userdata;
 | 
				
			||||||
| 
						 | 
					@ -374,7 +374,7 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name
 | 
				
			||||||
	if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SINK, name)) == NULL)
 | 
						if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SINK, name)) == NULL)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_node_volume(c, g, volume, g->node_info.mute);
 | 
						set_node_volume(c, g, volume, g->stream_info.mute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
						o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
				
			||||||
	d = o->userdata;
 | 
						d = o->userdata;
 | 
				
			||||||
| 
						 | 
					@ -534,7 +534,7 @@ static pa_source_state_t node_state_to_source(enum pw_node_state s)
 | 
				
			||||||
static void source_callback(struct source_data *d)
 | 
					static void source_callback(struct source_data *d)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct global *g = d->global;
 | 
						struct global *g = d->global;
 | 
				
			||||||
	struct pw_node_info *info = g->info;
 | 
						struct pw_endpoint_stream_info *info = g->info;
 | 
				
			||||||
	const char *str;
 | 
						const char *str;
 | 
				
			||||||
	uint32_t n;
 | 
						uint32_t n;
 | 
				
			||||||
	pa_source_info i;
 | 
						pa_source_info i;
 | 
				
			||||||
| 
						 | 
					@ -557,20 +557,20 @@ static void source_callback(struct source_data *d)
 | 
				
			||||||
		i.description = "unknown";
 | 
							i.description = "unknown";
 | 
				
			||||||
	i.sample_spec.format = PA_SAMPLE_S16LE;
 | 
						i.sample_spec.format = PA_SAMPLE_S16LE;
 | 
				
			||||||
	i.sample_spec.rate = 44100;
 | 
						i.sample_spec.rate = 44100;
 | 
				
			||||||
	if (g->node_info.n_channel_volumes)
 | 
						if (g->stream_info.n_channel_volumes)
 | 
				
			||||||
		i.sample_spec.channels = g->node_info.n_channel_volumes;
 | 
							i.sample_spec.channels = g->stream_info.n_channel_volumes;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		i.sample_spec.channels = 2;
 | 
							i.sample_spec.channels = 2;
 | 
				
			||||||
	pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
 | 
						pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
 | 
				
			||||||
	i.owner_module = 0;
 | 
						i.owner_module = 0;
 | 
				
			||||||
	i.volume.channels = i.sample_spec.channels;
 | 
						i.volume.channels = i.sample_spec.channels;
 | 
				
			||||||
	for (n = 0; n < i.volume.channels; n++)
 | 
						for (n = 0; n < i.volume.channels; n++)
 | 
				
			||||||
		i.volume.values[n] = g->node_info.volume * g->node_info.channel_volumes[n] * PA_VOLUME_NORM;
 | 
							i.volume.values[n] = g->stream_info.volume * g->stream_info.channel_volumes[n] * PA_VOLUME_NORM;
 | 
				
			||||||
	i.mute = g->node_info.mute;
 | 
						i.mute = g->stream_info.mute;
 | 
				
			||||||
	if (g->mask & PA_SUBSCRIPTION_MASK_SINK) {
 | 
						if (g->mask & PA_SUBSCRIPTION_MASK_SINK) {
 | 
				
			||||||
		i.monitor_of_sink = g->id;
 | 
							i.monitor_of_sink = g->id;
 | 
				
			||||||
		i.monitor_of_sink_name = "unknown";
 | 
							i.monitor_of_sink_name = "unknown";
 | 
				
			||||||
		i.index = g->node_info.monitor;
 | 
							i.index = g->stream_info.monitor;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		i.monitor_of_sink = PA_INVALID_INDEX;
 | 
							i.monitor_of_sink = PA_INVALID_INDEX;
 | 
				
			||||||
		i.monitor_of_sink_name = NULL;
 | 
							i.monitor_of_sink_name = NULL;
 | 
				
			||||||
| 
						 | 
					@ -582,7 +582,7 @@ static void source_callback(struct source_data *d)
 | 
				
			||||||
	i.proplist = pa_proplist_new_dict(info->props);
 | 
						i.proplist = pa_proplist_new_dict(info->props);
 | 
				
			||||||
	i.configured_latency = 0;
 | 
						i.configured_latency = 0;
 | 
				
			||||||
	i.base_volume = PA_VOLUME_NORM;
 | 
						i.base_volume = PA_VOLUME_NORM;
 | 
				
			||||||
	i.state = node_state_to_source(info->state);
 | 
						//i.state = node_state_to_source(info->state);
 | 
				
			||||||
	i.n_volume_steps = PA_VOLUME_NORM+1;
 | 
						i.n_volume_steps = PA_VOLUME_NORM+1;
 | 
				
			||||||
	i.card = PA_INVALID_INDEX;
 | 
						i.card = PA_INVALID_INDEX;
 | 
				
			||||||
	i.n_ports = 0;
 | 
						i.n_ports = 0;
 | 
				
			||||||
| 
						 | 
					@ -729,7 +729,7 @@ pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx,
 | 
				
			||||||
	if (!(g->mask & PA_SUBSCRIPTION_MASK_SOURCE))
 | 
						if (!(g->mask & PA_SUBSCRIPTION_MASK_SOURCE))
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_node_volume(c, g, volume, g->node_info.mute);
 | 
						set_node_volume(c, g, volume, g->stream_info.mute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
						o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
				
			||||||
	d = o->userdata;
 | 
						d = o->userdata;
 | 
				
			||||||
| 
						 | 
					@ -758,7 +758,7 @@ pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *na
 | 
				
			||||||
	if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SOURCE, name)) == NULL)
 | 
						if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SOURCE, name)) == NULL)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_node_volume(c, g, volume, g->node_info.mute);
 | 
						set_node_volume(c, g, volume, g->stream_info.mute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
						o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
				
			||||||
	d = o->userdata;
 | 
						d = o->userdata;
 | 
				
			||||||
| 
						 | 
					@ -1481,7 +1481,7 @@ struct sink_input_data {
 | 
				
			||||||
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, *cl;
 | 
						struct global *g = d->global, *cl;
 | 
				
			||||||
	struct pw_node_info *info = g->info;
 | 
						struct pw_endpoint_stream_info *info = g->info;
 | 
				
			||||||
	const char *name;
 | 
						const char *name;
 | 
				
			||||||
	uint32_t n;
 | 
						uint32_t n;
 | 
				
			||||||
	pa_sink_input_info i;
 | 
						pa_sink_input_info i;
 | 
				
			||||||
| 
						 | 
					@ -1502,13 +1502,13 @@ static void sink_input_callback(struct sink_input_data *d)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		name = "unknown";
 | 
							name = "unknown";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cl = pa_context_find_global(d->context, g->node_info.client_id);
 | 
						cl = pa_context_find_global(d->context, g->stream_info.client_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_zero(i);
 | 
						spa_zero(i);
 | 
				
			||||||
	i.index = g->id;
 | 
						i.index = g->id;
 | 
				
			||||||
	i.name = name;
 | 
						i.name = name;
 | 
				
			||||||
	i.owner_module = PA_INVALID_INDEX;
 | 
						i.owner_module = PA_INVALID_INDEX;
 | 
				
			||||||
	i.client = g->node_info.client_id;
 | 
						i.client = g->stream_info.client_id;
 | 
				
			||||||
	if (s) {
 | 
						if (s) {
 | 
				
			||||||
		i.sink = s->device_index;
 | 
							i.sink = s->device_index;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1529,7 +1529,7 @@ static void sink_input_callback(struct sink_input_data *d)
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		i.sample_spec.format = PA_SAMPLE_S16LE;
 | 
							i.sample_spec.format = PA_SAMPLE_S16LE;
 | 
				
			||||||
		i.sample_spec.rate = 44100;
 | 
							i.sample_spec.rate = 44100;
 | 
				
			||||||
		i.sample_spec.channels = g->node_info.n_channel_volumes;
 | 
							i.sample_spec.channels = g->stream_info.n_channel_volumes;
 | 
				
			||||||
		if (i.sample_spec.channels == 0)
 | 
							if (i.sample_spec.channels == 0)
 | 
				
			||||||
			i.sample_spec.channels = 2;
 | 
								i.sample_spec.channels = 2;
 | 
				
			||||||
		pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
 | 
							pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
 | 
				
			||||||
| 
						 | 
					@ -1540,9 +1540,9 @@ static void sink_input_callback(struct sink_input_data *d)
 | 
				
			||||||
	pa_cvolume_init(&i.volume);
 | 
						pa_cvolume_init(&i.volume);
 | 
				
			||||||
	i.volume.channels = i.sample_spec.channels;
 | 
						i.volume.channels = i.sample_spec.channels;
 | 
				
			||||||
	for (n = 0; n < i.volume.channels; n++)
 | 
						for (n = 0; n < i.volume.channels; n++)
 | 
				
			||||||
		i.volume.values[n] = g->node_info.volume * g->node_info.channel_volumes[n] * PA_VOLUME_NORM;
 | 
							i.volume.values[n] = g->stream_info.volume * g->stream_info.channel_volumes[n] * PA_VOLUME_NORM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i.mute = g->node_info.mute;
 | 
						i.mute = g->stream_info.mute;
 | 
				
			||||||
	i.buffer_usec = 0;
 | 
						i.buffer_usec = 0;
 | 
				
			||||||
	i.sink_usec = 0;
 | 
						i.sink_usec = 0;
 | 
				
			||||||
	i.resample_method = "PipeWire resampler";
 | 
						i.resample_method = "PipeWire resampler";
 | 
				
			||||||
| 
						 | 
					@ -1697,7 +1697,7 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, cons
 | 
				
			||||||
		set_stream_volume(c, s, volume, s->mute);
 | 
							set_stream_volume(c, s, volume, s->mute);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (g) {
 | 
						else if (g) {
 | 
				
			||||||
		set_node_volume(c, g, volume, g->node_info.mute);
 | 
							set_node_volume(c, g, volume, g->stream_info.mute);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
						o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
				
			||||||
	d = o->userdata;
 | 
						d = o->userdata;
 | 
				
			||||||
| 
						 | 
					@ -1780,7 +1780,7 @@ struct source_output_data {
 | 
				
			||||||
static void source_output_callback(struct source_output_data *d)
 | 
					static void source_output_callback(struct source_output_data *d)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct global *g = d->global, *l, *cl;
 | 
						struct global *g = d->global, *l, *cl;
 | 
				
			||||||
	struct pw_node_info *info = g->info;
 | 
						struct pw_endpoint_stream_info *info = g->info;
 | 
				
			||||||
	const char *name = NULL;
 | 
						const char *name = NULL;
 | 
				
			||||||
	uint32_t n;
 | 
						uint32_t n;
 | 
				
			||||||
	pa_source_output_info i;
 | 
						pa_source_output_info i;
 | 
				
			||||||
| 
						 | 
					@ -1802,13 +1802,13 @@ static void source_output_callback(struct source_output_data *d)
 | 
				
			||||||
	if (name == NULL)
 | 
						if (name == NULL)
 | 
				
			||||||
		name = "unknown";
 | 
							name = "unknown";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cl = pa_context_find_global(d->context, g->node_info.client_id);
 | 
						cl = pa_context_find_global(d->context, g->stream_info.client_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_zero(i);
 | 
						spa_zero(i);
 | 
				
			||||||
	i.index = g->id;
 | 
						i.index = g->id;
 | 
				
			||||||
	i.name = name ? name : "Unknown";
 | 
						i.name = name ? name : "Unknown";
 | 
				
			||||||
	i.owner_module = PA_INVALID_INDEX;
 | 
						i.owner_module = PA_INVALID_INDEX;
 | 
				
			||||||
	i.client = g->node_info.client_id;
 | 
						i.client = g->stream_info.client_id;
 | 
				
			||||||
	if (s) {
 | 
						if (s) {
 | 
				
			||||||
		i.source = s->device_index;
 | 
							i.source = s->device_index;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1828,7 +1828,7 @@ static void source_output_callback(struct source_output_data *d)
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		i.sample_spec.format = PA_SAMPLE_S16LE;
 | 
							i.sample_spec.format = PA_SAMPLE_S16LE;
 | 
				
			||||||
		i.sample_spec.rate = 44100;
 | 
							i.sample_spec.rate = 44100;
 | 
				
			||||||
		i.sample_spec.channels = g->node_info.n_channel_volumes;
 | 
							i.sample_spec.channels = g->stream_info.n_channel_volumes;
 | 
				
			||||||
		if (i.sample_spec.channels == 0)
 | 
							if (i.sample_spec.channels == 0)
 | 
				
			||||||
			i.sample_spec.channels = 2;
 | 
								i.sample_spec.channels = 2;
 | 
				
			||||||
		pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
 | 
							pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
 | 
				
			||||||
| 
						 | 
					@ -1839,9 +1839,9 @@ static void source_output_callback(struct source_output_data *d)
 | 
				
			||||||
	pa_cvolume_init(&i.volume);
 | 
						pa_cvolume_init(&i.volume);
 | 
				
			||||||
	i.volume.channels = i.sample_spec.channels;
 | 
						i.volume.channels = i.sample_spec.channels;
 | 
				
			||||||
	for (n = 0; n < i.volume.channels; n++)
 | 
						for (n = 0; n < i.volume.channels; n++)
 | 
				
			||||||
		i.volume.values[n] = g->node_info.volume * g->node_info.channel_volumes[n] * PA_VOLUME_NORM;
 | 
							i.volume.values[n] = g->stream_info.volume * g->stream_info.channel_volumes[n] * PA_VOLUME_NORM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i.mute = g->node_info.mute;
 | 
						i.mute = g->stream_info.mute;
 | 
				
			||||||
	i.buffer_usec = 0;
 | 
						i.buffer_usec = 0;
 | 
				
			||||||
	i.source_usec = 0;
 | 
						i.source_usec = 0;
 | 
				
			||||||
	i.resample_method = "PipeWire resampler";
 | 
						i.resample_method = "PipeWire resampler";
 | 
				
			||||||
| 
						 | 
					@ -1991,7 +1991,7 @@ pa_operation* pa_context_set_source_output_volume(pa_context *c, uint32_t idx, c
 | 
				
			||||||
		set_stream_volume(c, s, volume, s->mute);
 | 
							set_stream_volume(c, s, volume, s->mute);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (g) {
 | 
						else if (g) {
 | 
				
			||||||
		set_node_volume(c, g, volume, g->node_info.mute);
 | 
							set_node_volume(c, g, volume, g->stream_info.mute);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
						o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
 | 
				
			||||||
	d = o->userdata;
 | 
						d = o->userdata;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,7 +200,7 @@ static void configure_device(pa_stream *s)
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		if (s->direction == PA_STREAM_RECORD) {
 | 
							if (s->direction == PA_STREAM_RECORD) {
 | 
				
			||||||
			if (g->mask == (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE))
 | 
								if (g->mask == (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE))
 | 
				
			||||||
				s->device_index = g->node_info.monitor;
 | 
									s->device_index = g->stream_info.monitor;
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				s->device_index = g->id;
 | 
									s->device_index = g->id;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue