From 90b0410280da65f5b8f879da7f204735b6d27cb1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Mar 2021 12:39:58 +0100 Subject: [PATCH] conf: improve config files Make arrays from config sections that should really be an array. Having the module name as the object key technically makes it impossible to load the same module twice because the key can only be once in the object. The same applies to the context.objects and context.exec sections. This also makes it somewhat easier to parse the config.. --- src/daemon/client-rt.conf.in | 22 +-- src/daemon/client.conf.in | 20 +- src/daemon/jack.conf.in | 16 +- src/daemon/media-session.d/media-session.conf | 22 +-- src/daemon/pipewire-pulse.conf.in | 16 +- src/daemon/pipewire.conf.in | 66 +++---- src/pipewire/conf.c | 177 +++++++++--------- 7 files changed, 171 insertions(+), 168 deletions(-) diff --git a/src/daemon/client-rt.conf.in b/src/daemon/client-rt.conf.in index 1a667e9f8..a138bdd70 100644 --- a/src/daemon/client-rt.conf.in +++ b/src/daemon/client-rt.conf.in @@ -19,9 +19,9 @@ context.spa-libs = { support.* = support/libspa-support } -context.modules = { - # = { - # [ args = { = ... } ] +context.modules = [ + #{ name = + # [ args = { = ... } ] # [ flags = [ [ ifexists ] [ nofail ] ] #} # @@ -30,7 +30,7 @@ context.modules = { # If nofail is given, module initialization failures are ignored. # # Uses RTKit to boost the data thread priority. - libpipewire-module-rtkit = { + { name = libpipewire-module-rtkit args = { #nice.level = -11 #rt.prio = 88 @@ -41,28 +41,28 @@ context.modules = { } # The native communication protocol. - libpipewire-module-protocol-native = null + { name = libpipewire-module-protocol-native } # Allows creating nodes that run in the context of the # client. Is used by all clients that want to provide # data to PipeWire. - libpipewire-module-client-node = null + { name = libpipewire-module-client-node } # Allows creating devices that run in the context of the # client. Is used by the session manager. - libpipewire-module-client-device = null + { name = libpipewire-module-client-device } # Makes a factory for wrapping nodes in an adapter with a # converter and resampler. - libpipewire-module-adapter = null + { name = libpipewire-module-adapter } # Allows applications to create metadata objects. It creates # a factory for Metadata objects. - libpipewire-module-metadata = null + { name = libpipewire-module-metadata } # Provides factories to make session manager objects. - libpipewire-module-session-manager = null -} + { name = libpipewire-module-session-manager } +] filter.properties = { #node.latency = 1024/48000 diff --git a/src/daemon/client.conf.in b/src/daemon/client.conf.in index 83a9270a0..2b0232718 100644 --- a/src/daemon/client.conf.in +++ b/src/daemon/client.conf.in @@ -18,9 +18,9 @@ context.spa-libs = { support.* = support/libspa-support } -context.modules = { - # = { - # [ args = { = ... } ] +context.modules = [ + #{ name = + # [ args = { = ... } ] # [ flags = [ [ ifexists ] [ nofail ] ] #} # @@ -30,28 +30,28 @@ context.modules = { # # The native communication protocol. - libpipewire-module-protocol-native = null + { name = libpipewire-module-protocol-native } # Allows creating nodes that run in the context of the # client. Is used by all clients that want to provide # data to PipeWire. - libpipewire-module-client-node = null + { name = libpipewire-module-client-node } # Allows creating devices that run in the context of the # client. Is used by the session manager. - libpipewire-module-client-device = null + { name = libpipewire-module-client-device } # Makes a factory for wrapping nodes in an adapter with a # converter and resampler. - libpipewire-module-adapter = null + { name = libpipewire-module-adapter } # Allows applications to create metadata objects. It creates # a factory for Metadata objects. - libpipewire-module-metadata = null + { name = libpipewire-module-metadata } # Provides factories to make session manager objects. - libpipewire-module-session-manager = null -} + { name = libpipewire-module-session-manager } +] filter.properties = { #node.latency = 1024/48000 diff --git a/src/daemon/jack.conf.in b/src/daemon/jack.conf.in index d27d2bee9..1da61dcaa 100644 --- a/src/daemon/jack.conf.in +++ b/src/daemon/jack.conf.in @@ -18,9 +18,9 @@ context.spa-libs = { support.* = support/libspa-support } -context.modules = { - # = { - # [ args = { = ... } ] +context.modules = [ + #{ name = + # [ args = { = ... } ] # [ flags = [ [ ifexists ] [ nofail ] ] #} # @@ -30,7 +30,7 @@ context.modules = { # # # Uses RTKit to boost the data thread priority. - libpipewire-module-rtkit = { + { name = libpipewire-module-rtkit args = { #nice.level = -11 #rt.prio = 88 @@ -41,17 +41,17 @@ context.modules = { } # The native communication protocol. - libpipewire-module-protocol-native = null + { name = libpipewire-module-protocol-native } # Allows creating nodes that run in the context of the # client. Is used by all clients that want to provide # data to PipeWire. - libpipewire-module-client-node = null + { name = libpipewire-module-client-node } # Allows applications to create metadata objects. It creates # a factory for Metadata objects. - libpipewire-module-metadata = null -} + { name = libpipewire-module-metadata } +] jack.properties = { #node.latency = 1024/48000 diff --git a/src/daemon/media-session.d/media-session.conf b/src/daemon/media-session.d/media-session.conf index 857f886a7..f2c53a565 100644 --- a/src/daemon/media-session.d/media-session.conf +++ b/src/daemon/media-session.d/media-session.conf @@ -15,9 +15,9 @@ context.spa-libs = { api.libcamera.* = libcamera/libspa-libcamera } -context.modules = { - # = { - # [ args = { = ... } ] +context.modules = [ + #{ name = + # [ args = { = ... } ] # [ flags = [ [ ifexists ] [ nofail ] ] #} # @@ -26,7 +26,7 @@ context.modules = { # If nofail is given, module initialization failures are ignored. # # Uses RTKit to boost the data thread priority. - libpipewire-module-rtkit = { + { name = libpipewire-module-rtkit args = { #nice.level = -11 #rt.prio = 88 @@ -37,28 +37,28 @@ context.modules = { } # The native communication protocol. - libpipewire-module-protocol-native = null + { name = libpipewire-module-protocol-native } # Allows creating nodes that run in the context of the # client. Is used by all clients that want to provide # data to PipeWire. - libpipewire-module-client-node = null + { name = libpipewire-module-client-node } # Allows creating devices that run in the context of the # client. Is used by the session manager. - libpipewire-module-client-device = null + { name = libpipewire-module-client-device } # Makes a factory for wrapping nodes in an adapter with a # converter and resampler. - libpipewire-module-adapter = null + { name = libpipewire-module-adapter } # Allows applications to create metadata objects. It creates # a factory for Metadata objects. - libpipewire-module-metadata = null + { name = libpipewire-module-metadata } # Provides factories to make session manager objects. - libpipewire-module-session-manager = null -} + { name = libpipewire-module-session-manager } +] session.modules = { # These are the modules that are enabled when a file with diff --git a/src/daemon/pipewire-pulse.conf.in b/src/daemon/pipewire-pulse.conf.in index 4e348bd1b..ebd37c02e 100644 --- a/src/daemon/pipewire-pulse.conf.in +++ b/src/daemon/pipewire-pulse.conf.in @@ -12,8 +12,8 @@ context.spa-libs = { support.* = support/libspa-support } -context.modules = { - libpipewire-module-rtkit = { +context.modules = [ + { name = libpipewire-module-rtkit args = { #nice.level = -11 #rt.prio = 88 @@ -22,12 +22,12 @@ context.modules = { } flags = [ ifexists nofail ] } - libpipewire-module-protocol-native = null - libpipewire-module-client-node = null - libpipewire-module-adapter = null - libpipewire-module-metadata = null + { name = libpipewire-module-protocol-native } + { name = libpipewire-module-client-node } + { name = libpipewire-module-adapter } + { name = libpipewire-module-metadata } - libpipewire-module-protocol-pulse = { + { name = libpipewire-module-protocol-pulse args = { # the addresses this server listens on server.address = [ @@ -42,7 +42,7 @@ context.modules = { #pulse.min.quantum = 256/48000 # 5ms } } -} +] stream.properties = { #node.latency = 1024/48000 diff --git a/src/daemon/pipewire.conf.in b/src/daemon/pipewire.conf.in index ed4ee3b29..756802e7a 100644 --- a/src/daemon/pipewire.conf.in +++ b/src/daemon/pipewire.conf.in @@ -44,8 +44,8 @@ context.spa-libs = { #audiotestsrc = audiotestsrc/libspa-audiotestsrc } -context.modules = { - # = { +context.modules = [ + #{ name = # [ args = { = ... } ] # [ flags = [ [ ifexists ] [ nofail ] ] #} @@ -56,7 +56,7 @@ context.modules = { # # Uses RTKit to boost the data thread priority. - libpipewire-module-rtkit = { + { name = libpipewire-module-rtkit args = { #nice.level = -11 #rt.prio = 88 @@ -67,44 +67,44 @@ context.modules = { } # The native communication protocol. - libpipewire-module-protocol-native = null + { name = libpipewire-module-protocol-native } # The profile module. Allows application to access profiler # and performance data. It provides an interface that is used # by pw-top and pw-profiler. - libpipewire-module-profiler = null + { name = libpipewire-module-profiler } # Allows applications to create metadata objects. It creates # a factory for Metadata objects. - libpipewire-module-metadata = null + { name = libpipewire-module-metadata } # Creates a factory for making devices that run in the # context of the PipeWire server. - libpipewire-module-spa-device-factory = null + { name = libpipewire-module-spa-device-factory } # Creates a factory for making nodes that run in the # context of the PipeWire server. - libpipewire-module-spa-node-factory = null + { name = libpipewire-module-spa-node-factory } # Allows creating nodes that run in the context of the # client. Is used by all clients that want to provide # data to PipeWire. - libpipewire-module-client-node = null + { name = libpipewire-module-client-node } # Allows creating devices that run in the context of the # client. Is used by the session manager. - libpipewire-module-client-device = null + { name = libpipewire-module-client-device } # The portal module monitors the PID of the portal process # and tags connections with the same PID as portal # connections. - libpipewire-module-portal = { + { name = libpipewire-module-portal flags = [ ifexists nofail ] } # The access module can perform access checks and block # new clients. - libpipewire-module-access = { + { name = libpipewire-module-access args = { # access.allowed to list an array of paths of allowed # apps. @@ -126,17 +126,17 @@ context.modules = { # Makes a factory for wrapping nodes in an adapter with a # converter and resampler. - libpipewire-module-adapter = null + { name = libpipewire-module-adapter } # Makes a factory for creating links between ports. - libpipewire-module-link-factory = null + { name = libpipewire-module-link-factory } # Provides factories to make session manager objects. - libpipewire-module-session-manager = null -} + { name = libpipewire-module-session-manager } +] -context.objects = { - # = { +context.objects = [ + #{ factory = # [ args = { = ... } ] # [ flags = [ [ nofail ] ] #} @@ -144,16 +144,16 @@ context.objects = { # Creates an object from a PipeWire factory with the given parameters. # If nofail is given, errors are ignored (and no object is created). # - #spa-node-factory = { args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } } - #spa-device-factory = { args = { factory.name = api.jack.device foo=bar } flags = [ nofail ] } - #spa-device-factory = { args = { factory.name = api.alsa.enum.udev } } - #spa-device-factory = { args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } } - #adapter = { args = { factory.name = audiotestsrc node.name = my-test } } - #spa-node-factory = { args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } } + #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } } + #{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = [ nofail ] } + #{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } } + #{ factory = spa-device-factory args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } } + #{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test } } + #{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } } # A default dummy driver. This handles nodes marked with the "node.always-driver" # property when no other driver is currently active. JACK clients need this. - spa-node-factory = { + { factory = spa-node-factory args = { factory.name = support.node.driver node.name = Dummy-Driver @@ -162,7 +162,7 @@ context.objects = { } # This creates a new Source node. It will have input ports # that you can link, to provide audio for this source. - #adapter = { + #{ factory = adapter # args = { # factory.name = support.null-audio-sink # node.name = "my-mic" @@ -175,7 +175,7 @@ context.objects = { # This creates a single PCM source device for the given # alsa device path hw:0. You can change source to sink # to make a sink in the same way. - #adapter = { + #{ factory = adapter # args = { # factory.name = api.alsa.pcm.source # node.name = "alsa-source" @@ -192,10 +192,10 @@ context.objects = { # #audio.position = "FL,FR" # } #} -} +] -context.exec = { - # = { [ args = "" ] } +context.exec = [ + #{ path = [ args = "" ] } # # Execute the given program with arguments. # @@ -203,12 +203,12 @@ context.exec = { # but it is better to start it as a systemd service. # Run the session manager with -h for options. # - @comment@"@media_session_path@" = { args = "" } + @comment@{ path = "@media_session_path@" args = "" } # # You can optionally start the pulseaudio-server here as well # but it is better to start it as a systemd service. # It can be interesting to start another daemon here that listens # on another address with the -a option (eg. -a tcp:4713). # - @comment@"@pipewire_path@" = { args = "-c pipewire-pulse.conf" } -} + @comment@{ path = "@pipewire_path@" args = "-c pipewire-pulse.conf" } +] diff --git a/src/pipewire/conf.c b/src/pipewire/conf.c index 37b718feb..2ecb05047 100644 --- a/src/pipewire/conf.c +++ b/src/pipewire/conf.c @@ -273,6 +273,10 @@ int pw_conf_load_state(const char *prefix, const char *name, struct pw_propertie return conf_load(prefix, name, conf); } +/* context.spa-libs = { + * = + * } + */ static int parse_spa_libs(struct pw_context *context, const char *str) { struct spa_json it[2]; @@ -313,6 +317,14 @@ static int load_module(struct pw_context *context, const char *key, const char * return 0; } +/* + * context.modules = [ + * { name = + * [ args = { = ... } ] + * [ flags = [ [ ifexists ] [ nofail ] ] + * } + * ] + */ static int parse_modules(struct pw_context *context, const char *str) { struct spa_json it[3]; @@ -320,49 +332,41 @@ static int parse_modules(struct pw_context *context, const char *str) int res = 0; spa_json_init(&it[0], str, strlen(str)); - if (spa_json_enter_object(&it[0], &it[1]) < 0) + if (spa_json_enter_array(&it[0], &it[1]) < 0) return -EINVAL; - while (spa_json_get_string(&it[1], key, sizeof(key)-1) > 0) { - const char *val, *aval; - char *args = NULL, *flags = NULL; - int len, alen; + while (spa_json_enter_object(&it[1], &it[2]) > 0) { + char *name = NULL, *args = NULL, *flags = NULL; - if ((len = spa_json_next(&it[1], &val)) <= 0) - break; + while (spa_json_get_string(&it[2], key, sizeof(key)-1) > 0) { + const char *val; + int len; - if (key[0] == '#') - continue; + if ((len = spa_json_next(&it[2], &val)) <= 0) + break; - if (spa_json_is_object(val, len)) { - char arg[512]; + if (strcmp(key, "name") == 0) { + name = malloc(len + 1); + spa_json_parse_string(val, len, name); + } + else if (strcmp(key, "args") == 0) { + if (spa_json_is_container(val, len)) + len = spa_json_container_len(&it[2], val, len); - spa_json_enter(&it[1], &it[2]); + args = malloc(len + 1); + spa_json_parse_string(val, len, args); + } else if (strcmp(key, "flags") == 0) { + if (spa_json_is_container(val, len)) + len = spa_json_container_len(&it[2], val, len); - while (spa_json_get_string(&it[2], arg, sizeof(arg)-1) > 0) { - if ((alen = spa_json_next(&it[2], &aval)) <= 0) - break; - - if (strcmp(arg, "args") == 0) { - if (spa_json_is_container(aval, alen)) - alen = spa_json_container_len(&it[2], aval, alen); - - args = malloc(alen + 1); - spa_json_parse_string(aval, alen, args); - } else if (strcmp(arg, "flags") == 0) { - if (spa_json_is_container(aval, alen)) - alen = spa_json_container_len(&it[2], aval, alen); - - flags = malloc(alen + 1); - spa_json_parse_string(aval, alen, flags); - } + flags = malloc(len + 1); + spa_json_parse_string(val, len, flags); } } - else if (!spa_json_is_null(val, len)) - break; - - res = load_module(context, key, args, flags); + if (name != NULL) + res = load_module(context, name, args, flags); + free(name); free(args); free(flags); @@ -399,6 +403,14 @@ static int create_object(struct pw_context *context, const char *key, const char return 0; } +/* + * context.objects = [ + * { factory = + * [ args = { = ... } ] + * [ flags = [ [ nofail ] ] ] + * } + * ] + */ static int parse_objects(struct pw_context *context, const char *str) { struct spa_json it[3]; @@ -406,45 +418,36 @@ static int parse_objects(struct pw_context *context, const char *str) int res = 0; spa_json_init(&it[0], str, strlen(str)); - if (spa_json_enter_object(&it[0], &it[1]) < 0) + if (spa_json_enter_array(&it[0], &it[1]) < 0) return -EINVAL; - while (spa_json_get_string(&it[1], key, sizeof(key)-1) > 0) { - const char *val, *aval; - char *args = NULL, *flags = NULL; - int len, alen; + while (spa_json_enter_object(&it[1], &it[2]) > 0) { + char *factory = NULL, *args = NULL, *flags = NULL; - if ((len = spa_json_next(&it[1], &val)) <= 0) - break; + while (spa_json_get_string(&it[2], key, sizeof(key)-1) > 0) { + const char *val; + int len; - if (key[0] == '#') - continue; + if ((len = spa_json_next(&it[2], &val)) <= 0) + break; - if (spa_json_is_object(val, len)) { - char arg[512]; + if (strcmp(key, "factory") == 0) { + factory = malloc(len + 1); + spa_json_parse_string(val, len, factory); + } else if (strcmp(key, "args") == 0) { + if (spa_json_is_container(val, len)) + len = spa_json_container_len(&it[2], val, len); - spa_json_enter(&it[1], &it[2]); - - while (spa_json_get_string(&it[2], arg, sizeof(arg)-1) > 0) { - if ((alen = spa_json_next(&it[2], &aval)) <= 0) - break; - - if (strcmp(arg, "args") == 0) { - if (spa_json_is_container(aval, alen)) - alen = spa_json_container_len(&it[2], aval, alen); - - args = malloc(alen + 1); - spa_json_parse_string(aval, alen, args); - } else if (strcmp(arg, "flags") == 0) { - flags = strndup(aval, alen); - } + args = malloc(len + 1); + spa_json_parse_string(val, len, args); + } else if (strcmp(key, "flags") == 0) { + flags = strndup(val, len); } } - else if (!spa_json_is_null(val, len)) - break; - - res = create_object(context, key, args, flags); + if (factory != NULL) + res = create_object(context, factory, args, flags); + free(factory); free(args); free(flags); @@ -485,6 +488,13 @@ static int do_exec(struct pw_context *context, const char *key, const char *args return 0; } +/* + * context.exec = [ + * { path = + * [ args = "" ] + * } + * ] + */ static int parse_exec(struct pw_context *context, const char *str) { struct spa_json it[3]; @@ -492,38 +502,31 @@ static int parse_exec(struct pw_context *context, const char *str) int res = 0; spa_json_init(&it[0], str, strlen(str)); - if (spa_json_enter_object(&it[0], &it[1]) < 0) + if (spa_json_enter_array(&it[0], &it[1]) < 0) return -EINVAL; - while (spa_json_get_string(&it[1], key, sizeof(key)-1) > 0) { - const char *val; - char *args = NULL; - int len; + while (spa_json_enter_object(&it[1], &it[2]) > 0) { + char *path = NULL, *args = NULL; - if ((len = spa_json_next(&it[1], &val)) <= 0) - break; + while (spa_json_get_string(&it[2], key, sizeof(key)-1) > 0) { + const char *val; + int len; - if (key[0] == '#') - continue; + if ((len = spa_json_next(&it[2], &val)) <= 0) + break; - if (spa_json_is_object(val, len)) { - char arg[512], aval[1024]; - - spa_json_enter(&it[1], &it[2]); - - while (spa_json_get_string(&it[2], arg, sizeof(arg)-1) > 0) { - if (spa_json_get_string(&it[2], aval, sizeof(aval)-1) <= 0) - break; - - if (strcmp(arg, "args") == 0) - args = strdup(aval); + if (strcmp(key, "path") == 0) { + path = malloc(len + 1); + spa_json_parse_string(val, len, path); + } else if (strcmp(key, "args") == 0) { + args = malloc(len + 1); + spa_json_parse_string(val, len, args); } } - else if (!spa_json_is_null(val, len)) - break; - - res = do_exec(context, key, args); + if (path) + res = do_exec(context, path, args); + free(path); free(args); if (res < 0)