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)