From 80825aeaea752a4ca50aedf3a38e4b2ded3f50d1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Feb 2021 21:01:58 +0100 Subject: [PATCH] conf: more work on config changes Add -c option to pipewire to select config file. Use this to select the uninstalled conf file. Rename conf properties, prefix with context. Simplify the main daemon now that everything can go in config. Simplify pipewire-pulse now that we can put everything in config, it's now virtually the same as pipewire but with a differenct config file. Parse server addresses as array of strings. --- Makefile.in | 2 +- pipewire-jack/src/pipewire-jack.c | 3 + src/daemon/client-rt.conf.in | 8 +- src/daemon/client.conf.in | 9 +-- src/daemon/jack.conf.in | 8 +- src/daemon/main.c | 78 +++++++------------ src/daemon/media-session.d/media-session.conf | 7 +- src/daemon/meson.build | 3 + src/daemon/pipewire-pulse.c | 33 +++----- src/daemon/pipewire-pulse.conf.in | 44 +++-------- src/daemon/pipewire.conf.in | 16 ++-- .../module-protocol-pulse/pulse-server.c | 22 +++--- src/pipewire/conf.c | 8 +- src/pipewire/context.c | 17 ++-- src/pipewire/keys.h | 1 - src/tools/pw-dump.c | 1 - 16 files changed, 104 insertions(+), 156 deletions(-) diff --git a/Makefile.in b/Makefile.in index 522c0a295..2b081a1b8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -17,7 +17,7 @@ run: all PIPEWIRE_CONFIG_DIR=@BUILD_ROOT@/src/daemon/ \ ACP_PATHS_DIR=@SOURCE_ROOT@/spa/plugins/alsa/mixer/paths \ ACP_PROFILES_DIR=@SOURCE_ROOT@/spa/plugins/alsa/mixer/profile-sets \ - $(DBG) @BUILD_ROOT@/src/daemon/pipewire + $(DBG) @BUILD_ROOT@/src/daemon/pipewire -c pipewire-uninstalled.conf gdb: $(MAKE) run DBG=gdb diff --git a/pipewire-jack/src/pipewire-jack.c b/pipewire-jack/src/pipewire-jack.c index e7c467032..350fb4358 100644 --- a/pipewire-jack/src/pipewire-jack.c +++ b/pipewire-jack/src/pipewire-jack.c @@ -2424,6 +2424,9 @@ jack_client_t * jack_client_open (const char *client_name, client->context.l, pw_properties_copy(client->props), 0); + if (client->context.context == NULL) + goto no_props; + client->allow_mlock = client->context.context->defaults.mem_allow_mlock; client->warn_mlock = client->context.context->defaults.mem_warn_mlock; diff --git a/src/daemon/client-rt.conf.in b/src/daemon/client-rt.conf.in index 05f9f6344..70728d184 100644 --- a/src/daemon/client-rt.conf.in +++ b/src/daemon/client-rt.conf.in @@ -1,6 +1,6 @@ -# Daemon config file for PipeWire RT clients version @VERSION@ # +# Real-time Client config file for PipeWire version @VERSION@ # -properties = { +context.properties = { ## Configure properties in the system. #mem.warn-mlock = false #mem.allow-mlock = true @@ -8,7 +8,7 @@ properties = { #log.level = 2 } -spa-libs = { +context.spa-libs = { ## = # # Used to find spa factory names. It maps an spa factory name @@ -19,7 +19,7 @@ spa-libs = { support.* = support/libspa-support } -modules = { +context.modules = { ## = { [args = { = ... }] # [flags = [ [ifexists] [nofail] ]} # diff --git a/src/daemon/client.conf.in b/src/daemon/client.conf.in index 6ce408369..e1568a3df 100644 --- a/src/daemon/client.conf.in +++ b/src/daemon/client.conf.in @@ -1,6 +1,5 @@ -# Daemon config file for PipeWire clients version @VERSION@ # - -properties = { +# Client config file for PipeWire version @VERSION@ # +context.properties = { ## Configure properties in the system. #mem.warn-mlock = false #mem.allow-mlock = true @@ -8,7 +7,7 @@ properties = { #log.level = 2 } -spa-libs = { +context.spa-libs = { ## = # # Used to find spa factory names. It maps an spa factory name @@ -19,7 +18,7 @@ spa-libs = { support.* = support/libspa-support } -modules = { +context.modules = { ## = { [args = { = ... }] # [flags = [ [ifexists] [nofail] ]} # diff --git a/src/daemon/jack.conf.in b/src/daemon/jack.conf.in index d40ff142c..8356efac8 100644 --- a/src/daemon/jack.conf.in +++ b/src/daemon/jack.conf.in @@ -1,6 +1,6 @@ -# Daemon config file for PipeWire JACK clients version @VERSION@ # +# JACK client config file for PipeWire version @VERSION@ # -properties = { +context.properties = { ## Configure properties in the system. #mem.warn-mlock = false #mem.allow-mlock = true @@ -8,7 +8,7 @@ properties = { #log.level = 2 } -spa-libs = { +context.spa-libs = { ## = # # Used to find spa factory names. It maps an spa factory name @@ -18,7 +18,7 @@ spa-libs = { support.* = support/libspa-support } -modules = { +context.modules = { ## = { [args = { = ... }] # [flags = [ [ifexists] [nofail] ]} # diff --git a/src/daemon/main.c b/src/daemon/main.c index 8fd58f40a..579345901 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -24,56 +24,39 @@ #include #include -#include -#include -#include -#include -#include -#include -#include #include -#include - -#include +#include #include "config.h" -#define NAME "daemon" - -#define DEFAULT_CONFIG_FILE "pipewire.conf" - -struct data { - struct pw_context *context; - struct pw_main_loop *loop; - - const char *daemon_name; -}; +static const char *config_name = "pipewire.conf"; static void do_quit(void *data, int signal_number) { - struct data *d = data; - pw_main_loop_quit(d->loop); + struct pw_main_loop *loop = data; + pw_main_loop_quit(loop); } -static void show_help(struct data *d, const char *name) +static void show_help(const char *name) { fprintf(stdout, "%s [options]\n" " -h, --help Show this help\n" " --version Show version\n" - " -n, --name Daemon name (Default %s)\n", + " -c, --config Load config (Default %s)\n", name, - d->daemon_name); + config_name); } int main(int argc, char *argv[]) { - struct data d; + struct pw_context *context; + struct pw_main_loop *loop; struct pw_properties *properties; static const struct option long_options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, - { "name", required_argument, NULL, 'n' }, + { "config", required_argument, NULL, 'c' }, { NULL, 0, NULL, 0} }; @@ -82,19 +65,14 @@ int main(int argc, char *argv[]) if (setenv("PIPEWIRE_INTERNAL", "1", 1) < 0) fprintf(stderr, "can't set PIPEWIRE_INTERNAL env: %m"); - spa_zero(d); pw_init(&argc, &argv); - d.daemon_name = getenv("PIPEWIRE_CORE"); - if (d.daemon_name == NULL) - d.daemon_name = PW_DEFAULT_REMOTE; - - while ((c = getopt_long(argc, argv, "hVn:", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "hVc:", long_options, NULL)) != -1) { switch (c) { - case 'h' : - show_help(&d, argv[0]); + case 'h': + show_help(argv[0]); return 0; - case 'V' : + case 'V': fprintf(stdout, "%s\n" "Compiled with libpipewire %s\n" "Linked with libpipewire %s\n", @@ -102,9 +80,8 @@ int main(int argc, char *argv[]) pw_get_headers_version(), pw_get_library_version()); return 0; - case 'n' : - d.daemon_name = optarg; - fprintf(stdout, "set name %s\n", d.daemon_name); + case 'c': + config_name = optarg; break; default: return -1; @@ -112,31 +89,30 @@ int main(int argc, char *argv[]) } properties = pw_properties_new( - PW_KEY_CORE_NAME, d.daemon_name, - PW_KEY_CONFIG_NAME, "pipewire-uninstalled.conf", - PW_KEY_CORE_DAEMON, "true", NULL); + PW_KEY_CONFIG_NAME, config_name, + NULL); - d.loop = pw_main_loop_new(&properties->dict); - if (d.loop == NULL) { + loop = pw_main_loop_new(&properties->dict); + if (loop == NULL) { pw_log_error("failed to create main-loop: %m"); return -1; } - pw_loop_add_signal(pw_main_loop_get_loop(d.loop), SIGINT, do_quit, &d); - pw_loop_add_signal(pw_main_loop_get_loop(d.loop), SIGTERM, do_quit, &d); + pw_loop_add_signal(pw_main_loop_get_loop(loop), SIGINT, do_quit, loop); + pw_loop_add_signal(pw_main_loop_get_loop(loop), SIGTERM, do_quit, loop); - d.context = pw_context_new(pw_main_loop_get_loop(d.loop), properties, 0); - if (d.context == NULL) { + context = pw_context_new(pw_main_loop_get_loop(loop), properties, 0); + if (context == NULL) { pw_log_error("failed to create context: %m"); return -1; } pw_log_info("start main loop"); - pw_main_loop_run(d.loop); + pw_main_loop_run(loop); pw_log_info("leave main loop"); - pw_context_destroy(d.context); - pw_main_loop_destroy(d.loop); + pw_context_destroy(context); + pw_main_loop_destroy(loop); pw_deinit(); return 0; diff --git a/src/daemon/media-session.d/media-session.conf b/src/daemon/media-session.d/media-session.conf index 324d612b7..ae1053112 100644 --- a/src/daemon/media-session.d/media-session.conf +++ b/src/daemon/media-session.d/media-session.conf @@ -1,6 +1,5 @@ # Media session config file # - -properties = { +context.properties = { # Properties to configure the session and some # modules. #mem.mlock-all = false @@ -8,7 +7,7 @@ properties = { #dbus = true } -spa-libs = { +context.spa-libs = { # Mapping from factory name to library. api.bluez5.* = bluez5/libspa-bluez5 api.alsa.* = alsa/libspa-alsa @@ -16,7 +15,7 @@ spa-libs = { api.libcamera.* = libcamera/libspa-libcamera } -modules = { +context.modules = { ## = { [args = { = ... }] # [flags = [ [ifexists] [nofail] ]} # diff --git a/src/daemon/meson.build b/src/daemon/meson.build index 85e3efe87..c445c588c 100644 --- a/src/daemon/meson.build +++ b/src/daemon/meson.build @@ -11,12 +11,15 @@ pipewire_c_args = [ conf_config = configuration_data() conf_config.set('VERSION', '"@0@"'.format(pipewire_version)) conf_config.set('media_session_path', join_paths(pipewire_bindir, 'pipewire-media-session')) +conf_config.set('pipewire_path', join_paths(pipewire_bindir, 'pipewire')) conf_config.set('pipewire_pulse_path', join_paths(pipewire_bindir, 'pipewire-pulse')) conf_install_dir = join_paths(get_option('sysconfdir'), 'pipewire') conf_config_uninstalled = conf_config conf_config_uninstalled.set('media_session_path', join_paths(meson.build_root(), 'src', 'examples', 'pipewire-media-session')) +conf_config_uninstalled.set('pipewire_path', + join_paths(meson.build_root(), 'src', 'daemon', 'pipewire')) conf_config_uninstalled.set('pipewire_pulse_path', join_paths(meson.build_root(), 'src', 'daemon', 'pipewire-pulse')) diff --git a/src/daemon/pipewire-pulse.c b/src/daemon/pipewire-pulse.c index 95d576db8..18601c71e 100644 --- a/src/daemon/pipewire-pulse.c +++ b/src/daemon/pipewire-pulse.c @@ -27,11 +27,11 @@ #include -#include +#include #include "config.h" -static const char *address; +static const char *config_name = "pipewire-pulse.conf"; static void do_quit(void *data, int signal_number) { @@ -45,11 +45,9 @@ static void show_help(const char *name) "Start a pulseaudio compatible daemon.\n\n" " -h, --help Show this help\n" " --version Show version\n" - " -a --address comma separated list of addresses (Default %s)\n" - " unix:\n" - " tcp:[][:]\n", + " -c, --config Load config (Default %s)\n", name, - address); + config_name); } int main(int argc, char *argv[]) @@ -57,20 +55,17 @@ int main(int argc, char *argv[]) struct pw_context *context; struct pw_main_loop *loop; struct pw_properties *properties; - char *args; static const struct option long_options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, - { "address", required_argument, NULL, 'a' }, + { "config", required_argument, NULL, 'c' }, { NULL, 0, NULL, 0} }; int c; pw_init(&argc, &argv); - address = "unix:native"; - - while ((c = getopt_long(argc, argv, "hVa:", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "hVc:", long_options, NULL)) != -1) { switch (c) { case 'h': show_help(argv[0]); @@ -83,9 +78,8 @@ int main(int argc, char *argv[]) pw_get_headers_version(), pw_get_library_version()); return 0; - case 'a': - address = optarg; - fprintf(stdout, "set address %s\n", address); + case 'c': + config_name = optarg; break; default: return -1; @@ -93,7 +87,7 @@ int main(int argc, char *argv[]) } properties = pw_properties_new( - PW_KEY_CONFIG_NAME, "pipewire-pulse.conf", + PW_KEY_CONFIG_NAME, config_name, NULL); loop = pw_main_loop_new(&properties->dict); @@ -111,19 +105,10 @@ int main(int argc, char *argv[]) return -1; } - args = spa_aprintf("server.address=\"%s\"", address); - if (pw_context_load_module(context, - "libpipewire-module-protocol-pulse", - args, NULL) == NULL) { - pw_log_error("failed to create pulse module: %m"); - return -1; - } - pw_log_info("start main loop"); pw_main_loop_run(loop); pw_log_info("leave main loop"); - free(args); pw_context_destroy(context); pw_main_loop_destroy(loop); pw_deinit(); diff --git a/src/daemon/pipewire-pulse.conf.in b/src/daemon/pipewire-pulse.conf.in index 19475ad29..f28687b7d 100644 --- a/src/daemon/pipewire-pulse.conf.in +++ b/src/daemon/pipewire-pulse.conf.in @@ -1,6 +1,5 @@ -# Daemon config file for PipeWire pulse version @VERSION@ # - -properties = { +# PulseAudio config file for PipeWire version @VERSION@ # +context.properties = { ## Configure properties in the system. #mem.warn-mlock = false #mem.allow-mlock = true @@ -8,49 +7,30 @@ properties = { #log.level = 2 } -spa-libs = { - ## = - # - # Used to find spa factory names. It maps an spa factory name - # regular expression to a library name that should contain - # that factory. - # +context.spa-libs = { audio.convert* = audioconvert/libspa-audioconvert support.* = support/libspa-support } -modules = { - ## = { [args = { = ... }] - # [flags = [ [ifexists] [nofail] ]} - # - # Loads a module with the given parameters. - # If ifexists is given, the module is ignored when it is not found. - # If nofail is given, module initialization failures are ignored. - # - # Uses RTKit to boost the data thread priority. +context.modules = { libpipewire-module-rtkit = { args = { - nice.level = -14 + #nice.level = -11 #rt.prio = 20 #rt.time.soft = 200000 #rt.time.hard = 200000 } flags = [ ifexists nofail ] } - - # The native communication protocol. libpipewire-module-protocol-native = null - - # 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 - - # Makes a factory for wrapping nodes in an adapter with a - # converter and resampler. libpipewire-module-adapter = null - - # Allows applications to create metadata objects. It creates - # a factory for Metadata objects. libpipewire-module-metadata = null + libpipewire-module-protocol-pulse = { + args = { + server.address = [ + "unix:native" + # "tcp:4713" + } + } } diff --git a/src/daemon/pipewire.conf.in b/src/daemon/pipewire.conf.in index cf3c06402..29294d168 100644 --- a/src/daemon/pipewire.conf.in +++ b/src/daemon/pipewire.conf.in @@ -1,6 +1,5 @@ # Daemon config file for PipeWire version @VERSION@ # - -properties = { +context.properties = { ## Configure properties in the system. #library.name.system = support/libspa-support #context.data-loop.library.name.system = support/libspa-support @@ -11,6 +10,9 @@ properties = { #mem.mlock-all = false #log.level = 2 + core.daemon = true # listening for socket connections + core.name = pipewire-0 # core name and socket name + ## Properties for the DSP configuration. #default.clock.rate = 48000 #default.clock.quantum = 1024 @@ -22,7 +24,7 @@ properties = { #default.video.rate.denom = 1 } -spa-libs = { +context.spa-libs = { # = # # Used to find spa factory names. It maps an spa factory name @@ -41,7 +43,7 @@ spa-libs = { #audiotestsrc = audiotestsrc/libspa-audiotestsrc } -modules = { +context.modules = { # = { # [ args = { = ... } ] # [ flags = [ [ ifexists ] [ nofail ] ] @@ -130,7 +132,7 @@ modules = { libpipewire-module-session-manager = null } -objects = { +context.objects = { # = { # [ args = { = ... } ] # [ flags = [ [ nofail ] ] @@ -168,7 +170,7 @@ objects = { #} } -exec = { +context.exec = { # = { [ args = "" ] } # # Execute the given program with arguments. @@ -183,5 +185,5 @@ exec = { # It can be interesting to start another daemon here that listens # on another address with the -a option (eg. -a tcp:4713). # - #"@pipewire_pulse_path@" = { "#args" = "-a tcp:4713" } + #"@pipewire_path@" = { args = "-c pipewire-pulse.conf" } } diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index 74622ba11..505380ebf 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -5736,8 +5736,9 @@ struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context, { struct impl *impl; const char *str; - int i, n_addr; - char **addr, *free_str = NULL; + char *free_str = NULL; + struct spa_json it[2]; + char value[512]; impl = calloc(1, sizeof(struct impl) + user_data_size); if (impl == NULL) @@ -5747,7 +5748,7 @@ struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context, if (props != NULL) str = pw_properties_get(props, "server.address"); if (str == NULL) { - str = free_str = spa_aprintf("%s-%s", + str = free_str = spa_aprintf("[ \"%s-%s\" ]", PW_PROTOCOL_PULSE_DEFAULT_SERVER, get_server_name(context)); } @@ -5775,16 +5776,15 @@ struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context, pw_context_add_listener(context, &impl->context_listener, &context_events, impl); - addr = pw_split_strv(str, ",", INT_MAX, &n_addr); - for (i = 0; i < n_addr; i++) { - if (addr[i] == NULL) - continue; - if (create_server(impl, addr[i]) == NULL) { - pw_log_warn(NAME" %p: can't create server for %s: %m", - impl, addr[i]); + spa_json_init(&it[0], str, strlen(str)); + if (spa_json_enter_array(&it[0], &it[1]) > 0) { + while (spa_json_get_string(&it[1], value, sizeof(value)-1) > 0) { + if (create_server(impl, value) == NULL) { + pw_log_warn(NAME" %p: can't create server for %s: %m", + impl, value); + } } } - pw_free_strv(addr); free(free_str); dbus_request_name(context, "org.pulseaudio.Server"); diff --git a/src/pipewire/conf.c b/src/pipewire/conf.c index d9dd9d671..dc88e80dc 100644 --- a/src/pipewire/conf.c +++ b/src/pipewire/conf.c @@ -535,13 +535,13 @@ int pw_context_parse_conf_section(struct pw_context *context, if ((str = pw_properties_get(conf, section)) == NULL) return -ENOENT; - if (strcmp(section, "spa-libs") == 0) + if (strcmp(section, "context.spa-libs") == 0) res = parse_spa_libs(context, str); - else if (strcmp(section, "modules") == 0) + else if (strcmp(section, "context.modules") == 0) res = parse_modules(context, str); - else if (strcmp(section, "objects") == 0) + else if (strcmp(section, "context.objects") == 0) res = parse_objects(context, str); - else if (strcmp(section, "exec") == 0) + else if (strcmp(section, "context.exec") == 0) res = parse_exec(context, str); else res = -EINVAL; diff --git a/src/pipewire/context.c b/src/pipewire/context.c index 09626c096..1f3580519 100644 --- a/src/pipewire/context.c +++ b/src/pipewire/context.c @@ -219,8 +219,11 @@ struct pw_context *pw_context_new(struct pw_loop *main_loop, this, conf_name, spa_strerror(res)); goto error_free; } else { - pw_log_warn(NAME" %p: can't load config %s: %s. Using client.conf fallback", - this, conf_name, spa_strerror(res)); + pw_log_warn(NAME" %p: can't load config %s%s%s: %s. Using client.conf fallback", + this, + conf_prefix ? conf_prefix : "", + conf_prefix ? "/" : "", + conf_name, spa_strerror(res)); } conf_prefix = NULL; if ((res = pw_conf_load_conf(NULL, "client.conf", conf)) < 0) { @@ -231,7 +234,7 @@ struct pw_context *pw_context_new(struct pw_loop *main_loop, } this->conf = conf; - if ((str = pw_properties_get(conf, "properties")) != NULL) + if ((str = pw_properties_get(conf, "context.properties")) != NULL) pw_properties_update_string(properties, str, strlen(str)); if ((str = pw_properties_get(properties, "mem.mlock-all")) != NULL && @@ -329,10 +332,10 @@ struct pw_context *pw_context_new(struct pw_loop *main_loop, this->sc_pagesize = sysconf(_SC_PAGESIZE); - pw_context_parse_conf_section(this, conf, "spa-libs"); - pw_context_parse_conf_section(this, conf, "modules"); - pw_context_parse_conf_section(this, conf, "objects"); - pw_context_parse_conf_section(this, conf, "exec"); + pw_context_parse_conf_section(this, conf, "context.spa-libs"); + pw_context_parse_conf_section(this, conf, "context.modules"); + pw_context_parse_conf_section(this, conf, "context.objects"); + pw_context_parse_conf_section(this, conf, "context.exec"); pw_log_debug(NAME" %p: created", this); diff --git a/src/pipewire/keys.h b/src/pipewire/keys.h index 9bf4ed7ad..1732e8ea1 100644 --- a/src/pipewire/keys.h +++ b/src/pipewire/keys.h @@ -65,7 +65,6 @@ extern "C" { /* context */ #define PW_KEY_CONTEXT_PROFILE_MODULES "context.profile.modules" /**< a context profile for modules, deprecated */ -#define PW_KEY_CONTEXT_MODULES_ARGS "context.modules.args" /**< arguments for context modules */ #define PW_KEY_USER_NAME "context.user-name" /**< The user name that runs pipewire */ #define PW_KEY_HOST_NAME "context.host-name" /**< The host name of the machine */ diff --git a/src/tools/pw-dump.c b/src/tools/pw-dump.c index 1ccedb6bb..355f4d64b 100644 --- a/src/tools/pw-dump.c +++ b/src/tools/pw-dump.c @@ -530,7 +530,6 @@ static void core_dump(struct object *o) put_value(d, "host-name", i->host_name); put_value(d, "version", i->version); put_value(d, "name", i->name); - put_value(d, "name", i->name); put_flags(d, "change-mask", i->change_mask, fl); put_dict(d, "props", i->props); put_end(d, "}", 0);