From 37210794d8418bc954aac2f67904bfe71b27e7d2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 4 May 2023 18:43:08 +0200 Subject: [PATCH] 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. --- src/modules/module-protocol-pulse/module.c | 81 +++++++++++++----- src/modules/module-protocol-pulse/module.h | 7 ++ .../modules/module-combine-sink.c | 83 ++++++++++--------- .../modules/module-echo-cancel.c | 31 +++---- .../modules/module-ladspa-sink.c | 20 +---- .../modules/module-ladspa-source.c | 20 +---- .../modules/module-loopback.c | 42 ++++------ .../modules/module-null-sink.c | 30 +------ .../modules/module-pipe-sink.c | 56 ++++--------- .../modules/module-pipe-source.c | 54 ++++-------- .../modules/module-remap-sink.c | 37 ++------- .../modules/module-remap-source.c | 37 ++------- .../modules/module-rtp-send.c | 31 +------ .../modules/module-simple-protocol-tcp.c | 23 +---- .../modules/module-tunnel-sink.c | 46 +++------- .../modules/module-tunnel-source.c | 38 +++------ 16 files changed, 227 insertions(+), 409 deletions(-) diff --git a/src/modules/module-protocol-pulse/module.c b/src/modules/module-protocol-pulse/module.c index 70afff66a..7601f38b8 100644 --- a/src/modules/module-protocol-pulse/module.c +++ b/src/modules/module-protocol-pulse/module.c @@ -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[]; diff --git a/src/modules/module-protocol-pulse/module.h b/src/modules/module-protocol-pulse/module.h index bfb745057..20ad90faf 100644 --- a/src/modules/module-protocol-pulse/module.h +++ b/src/modules/module-protocol-pulse/module.h @@ -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 diff --git a/src/modules/module-protocol-pulse/modules/module-combine-sink.c b/src/modules/module-protocol-pulse/modules/module-combine-sink.c index 136dc36ba..82a8c2266 100644 --- a/src/modules/module-protocol-pulse/modules/module-combine-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-combine-sink.c @@ -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; } diff --git a/src/modules/module-protocol-pulse/modules/module-echo-cancel.c b/src/modules/module-protocol-pulse/modules/module-echo-cancel.c index 2341cdd60..a6b5966cb 100644 --- a/src/modules/module-protocol-pulse/modules/module-echo-cancel.c +++ b/src/modules/module-protocol-pulse/modules/module-echo-cancel.c @@ -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); diff --git a/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c b/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c index 99227524c..5dd26567b 100644 --- a/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c @@ -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"); diff --git a/src/modules/module-protocol-pulse/modules/module-ladspa-source.c b/src/modules/module-protocol-pulse/modules/module-ladspa-source.c index 2a0040066..2e876ae4c 100644 --- a/src/modules/module-protocol-pulse/modules/module-ladspa-source.c +++ b/src/modules/module-protocol-pulse/modules/module-ladspa-source.c @@ -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"); diff --git a/src/modules/module-protocol-pulse/modules/module-loopback.c b/src/modules/module-protocol-pulse/modules/module-loopback.c index 60ff42487..d1285d309 100644 --- a/src/modules/module-protocol-pulse/modules/module-loopback.c +++ b/src/modules/module-protocol-pulse/modules/module-loopback.c @@ -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); diff --git a/src/modules/module-protocol-pulse/modules/module-null-sink.c b/src/modules/module-protocol-pulse/modules/module-null-sink.c index 5af46aac6..15e679d38 100644 --- a/src/modules/module-protocol-pulse/modules/module-null-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-null-sink.c @@ -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"); diff --git a/src/modules/module-protocol-pulse/modules/module-pipe-sink.c b/src/modules/module-protocol-pulse/modules/module-pipe-sink.c index beb7462c3..80f2fb40f 100644 --- a/src/modules/module-protocol-pulse/modules/module-pipe-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-pipe-sink.c @@ -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; } diff --git a/src/modules/module-protocol-pulse/modules/module-pipe-source.c b/src/modules/module-protocol-pulse/modules/module-pipe-source.c index be3bbfd84..0769e1199 100644 --- a/src/modules/module-protocol-pulse/modules/module-pipe-source.c +++ b/src/modules/module-protocol-pulse/modules/module-pipe-source.c @@ -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; } diff --git a/src/modules/module-protocol-pulse/modules/module-remap-sink.c b/src/modules/module-protocol-pulse/modules/module-remap-sink.c index 8b509fa4a..1f40c6520 100644 --- a/src/modules/module-protocol-pulse/modules/module-remap-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-remap-sink.c @@ -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; } diff --git a/src/modules/module-protocol-pulse/modules/module-remap-source.c b/src/modules/module-protocol-pulse/modules/module-remap-source.c index 0778c5f1a..6e806d1b6 100644 --- a/src/modules/module-protocol-pulse/modules/module-remap-source.c +++ b/src/modules/module-protocol-pulse/modules/module-remap-source.c @@ -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; } diff --git a/src/modules/module-protocol-pulse/modules/module-rtp-send.c b/src/modules/module-protocol-pulse/modules/module-rtp-send.c index fad626304..5479f0857 100644 --- a/src/modules/module-protocol-pulse/modules/module-rtp-send.c +++ b/src/modules/module-protocol-pulse/modules/module-rtp-send.c @@ -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: diff --git a/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c b/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c index 247159d81..d0479a788 100644 --- a/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c +++ b/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c @@ -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); diff --git a/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c b/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c index b3f63f61b..758f71c2c 100644 --- a/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c @@ -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; } diff --git a/src/modules/module-protocol-pulse/modules/module-tunnel-source.c b/src/modules/module-protocol-pulse/modules/module-tunnel-source.c index fba392499..1e4a4c19a 100644 --- a/src/modules/module-protocol-pulse/modules/module-tunnel-source.c +++ b/src/modules/module-protocol-pulse/modules/module-tunnel-source.c @@ -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; }