diff --git a/src/modules/module-avb/maap.c b/src/modules/module-avb/maap.c index 866d234c9..b66eb9437 100644 --- a/src/modules/module-avb/maap.c +++ b/src/modules/module-avb/maap.c @@ -4,7 +4,7 @@ #include -#include +#include #include @@ -298,23 +298,26 @@ static int load_state(struct maap *maap) static int save_state(struct maap *maap) { + struct spa_json_builder b; char *ptr; size_t size; - FILE *f; char key[512]; uint32_t count; + int res; - if ((f = open_memstream(&ptr, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &ptr, &size, 0)) < 0) + return res; - fprintf(f, "[ "); - fprintf(f, "{ \"start\": \"%02x:%02x:%02x:%02x:%02x:%02x\", ", + spa_json_builder_array_push(&b, "["); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_stringf(&b, "start", "%02x:%02x:%02x:%02x:%02x:%02x", maap_base[0], maap_base[1], maap_base[2], maap_base[3], (maap->offset >> 8) & 0xff, maap->offset & 0xff); - fprintf(f, " \"count\": %u } ", maap->count); - fprintf(f, "]"); - fclose(f); + spa_json_builder_object_uint(&b, "count", maap->count); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "]"); + spa_json_builder_close(&b); count = pw_properties_set(maap->props, "maap.addresses", ptr); free(ptr); diff --git a/src/modules/module-jackdbus-detect.c b/src/modules/module-jackdbus-detect.c index 622ca6efe..11ad5bdb3 100644 --- a/src/modules/module-jackdbus-detect.c +++ b/src/modules/module-jackdbus-detect.c @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -116,22 +117,21 @@ static const struct pw_impl_module_events tunnelmodule_events = { static int load_jack_tunnel(struct impl *impl) { - FILE *f; + struct spa_json_builder b; char *args; size_t size; int res = 0; - if ((f = open_memstream(&args, &size)) == NULL) { - res = -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) { pw_log_error("Can't open memstream: %m"); goto done; } - fprintf(f, "{"); + spa_json_builder_array_push(&b, "{"); if (impl->properties != NULL) - pw_properties_serialize_dict(f, &impl->properties->dict, 0); - fprintf(f, " }"); - fclose(f); + pw_properties_serialize_dict(b.f, &impl->properties->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); pw_log_info("loading module args:'%s'", args); impl->jack_tunnel = pw_context_load_module(impl->context, diff --git a/src/modules/module-parametric-equalizer.c b/src/modules/module-parametric-equalizer.c index d0f2885ef..9f0ef7247 100644 --- a/src/modules/module-parametric-equalizer.c +++ b/src/modules/module-parametric-equalizer.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include @@ -162,7 +162,7 @@ static const struct pw_impl_module_events filter_chain_module_events = { static int enhance_properties(struct pw_properties *props, const char *key, ...) { - FILE *f; + struct spa_json_builder b; spa_autoptr(pw_properties) p = NULL; char *args = NULL; const char *str; @@ -187,13 +187,12 @@ static int enhance_properties(struct pw_properties *props, const char *key, ...) } va_end(varargs); - if ((f = open_memstream(&args, &size)) == NULL) { - res = -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) { pw_log_error("Can't open memstream: %m"); return res; } - pw_properties_serialize_dict(f, &p->dict, PW_PROPERTIES_FLAG_ENCLOSE); - fclose(f); + pw_properties_serialize_dict(b.f, &p->dict, PW_PROPERTIES_FLAG_ENCLOSE); + spa_json_builder_close(&b); pw_properties_set(props, key, args); free(args); @@ -202,12 +201,11 @@ static int enhance_properties(struct pw_properties *props, const char *key, ...) static int create_eq_filter(struct impl *impl, const char *filename) { - FILE *f = NULL; + struct spa_json_builder b; const char* str; char *args = NULL; size_t size; int32_t res = 0; - char path[PATH_MAX]; if ((str = pw_properties_get(impl->props, "equalizer.description")) != NULL) { if (pw_properties_get(impl->props, PW_KEY_NODE_DESCRIPTION) == NULL) @@ -216,47 +214,47 @@ static int create_eq_filter(struct impl *impl, const char *filename) pw_properties_set(impl->props, PW_KEY_MEDIA_NAME, str); } - spa_json_encode_string(path, sizeof(path), filename); - pw_properties_setf(impl->props, "filter.graph", - "{" - " nodes = [ " - " { type = builtin name = eq label = param_eq " - " config = { filename = %s } " - " } " - " ] " - "}", path); - enhance_properties(impl->props, "capture.props", PW_KEY_MEDIA_CLASS, "Audio/Sink", NULL); enhance_properties(impl->props, "playback.props", PW_KEY_NODE_PASSIVE, "true", NULL); - if ((f = open_memstream(&args, &size)) == NULL) { - res = -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) { pw_log_error("Can't open memstream: %m"); - goto done; + return res; } - pw_properties_serialize_dict(f, &impl->props->dict, PW_PROPERTIES_FLAG_ENCLOSE); - fclose(f); + + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_push(&b, "filter.graph", "{"); + spa_json_builder_object_push(&b, "nodes", "["); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_string(&b, "type", "builtin"); + spa_json_builder_object_string(&b, "name", "eq"); + spa_json_builder_object_string(&b, "label", "param_eq"); + spa_json_builder_object_push(&b, "config", "{"); + spa_json_builder_object_string(&b, "filename", filename); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "]"); + spa_json_builder_pop(&b, "}"); + pw_properties_serialize_dict(b.f, &impl->props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); pw_log_info("loading new module-filter-chain with args: %s", args); impl->eq_module = pw_context_load_module(impl->context, "libpipewire-module-filter-chain", args, NULL); + free(args); + if (!impl->eq_module) { - res = -errno; pw_log_error("Can't load module: %m"); - goto done; + return -errno; } pw_log_info("loaded new module-filter-chain"); pw_impl_module_add_listener(impl->eq_module, &impl->eq_module_listener, &filter_chain_module_events, impl); - - res = 0; - -done: - free(args); - return res; + return 0; } static void core_error(void *data, uint32_t id, int seq, int res, const char *message) diff --git a/src/modules/module-protocol-pulse/format.c b/src/modules/module-protocol-pulse/format.c index 99e8919c7..56f164469 100644 --- a/src/modules/module-protocol-pulse/format.c +++ b/src/modules/module-protocol-pulse/format.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include "format.h" @@ -703,18 +703,19 @@ static int add_int(struct format_info *info, const char *k, struct spa_pod *para break; case SPA_CHOICE_Enum: { + struct spa_json_builder b; char *ptr; size_t size; - FILE *f; + int res; - if ((f = open_memstream(&ptr, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &ptr, &size, 0)) < 0) + return res; - fprintf(f, "["); + spa_json_builder_array_push(&b, "["); for (i = 1; i < n_values; i++) - fprintf(f, "%s %d", i == 1 ? "" : ",", values[i]); - fprintf(f, " ]"); - fclose(f); + spa_json_builder_array_int(&b, values[i]); + spa_json_builder_pop(&b, "]"); + spa_json_builder_close(&b); pw_properties_set(info->props, k, ptr); free(ptr); diff --git a/src/modules/module-protocol-pulse/modules/module-always-sink.c b/src/modules/module-protocol-pulse/modules/module-always-sink.c index f51c39df8..a57c263af 100644 --- a/src/modules/module-protocol-pulse/modules/module-always-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-always-sink.c @@ -2,7 +2,7 @@ /* SPDX-FileCopyrightText: Copyright © 2022 Wim Taymans */ /* SPDX-License-Identifier: MIT */ -#include +#include #include #include "../module.h" @@ -48,22 +48,20 @@ static const struct pw_impl_module_events module_events = { static int module_always_sink_load(struct module *module) { struct module_always_sink_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; const char *str; - char encoded[1024]; size_t size; + int res; - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - if ((str = pw_properties_get(module->props, "sink_name")) != NULL) { - spa_json_encode_string(encoded, sizeof(encoded), str); - fprintf(f, " sink.name = %s", encoded); - } - fprintf(f, " }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + if ((str = pw_properties_get(module->props, "sink_name")) != NULL) + spa_json_builder_object_string(&b, "sink.name", str); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-fallback-sink", 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 b19d0b552..809dd7bd0 100644 --- a/src/modules/module-protocol-pulse/modules/module-combine-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-combine-sink.c @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -155,8 +156,9 @@ static const struct pw_impl_module_events module_events = { static int module_combine_sink_load(struct module *module) { struct module_combine_sink_data *data = module->user_data; + struct spa_json_builder b; uint32_t i; - FILE *f; + int res; char *args; size_t size; @@ -169,33 +171,41 @@ static int module_combine_sink_load(struct module *module) pw_properties_setf(data->stream_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &data->props->dict, 0); - fprintf(f, " combine.props = {"); - pw_properties_serialize_dict(f, &data->combine_props->dict, 0); - fprintf(f, " } stream.props = {"); - pw_properties_serialize_dict(f, &data->stream_props->dict, 0); - fprintf(f, " } stream.rules = ["); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->props->dict, 0); + spa_json_builder_object_push(&b, "combine.props", "{"); + pw_properties_serialize_dict(b.f, &data->combine_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "stream.props", "{"); + pw_properties_serialize_dict(b.f, &data->stream_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "stream.rules", "["); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_push(&b, "matches", "["); if (data->sink_names == NULL) { - fprintf(f, " { matches = [ { media.class = \"Audio/Sink\" } ]"); - fprintf(f, " actions = { create-stream = { } } }"); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_string(&b, "media.class", "Audio/Sink"); + spa_json_builder_pop(&b, "}"); } else { for (i = 0; data->sink_names[i] != NULL; i++) { - char name[1024]; - if (spa_json_encode_string(name, sizeof(name), data->sink_names[i]) >= (int)sizeof(name)) - continue; - - fprintf(f, " { matches = [ { media.class = \"Audio/Sink\" "); - fprintf(f, " node.name = %s } ]", name); - fprintf(f, " actions = { create-stream = { } } }"); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_string(&b, "media.class", "Audio/Sink"); + spa_json_builder_object_string(&b, "node.name", data->sink_names[i]); + spa_json_builder_pop(&b, "}"); } } - fprintf(f, " ]"); - fprintf(f, "}"); - fclose(f); + spa_json_builder_pop(&b, "]"); + spa_json_builder_object_push(&b, "actions", "{"); + spa_json_builder_object_push(&b, "create-stream", "{"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "]"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-combine-stream", 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 b3a11c339..ee1eb1671 100644 --- a/src/modules/module-protocol-pulse/modules/module-echo-cancel.c +++ b/src/modules/module-protocol-pulse/modules/module-echo-cancel.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include "../defs.h" @@ -87,33 +87,38 @@ static const struct pw_impl_module_events module_events = { static int module_echo_cancel_load(struct module *module) { struct module_echo_cancel_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); pw_properties_setf(data->source_props, "pulse.module.id", "%u", module->index); pw_properties_setf(data->sink_props, "pulse.module.id", "%u", module->index); pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - 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, " }"); - fprintf(f, " capture.props = {"); - pw_properties_serialize_dict(f, &data->capture_props->dict, 0); - fprintf(f, " } source.props = {"); - pw_properties_serialize_dict(f, &data->source_props->dict, 0); - fprintf(f, " } sink.props = {"); - pw_properties_serialize_dict(f, &data->sink_props->dict, 0); - fprintf(f, " } playback.props = {"); - pw_properties_serialize_dict(f, &data->playback_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->global_props->dict, 0); + spa_json_builder_object_push(&b, "aec.args", "{"); + pw_properties_serialize_dict(b.f, &data->props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "capture.props", "{"); + pw_properties_serialize_dict(b.f, &data->capture_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "source.props", "{"); + pw_properties_serialize_dict(b.f, &data->source_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "sink.props", "{"); + pw_properties_serialize_dict(b.f, &data->sink_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "playback.props", "{"); + pw_properties_serialize_dict(b.f, &data->playback_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-echo-cancel", @@ -176,40 +181,41 @@ static int parse_point(const char **point, float f[3]) static int rename_geometry(struct pw_properties *props, const char *pa_key, const char *pw_key) { const char *str; - int i = 0, len; + int i = 0, len, res; char *args; size_t size; - FILE *f; + struct spa_json_builder b; if ((str = pw_properties_get(props, pa_key)) == NULL) return 0; pw_log_info("geometry: %s", str); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "["); + spa_json_builder_array_push(&b, "["); while (true) { float p[3]; - char ps0[64], ps1[64], ps2[64]; if ((len = parse_point(&str, p)) < 0) break; pw_log_info("Got mic #%d position: (%g, %g, %g)", i, p[0], p[1], p[2]); - fprintf(f, "%s [ %s, %s, %s ]", i == 0 ? "" : ",", - spa_dtoa(ps0, sizeof(ps0), p[0]), - spa_dtoa(ps1, sizeof(ps1), p[1]), - spa_dtoa(ps2, sizeof(ps2), p[2])); + spa_json_builder_array_push(&b, "["); + spa_json_builder_array_double(&b, p[0]); + spa_json_builder_array_double(&b, p[1]); + spa_json_builder_array_double(&b, p[2]); + spa_json_builder_pop(&b, "]"); + str += len; if (*str != ',') break; str++; i++; } - fprintf(f, " ]"); - fclose(f); + spa_json_builder_pop(&b, "]"); + spa_json_builder_close(&b); pw_properties_set(props, pw_key, args); free(args); diff --git a/src/modules/module-protocol-pulse/modules/module-jackdbus-detect.c b/src/modules/module-protocol-pulse/modules/module-jackdbus-detect.c index c015673f9..cf07a7bcb 100644 --- a/src/modules/module-protocol-pulse/modules/module-jackdbus-detect.c +++ b/src/modules/module-protocol-pulse/modules/module-jackdbus-detect.c @@ -3,6 +3,7 @@ /* SPDX-License-Identifier: MIT */ #include +#include #include #include "../defs.h" @@ -70,26 +71,29 @@ static const struct pw_impl_module_events module_events = { static int module_jackdbus_detect_load(struct module *module) { struct module_jackdbus_detect_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->sink_props, "pulse.module.id", "%u", module->index); pw_properties_setf(data->source_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &data->props->dict, 0); - fprintf(f, " source.props = {"); - pw_properties_serialize_dict(f, &data->source_props->dict, 0); - fprintf(f, " } sink.props = {"); - pw_properties_serialize_dict(f, &data->sink_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->props->dict, 0); + spa_json_builder_object_push(&b, "source.props", "{"); + pw_properties_serialize_dict(b.f, &data->source_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "sink.props", "{"); + pw_properties_serialize_dict(b.f, &data->sink_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-jackdbus-detect", 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 4c9f33c47..049433add 100644 --- a/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c @@ -3,7 +3,7 @@ /* SPDX-License-Identifier: MIT */ #include -#include +#include #include #include @@ -73,11 +73,11 @@ static const struct pw_impl_module_events module_events = { static int module_ladspa_sink_load(struct module *module) { struct module_ladspa_sink_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; const char *str, *plugin, *label; - char encoded_plugin[1024], encoded_label[1024]; size_t size; + int res; if ((plugin = pw_properties_get(module->props, "plugin")) == NULL) return -EINVAL; @@ -89,43 +89,59 @@ static int module_ladspa_sink_load(struct module *module) pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &module->props->dict, 0); - fprintf(f, " filter.graph = {"); - fprintf(f, " nodes = [ { "); - spa_json_encode_string(encoded_plugin, sizeof(encoded_plugin), plugin); - spa_json_encode_string(encoded_label, sizeof(encoded_label), label); - - fprintf(f, " type = ladspa "); - fprintf(f, " plugin = %s ", encoded_plugin); - fprintf(f, " label = %s ", encoded_label); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &module->props->dict, 0); + spa_json_builder_object_push(&b, "filter.graph", "{"); + spa_json_builder_object_push(&b, "nodes", "["); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_string(&b, "type", "ladspa"); + spa_json_builder_object_string(&b, "plugin", plugin); + spa_json_builder_object_string(&b, "label", label); if ((str = pw_properties_get(module->props, "control")) != NULL) { + int count = 0; size_t len; const char *s, *state = NULL; - int count = 0; - fprintf(f, " control = {"); + spa_json_builder_object_push(&b, "control", "{"); while ((s = pw_split_walk(str, ", ", &len, &state))) { - fprintf(f, " \"%d\" = %.*s", count, (int)len, s); + char key[16]; + snprintf(key, sizeof(key), "%d", count); + spa_json_builder_object_value_full(&b, false, + key, INT_MAX, s, len); count++; } - fprintf(f, " }"); + spa_json_builder_pop(&b, "}"); } - fprintf(f, " } ]"); - if ((str = pw_properties_get(module->props, "inputs")) != NULL) - fprintf(f, " inputs = [ %s ] ", str); - if ((str = pw_properties_get(module->props, "outputs")) != NULL) - fprintf(f, " outputs = [ %s ] ", str); - fprintf(f, " }"); - fprintf(f, " capture.props = {"); - pw_properties_serialize_dict(f, &data->capture_props->dict, 0); - fprintf(f, " } playback.props = {"); - pw_properties_serialize_dict(f, &data->playback_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "]"); + if ((str = pw_properties_get(module->props, "input_ladspaport_map")) != NULL) { + const char *s, *state = NULL; + size_t len; + spa_json_builder_object_push(&b, "inputs", "["); + while ((s = pw_split_walk(str, ", ", &len, &state))) + spa_json_builder_add_simple(&b, NULL, 0, 'S', s, len); + spa_json_builder_pop(&b, "]"); + } + if ((str = pw_properties_get(module->props, "output_ladspaport_map")) != NULL) { + const char *s, *state = NULL; + size_t len; + spa_json_builder_object_push(&b, "outputs", "["); + while ((s = pw_split_walk(str, ", ", &len, &state))) + spa_json_builder_add_simple(&b, NULL, 0, 'S', s, len); + spa_json_builder_pop(&b, "]"); + } + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "capture.props", "{"); + pw_properties_serialize_dict(b.f, &data->capture_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "playback.props", "{"); + pw_properties_serialize_dict(b.f, &data->playback_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-filter-chain", 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 d4883b551..94b3c428c 100644 --- a/src/modules/module-protocol-pulse/modules/module-ladspa-source.c +++ b/src/modules/module-protocol-pulse/modules/module-ladspa-source.c @@ -3,7 +3,7 @@ /* SPDX-License-Identifier: MIT */ #include -#include +#include #include #include @@ -73,11 +73,11 @@ static const struct pw_impl_module_events module_events = { static int module_ladspa_source_load(struct module *module) { struct module_ladspa_source_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; const char *str, *plugin, *label; - char encoded_plugin[1024], encoded_label[1024]; size_t size; + int res; if ((plugin = pw_properties_get(module->props, "plugin")) == NULL) return -EINVAL; @@ -89,43 +89,59 @@ static int module_ladspa_source_load(struct module *module) pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &module->props->dict, 0); - fprintf(f, " filter.graph = {"); - fprintf(f, " nodes = [ { "); - spa_json_encode_string(encoded_plugin, sizeof(encoded_plugin), plugin); - spa_json_encode_string(encoded_label, sizeof(encoded_label), label); - - fprintf(f, " type = ladspa "); - fprintf(f, " plugin = %s ", encoded_plugin); - fprintf(f, " label = %s ", encoded_label); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &module->props->dict, 0); + spa_json_builder_object_push(&b, "filter.graph", "{"); + spa_json_builder_object_push(&b, "nodes", "["); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_string(&b, "type", "ladspa"); + spa_json_builder_object_string(&b, "plugin", plugin); + spa_json_builder_object_string(&b, "label", label); if ((str = pw_properties_get(module->props, "control")) != NULL) { size_t len; const char *s, *state = NULL; int count = 0; - fprintf(f, " control = {"); + spa_json_builder_object_push(&b, "control", "{"); while ((s = pw_split_walk(str, ", ", &len, &state))) { - fprintf(f, " \"%d\" = %.*s", count, (int)len, s); + char key[16]; + snprintf(key, sizeof(key), "%d", count); + spa_json_builder_object_value_full(&b, false, + key, INT_MAX, s, len); count++; } - fprintf(f, " }"); + spa_json_builder_pop(&b, "}"); } - fprintf(f, " } ]"); - if ((str = pw_properties_get(module->props, "inputs")) != NULL) - fprintf(f, " inputs = [ %s ] ", str); - if ((str = pw_properties_get(module->props, "outputs")) != NULL) - fprintf(f, " outputs = [ %s ] ", str); - fprintf(f, " }"); - fprintf(f, " capture.props = {"); - pw_properties_serialize_dict(f, &data->capture_props->dict, 0); - fprintf(f, " } playback.props = {"); - pw_properties_serialize_dict(f, &data->playback_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "]"); + if ((str = pw_properties_get(module->props, "input_ladspaport_map")) != NULL) { + const char *s, *state = NULL; + size_t len; + spa_json_builder_object_push(&b, "inputs", "["); + while ((s = pw_split_walk(str, ", ", &len, &state))) + spa_json_builder_add_simple(&b, NULL, 0, 'S', s, len); + spa_json_builder_pop(&b, "]"); + } + if ((str = pw_properties_get(module->props, "output_ladspaport_map")) != NULL) { + const char *s, *state = NULL; + size_t len; + spa_json_builder_object_push(&b, "outputs", "["); + while ((s = pw_split_walk(str, ", ", &len, &state))) + spa_json_builder_add_simple(&b, NULL, 0, 'S', s, len); + spa_json_builder_pop(&b, "]"); + } + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "capture.props", "{"); + pw_properties_serialize_dict(b.f, &data->capture_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "playback.props", "{"); + pw_properties_serialize_dict(b.f, &data->playback_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-filter-chain", diff --git a/src/modules/module-protocol-pulse/modules/module-loopback.c b/src/modules/module-protocol-pulse/modules/module-loopback.c index 2ef85fa5e..5808e196e 100644 --- a/src/modules/module-protocol-pulse/modules/module-loopback.c +++ b/src/modules/module-protocol-pulse/modules/module-loopback.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include "../defs.h" @@ -71,26 +71,29 @@ static const struct pw_impl_module_events module_events = { static int module_loopback_load(struct module *module) { struct module_loopback_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; 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); pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - 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 = {"); - pw_properties_serialize_dict(f, &data->playback_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->global_props->dict, 0); + spa_json_builder_object_push(&b, "capture.props", "{"); + pw_properties_serialize_dict(b.f, &data->capture_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "playback.props", "{"); + pw_properties_serialize_dict(b.f, &data->playback_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-loopback", diff --git a/src/modules/module-protocol-pulse/modules/module-native-protocol-tcp.c b/src/modules/module-protocol-pulse/modules/module-native-protocol-tcp.c index 1d0fbb5ab..071322658 100644 --- a/src/modules/module-protocol-pulse/modules/module-native-protocol-tcp.c +++ b/src/modules/module-protocol-pulse/modules/module-native-protocol-tcp.c @@ -2,7 +2,7 @@ /* SPDX-FileCopyrightText: Copyright © 2021 Wim Taymans */ /* SPDX-License-Identifier: MIT */ -#include +#include #include #include "../module.h" @@ -79,10 +79,10 @@ static int module_native_protocol_tcp_prepare(struct module * const module) struct module_native_protocol_tcp_data * const d = module->user_data; struct pw_properties * const props = module->props; const char *port, *listen, *auth; - char address[1024], encoded[1024]; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; PW_LOG_TOPIC_INIT(mod_topic); @@ -93,20 +93,18 @@ static int module_native_protocol_tcp_prepare(struct module * const module) auth = pw_properties_get(props, "auth-anonymous"); - f = open_memstream(&args, &size); - if (f == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - snprintf(address, sizeof(address), "tcp:%s%s%s", + spa_json_builder_array_push(&b, "["); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_stringf(&b, "address", "tcp:%s%s%s", listen ? listen : "", listen ? ":" : "", port); - spa_json_encode_string(encoded, sizeof(encoded), address); - - fprintf(f, "[ { "); - fprintf(f, " \"address\": %s ", encoded); if (auth && module_args_parse_bool(auth)) - fprintf(f, " \"client.access\": \"unrestricted\" "); - fprintf(f, "} ]"); - fclose(f); + spa_json_builder_object_string(&b, "client.access", "unrestricted"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "]"); + spa_json_builder_close(&b); pw_properties_set(props, "pulse.tcp", args); free(args); 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 0f910ac6b..c80caecc0 100644 --- a/src/modules/module-protocol-pulse/modules/module-pipe-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-pipe-sink.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -70,22 +71,24 @@ static const struct pw_impl_module_events module_events = { static int module_pipe_sink_load(struct module *module) { struct module_pipesink_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->stream_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &data->global_props->dict, 0); - fprintf(f, " \"stream.props\": {"); - pw_properties_serialize_dict(f, &data->stream_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->global_props->dict, 0); + spa_json_builder_object_push(&b, "stream.props", "{"); + pw_properties_serialize_dict(b.f, &data->stream_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-pipe-tunnel", 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 ff44f3c38..4e69d1d6b 100644 --- a/src/modules/module-protocol-pulse/modules/module-pipe-source.c +++ b/src/modules/module-protocol-pulse/modules/module-pipe-source.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -69,22 +70,24 @@ static const struct pw_impl_module_events module_events = { static int module_pipe_source_load(struct module *module) { struct module_pipesrc_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->stream_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &data->global_props->dict, 0); - fprintf(f, " \"stream.props\": {"); - pw_properties_serialize_dict(f, &data->stream_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->global_props->dict, 0); + spa_json_builder_object_push(&b, "stream.props", "{"); + pw_properties_serialize_dict(b.f, &data->stream_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-pipe-tunnel", diff --git a/src/modules/module-protocol-pulse/modules/module-raop-discover.c b/src/modules/module-protocol-pulse/modules/module-raop-discover.c index 4e1cf8adb..d1c06e183 100644 --- a/src/modules/module-protocol-pulse/modules/module-raop-discover.c +++ b/src/modules/module-protocol-pulse/modules/module-raop-discover.c @@ -3,6 +3,7 @@ /* SPDX-License-Identifier: MIT */ #include +#include #include #include "../defs.h" @@ -54,18 +55,19 @@ static const struct pw_impl_module_events module_events = { static int module_raop_discover_load(struct module *module) { struct module_raop_discover_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); + spa_json_builder_array_push(&b, "{"); if (data->latency_msec > 0) - fprintf(f, " raop.latency.ms = %u ", data->latency_msec); - fprintf(f, "}"); - fclose(f); + spa_json_builder_object_uint(&b, "raop.latency.ms", data->latency_msec); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-raop-discover", 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 103579fe2..92feb5543 100644 --- a/src/modules/module-protocol-pulse/modules/module-remap-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-remap-sink.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include "../defs.h" @@ -68,26 +68,29 @@ static const struct pw_impl_module_events module_events = { static int module_remap_sink_load(struct module *module) { struct module_remap_sink_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->index); pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->index); pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &module->props->dict, 0); - fprintf(f, " capture.props = {"); - pw_properties_serialize_dict(f, &data->capture_props->dict, 0); - fprintf(f, " } playback.props = {"); - pw_properties_serialize_dict(f, &data->playback_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &module->props->dict, 0); + spa_json_builder_object_push(&b, "capture.props", "{"); + pw_properties_serialize_dict(b.f, &data->capture_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "playback.props", "{"); + pw_properties_serialize_dict(b.f, &data->playback_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-loopback", 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 eaff91b08..d67f150df 100644 --- a/src/modules/module-protocol-pulse/modules/module-remap-source.c +++ b/src/modules/module-protocol-pulse/modules/module-remap-source.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include "../defs.h" @@ -68,26 +68,29 @@ static const struct pw_impl_module_events module_events = { static int module_remap_source_load(struct module *module) { struct module_remap_source_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->index); pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->index); pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &module->props->dict, 0); - fprintf(f, " capture.props = { "); - pw_properties_serialize_dict(f, &data->capture_props->dict, 0); - fprintf(f, " } playback.props = { "); - pw_properties_serialize_dict(f, &data->playback_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &module->props->dict, 0); + spa_json_builder_object_push(&b, "capture.props", "{"); + pw_properties_serialize_dict(b.f, &data->capture_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "playback.props", "{"); + pw_properties_serialize_dict(b.f, &data->playback_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-loopback", diff --git a/src/modules/module-protocol-pulse/modules/module-roc-sink-input.c b/src/modules/module-protocol-pulse/modules/module-roc-sink-input.c index 2200a7bfc..76e6eebba 100644 --- a/src/modules/module-protocol-pulse/modules/module-roc-sink-input.c +++ b/src/modules/module-protocol-pulse/modules/module-roc-sink-input.c @@ -4,6 +4,7 @@ /* SPDX-License-Identifier: MIT */ #include +#include #include #include "../defs.h" @@ -67,22 +68,24 @@ static const struct pw_impl_module_events module_events = { static int module_roc_sink_input_load(struct module *module) { struct module_roc_sink_input_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->source_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &data->roc_props->dict, 0); - fprintf(f, " source.props = {"); - pw_properties_serialize_dict(f, &data->source_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->roc_props->dict, 0); + spa_json_builder_object_push(&b, "source.props", "{"); + pw_properties_serialize_dict(b.f, &data->source_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-roc-source", diff --git a/src/modules/module-protocol-pulse/modules/module-roc-sink.c b/src/modules/module-protocol-pulse/modules/module-roc-sink.c index 6b03006ab..bdddadda2 100644 --- a/src/modules/module-protocol-pulse/modules/module-roc-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-roc-sink.c @@ -4,6 +4,7 @@ /* SPDX-License-Identifier: MIT */ #include +#include #include #include "../defs.h" @@ -65,22 +66,24 @@ static const struct pw_impl_module_events module_events = { static int module_roc_sink_load(struct module *module) { struct module_roc_sink_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->sink_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &data->roc_props->dict, 0); - fprintf(f, " sink.props = {"); - pw_properties_serialize_dict(f, &data->sink_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->roc_props->dict, 0); + spa_json_builder_object_push(&b, "sink.props", "{"); + pw_properties_serialize_dict(b.f, &data->sink_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-roc-sink", diff --git a/src/modules/module-protocol-pulse/modules/module-roc-source.c b/src/modules/module-protocol-pulse/modules/module-roc-source.c index 661153d1e..4607ffbd6 100644 --- a/src/modules/module-protocol-pulse/modules/module-roc-source.c +++ b/src/modules/module-protocol-pulse/modules/module-roc-source.c @@ -4,6 +4,7 @@ /* SPDX-License-Identifier: MIT */ #include +#include #include #include "../defs.h" @@ -67,22 +68,24 @@ static const struct pw_impl_module_events module_events = { static int module_roc_source_load(struct module *module) { struct module_roc_source_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->source_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &data->roc_props->dict, 0); - fprintf(f, " source.props = {"); - pw_properties_serialize_dict(f, &data->source_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->roc_props->dict, 0); + spa_json_builder_object_push(&b, "source.props", "{"); + pw_properties_serialize_dict(b.f, &data->source_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-roc-source", diff --git a/src/modules/module-protocol-pulse/modules/module-rtp-recv.c b/src/modules/module-protocol-pulse/modules/module-rtp-recv.c index f81e19047..fc6e2491c 100644 --- a/src/modules/module-protocol-pulse/modules/module-rtp-recv.c +++ b/src/modules/module-protocol-pulse/modules/module-rtp-recv.c @@ -3,6 +3,7 @@ /* SPDX-License-Identifier: MIT */ #include +#include #include #include "../defs.h" @@ -60,25 +61,35 @@ static const struct pw_impl_module_events module_events = { static int module_rtp_recv_load(struct module *module) { struct module_rtp_recv_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->stream_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &data->global_props->dict, 0); - fprintf(f, " stream.rules = "); - fprintf(f, "[ { matches = [ { rtp.session = \"~.*\" } ] "), - fprintf(f, " actions = { create-stream = { "); - pw_properties_serialize_dict(f, &data->stream_props->dict, 0); - fprintf(f, " } } } ] "); - fprintf(f, " }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->global_props->dict, 0); + spa_json_builder_object_push(&b, "stream.rules", "["); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_push(&b, "matches", "["); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_string(&b, "rtp.session", "~.*"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "]"); + spa_json_builder_object_push(&b, "actions", "{"); + spa_json_builder_object_push(&b, "create-stream", "{"); + pw_properties_serialize_dict(b.f, &data->stream_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "]"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-rtp-sap", 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 aa4015d12..3a6d1d6c6 100644 --- a/src/modules/module-protocol-pulse/modules/module-rtp-send.c +++ b/src/modules/module-protocol-pulse/modules/module-rtp-send.c @@ -3,6 +3,7 @@ /* SPDX-License-Identifier: MIT */ #include +#include #include #include "../defs.h" @@ -87,22 +88,24 @@ static const struct pw_impl_module_events sap_module_events = { static int module_rtp_send_load(struct module *module) { struct module_rtp_send_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->stream_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &data->global_props->dict, 0); - fprintf(f, " stream.props = {"); - pw_properties_serialize_dict(f, &data->stream_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->global_props->dict, 0); + spa_json_builder_object_push(&b, "stream.props", "{"); + pw_properties_serialize_dict(b.f, &data->stream_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-rtp-sink", @@ -116,16 +119,26 @@ static int module_rtp_send_load(struct module *module) &data->mod_listener, &module_events, data); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &data->sap_props->dict, 0); - fprintf(f, " stream.rules = ["); - fprintf(f, " { matches = [ { pulse.module.id = %u } ] ", module->index); - fprintf(f, " actions = { announce-stream = { } } "); - fprintf(f, " } ] }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->sap_props->dict, 0); + spa_json_builder_object_push(&b, "stream.rules", "["); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_push(&b, "matches", "["); + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_uint(&b, "pulse.module.id", module->index); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "]"); + spa_json_builder_object_push(&b, "actions", "{"); + spa_json_builder_object_push(&b, "announce-stream", "{"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "]"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->sap = pw_context_load_module(module->impl->context, "libpipewire-module-rtp-sap", 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 852cd87ab..edc52af07 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 @@ -2,7 +2,7 @@ /* SPDX-FileCopyrightText: Copyright © 2021 Wim Taymans */ /* SPDX-License-Identifier: MIT */ -#include +#include #include #include @@ -70,17 +70,18 @@ static int module_simple_protocol_tcp_load(struct module *module) { struct module_simple_protocol_tcp_data *data = module->user_data; struct impl *impl = module->impl; + struct spa_json_builder b; char *args; size_t size; - FILE *f; + int res; - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &data->module_props->dict, 0); - fprintf(f, "}"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->module_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(impl->context, "libpipewire-module-protocol-simple", @@ -171,11 +172,21 @@ static int module_simple_protocol_tcp_prepare(struct module * const module) listen = pw_properties_get(props, "listen"); { - char address[1024], encoded[1024]; - snprintf(address, sizeof(address), "tcp:%s%s%s", + struct spa_json_builder ab; + char *addr; + size_t addr_size; + + if ((res = spa_json_builder_memstream(&ab, &addr, &addr_size, 0)) < 0) + goto out; + + spa_json_builder_array_push(&ab, "["); + spa_json_builder_array_stringf(&ab, "tcp:%s%s%s", listen ? listen : "", listen ? ":" : "", port); - spa_json_encode_string(encoded, sizeof(encoded), address); - pw_properties_setf(module_props, "server.address", "[ %s ]", encoded); + spa_json_builder_pop(&ab, "]"); + spa_json_builder_close(&ab); + + pw_properties_set(module_props, "server.address", addr); + free(addr); } d->module = module; diff --git a/src/modules/module-protocol-pulse/modules/module-stream-restore.c b/src/modules/module-protocol-pulse/modules/module-stream-restore.c index 3304a0dec..a56a8e5f3 100644 --- a/src/modules/module-protocol-pulse/modules/module-stream-restore.c +++ b/src/modules/module-protocol-pulse/modules/module-stream-restore.c @@ -64,7 +64,7 @@ enum { #include #include #include -#include +#include #include #include @@ -262,10 +262,9 @@ static int do_extension_stream_restore_write(struct module *module, struct clien struct volume vol; bool mute = false; uint32_t i; - FILE *f; char *ptr; size_t size; - char key[1024], buf[128]; + char key[1024]; spa_zero(map); spa_zero(vol); @@ -282,35 +281,36 @@ static int do_extension_stream_restore_write(struct module *module, struct clien if (name == NULL || name[0] == '\0') return -EPROTO; - if ((f = open_memstream(&ptr, &size)) == NULL) - return -errno; + { + struct spa_json_builder b; + int bres; - fprintf(f, "{"); - fprintf(f, " \"mute\": %s", mute ? "true" : "false"); + if ((bres = spa_json_builder_memstream(&b, &ptr, &size, 0)) < 0) + return bres; + + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_bool(&b, "mute", mute); if (vol.channels > 0) { - fprintf(f, ", \"volumes\": ["); + spa_json_builder_object_push(&b, "volumes", "["); for (i = 0; i < vol.channels; i++) - fprintf(f, "%s%s", (i == 0 ? " ":", "), - spa_json_format_float(buf, sizeof(buf), vol.values[i])); - fprintf(f, " ]"); + spa_json_builder_array_double(&b, vol.values[i]); + spa_json_builder_pop(&b, "]"); } if (map.channels > 0) { char pos[8]; - fprintf(f, ", \"channels\": ["); + spa_json_builder_object_push(&b, "channels", "["); for (i = 0; i < map.channels; i++) - fprintf(f, "%s\"%s\"", (i == 0 ? " ":", "), + spa_json_builder_array_string(&b, channel_id2name(map.map[i], pos, sizeof(pos))); - fprintf(f, " ]"); + spa_json_builder_pop(&b, "]"); } if (device_name != NULL && device_name[0] && (client->default_source == NULL || !spa_streq(device_name, client->default_source)) && - (client->default_sink == NULL || !spa_streq(device_name, client->default_sink))) { - char target[1024]; - spa_json_encode_string(target, sizeof(target), device_name); - fprintf(f, ", \"target-node\": %s", target); + (client->default_sink == NULL || !spa_streq(device_name, client->default_sink))) + spa_json_builder_object_string(&b, "target-node", device_name); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); } - fprintf(f, " }"); - fclose(f); if (key_from_name(name, key, sizeof(key)) >= 0) { pw_log_debug("%s -> %s: %s", name, key, ptr); if ((res = pw_manager_set_metadata(client->manager, diff --git a/src/modules/module-protocol-pulse/modules/module-switch-on-connect.c b/src/modules/module-protocol-pulse/modules/module-switch-on-connect.c index 55c901d0b..33150d517 100644 --- a/src/modules/module-protocol-pulse/modules/module-switch-on-connect.c +++ b/src/modules/module-protocol-pulse/modules/module-switch-on-connect.c @@ -4,7 +4,7 @@ /* SPDX-License-Identifier: MIT */ #include -#include +#include #include #include @@ -136,13 +136,23 @@ static void manager_added(void *data, struct pw_manager_object *o) pw_log_debug("switching to %s", name); { - char encoded[1024]; - spa_json_encode_string(encoded, sizeof(encoded), name); - pw_manager_set_metadata(d->manager, d->metadata_default, - PW_ID_CORE, - pw_manager_object_is_sink(o) ? METADATA_CONFIG_DEFAULT_SINK - : METADATA_CONFIG_DEFAULT_SOURCE, - "Spa:String:JSON", "{ \"name\" %s }", encoded); + struct spa_json_builder b; + char *val; + size_t val_size; + + if (spa_json_builder_memstream(&b, &val, &val_size, 0) >= 0) { + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_string(&b, "name", name); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); + + pw_manager_set_metadata(d->manager, d->metadata_default, + PW_ID_CORE, + pw_manager_object_is_sink(o) ? METADATA_CONFIG_DEFAULT_SINK + : METADATA_CONFIG_DEFAULT_SOURCE, + "Spa:String:JSON", "%s", val); + free(val); + } } } 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 59de3c6c2..7c34b5f6b 100644 --- a/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include @@ -70,22 +70,24 @@ static const struct pw_impl_module_events module_events = { static int module_tunnel_sink_load(struct module *module) { struct module_tunnel_sink_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->stream_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &module->props->dict, 0); - fprintf(f, " stream.props = {"); - pw_properties_serialize_dict(f, &data->stream_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &module->props->dict, 0); + spa_json_builder_object_push(&b, "stream.props", "{"); + pw_properties_serialize_dict(b.f, &data->stream_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-pulse-tunnel", 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 415f2ddd1..af6a29d87 100644 --- a/src/modules/module-protocol-pulse/modules/module-tunnel-source.c +++ b/src/modules/module-protocol-pulse/modules/module-tunnel-source.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include @@ -70,22 +70,24 @@ static const struct pw_impl_module_events module_events = { static int module_tunnel_source_load(struct module *module) { struct module_tunnel_source_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->stream_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - pw_properties_serialize_dict(f, &module->props->dict, 0); - fprintf(f, " stream.props = {"); - pw_properties_serialize_dict(f, &data->stream_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &module->props->dict, 0); + spa_json_builder_object_push(&b, "stream.props", "{"); + pw_properties_serialize_dict(b.f, &data->stream_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-pulse-tunnel", diff --git a/src/modules/module-protocol-pulse/modules/module-virtual-sink.c b/src/modules/module-protocol-pulse/modules/module-virtual-sink.c index e3193f2f6..66e196169 100644 --- a/src/modules/module-protocol-pulse/modules/module-virtual-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-virtual-sink.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include "../defs.h" @@ -66,26 +66,29 @@ static const struct pw_impl_module_events module_events = { static int module_virtual_sink_load(struct module *module) { struct module_virtual_sink_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "virtual-sink-%u", module->index); pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "virtual-sink-%u", module->index); pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - 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 = {"); - pw_properties_serialize_dict(f, &data->playback_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->global_props->dict, 0); + spa_json_builder_object_push(&b, "capture.props", "{"); + pw_properties_serialize_dict(b.f, &data->capture_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "playback.props", "{"); + pw_properties_serialize_dict(b.f, &data->playback_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-loopback", diff --git a/src/modules/module-protocol-pulse/modules/module-virtual-source.c b/src/modules/module-protocol-pulse/modules/module-virtual-source.c index fe3f10648..da6947e45 100644 --- a/src/modules/module-protocol-pulse/modules/module-virtual-source.c +++ b/src/modules/module-protocol-pulse/modules/module-virtual-source.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include "../defs.h" @@ -68,26 +68,29 @@ static const struct pw_impl_module_events module_events = { static int module_virtual_source_load(struct module *module) { struct module_virtual_source_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "virtual-source-%u", module->index); pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "virtual-source-%u", module->index); pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - 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 = {"); - pw_properties_serialize_dict(f, &data->playback_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &data->global_props->dict, 0); + spa_json_builder_object_push(&b, "capture.props", "{"); + pw_properties_serialize_dict(b.f, &data->capture_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "playback.props", "{"); + pw_properties_serialize_dict(b.f, &data->playback_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-loopback", diff --git a/src/modules/module-protocol-pulse/modules/module-x11-bell.c b/src/modules/module-protocol-pulse/modules/module-x11-bell.c index b9d7c4908..9ae13d915 100644 --- a/src/modules/module-protocol-pulse/modules/module-x11-bell.c +++ b/src/modules/module-protocol-pulse/modules/module-x11-bell.c @@ -2,7 +2,7 @@ /* SPDX-FileCopyrightText: Copyright © 2022 Wim Taymans */ /* SPDX-License-Identifier: MIT */ -#include +#include #include #include "../module.h" @@ -56,34 +56,26 @@ static const struct pw_impl_module_events module_events = { static int module_x11_bell_load(struct module *module) { struct module_x11_bell_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; const char *str; - char encoded[1024]; size_t size; + int res; - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); - if ((str = pw_properties_get(module->props, "sink")) != NULL) { - spa_json_encode_string(encoded, sizeof(encoded), str); - fprintf(f, " sink.name = %s", encoded); - } - if ((str = pw_properties_get(module->props, "sample")) != NULL) { - spa_json_encode_string(encoded, sizeof(encoded), str); - fprintf(f, " sample.name = %s", encoded); - } - if ((str = pw_properties_get(module->props, "display")) != NULL) { - spa_json_encode_string(encoded, sizeof(encoded), str); - fprintf(f, " x11.display = %s", encoded); - } - if ((str = pw_properties_get(module->props, "xauthority")) != NULL) { - spa_json_encode_string(encoded, sizeof(encoded), str); - fprintf(f, " x11.xauthority = %s", encoded); - } - fprintf(f, " }"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + if ((str = pw_properties_get(module->props, "sink")) != NULL) + spa_json_builder_object_string(&b, "sink.name", str); + if ((str = pw_properties_get(module->props, "sample")) != NULL) + spa_json_builder_object_string(&b, "sample.name", str); + if ((str = pw_properties_get(module->props, "display")) != NULL) + spa_json_builder_object_string(&b, "x11.display", str); + if ((str = pw_properties_get(module->props, "xauthority")) != NULL) + spa_json_builder_object_string(&b, "x11.xauthority", str); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-x11-bell", diff --git a/src/modules/module-protocol-pulse/modules/module-zeroconf-discover.c b/src/modules/module-protocol-pulse/modules/module-zeroconf-discover.c index 5b1763eb8..b2b3acec9 100644 --- a/src/modules/module-protocol-pulse/modules/module-zeroconf-discover.c +++ b/src/modules/module-protocol-pulse/modules/module-zeroconf-discover.c @@ -3,6 +3,7 @@ /* SPDX-License-Identifier: MIT */ #include +#include #include #include "../defs.h" @@ -57,18 +58,19 @@ static const struct pw_impl_module_events module_events = { static int module_zeroconf_discover_load(struct module *module) { struct module_zeroconf_discover_data *data = module->user_data; - FILE *f; + struct spa_json_builder b; char *args; size_t size; + int res; - if ((f = open_memstream(&args, &size)) == NULL) - return -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) + return res; - fprintf(f, "{"); + spa_json_builder_array_push(&b, "{"); if (data->latency_msec > 0) - fprintf(f, " pulse.latency = %u ", data->latency_msec); - fprintf(f, "}"); - fclose(f); + spa_json_builder_object_uint(&b, "pulse.latency", data->latency_msec); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); data->mod = pw_context_load_module(module->impl->context, "libpipewire-module-zeroconf-discover", diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index 5191dd6b4..eea6693c3 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -4818,12 +4818,23 @@ static int do_set_default(struct client *client, uint32_t command, uint32_t tag, else if (spa_strendswith(name, ".monitor")) name = strndupa(name, strlen(name)-8); - char val[1024]; - spa_json_encode_string(val, sizeof(val), name); + struct spa_json_builder b; + char *val; + size_t val_size; + + if ((res = spa_json_builder_memstream(&b, &val, &val_size, 0)) < 0) + return res; + + spa_json_builder_array_push(&b, "{"); + spa_json_builder_object_string(&b, "name", name); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); + res = pw_manager_set_metadata(manager, client->metadata_default, PW_ID_CORE, sink ? METADATA_CONFIG_DEFAULT_SINK : METADATA_CONFIG_DEFAULT_SOURCE, - "Spa:String:JSON", "{ \"name\": %s }", val); + "Spa:String:JSON", "%s", val); + free(val); } else { res = pw_manager_set_metadata(manager, client->metadata_default, PW_ID_CORE, diff --git a/src/modules/module-protocol-simple.c b/src/modules/module-protocol-simple.c index ffc225b98..3a405684d 100644 --- a/src/modules/module-protocol-simple.c +++ b/src/modules/module-protocol-simple.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include @@ -961,7 +961,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) struct pw_properties *props; struct impl *impl; struct server *s; - FILE *f; + struct spa_json_builder b; char *str; size_t size; int res; @@ -994,13 +994,12 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) if ((res = parse_params(impl)) < 0) goto error_free; - if ((f = open_memstream(&str, &size)) == NULL) { - res = -errno; + if ((res = spa_json_builder_memstream(&b, &str, &size, 0)) < 0) { pw_log_error("Can't open memstream: %m"); goto error_free; } - fprintf(f, "["); + spa_json_builder_array_push(&b, "["); spa_list_for_each(s, &impl->server_list, link) { char ip[128]; @@ -1010,10 +1009,11 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) if (pw_net_get_ip(&s->addr, ip, sizeof(ip), &ipv4, &port) < 0) continue; - fprintf(f, " \"%s%s%s:%d\"", ipv4 ? "" : "[", ip, ipv4 ? "" : "]", port); + spa_json_builder_array_stringf(&b, "%s%s%s:%d", + ipv4 ? "" : "[", ip, ipv4 ? "" : "]", port); } - fprintf(f, " ]"); - fclose(f); + spa_json_builder_pop(&b, "]"); + spa_json_builder_close(&b); pw_log_info("listening on %s", str); it[0] = SPA_DICT_ITEM_INIT("server.address", str); diff --git a/src/modules/module-raop-discover.c b/src/modules/module-raop-discover.c index 60bdfa563..33ec653e8 100644 --- a/src/modules/module-raop-discover.c +++ b/src/modules/module-raop-discover.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include @@ -232,22 +232,21 @@ struct match_info { static int create_stream(struct impl *impl, struct pw_properties *props, struct tunnel *t) { - FILE *f; + struct spa_json_builder b; char *args; size_t size; int res = 0; struct pw_impl_module *mod; - if ((f = open_memstream(&args, &size)) == NULL) { - res = -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) { pw_log_error("Can't open memstream: %m"); goto done; } - fprintf(f, "{"); - pw_properties_serialize_dict(f, &props->dict, 0); - fprintf(f, "}"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); pw_log_info("loading module args:'%s'", args); mod = pw_context_load_module(impl->context, diff --git a/src/modules/module-rtp-sap.c b/src/modules/module-rtp-sap.c index a8c1fc5e5..c1292ca20 100644 --- a/src/modules/module-rtp-sap.c +++ b/src/modules/module-rtp-sap.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -1269,37 +1269,34 @@ static int session_load_source(struct session *session, struct pw_properties *pr { struct impl *impl = session->impl; struct pw_context *context = pw_impl_module_get_context(impl->module); - FILE *f = NULL; + struct spa_json_builder b; char *args = NULL; size_t size; const char *str, *media; int res; - if ((f = open_memstream(&args, &size)) == NULL) { - res = -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) { pw_log_error("Can't open memstream: %m"); - goto done; + return res; } - fprintf(f, "{"); + spa_json_builder_array_push(&b, "{"); if ((str = pw_properties_get(props, "rtp.destination.ip")) != NULL) - fprintf(f, "\"source.ip\" = \"%s\", ", str); + spa_json_builder_object_string(&b, "source.ip", str); if ((str = pw_properties_get(props, "rtp.destination.port")) != NULL) - fprintf(f, "\"source.port\" = %s, ", str); + spa_json_builder_object_value(&b, false, "source.port", str); if ((str = pw_properties_get(props, "rtp.session")) != NULL) - fprintf(f, "\"sess.name\" = \"%s\", ", str); + spa_json_builder_object_string(&b, "sess.name", str); /* Use an interface if explicitly specified, else use the SAP interface if that was specified */ - if ((str = pw_properties_get(props, "local.ifname")) != NULL || (str = impl->ifname) != NULL) { - fprintf(f, "\"local.ifname\" = \"%s\", ", str); - } + if ((str = pw_properties_get(props, "local.ifname")) != NULL || (str = impl->ifname) != NULL) + spa_json_builder_object_string(&b, "local.ifname", str); if ((media = pw_properties_get(props, "sess.media")) == NULL) media = "audio"; - if ((str = pw_properties_get(props, "cleanup.sec")) != NULL) { - fprintf(f, "\"cleanup.sec\" = \"%s\", ", str); - } + if ((str = pw_properties_get(props, "cleanup.sec")) != NULL) + spa_json_builder_object_string(&b, "cleanup.sec", str); if (spa_streq(media, "audio")) { const char *mime; @@ -1308,15 +1305,16 @@ static int session_load_source(struct session *session, struct pw_properties *pr if ((mime = pw_properties_get(props, "rtp.mime")) == NULL) { pw_log_error("missing rtp.mime property"); res = -EINVAL; - goto done; + goto error; } format_info = find_audio_format_info(mime); if (format_info == NULL) { pw_log_error("unknown rtp.mime type %s", mime); res = -ENOTSUP; - goto done; + goto error; } - fprintf(f, "\"sess.media\" = \"%s\", ", format_info->media_type); + spa_json_builder_object_string(&b, "sess.media", format_info->media_type); + if (format_info->format_str != NULL) { pw_properties_set(props, "audio.format", format_info->format_str); if ((str = pw_properties_get(props, "rtp.rate")) != NULL) @@ -1325,41 +1323,40 @@ static int session_load_source(struct session *session, struct pw_properties *pr pw_properties_set(props, "audio.channels", str); } if ((str = pw_properties_get(props, "rtp.ssrc")) != NULL) - fprintf(f, "\"rtp.receiver-ssrc\" = \"%s\", ", str); + spa_json_builder_object_string(&b, "rtp.receiver-ssrc", str); } else { pw_log_error("Unhandled media %s", media); res = -EINVAL; - goto done; + goto error; } if ((str = pw_properties_get(props, "rtp.ts-offset")) != NULL) - fprintf(f, "\"sess.ts-offset\" = %s, ", str); + spa_json_builder_object_value(&b, false, "sess.ts-offset", str); - fprintf(f, " stream.props = {"); - pw_properties_serialize_dict(f, &props->dict, 0); - fprintf(f, " }"); - fprintf(f, "}"); - fclose(f); - f = NULL; + spa_json_builder_object_push(&b, "stream.props", "{"); + pw_properties_serialize_dict(b.f, &props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); pw_log_info("loading new RTP source"); session->module = pw_context_load_module(context, "libpipewire-module-rtp-source", args, NULL); + free(args); + if (session->module == NULL) { - res = -errno; pw_log_error("Can't load module: %m"); - goto done; + return -errno; } pw_impl_module_add_listener(session->module, &session->module_listener, &session_module_events, session); - res = 0; -done: - if (f != NULL) - fclose(f); + return 0; +error: + spa_json_builder_close(&b); free(args); return res; } diff --git a/src/modules/module-snapcast-discover.c b/src/modules/module-snapcast-discover.c index 5c7896bcf..677725699 100644 --- a/src/modules/module-snapcast-discover.c +++ b/src/modules/module-snapcast-discover.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include @@ -523,7 +523,7 @@ static int parse_audio_info(struct pw_properties *props, struct spa_audio_info_r static int create_stream(struct impl *impl, struct pw_properties *props, struct tunnel *t) { - FILE *f; + struct spa_json_builder b; char *args; size_t size; int res = 0; @@ -548,16 +548,15 @@ static int create_stream(struct impl *impl, struct pw_properties *props, goto done; } - if ((f = open_memstream(&args, &size)) == NULL) { - res = -errno; + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) { pw_log_error("Can't open memstream: %m"); goto done; } - fprintf(f, "{"); - pw_properties_serialize_dict(f, &props->dict, 0); - fprintf(f, "}"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); pw_log_info("loading module args:'%s'", args); mod = pw_context_load_module(impl->context, diff --git a/src/modules/module-zeroconf-discover.c b/src/modules/module-zeroconf-discover.c index 61108d424..c2dd72188 100644 --- a/src/modules/module-zeroconf-discover.c +++ b/src/modules/module-zeroconf-discover.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include @@ -233,7 +233,7 @@ static void on_zeroconf_added(void *data, const void *user_data, const struct sp struct tunnel *t; struct tunnel_info tinfo; const struct spa_dict_item *it; - FILE *f; + struct spa_json_builder b; char *args; size_t size; struct pw_impl_module *mod; @@ -309,17 +309,17 @@ static void on_zeroconf_added(void *data, const void *user_data, const struct sp if ((str = pw_properties_get(impl->properties, "pulse.latency")) != NULL) pw_properties_set(props, "pulse.latency", str); - if ((f = open_memstream(&args, &size)) == NULL) { + if (spa_json_builder_memstream(&b, &args, &size, 0) < 0) { pw_log_error("Can't open memstream: %m"); goto done; } - fprintf(f, "{"); - pw_properties_serialize_dict(f, &props->dict, 0); - fprintf(f, " stream.props = {"); - fprintf(f, " }"); - fprintf(f, "}"); - fclose(f); + spa_json_builder_array_push(&b, "{"); + pw_properties_serialize_dict(b.f, &props->dict, 0); + spa_json_builder_object_push(&b, "stream.props", "{"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); pw_log_info("loading module args:'%s'", args); mod = pw_context_load_module(impl->context, diff --git a/src/tools/pw-loopback.c b/src/tools/pw-loopback.c index 991934a37..3375beae4 100644 --- a/src/tools/pw-loopback.c +++ b/src/tools/pw-loopback.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -92,10 +92,10 @@ int main(int argc, char *argv[]) struct data data = { 0 }; struct pw_loop *l; const char *opt_remote = NULL, *remote_name; - char cname[256], value[256]; + char cname[256]; + struct spa_json_builder b; char *args; size_t size; - FILE *f; static const struct option long_options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, @@ -214,42 +214,44 @@ int main(int argc, char *argv[]) } - if ((f = open_memstream(&args, &size)) == NULL) { + if ((res = spa_json_builder_memstream(&b, &args, &size, 0)) < 0) { fprintf(stderr, "can't open memstream: %m\n"); goto exit; } - fprintf(f, "{"); - remote_name = "[" PW_DEFAULT_REMOTE "-manager," PW_DEFAULT_REMOTE "]"; if (opt_remote) remote_name = opt_remote; - fprintf(f, " remote.name = \"%s\"", remote_name); + spa_json_builder_array_push(&b, "{"); + + spa_json_builder_object_string(&b, "remote.name", remote_name); if (data.latency != 0) - fprintf(f, " node.latency = %u/%u", data.latency, DEFAULT_RATE); + spa_json_builder_object_stringf(&b, "node.latency", "%u/%u", + data.latency, DEFAULT_RATE); if (data.delay != 0.0f) - fprintf(f, " target.delay.sec = %s", - spa_json_format_float(value, sizeof(value), data.delay)); + spa_json_builder_object_double(&b, "target.delay.sec", data.delay); if (data.channels != 0) - fprintf(f, " audio.channels = %u", data.channels); + spa_json_builder_object_uint(&b, "audio.channels", data.channels); if (data.opt_channel_map != NULL) - fprintf(f, " audio.position = %s", data.opt_channel_map); + spa_json_builder_object_value(&b, true, "audio.position", data.opt_channel_map); if (data.opt_node_name != NULL) - fprintf(f, " node.name = %s", data.opt_node_name); + spa_json_builder_object_string(&b, "node.name", data.opt_node_name); if (data.opt_group_name != NULL) { pw_properties_set(data.capture_props, PW_KEY_NODE_GROUP, data.opt_group_name); pw_properties_set(data.playback_props, PW_KEY_NODE_GROUP, data.opt_group_name); } - fprintf(f, " capture.props = {"); - pw_properties_serialize_dict(f, &data.capture_props->dict, 0); - fprintf(f, " } playback.props = {"); - pw_properties_serialize_dict(f, &data.playback_props->dict, 0); - fprintf(f, " } }"); - fclose(f); + spa_json_builder_object_push(&b, "capture.props", "{"); + pw_properties_serialize_dict(b.f, &data.capture_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_object_push(&b, "playback.props", "{"); + pw_properties_serialize_dict(b.f, &data.playback_props->dict, 0); + spa_json_builder_pop(&b, "}"); + spa_json_builder_pop(&b, "}"); + spa_json_builder_close(&b); pw_log_info("loading module with %s", args);