mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	pulse-server: rework audioinfo argument parsing
Make a new method to parse parts of the audioinfo based on custom keys, leaving unparsed values to defaults. Implement the generic audio parsing with this. We can then remove some duplicate code where the audio keys didn't match or where only parts of the info needed to be parsed. Also make a method to serialize the audioinfo to properties and use that when making arguments to load the modules. Avoid doing some custom property serialization, move all key/values into properties and serialize those with the generic functions.
This commit is contained in:
		
							parent
							
								
									11c478d0fa
								
							
						
					
					
						commit
						37210794d8
					
				
					 16 changed files with 227 additions and 409 deletions
				
			
		| 
						 | 
				
			
			@ -163,41 +163,48 @@ void module_args_add_props(struct pw_properties *props, const char *str)
 | 
			
		|||
	free(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int module_args_to_audioinfo(struct impl *impl, struct pw_properties *props, struct spa_audio_info_raw *info)
 | 
			
		||||
int module_args_to_audioinfo_keys(struct impl *impl, struct pw_properties *props,
 | 
			
		||||
		const char *key_format, const char *key_rate,
 | 
			
		||||
		const char *key_channels, const char *key_channel_map,
 | 
			
		||||
		struct spa_audio_info_raw *info)
 | 
			
		||||
{
 | 
			
		||||
	const char *str;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	/* We don't use any incoming format setting and use our native format */
 | 
			
		||||
	spa_zero(*info);
 | 
			
		||||
	info->flags = SPA_AUDIO_FLAG_UNPOSITIONED;
 | 
			
		||||
	info->format = SPA_AUDIO_FORMAT_F32P;
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "channels")) != NULL) {
 | 
			
		||||
		info->channels = pw_properties_parse_int(str);
 | 
			
		||||
		if (info->channels == 0 || info->channels > SPA_AUDIO_MAX_CHANNELS) {
 | 
			
		||||
			pw_log_error("invalid channels '%s'", str);
 | 
			
		||||
	if (key_format && (str = pw_properties_get(props, key_format)) != NULL) {
 | 
			
		||||
		info->format = format_paname2id(str, strlen(str));
 | 
			
		||||
		if (info->format == SPA_AUDIO_FORMAT_UNKNOWN) {
 | 
			
		||||
			pw_log_error("invalid %s '%s'", key_format, str);
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		pw_properties_set(props, "channels", NULL);
 | 
			
		||||
		pw_properties_set(props, key_format, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if ((str = pw_properties_get(props, "channel_map")) != NULL) {
 | 
			
		||||
	if (key_channels && (str = pw_properties_get(props, key_channels)) != NULL) {
 | 
			
		||||
		info->channels = pw_properties_parse_int(str);
 | 
			
		||||
		if (info->channels == 0 || info->channels > SPA_AUDIO_MAX_CHANNELS) {
 | 
			
		||||
			pw_log_error("invalid %s '%s'", key_channels, str);
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		pw_properties_set(props, key_channels, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if (key_channel_map && (str = pw_properties_get(props, key_channel_map)) != NULL) {
 | 
			
		||||
		struct channel_map map;
 | 
			
		||||
 | 
			
		||||
		channel_map_parse(str, &map);
 | 
			
		||||
		if (map.channels == 0 || map.channels > SPA_AUDIO_MAX_CHANNELS) {
 | 
			
		||||
			pw_log_error("invalid channel_map '%s'", str);
 | 
			
		||||
			pw_log_error("invalid %s '%s'", key_channel_map, str);
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		if (info->channels == 0)
 | 
			
		||||
			info->channels = map.channels;
 | 
			
		||||
		if (info->channels != map.channels) {
 | 
			
		||||
			pw_log_error("Mismatched channel map");
 | 
			
		||||
			pw_log_error("Mismatched %s and %s (%d vs %d)",
 | 
			
		||||
					key_channels, key_channel_map,
 | 
			
		||||
					info->channels, map.channels);
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		channel_map_to_positions(&map, info->position);
 | 
			
		||||
		info->flags &= ~SPA_AUDIO_FLAG_UNPOSITIONED;
 | 
			
		||||
		pw_properties_set(props, "channel_map", NULL);
 | 
			
		||||
		pw_properties_set(props, key_channel_map, NULL);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (info->channels == 0)
 | 
			
		||||
			info->channels = impl->defs.sample_spec.channels;
 | 
			
		||||
| 
						 | 
				
			
			@ -214,19 +221,25 @@ int module_args_to_audioinfo(struct impl *impl, struct pw_properties *props, str
 | 
			
		|||
			for (i = 0; i < info->channels; i++)
 | 
			
		||||
				info->position[i] = SPA_AUDIO_CHANNEL_UNKNOWN;
 | 
			
		||||
		}
 | 
			
		||||
		if (info->position[0] != SPA_AUDIO_CHANNEL_UNKNOWN)
 | 
			
		||||
			info->flags &= ~SPA_AUDIO_FLAG_UNPOSITIONED;
 | 
			
		||||
		if (info->position[0] == SPA_AUDIO_CHANNEL_UNKNOWN)
 | 
			
		||||
			info->flags |= SPA_AUDIO_FLAG_UNPOSITIONED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "rate")) != NULL) {
 | 
			
		||||
	if (key_rate && (str = pw_properties_get(props, key_rate)) != NULL) {
 | 
			
		||||
		info->rate = pw_properties_parse_int(str);
 | 
			
		||||
		pw_properties_set(props, "rate", NULL);
 | 
			
		||||
	} else {
 | 
			
		||||
		info->rate = 0;
 | 
			
		||||
		pw_properties_set(props, key_rate, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int module_args_to_audioinfo(struct impl *impl, struct pw_properties *props, struct spa_audio_info_raw *info)
 | 
			
		||||
{
 | 
			
		||||
	/* We don't use any incoming format setting and use our native format */
 | 
			
		||||
	spa_zero(*info);
 | 
			
		||||
	info->format = SPA_AUDIO_FORMAT_F32P;
 | 
			
		||||
	return module_args_to_audioinfo_keys(impl, props,
 | 
			
		||||
			NULL, "rate", "channels", "channel_map", info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool module_args_parse_bool(const char *v)
 | 
			
		||||
{
 | 
			
		||||
	if (spa_streq(v, "1") || !strcasecmp(v, "y") || !strcasecmp(v, "t") ||
 | 
			
		||||
| 
						 | 
				
			
			@ -235,6 +248,28 @@ bool module_args_parse_bool(const char *v)
 | 
			
		|||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audioinfo_to_properties(struct spa_audio_info_raw *info, struct pw_properties *props)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	if (info->format)
 | 
			
		||||
		pw_properties_setf(props, SPA_KEY_AUDIO_FORMAT, "%s",
 | 
			
		||||
					format_id2name(info->format));
 | 
			
		||||
	if (info->rate)
 | 
			
		||||
		pw_properties_setf(props, SPA_KEY_AUDIO_RATE, "%u", info->rate);
 | 
			
		||||
	if (info->channels) {
 | 
			
		||||
		char *s, *p;
 | 
			
		||||
 | 
			
		||||
		pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
 | 
			
		||||
 | 
			
		||||
		p = s = alloca(info->channels * 8);
 | 
			
		||||
		for (i = 0; i < info->channels; i++)
 | 
			
		||||
			p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
 | 
			
		||||
					channel_id2name(info->position[i]));
 | 
			
		||||
		pw_properties_setf(props, SPA_KEY_AUDIO_POSITION, "[ %s ]", s);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct module_info *find_module_info(const char *name)
 | 
			
		||||
{
 | 
			
		||||
	extern const struct module_info __start_pw_mod_pulse_modules[];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,5 +70,12 @@ void module_add_listener(struct module *module,
 | 
			
		|||
void module_args_add_props(struct pw_properties *props, const char *str);
 | 
			
		||||
int module_args_to_audioinfo(struct impl *impl, struct pw_properties *props, struct spa_audio_info_raw *info);
 | 
			
		||||
bool module_args_parse_bool(const char *str);
 | 
			
		||||
int module_args_to_audioinfo_keys(struct impl *impl, struct pw_properties *props,
 | 
			
		||||
		const char *key_format, const char *key_rate,
 | 
			
		||||
		const char *key_channels, const char *key_channel_map,
 | 
			
		||||
		struct spa_audio_info_raw *info);
 | 
			
		||||
 | 
			
		||||
void audioinfo_to_properties(struct spa_audio_info_raw *info, struct pw_properties *props);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,17 +49,16 @@ struct module_combine_sink_data {
 | 
			
		|||
	struct pw_impl_module *mod;
 | 
			
		||||
	struct spa_hook mod_listener;
 | 
			
		||||
 | 
			
		||||
	char *sink_name;
 | 
			
		||||
	char **sink_names;
 | 
			
		||||
	struct pw_properties *props;
 | 
			
		||||
	struct pw_properties *combine_props;
 | 
			
		||||
	struct pw_properties *stream_props;
 | 
			
		||||
 | 
			
		||||
	struct spa_source *sinks_timeout;
 | 
			
		||||
 | 
			
		||||
	struct spa_audio_info_raw info;
 | 
			
		||||
 | 
			
		||||
	unsigned int sinks_pending;
 | 
			
		||||
	unsigned int remix:1;
 | 
			
		||||
	unsigned int latency_compensate:1;
 | 
			
		||||
	unsigned int load_emitted:1;
 | 
			
		||||
	unsigned int start_error:1;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -150,33 +149,20 @@ static int module_combine_sink_load(struct module *module)
 | 
			
		|||
	if (data->core == NULL)
 | 
			
		||||
		return -errno;
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(data->combine_props, "pulse.module.id", "%u",
 | 
			
		||||
			module->index);
 | 
			
		||||
	pw_properties_setf(data->stream_props, "pulse.module.id", "%u",
 | 
			
		||||
			module->index);
 | 
			
		||||
 | 
			
		||||
	if ((f = open_memstream(&args, &size)) == NULL)
 | 
			
		||||
		return -errno;
 | 
			
		||||
 | 
			
		||||
	fprintf(f, "{");
 | 
			
		||||
	fprintf(f, " node.name = %s", data->sink_name);
 | 
			
		||||
	fprintf(f, " node.description = %s", data->sink_name);
 | 
			
		||||
	if (data->latency_compensate)
 | 
			
		||||
		fprintf(f, " combine.latency-compensate = true");
 | 
			
		||||
	if (data->info.rate != 0)
 | 
			
		||||
		fprintf(f, " audio.rate = %u", data->info.rate);
 | 
			
		||||
	if (data->info.channels != 0) {
 | 
			
		||||
		fprintf(f, " audio.channels = %u", data->info.channels);
 | 
			
		||||
		if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
 | 
			
		||||
			fprintf(f, " audio.position = [ ");
 | 
			
		||||
			for (i = 0; i < data->info.channels; i++)
 | 
			
		||||
				fprintf(f, "%s%s", i == 0 ? "" : ",",
 | 
			
		||||
					channel_id2name(data->info.position[i]));
 | 
			
		||||
			fprintf(f, " ]");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->props->dict, 0);
 | 
			
		||||
	fprintf(f, " combine.props = {");
 | 
			
		||||
	fprintf(f, " pulse.module.id = %u", module->index);
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->combine_props->dict, 0);
 | 
			
		||||
	fprintf(f, " } stream.props = {");
 | 
			
		||||
	if (!data->remix)
 | 
			
		||||
		fprintf(f, "   "PW_KEY_STREAM_DONT_REMIX" = true");
 | 
			
		||||
	fprintf(f, "   pulse.module.id = %u", module->index);
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->stream_props->dict, 0);
 | 
			
		||||
	fprintf(f, " } stream.rules = [");
 | 
			
		||||
	if (data->sink_names == NULL) {
 | 
			
		||||
		fprintf(f, "  { matches = [ { media.class = \"Audio/Sink\" } ]");
 | 
			
		||||
| 
						 | 
				
			
			@ -244,8 +230,9 @@ static int module_combine_sink_unload(struct module *module)
 | 
			
		|||
		pw_core_disconnect(d->core);
 | 
			
		||||
	}
 | 
			
		||||
	pw_free_strv(d->sink_names);
 | 
			
		||||
	free(d->sink_name);
 | 
			
		||||
	pw_properties_free(d->stream_props);
 | 
			
		||||
	pw_properties_free(d->combine_props);
 | 
			
		||||
	pw_properties_free(d->props);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -253,39 +240,51 @@ static int module_combine_sink_prepare(struct module * const module)
 | 
			
		|||
{
 | 
			
		||||
	struct module_combine_sink_data * const d = module->user_data;
 | 
			
		||||
	struct pw_properties * const props = module->props;
 | 
			
		||||
	struct pw_properties *combine_props = NULL;
 | 
			
		||||
	struct pw_properties *combine_props = NULL, *global_props = NULL, *stream_props = NULL;
 | 
			
		||||
	const char *str;
 | 
			
		||||
	char *sink_name = NULL, **sink_names = NULL;
 | 
			
		||||
	char **sink_names = NULL;
 | 
			
		||||
	struct spa_audio_info_raw info = { 0 };
 | 
			
		||||
	int res;
 | 
			
		||||
	int num_sinks = 0;
 | 
			
		||||
 | 
			
		||||
	PW_LOG_TOPIC_INIT(mod_topic);
 | 
			
		||||
 | 
			
		||||
	global_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	combine_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "sink_name")) != NULL) {
 | 
			
		||||
		sink_name = strdup(str);
 | 
			
		||||
		pw_properties_set(props, "sink_name", NULL);
 | 
			
		||||
	} else {
 | 
			
		||||
		sink_name = strdup("combined");
 | 
			
		||||
	stream_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	if (global_props == NULL || combine_props == NULL || stream_props == NULL) {
 | 
			
		||||
		res = -ENOMEM;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(module->props, "sink_properties")) != NULL)
 | 
			
		||||
	if ((str = pw_properties_get(props, "sink_name")) != NULL) {
 | 
			
		||||
		pw_properties_set(global_props, PW_KEY_NODE_NAME, str);
 | 
			
		||||
		pw_properties_set(global_props, PW_KEY_NODE_DESCRIPTION, str);
 | 
			
		||||
		pw_properties_set(props, "sink_name", NULL);
 | 
			
		||||
	} else {
 | 
			
		||||
		str = "combined";
 | 
			
		||||
		pw_properties_set(global_props, PW_KEY_NODE_NAME, str);
 | 
			
		||||
		pw_properties_set(global_props, PW_KEY_NODE_DESCRIPTION, str);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "sink_properties")) != NULL)
 | 
			
		||||
		module_args_add_props(combine_props, str);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "slaves")) != NULL) {
 | 
			
		||||
		sink_names = pw_split_strv(str, ",", MAX_SINKS, &num_sinks);
 | 
			
		||||
		pw_properties_set(props, "slaves", NULL);
 | 
			
		||||
	}
 | 
			
		||||
	d->remix = true;
 | 
			
		||||
	if ((str = pw_properties_get(props, "remix")) != NULL) {
 | 
			
		||||
		d->remix = pw_properties_parse_bool(str);
 | 
			
		||||
		pw_properties_set(stream_props, PW_KEY_STREAM_DONT_REMIX,
 | 
			
		||||
				module_args_parse_bool(str) ? "false" : "true");
 | 
			
		||||
		pw_properties_set(props, "remix", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "latency_compensate")) != NULL)
 | 
			
		||||
		d->latency_compensate = pw_properties_parse_bool(str);
 | 
			
		||||
	if ((str = pw_properties_get(props, "latency_compensate")) != NULL) {
 | 
			
		||||
		pw_properties_set(global_props, "combine.latency-compensate",
 | 
			
		||||
				module_args_parse_bool(str) ? "true" : "false");
 | 
			
		||||
		pw_properties_set(props, "latency_compensate", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "adjust_time")) != NULL) {
 | 
			
		||||
		pw_log_info("The `adjust_time` modarg is ignored");
 | 
			
		||||
| 
						 | 
				
			
			@ -297,23 +296,27 @@ static int module_combine_sink_prepare(struct module * const module)
 | 
			
		|||
		pw_properties_set(props, "resample_method", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			NULL, "rate", "channels", "channel_map", &info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	audioinfo_to_properties(&info, global_props);
 | 
			
		||||
 | 
			
		||||
	d->module = module;
 | 
			
		||||
	d->info = info;
 | 
			
		||||
	d->sink_name = sink_name;
 | 
			
		||||
	d->sink_names = sink_names;
 | 
			
		||||
	d->sinks_pending = (sink_names == NULL) ? 0 : num_sinks;
 | 
			
		||||
	d->stream_props = stream_props;
 | 
			
		||||
	d->combine_props = combine_props;
 | 
			
		||||
	d->props = global_props;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
out:
 | 
			
		||||
	free(sink_name);
 | 
			
		||||
	pw_free_strv(sink_names);
 | 
			
		||||
	pw_properties_free(stream_props);
 | 
			
		||||
	pw_properties_free(combine_props);
 | 
			
		||||
	pw_properties_free(global_props);
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@ struct module_echo_cancel_data {
 | 
			
		|||
	struct pw_impl_module *mod;
 | 
			
		||||
	struct spa_hook mod_listener;
 | 
			
		||||
 | 
			
		||||
	struct pw_properties *global_props;
 | 
			
		||||
	struct pw_properties *props;
 | 
			
		||||
	struct pw_properties *capture_props;
 | 
			
		||||
	struct pw_properties *source_props;
 | 
			
		||||
| 
						 | 
				
			
			@ -58,26 +59,10 @@ static int module_echo_cancel_load(struct module *module)
 | 
			
		|||
		return -errno;
 | 
			
		||||
 | 
			
		||||
	fprintf(f, "{");
 | 
			
		||||
	if ((method = pw_properties_get(props, "aec_method")) == NULL)
 | 
			
		||||
		method = "webrtc";
 | 
			
		||||
 | 
			
		||||
	fprintf(f, " library.name = \"aec/libspa-aec-%s\"", method);
 | 
			
		||||
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->global_props->dict, 0);
 | 
			
		||||
	fprintf(f, " aec.args = {");
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->props->dict, 0);
 | 
			
		||||
	fprintf(f, " }");
 | 
			
		||||
	if (data->info.rate != 0)
 | 
			
		||||
		fprintf(f, " audio.rate = %u", data->info.rate);
 | 
			
		||||
	if (data->info.channels != 0) {
 | 
			
		||||
		fprintf(f, " audio.channels = %u", data->info.channels);
 | 
			
		||||
		if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
 | 
			
		||||
			fprintf(f, " audio.position = [ ");
 | 
			
		||||
			for (i = 0; i < data->info.channels; i++)
 | 
			
		||||
				fprintf(f, "%s%s", i == 0 ? "" : ",",
 | 
			
		||||
					channel_id2name(data->info.position[i]));
 | 
			
		||||
			fprintf(f, " ]");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	fprintf(f, " capture.props = {");
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->capture_props->dict, 0);
 | 
			
		||||
	fprintf(f, " } source.props = {");
 | 
			
		||||
| 
						 | 
				
			
			@ -114,6 +99,7 @@ static int module_echo_cancel_unload(struct module *module)
 | 
			
		|||
		d->mod = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pw_properties_free(d->global_props);
 | 
			
		||||
	pw_properties_free(d->props);
 | 
			
		||||
	pw_properties_free(d->capture_props);
 | 
			
		||||
	pw_properties_free(d->source_props);
 | 
			
		||||
| 
						 | 
				
			
			@ -231,22 +217,28 @@ static int module_echo_cancel_prepare(struct module * const module)
 | 
			
		|||
	struct pw_properties * const props = module->props;
 | 
			
		||||
	struct pw_properties *aec_props = NULL, *sink_props = NULL, *source_props = NULL;
 | 
			
		||||
	struct pw_properties *playback_props = NULL, *capture_props = NULL;
 | 
			
		||||
	struct pw_properties *global_props = NULL;
 | 
			
		||||
	const char *str, *method;
 | 
			
		||||
	struct spa_audio_info_raw info = { 0 };
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	PW_LOG_TOPIC_INIT(mod_topic);
 | 
			
		||||
 | 
			
		||||
	global_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	aec_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	capture_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	source_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	sink_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	playback_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	if (!aec_props || !source_props || !sink_props || !capture_props || !playback_props) {
 | 
			
		||||
	if (!global_props || !aec_props || !source_props || !sink_props || !capture_props || !playback_props) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "aec_method")) == NULL)
 | 
			
		||||
		str = "webrtc";
 | 
			
		||||
	pw_properties_setf(global_props, "library.name", "aec/libspa-aec-%s", str);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "source_name")) != NULL) {
 | 
			
		||||
		pw_properties_set(source_props, PW_KEY_NODE_NAME, str);
 | 
			
		||||
		pw_properties_set(props, "source_name", NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -282,6 +274,7 @@ static int module_echo_cancel_prepare(struct module * const module)
 | 
			
		|||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	audioinfo_to_properties(&info, global_props);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "source_properties")) != NULL) {
 | 
			
		||||
		module_args_add_props(source_props, str);
 | 
			
		||||
| 
						 | 
				
			
			@ -314,6 +307,7 @@ static int module_echo_cancel_prepare(struct module * const module)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	d->module = module;
 | 
			
		||||
	d->global_props = global_props;
 | 
			
		||||
	d->props = aec_props;
 | 
			
		||||
	d->capture_props = capture_props;
 | 
			
		||||
	d->source_props = source_props;
 | 
			
		||||
| 
						 | 
				
			
			@ -323,6 +317,7 @@ static int module_echo_cancel_prepare(struct module * const module)
 | 
			
		|||
 | 
			
		||||
	return 0;
 | 
			
		||||
out:
 | 
			
		||||
	pw_properties_free(global_props);
 | 
			
		||||
	pw_properties_free(aec_props);
 | 
			
		||||
	pw_properties_free(playback_props);
 | 
			
		||||
	pw_properties_free(sink_props);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -144,19 +144,6 @@ static const struct spa_dict_item module_ladspa_sink_info[] = {
 | 
			
		|||
	{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void position_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
 | 
			
		||||
{
 | 
			
		||||
	char *s, *p;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
 | 
			
		||||
	p = s = alloca(info->channels * 8);
 | 
			
		||||
	for (i = 0; i < info->channels; i++)
 | 
			
		||||
		p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
 | 
			
		||||
				channel_id2name(info->position[i]));
 | 
			
		||||
	pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int module_ladspa_sink_prepare(struct module * const module)
 | 
			
		||||
{
 | 
			
		||||
	struct module_ladspa_sink_data * const d = module->user_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -203,14 +190,15 @@ static int module_ladspa_sink_prepare(struct module * const module)
 | 
			
		|||
		pw_properties_set(props, "master", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &capture_info) < 0) {
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			NULL, NULL, "channels", "channel_map", &capture_info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	playback_info = capture_info;
 | 
			
		||||
 | 
			
		||||
	position_to_props(&capture_info, capture_props);
 | 
			
		||||
	position_to_props(&playback_info, playback_props);
 | 
			
		||||
	audioinfo_to_properties(&capture_info, capture_props);
 | 
			
		||||
	audioinfo_to_properties(&playback_info, playback_props);
 | 
			
		||||
 | 
			
		||||
	if (pw_properties_get(playback_props, PW_KEY_NODE_PASSIVE) == NULL)
 | 
			
		||||
		pw_properties_set(playback_props, PW_KEY_NODE_PASSIVE, "true");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -144,19 +144,6 @@ static const struct spa_dict_item module_ladspa_source_info[] = {
 | 
			
		|||
	{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void position_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
 | 
			
		||||
{
 | 
			
		||||
	char *s, *p;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
 | 
			
		||||
	p = s = alloca(info->channels * 8);
 | 
			
		||||
	for (i = 0; i < info->channels; i++)
 | 
			
		||||
		p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
 | 
			
		||||
				channel_id2name(info->position[i]));
 | 
			
		||||
	pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int module_ladspa_source_prepare(struct module * const module)
 | 
			
		||||
{
 | 
			
		||||
	struct module_ladspa_source_data * const d = module->user_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -211,14 +198,15 @@ static int module_ladspa_source_prepare(struct module * const module)
 | 
			
		|||
		pw_properties_set(props, "master", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &playback_info) < 0) {
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			NULL, NULL, "channels", "channel_map", &playback_info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	capture_info = playback_info;
 | 
			
		||||
 | 
			
		||||
	position_to_props(&capture_info, capture_props);
 | 
			
		||||
	position_to_props(&playback_info, playback_props);
 | 
			
		||||
	audioinfo_to_properties(&capture_info, capture_props);
 | 
			
		||||
	audioinfo_to_properties(&playback_info, playback_props);
 | 
			
		||||
 | 
			
		||||
	if (pw_properties_get(capture_props, PW_KEY_NODE_PASSIVE) == NULL)
 | 
			
		||||
		pw_properties_set(capture_props, PW_KEY_NODE_PASSIVE, "true");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,11 +22,9 @@ struct module_loopback_data {
 | 
			
		|||
	struct pw_impl_module *mod;
 | 
			
		||||
	struct spa_hook mod_listener;
 | 
			
		||||
 | 
			
		||||
	struct pw_properties *global_props;
 | 
			
		||||
	struct pw_properties *capture_props;
 | 
			
		||||
	struct pw_properties *playback_props;
 | 
			
		||||
 | 
			
		||||
	struct spa_audio_info_raw info;
 | 
			
		||||
	uint32_t latency_msec;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void module_destroy(void *data)
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +46,6 @@ static int module_loopback_load(struct module *module)
 | 
			
		|||
	FILE *f;
 | 
			
		||||
	char *args;
 | 
			
		||||
	size_t size, i;
 | 
			
		||||
	char val[256];
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index);
 | 
			
		||||
	pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index);
 | 
			
		||||
| 
						 | 
				
			
			@ -59,20 +56,7 @@ static int module_loopback_load(struct module *module)
 | 
			
		|||
		return -errno;
 | 
			
		||||
 | 
			
		||||
	fprintf(f, "{");
 | 
			
		||||
	if (data->info.channels != 0) {
 | 
			
		||||
		fprintf(f, " audio.channels = %u", data->info.channels);
 | 
			
		||||
		if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
 | 
			
		||||
			fprintf(f, " audio.position = [ ");
 | 
			
		||||
			for (i = 0; i < data->info.channels; i++)
 | 
			
		||||
				fprintf(f, "%s%s", i == 0 ? "" : ",",
 | 
			
		||||
					channel_id2name(data->info.position[i]));
 | 
			
		||||
			fprintf(f, " ]");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (data->latency_msec != 0)
 | 
			
		||||
		fprintf(f, " target.delay.sec = %s",
 | 
			
		||||
				spa_json_format_float(val, sizeof(val),
 | 
			
		||||
					data->latency_msec / 1000.0f));
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->global_props->dict, 0);
 | 
			
		||||
	fprintf(f, " capture.props = {");
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->capture_props->dict, 0);
 | 
			
		||||
	fprintf(f, " } playback.props = {");
 | 
			
		||||
| 
						 | 
				
			
			@ -107,6 +91,7 @@ static int module_loopback_unload(struct module *module)
 | 
			
		|||
 | 
			
		||||
	pw_properties_free(d->capture_props);
 | 
			
		||||
	pw_properties_free(d->playback_props);
 | 
			
		||||
	pw_properties_free(d->global_props);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -132,16 +117,17 @@ static int module_loopback_prepare(struct module * const module)
 | 
			
		|||
{
 | 
			
		||||
	struct module_loopback_data * const d = module->user_data;
 | 
			
		||||
	struct pw_properties * const props = module->props;
 | 
			
		||||
	struct pw_properties *playback_props = NULL, *capture_props = NULL;
 | 
			
		||||
	struct pw_properties *global_props = NULL, *playback_props = NULL, *capture_props = NULL;
 | 
			
		||||
	const char *str;
 | 
			
		||||
	struct spa_audio_info_raw info = { 0 };
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	PW_LOG_TOPIC_INIT(mod_topic);
 | 
			
		||||
 | 
			
		||||
	global_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	capture_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	playback_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	if (!capture_props || !playback_props) {
 | 
			
		||||
	if (!global_props || !capture_props || !playback_props) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -167,10 +153,12 @@ static int module_loopback_prepare(struct module * const module)
 | 
			
		|||
		pw_properties_set(props, "sink", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
				NULL, NULL, "channels", "channel_map", &info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	audioinfo_to_properties(&info, global_props);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "source_dont_move")) != NULL) {
 | 
			
		||||
		pw_properties_set(capture_props, PW_KEY_NODE_DONT_RECONNECT, str);
 | 
			
		||||
| 
						 | 
				
			
			@ -189,8 +177,13 @@ static int module_loopback_prepare(struct module * const module)
 | 
			
		|||
		pw_properties_set(props, "remix", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "latency_msec")) != NULL)
 | 
			
		||||
		d->latency_msec = atoi(str);
 | 
			
		||||
	if ((str = pw_properties_get(props, "latency_msec")) != NULL) {
 | 
			
		||||
		uint32_t latency_msec = atoi(str);
 | 
			
		||||
		char val[256];
 | 
			
		||||
		pw_properties_setf(global_props, "target.delay.sec",
 | 
			
		||||
				"%s", spa_json_format_float(val, sizeof(val),
 | 
			
		||||
					latency_msec / 1000.0f));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "sink_input_properties")) != NULL) {
 | 
			
		||||
		module_args_add_props(playback_props, str);
 | 
			
		||||
| 
						 | 
				
			
			@ -203,12 +196,13 @@ static int module_loopback_prepare(struct module * const module)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	d->module = module;
 | 
			
		||||
	d->global_props = global_props;
 | 
			
		||||
	d->capture_props = capture_props;
 | 
			
		||||
	d->playback_props = playback_props;
 | 
			
		||||
	d->info = info;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
out:
 | 
			
		||||
	pw_properties_free(global_props);
 | 
			
		||||
	pw_properties_free(playback_props);
 | 
			
		||||
	pw_properties_free(capture_props);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -160,35 +160,11 @@ static int module_null_sink_prepare(struct module * const module)
 | 
			
		|||
		pw_properties_set(props, "sink_properties", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &info) < 0)
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			"format", "rate", "channels", "channel_map", &info) < 0)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	info.format = module->impl->defs.sample_spec.format;
 | 
			
		||||
	if ((str = pw_properties_get(props, "format")) != NULL) {
 | 
			
		||||
		info.format = format_paname2id(str, strlen(str));
 | 
			
		||||
		if (info.format == SPA_AUDIO_FORMAT_UNKNOWN) {
 | 
			
		||||
			pw_log_error("invalid format '%s'", str);
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		pw_properties_set(props, "format", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (info.format)
 | 
			
		||||
		pw_properties_setf(props, SPA_KEY_AUDIO_FORMAT, "%s",
 | 
			
		||||
					format_id2name(info.format));
 | 
			
		||||
	if (info.rate)
 | 
			
		||||
		pw_properties_setf(props, SPA_KEY_AUDIO_RATE, "%u", info.rate);
 | 
			
		||||
	if (info.channels) {
 | 
			
		||||
		char *s, *p;
 | 
			
		||||
 | 
			
		||||
		pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info.channels);
 | 
			
		||||
 | 
			
		||||
		p = s = alloca(info.channels * 8);
 | 
			
		||||
		for (i = 0; i < info.channels; i++)
 | 
			
		||||
			p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
 | 
			
		||||
					channel_id2name(info.position[i]));
 | 
			
		||||
		pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
 | 
			
		||||
	}
 | 
			
		||||
	audioinfo_to_properties(&info, props);
 | 
			
		||||
 | 
			
		||||
	if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL)
 | 
			
		||||
		pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,9 +25,8 @@ struct module_pipesink_data {
 | 
			
		|||
	struct spa_hook mod_listener;
 | 
			
		||||
	struct pw_impl_module *mod;
 | 
			
		||||
 | 
			
		||||
	struct pw_properties *global_props;
 | 
			
		||||
	struct pw_properties *capture_props;
 | 
			
		||||
	struct spa_audio_info_raw info;
 | 
			
		||||
	char *filename;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void module_destroy(void *data)
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +48,6 @@ static int module_pipe_sink_load(struct module *module)
 | 
			
		|||
	FILE *f;
 | 
			
		||||
	char *args;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(data->capture_props, "pulse.module.id",
 | 
			
		||||
			"%u", module->index);
 | 
			
		||||
| 
						 | 
				
			
			@ -58,23 +56,7 @@ static int module_pipe_sink_load(struct module *module)
 | 
			
		|||
		return -errno;
 | 
			
		||||
 | 
			
		||||
	fprintf(f, "{");
 | 
			
		||||
	fprintf(f, " \"tunnel.mode\" = \"sink\" ");
 | 
			
		||||
	if (data->filename != NULL)
 | 
			
		||||
		fprintf(f, " \"pipe.filename\": \"%s\"", data->filename);
 | 
			
		||||
	if (data->info.format != 0)
 | 
			
		||||
		fprintf(f, " \"audio.format\": \"%s\"", format_id2name(data->info.format));
 | 
			
		||||
	if (data->info.rate != 0)
 | 
			
		||||
		fprintf(f, " \"audio.rate\": %u,", data->info.rate);
 | 
			
		||||
	if (data->info.channels != 0) {
 | 
			
		||||
		fprintf(f, " \"audio.channels\": %u,", data->info.channels);
 | 
			
		||||
		if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
 | 
			
		||||
			fprintf(f, " \"audio.position\": [ ");
 | 
			
		||||
			for (i = 0; i < data->info.channels; i++)
 | 
			
		||||
				fprintf(f, "%s\"%s\"", i == 0 ? "" : ",",
 | 
			
		||||
					channel_id2name(data->info.position[i]));
 | 
			
		||||
			fprintf(f, " ],");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->global_props->dict, 0);
 | 
			
		||||
	fprintf(f, " \"stream.props\": {");
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->capture_props->dict, 0);
 | 
			
		||||
	fprintf(f, " } }");
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +87,7 @@ static int module_pipe_sink_unload(struct module *module)
 | 
			
		|||
		d->mod = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	pw_properties_free(d->capture_props);
 | 
			
		||||
	free(d->filename);
 | 
			
		||||
	pw_properties_free(d->global_props);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -126,35 +108,30 @@ static int module_pipe_sink_prepare(struct module * const module)
 | 
			
		|||
{
 | 
			
		||||
	struct module_pipesink_data * const d = module->user_data;
 | 
			
		||||
	struct pw_properties * const props = module->props;
 | 
			
		||||
	struct pw_properties *capture_props = NULL;
 | 
			
		||||
	struct pw_properties *global_props = NULL, *capture_props = NULL;
 | 
			
		||||
	struct spa_audio_info_raw info = { 0 };
 | 
			
		||||
	const char *str;
 | 
			
		||||
	char *filename = NULL;
 | 
			
		||||
	int res = 0;
 | 
			
		||||
 | 
			
		||||
	PW_LOG_TOPIC_INIT(mod_topic);
 | 
			
		||||
 | 
			
		||||
	global_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	capture_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	if (!capture_props) {
 | 
			
		||||
	if (!global_props || !capture_props) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	pw_properties_set(global_props, "tunnel.mode", "sink");
 | 
			
		||||
 | 
			
		||||
	info.format = SPA_AUDIO_FORMAT_S16;
 | 
			
		||||
	if ((str = pw_properties_get(props, "format")) != NULL) {
 | 
			
		||||
		info.format = format_paname2id(str, strlen(str));
 | 
			
		||||
		if (info.format == SPA_AUDIO_FORMAT_UNKNOWN) {
 | 
			
		||||
			pw_log_error("invalid format '%s'", str);
 | 
			
		||||
			res = -EINVAL;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		pw_properties_set(props, "format", NULL);
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			"format", "rate", "channels", "channel_map", &info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	audioinfo_to_properties(&info, global_props);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "sink_name")) != NULL) {
 | 
			
		||||
		pw_properties_set(capture_props, PW_KEY_NODE_NAME, str);
 | 
			
		||||
		pw_properties_set(props, "sink_name", NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +140,7 @@ static int module_pipe_sink_prepare(struct module * const module)
 | 
			
		|||
		module_args_add_props(capture_props, str);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "file")) != NULL) {
 | 
			
		||||
		filename = strdup(str);
 | 
			
		||||
		pw_properties_set(global_props, "pipe.filename", str);
 | 
			
		||||
		pw_properties_set(props, "file", NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if ((str = pw_properties_get(capture_props, PW_KEY_DEVICE_ICON_NAME)) == NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -174,14 +151,13 @@ static int module_pipe_sink_prepare(struct module * const module)
 | 
			
		|||
				"fifo_output");
 | 
			
		||||
 | 
			
		||||
	d->module = module;
 | 
			
		||||
	d->global_props = global_props;
 | 
			
		||||
	d->capture_props = capture_props;
 | 
			
		||||
	d->info = info;
 | 
			
		||||
	d->filename = filename;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
out:
 | 
			
		||||
	pw_properties_free(global_props);
 | 
			
		||||
	pw_properties_free(capture_props);
 | 
			
		||||
	free(filename);
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,9 +25,8 @@ struct module_pipesrc_data {
 | 
			
		|||
	struct spa_hook mod_listener;
 | 
			
		||||
	struct pw_impl_module *mod;
 | 
			
		||||
 | 
			
		||||
	struct pw_properties *global_props;
 | 
			
		||||
	struct pw_properties *playback_props;
 | 
			
		||||
	struct spa_audio_info_raw info;
 | 
			
		||||
	char *filename;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void module_destroy(void *data)
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +48,6 @@ static int module_pipe_source_load(struct module *module)
 | 
			
		|||
	FILE *f;
 | 
			
		||||
	char *args;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(data->playback_props, "pulse.module.id",
 | 
			
		||||
			"%u", module->index);
 | 
			
		||||
| 
						 | 
				
			
			@ -58,23 +56,7 @@ static int module_pipe_source_load(struct module *module)
 | 
			
		|||
		return -errno;
 | 
			
		||||
 | 
			
		||||
	fprintf(f, "{");
 | 
			
		||||
	fprintf(f, " \"tunnel.mode\" = \"source\" ");
 | 
			
		||||
	if (data->filename != NULL)
 | 
			
		||||
		fprintf(f, " \"pipe.filename\": \"%s\"", data->filename);
 | 
			
		||||
	if (data->info.format != 0)
 | 
			
		||||
		fprintf(f, " \"audio.format\": \"%s\"", format_id2name(data->info.format));
 | 
			
		||||
	if (data->info.rate != 0)
 | 
			
		||||
		fprintf(f, " \"audio.rate\": %u,", data->info.rate);
 | 
			
		||||
	if (data->info.channels != 0) {
 | 
			
		||||
		fprintf(f, " \"audio.channels\": %u,", data->info.channels);
 | 
			
		||||
		if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
 | 
			
		||||
			fprintf(f, " \"audio.position\": [ ");
 | 
			
		||||
			for (i = 0; i < data->info.channels; i++)
 | 
			
		||||
				fprintf(f, "%s\"%s\"", i == 0 ? "" : ",",
 | 
			
		||||
					channel_id2name(data->info.position[i]));
 | 
			
		||||
			fprintf(f, " ],");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->global_props->dict, 0);
 | 
			
		||||
	fprintf(f, " \"stream.props\": {");
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->playback_props->dict, 0);
 | 
			
		||||
	fprintf(f, " } }");
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +87,7 @@ static int module_pipe_source_unload(struct module *module)
 | 
			
		|||
		d->mod = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	pw_properties_free(d->playback_props);
 | 
			
		||||
	free(d->filename);
 | 
			
		||||
	pw_properties_free(d->global_props);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -126,35 +108,30 @@ static int module_pipe_source_prepare(struct module * const module)
 | 
			
		|||
{
 | 
			
		||||
	struct module_pipesrc_data * const d = module->user_data;
 | 
			
		||||
	struct pw_properties * const props = module->props;
 | 
			
		||||
	struct pw_properties *playback_props = NULL;
 | 
			
		||||
	struct pw_properties *global_props = NULL, *playback_props = NULL;
 | 
			
		||||
	struct spa_audio_info_raw info = { 0 };
 | 
			
		||||
	const char *str;
 | 
			
		||||
	char *filename = NULL;
 | 
			
		||||
	int res = 0;
 | 
			
		||||
 | 
			
		||||
	PW_LOG_TOPIC_INIT(mod_topic);
 | 
			
		||||
 | 
			
		||||
	global_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	playback_props = pw_properties_new(NULL, NULL);
 | 
			
		||||
	if (!playback_props) {
 | 
			
		||||
	if (!global_props || !playback_props) {
 | 
			
		||||
		res = -errno;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
 | 
			
		||||
	pw_properties_set(global_props, "tunnel.mode", "source");
 | 
			
		||||
 | 
			
		||||
	info.format = SPA_AUDIO_FORMAT_S16;
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			"format", "rate", "channels", "channel_map", &info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	audioinfo_to_properties(&info, global_props);
 | 
			
		||||
 | 
			
		||||
	info.format = SPA_AUDIO_FORMAT_S16;
 | 
			
		||||
	if ((str = pw_properties_get(props, "format")) != NULL) {
 | 
			
		||||
		info.format = format_paname2id(str, strlen(str));
 | 
			
		||||
		if (info.format == SPA_AUDIO_FORMAT_UNKNOWN) {
 | 
			
		||||
			pw_log_error("invalid format '%s'", str);
 | 
			
		||||
			res = -EINVAL;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		pw_properties_set(props, "format", NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if ((str = pw_properties_get(props, "source_name")) != NULL) {
 | 
			
		||||
		pw_properties_set(playback_props, PW_KEY_NODE_NAME, str);
 | 
			
		||||
		pw_properties_set(props, "source_name", NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +140,7 @@ static int module_pipe_source_prepare(struct module * const module)
 | 
			
		|||
		module_args_add_props(playback_props, str);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "file")) != NULL) {
 | 
			
		||||
		filename = strdup(str);
 | 
			
		||||
		pw_properties_set(global_props, "pipe.filename", str);
 | 
			
		||||
		pw_properties_set(props, "file", NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if ((str = pw_properties_get(playback_props, PW_KEY_DEVICE_ICON_NAME)) == NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -175,13 +152,12 @@ static int module_pipe_source_prepare(struct module * const module)
 | 
			
		|||
 | 
			
		||||
	d->module = module;
 | 
			
		||||
	d->playback_props = playback_props;
 | 
			
		||||
	d->info = info;
 | 
			
		||||
	d->filename = filename;
 | 
			
		||||
	d->global_props = global_props;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
out:
 | 
			
		||||
	pw_properties_free(global_props);
 | 
			
		||||
	pw_properties_free(playback_props);
 | 
			
		||||
	free(filename);
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -109,19 +109,6 @@ static const struct spa_dict_item module_remap_sink_info[] = {
 | 
			
		|||
	{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void position_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
 | 
			
		||||
{
 | 
			
		||||
	char *s, *p;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
 | 
			
		||||
	p = s = alloca(info->channels * 8);
 | 
			
		||||
	for (i = 0; i < info->channels; i++)
 | 
			
		||||
		p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
 | 
			
		||||
				channel_id2name(info->position[i]));
 | 
			
		||||
	pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int module_remap_sink_prepare(struct module * const module)
 | 
			
		||||
{
 | 
			
		||||
	struct module_remap_sink_data * const d = module->user_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -180,26 +167,19 @@ static int module_remap_sink_prepare(struct module * const module)
 | 
			
		|||
		pw_properties_set(props, "master", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &capture_info) < 0) {
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			NULL, NULL, "channels", "channel_map", &capture_info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	playback_info = capture_info;
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "master_channel_map")) != NULL) {
 | 
			
		||||
		struct channel_map map;
 | 
			
		||||
 | 
			
		||||
		channel_map_parse(str, &map);
 | 
			
		||||
		if (map.channels == 0 || map.channels > SPA_AUDIO_MAX_CHANNELS) {
 | 
			
		||||
			pw_log_error("invalid channel_map '%s'", str);
 | 
			
		||||
			res = -EINVAL;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		channel_map_to_positions(&map, playback_info.position);
 | 
			
		||||
		pw_properties_set(props, "master_channel_map", NULL);
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			NULL, NULL, NULL, "master_channel_map", &playback_info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	position_to_props(&capture_info, capture_props);
 | 
			
		||||
	position_to_props(&playback_info, playback_props);
 | 
			
		||||
	audioinfo_to_properties(&capture_info, capture_props);
 | 
			
		||||
	audioinfo_to_properties(&playback_info, playback_props);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "remix")) != NULL) {
 | 
			
		||||
		/* Note that the boolean is inverted */
 | 
			
		||||
| 
						 | 
				
			
			@ -219,7 +199,6 @@ static int module_remap_sink_prepare(struct module * const module)
 | 
			
		|||
out:
 | 
			
		||||
	pw_properties_free(playback_props);
 | 
			
		||||
	pw_properties_free(capture_props);
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -109,19 +109,6 @@ static const struct spa_dict_item module_remap_source_info[] = {
 | 
			
		|||
	{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void position_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
 | 
			
		||||
{
 | 
			
		||||
	char *s, *p;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
 | 
			
		||||
	p = s = alloca(info->channels * 8);
 | 
			
		||||
	for (i = 0; i < info->channels; i++)
 | 
			
		||||
		p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
 | 
			
		||||
				channel_id2name(info->position[i]));
 | 
			
		||||
	pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int module_remap_source_prepare(struct module * const module)
 | 
			
		||||
{
 | 
			
		||||
	struct module_remap_source_data * const d = module->user_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -187,26 +174,19 @@ static int module_remap_source_prepare(struct module * const module)
 | 
			
		|||
		pw_properties_set(props, "master", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &playback_info) < 0) {
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			NULL, NULL, "channels", "channel_map", &playback_info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	capture_info = playback_info;
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "master_channel_map")) != NULL) {
 | 
			
		||||
		struct channel_map map;
 | 
			
		||||
 | 
			
		||||
		channel_map_parse(str, &map);
 | 
			
		||||
		if (map.channels == 0 || map.channels > SPA_AUDIO_MAX_CHANNELS) {
 | 
			
		||||
			pw_log_error("invalid channel_map '%s'", str);
 | 
			
		||||
			res = -EINVAL;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		channel_map_to_positions(&map, capture_info.position);
 | 
			
		||||
		pw_properties_set(props, "master_channel_map", NULL);
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			NULL, NULL, NULL, "master_channel_map", &capture_info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	position_to_props(&playback_info, playback_props);
 | 
			
		||||
	position_to_props(&capture_info, capture_props);
 | 
			
		||||
	audioinfo_to_properties(&playback_info, playback_props);
 | 
			
		||||
	audioinfo_to_properties(&capture_info, capture_props);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "remix")) != NULL) {
 | 
			
		||||
		/* Note that the boolean is inverted */
 | 
			
		||||
| 
						 | 
				
			
			@ -226,7 +206,6 @@ static int module_remap_source_prepare(struct module * const module)
 | 
			
		|||
out:
 | 
			
		||||
	pw_properties_free(playback_props);
 | 
			
		||||
	pw_properties_free(capture_props);
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,8 +25,6 @@ struct module_rtp_send_data {
 | 
			
		|||
	struct pw_properties *stream_props;
 | 
			
		||||
	struct pw_properties *global_props;
 | 
			
		||||
	struct pw_properties *sap_props;
 | 
			
		||||
 | 
			
		||||
	struct spa_audio_info_raw info;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void module_destroy(void *data)
 | 
			
		||||
| 
						 | 
				
			
			@ -71,20 +69,6 @@ static int module_rtp_send_load(struct module *module)
 | 
			
		|||
 | 
			
		||||
	fprintf(f, "{");
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->global_props->dict, 0);
 | 
			
		||||
	if (data->info.format != 0)
 | 
			
		||||
		fprintf(f, " \"audio.format\": \"%s\"", format_id2name(data->info.format));
 | 
			
		||||
	if (data->info.rate != 0)
 | 
			
		||||
		fprintf(f, " \"audio.rate\": %u,", data->info.rate);
 | 
			
		||||
	if (data->info.channels != 0) {
 | 
			
		||||
		fprintf(f, " \"audio.channels\": %u,", data->info.channels);
 | 
			
		||||
		if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
 | 
			
		||||
			fprintf(f, " \"audio.position\": [ ");
 | 
			
		||||
			for (i = 0; i < data->info.channels; i++)
 | 
			
		||||
				fprintf(f, "%s\"%s\"", i == 0 ? "" : ",",
 | 
			
		||||
					channel_id2name(data->info.position[i]));
 | 
			
		||||
			fprintf(f, " ],");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	fprintf(f, " stream.props = {");
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->stream_props->dict, 0);
 | 
			
		||||
	fprintf(f, " } }");
 | 
			
		||||
| 
						 | 
				
			
			@ -198,19 +182,13 @@ static int module_rtp_send_prepare(struct module * const module)
 | 
			
		|||
			pw_properties_set(stream_props, PW_KEY_TARGET_OBJECT, str);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
 | 
			
		||||
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			"format", "rate", "channels", "channel_map", &info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	info.format = 0;
 | 
			
		||||
	if ((str = pw_properties_get(props, "format")) != NULL) {
 | 
			
		||||
		if ((info.format = format_paname2id(str, strlen(str))) ==
 | 
			
		||||
				SPA_AUDIO_FORMAT_UNKNOWN) {
 | 
			
		||||
			pw_log_error("unknown format %s", str);
 | 
			
		||||
			res = -EINVAL;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	audioinfo_to_properties(&info, global_props);
 | 
			
		||||
 | 
			
		||||
	pw_properties_set(global_props, "sess.media", "audio");
 | 
			
		||||
	if ((str = pw_properties_get(props, "enable_opus")) != NULL) {
 | 
			
		||||
| 
						 | 
				
			
			@ -245,7 +223,6 @@ static int module_rtp_send_prepare(struct module * const module)
 | 
			
		|||
	d->stream_props = stream_props;
 | 
			
		||||
	d->global_props = global_props;
 | 
			
		||||
	d->sap_props = sap_props;
 | 
			
		||||
	d->info = info;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
out:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,25 +44,12 @@ static int module_simple_protocol_tcp_load(struct module *module)
 | 
			
		|||
	struct impl *impl = module->impl;
 | 
			
		||||
	char *args;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
	FILE *f;
 | 
			
		||||
 | 
			
		||||
	if ((f = open_memstream(&args, &size)) == NULL)
 | 
			
		||||
		return -errno;
 | 
			
		||||
 | 
			
		||||
	fprintf(f, "{");
 | 
			
		||||
	if (data->info.rate != 0)
 | 
			
		||||
		fprintf(f, " \"audio.rate\": %u,", data->info.rate);
 | 
			
		||||
	if (data->info.channels != 0) {
 | 
			
		||||
		fprintf(f, " \"audio.channels\": %u,", data->info.channels);
 | 
			
		||||
		if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
 | 
			
		||||
			fprintf(f, " \"audio.position\": [ ");
 | 
			
		||||
			for (i = 0; i < data->info.channels; i++)
 | 
			
		||||
				fprintf(f, "%s\"%s\"", i == 0 ? "" : ",",
 | 
			
		||||
					channel_id2name(data->info.position[i]));
 | 
			
		||||
			fprintf(f, " ],");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->module_props->dict, 0);
 | 
			
		||||
	fprintf(f, "}");
 | 
			
		||||
	fclose(f);
 | 
			
		||||
| 
						 | 
				
			
			@ -127,15 +114,13 @@ static int module_simple_protocol_tcp_prepare(struct module * const module)
 | 
			
		|||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "format")) != NULL) {
 | 
			
		||||
		pw_properties_set(module_props, "audio.format",
 | 
			
		||||
				format_id2name(format_paname2id(str, strlen(str))));
 | 
			
		||||
		pw_properties_set(props, "format", NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			"format", "rate", "channels", "channel_map", &info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	audioinfo_to_properties(&info, module_props);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "playback")) != NULL) {
 | 
			
		||||
		pw_properties_set(module_props, "playback", str);
 | 
			
		||||
		pw_properties_set(props, "playback", NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,8 +23,6 @@ struct module_tunnel_sink_data {
 | 
			
		|||
	struct pw_impl_module *mod;
 | 
			
		||||
	struct spa_hook mod_listener;
 | 
			
		||||
 | 
			
		||||
	uint32_t latency_msec;
 | 
			
		||||
 | 
			
		||||
	struct pw_properties *stream_props;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,9 +45,6 @@ static int module_tunnel_sink_load(struct module *module)
 | 
			
		|||
	FILE *f;
 | 
			
		||||
	char *args;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	const char *server;
 | 
			
		||||
 | 
			
		||||
	server = pw_properties_get(module->props, "server");
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(data->stream_props, "pulse.module.id",
 | 
			
		||||
			"%u", module->index);
 | 
			
		||||
| 
						 | 
				
			
			@ -59,10 +54,6 @@ static int module_tunnel_sink_load(struct module *module)
 | 
			
		|||
 | 
			
		||||
	fprintf(f, "{");
 | 
			
		||||
	pw_properties_serialize_dict(f, &module->props->dict, 0);
 | 
			
		||||
	fprintf(f, " pulse.server.address = \"%s\" ", server);
 | 
			
		||||
	fprintf(f, " tunnel.mode = sink ");
 | 
			
		||||
	if (data->latency_msec > 0)
 | 
			
		||||
		fprintf(f, " pulse.latency = %u ", data->latency_msec);
 | 
			
		||||
	fprintf(f, " stream.props = {");
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->stream_props->dict, 0);
 | 
			
		||||
	fprintf(f, " } }");
 | 
			
		||||
| 
						 | 
				
			
			@ -115,19 +106,6 @@ static const struct spa_dict_item module_tunnel_sink_info[] = {
 | 
			
		|||
	{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void audio_info_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
 | 
			
		||||
{
 | 
			
		||||
	char *s, *p;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
 | 
			
		||||
	p = s = alloca(info->channels * 8);
 | 
			
		||||
	for (i = 0; i < info->channels; i++)
 | 
			
		||||
		p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
 | 
			
		||||
				channel_id2name(info->position[i]));
 | 
			
		||||
	pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int module_tunnel_sink_prepare(struct module * const module)
 | 
			
		||||
{
 | 
			
		||||
	struct module_tunnel_sink_data * const d = module->user_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -145,6 +123,8 @@ static int module_tunnel_sink_prepare(struct module * const module)
 | 
			
		|||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pw_properties_set(props, "tunnel.mode", "sink");
 | 
			
		||||
 | 
			
		||||
	remote_sink_name = pw_properties_get(props, "sink");
 | 
			
		||||
	if (remote_sink_name)
 | 
			
		||||
		pw_properties_set(props, PW_KEY_TARGET_OBJECT, remote_sink_name);
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +133,8 @@ static int module_tunnel_sink_prepare(struct module * const module)
 | 
			
		|||
		pw_log_error("no server given");
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	} else {
 | 
			
		||||
		pw_properties_set(props, "pulse.server.address", server);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(stream_props, PW_KEY_NODE_DESCRIPTION,
 | 
			
		||||
| 
						 | 
				
			
			@ -167,36 +149,30 @@ static int module_tunnel_sink_prepare(struct module * const module)
 | 
			
		|||
		pw_properties_setf(stream_props, PW_KEY_NODE_NAME,
 | 
			
		||||
				"tunnel-sink.%s", server);
 | 
			
		||||
	}
 | 
			
		||||
	pw_properties_set(props, "server", NULL);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "sink_properties")) != NULL) {
 | 
			
		||||
		module_args_add_props(stream_props, str);
 | 
			
		||||
		pw_properties_set(props, "sink_properties", NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			NULL, NULL, "channels", "channel_map", &info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	audioinfo_to_properties(&info, stream_props);
 | 
			
		||||
 | 
			
		||||
	audio_info_to_props(&info, stream_props);
 | 
			
		||||
	if ((str = pw_properties_get(props, "format")) != NULL) {
 | 
			
		||||
		uint32_t id = format_paname2id(str, strlen(str));
 | 
			
		||||
		if (id == SPA_AUDIO_FORMAT_UNKNOWN) {
 | 
			
		||||
			res = -EINVAL;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pw_properties_set(stream_props, PW_KEY_AUDIO_FORMAT, format_id2name(id));
 | 
			
		||||
	if ((str = pw_properties_get(props, "latency_msec")) != NULL) {
 | 
			
		||||
		pw_properties_set(props, "pulse.latency", str);
 | 
			
		||||
		pw_properties_set(props, "latency_msec", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	d->module = module;
 | 
			
		||||
	d->stream_props = stream_props;
 | 
			
		||||
 | 
			
		||||
	pw_properties_fetch_uint32(props, "latency_msec", &d->latency_msec);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
out:
 | 
			
		||||
	pw_properties_free(stream_props);
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,8 +23,6 @@ struct module_tunnel_source_data {
 | 
			
		|||
	struct pw_impl_module *mod;
 | 
			
		||||
	struct spa_hook mod_listener;
 | 
			
		||||
 | 
			
		||||
	uint32_t latency_msec;
 | 
			
		||||
 | 
			
		||||
	struct pw_properties *stream_props;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,22 +45,15 @@ static int module_tunnel_source_load(struct module *module)
 | 
			
		|||
	FILE *f;
 | 
			
		||||
	char *args;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	const char *server;
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(data->stream_props, "pulse.module.id",
 | 
			
		||||
			"%u", module->index);
 | 
			
		||||
 | 
			
		||||
	server = pw_properties_get(module->props, "server");
 | 
			
		||||
 | 
			
		||||
	if ((f = open_memstream(&args, &size)) == NULL)
 | 
			
		||||
		return -errno;
 | 
			
		||||
 | 
			
		||||
	fprintf(f, "{");
 | 
			
		||||
	pw_properties_serialize_dict(f, &module->props->dict, 0);
 | 
			
		||||
	fprintf(f, " pulse.server.address = \"%s\" ", server);
 | 
			
		||||
	fprintf(f, " tunnel.mode = source ");
 | 
			
		||||
	if (data->latency_msec > 0)
 | 
			
		||||
		fprintf(f, " pulse.latency = %u ", data->latency_msec);
 | 
			
		||||
	fprintf(f, " stream.props = {");
 | 
			
		||||
	pw_properties_serialize_dict(f, &data->stream_props->dict, 0);
 | 
			
		||||
	fprintf(f, " } }");
 | 
			
		||||
| 
						 | 
				
			
			@ -115,19 +106,6 @@ static const struct spa_dict_item module_tunnel_source_info[] = {
 | 
			
		|||
	{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void audio_info_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
 | 
			
		||||
{
 | 
			
		||||
	char *s, *p;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
 | 
			
		||||
	p = s = alloca(info->channels * 8);
 | 
			
		||||
	for (i = 0; i < info->channels; i++)
 | 
			
		||||
		p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
 | 
			
		||||
				channel_id2name(info->position[i]));
 | 
			
		||||
	pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int module_tunnel_source_prepare(struct module * const module)
 | 
			
		||||
{
 | 
			
		||||
	struct module_tunnel_source_data * const d = module->user_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -145,6 +123,8 @@ static int module_tunnel_source_prepare(struct module * const module)
 | 
			
		|||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pw_properties_set(props, "tunnel.mode", "source");
 | 
			
		||||
 | 
			
		||||
	remote_source_name = pw_properties_get(props, "source");
 | 
			
		||||
	if (remote_source_name)
 | 
			
		||||
		pw_properties_set(props, PW_KEY_TARGET_OBJECT, remote_source_name);
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +133,8 @@ static int module_tunnel_source_prepare(struct module * const module)
 | 
			
		|||
		pw_log_error("no server given");
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	} else {
 | 
			
		||||
		pw_properties_set(props, "pulse.server.address", server);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(stream_props, PW_KEY_NODE_DESCRIPTION,
 | 
			
		||||
| 
						 | 
				
			
			@ -171,22 +153,24 @@ static int module_tunnel_source_prepare(struct module * const module)
 | 
			
		|||
		module_args_add_props(stream_props, str);
 | 
			
		||||
		pw_properties_set(props, "source_properties", NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
 | 
			
		||||
	if (module_args_to_audioinfo_keys(module->impl, props,
 | 
			
		||||
			NULL, NULL, "channels", "channel_map", &info) < 0) {
 | 
			
		||||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	audioinfo_to_properties(&info, stream_props);
 | 
			
		||||
 | 
			
		||||
	audio_info_to_props(&info, stream_props);
 | 
			
		||||
	if ((str = pw_properties_get(props, "latency_msec")) != NULL) {
 | 
			
		||||
		pw_properties_set(props, "pulse.latency", str);
 | 
			
		||||
		pw_properties_set(props, "latency_msec", NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	d->module = module;
 | 
			
		||||
	d->stream_props = stream_props;
 | 
			
		||||
 | 
			
		||||
	pw_properties_fetch_uint32(props, "latency_msec", &d->latency_msec);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
out:
 | 
			
		||||
	pw_properties_free(stream_props);
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue