media-session: add config files

Remove -e and -d options
Manage modules in media-session.conf
Add alsa-monitor.conf that can match node/device properties with
a regex and update properties on it. All previous configuration and
more cane be done with this.
This commit is contained in:
Wim Taymans 2020-12-30 13:12:48 +01:00
parent 389a125488
commit 24c68b0067
6 changed files with 383 additions and 154 deletions

View file

@ -0,0 +1,57 @@
{
"properties": {
},
"rules": [
{
"#": [ "rules for matching a device or node. It is an array of",
"properties that all need to match the regexp. If any of the",
"matches work, the actions are executed for the object."
],
"matches": [
{
"device.name": "~alsa_card.*"
}
],
"actions": {
"#": [ "actions can update properties on the matched object."
],
"update-props": {
"api.alsa.use-acp": true,
"#api.alsa.use-ucm": true,
"#api.alsa.soft-mixer": false,
"#api.alsa.ignore-dB": false,
"#device.profile-set": "profileset-name",
"#device.profile": "default profile name",
"#api.acp.auto-port": true,
"#api.acp.auto-profile": true
"#device.nick": "My Device",
}
}
},
{
"matches": [
{
"node.name": "~alsa_input.*"
},
{
"node.name": "~alsa_output.*"
}
],
"actions": {
"update-props": {
"#node.nick": "My Node",
"#node.nick": null,
"#priority.driver": 100,
"#resample.quality": 4,
"#channelmix.normalize": false,
"#channelmix.mix-lfe": false,
"#audio.format": "S16LE",
"#audio.rate": 44100,
"#audio.position": "FL,FR"
}
}
}
]
}

View file

@ -0,0 +1,55 @@
{
"properties": {
},
"spa-libs": {
"#": [ "Mapping from factory name to library."
],
"api.bluez5.*": "bluez5/libspa-bluez5",
"api.alsa.*": "alsa/libspa-alsa",
"api.v4l2.*": "v4l2/libspa-v4l2",
"api.libcamera.*": "libcamera/libspa-libcamera"
},
"modules": {
"#": [ "These are the modules that are enabled when a file with",
"the key name is found in the media-session.d config directory.",
"the default bundle is always enabled."
],
"default": [
"flatpak", "# manages flatpak access",
"portal", "# manage portal permissions",
"v4l2", "# video for linux udev detection",
"#libcamera", "# libcamera udev detection",
"suspend-node", "# suspend inactive nodes",
"policy-node", "# configure and link nodes",
"#metadata", "# export metadata API",
"#default-nodes", "# restore default nodes",
"#default-profile", "# restore default profiles",
"#default-routes", "# restore default route",
"#alsa-seq", "# alsa seq midi support",
"#alsa-monitor", "# alsa udev detection",
"#bluez5", "# bluetooth support",
"#restore-stream", "#restore stream settings"
],
"with-audio": [
"metadata",
"default-nodes",
"default-profile",
"default-routes",
"alsa-seq",
"alsa-monitor"
],
"with-alsa": [
"with-audio"
],
"with-jack": [
"with-audio"
],
"with-pulseaudio": [
"with-audio",
"bluez5",
"restore-stream"
]
}
}

View file

@ -22,7 +22,11 @@ conf_config.set('pipewire_pulse_path', join_paths(pipewire_bindir, 'pipewire-pul
conf_install_dir = join_paths(get_option('sysconfdir'), 'pipewire') conf_install_dir = join_paths(get_option('sysconfdir'), 'pipewire')
install_data( install_data(
sources : ['media-session.d/with-jack', 'media-session.d/with-pulseaudio'], sources : [
'media-session.d/with-jack',
'media-session.d/with-pulseaudio',
'media-session.d/media-session.conf',
'media-session.d/alsa-monitor.conf' ],
install_dir : join_paths(conf_install_dir, 'media-session.d')) install_dir : join_paths(conf_install_dir, 'media-session.d'))
conf_config_uninstalled = conf_config conf_config_uninstalled = conf_config

View file

@ -27,6 +27,7 @@
#include <errno.h> #include <errno.h>
#include <math.h> #include <math.h>
#include <time.h> #include <time.h>
#include <regex.h>
#include "config.h" #include "config.h"
@ -40,6 +41,7 @@
#include <spa/utils/hook.h> #include <spa/utils/hook.h>
#include <spa/utils/names.h> #include <spa/utils/names.h>
#include <spa/utils/keys.h> #include <spa/utils/keys.h>
#include <spa/utils/json.h>
#include <spa/param/props.h> #include <spa/param/props.h>
#include <spa/pod/builder.h> #include <spa/pod/builder.h>
#include <spa/pod/parser.h> #include <spa/pod/parser.h>
@ -55,6 +57,8 @@
#include "reserve.c" #include "reserve.c"
#define SESSION_CONF "alsa-monitor.conf"
#define DEFAULT_JACK_SECONDS 1 #define DEFAULT_JACK_SECONDS 1
struct node { struct node {
@ -102,6 +106,7 @@ struct device {
unsigned int first:1; unsigned int first:1;
unsigned int appeared:1; unsigned int appeared:1;
unsigned int probed:1; unsigned int probed:1;
unsigned int use_acp:1;
struct spa_list node_list; struct spa_list node_list;
}; };
@ -109,6 +114,8 @@ struct impl {
struct sm_media_session *session; struct sm_media_session *session;
struct spa_hook session_listener; struct spa_hook session_listener;
struct pw_properties *conf;
DBusConnection *conn; DBusConnection *conn;
struct spa_handle *handle; struct spa_handle *handle;
@ -120,8 +127,6 @@ struct impl {
struct spa_source *jack_timeout; struct spa_source *jack_timeout;
struct pw_proxy *jack_device; struct pw_proxy *jack_device;
unsigned int use_acp:1;
}; };
#undef NAME #undef NAME
@ -192,6 +197,111 @@ static const struct sm_object_methods node_methods = {
.release = node_release, .release = node_release,
}; };
static bool find_match(struct spa_json *arr, struct pw_properties *props)
{
struct spa_json it[1];
while (spa_json_enter_object(arr, &it[0]) > 0) {
char key[256], val[1024];
const char *str, *value;
int match = 0, fail = 0;
int len;
while (spa_json_get_string(&it[0], key, sizeof(key)-1) > 0) {
bool success = false;
if ((len = spa_json_next(&it[0], &value)) <= 0)
break;
if (key[0] == '#')
continue;
str = pw_properties_get(props, key);
if (spa_json_is_null(value, len)) {
success = str == NULL;
}
else if (spa_json_is_string(value, len)) {
spa_json_parse_string(value, SPA_MIN(len, 1024), val);
value = val;
len = strlen(val);
}
if (str != NULL) {
if (value[0] == '~') {
regex_t preg;
if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) {
if (regexec(&preg, str, 0, NULL, 0) == 0)
success = true;
regfree(&preg);
}
} else if (strncmp(str, value, len) == 0) {
success = true;
}
}
if (success) {
match++;
pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value);
}
else
fail++;
}
if (match > 0 && fail == 0)
return true;
}
return false;
}
static int apply_matches(struct impl *impl, struct pw_properties *props)
{
const char *rules, *val;
struct spa_json it[4], actions;;
if ((rules = pw_properties_get(impl->conf, "rules")) == NULL)
return 0;
spa_json_init(&it[0], rules, strlen(rules));
if (spa_json_enter_array(&it[0], &it[1]) < 0)
return 0;
while (spa_json_enter_object(&it[1], &it[2]) > 0) {
char key[64];
bool have_match = false, have_actions = false;
while (spa_json_get_string(&it[2], key, sizeof(key)-1) > 0) {
if (strcmp(key, "matches") == 0) {
if (spa_json_enter_array(&it[2], &it[3]) < 0)
break;
have_match = find_match(&it[3], props);
}
else if (strcmp(key, "actions") == 0) {
if (spa_json_enter_object(&it[2], &actions) > 0)
have_actions = true;
}
else if (spa_json_next(&it[2], &val) <= 0)
break;
}
if (!have_match || !have_actions)
continue;
while (spa_json_get_string(&actions, key, sizeof(key)-1) > 0) {
int len;
pw_log_debug("action %s", key);
if (strcmp(key, "update-props") == 0) {
if ((len = spa_json_next(&actions, &val)) <= 0)
continue;
if (!spa_json_is_object(val, len))
continue;
len = spa_json_container_len(&actions, val, len);
pw_properties_update_string(props, val, len);
}
else if (spa_json_next(&actions, &val) <= 0)
break;
}
}
return 1;
}
static struct node *alsa_create_node(struct device *device, uint32_t id, static struct node *alsa_create_node(struct device *device, uint32_t id,
const struct spa_device_object_info *info) const struct spa_device_object_info *info)
{ {
@ -314,6 +424,9 @@ static struct node *alsa_create_node(struct device *device, uint32_t id,
node->impl = impl; node->impl = impl;
node->device = device; node->device = device;
node->id = id; node->id = id;
apply_matches(impl, node->props);
node->snode = sm_media_session_create_node(impl->session, node->snode = sm_media_session_create_node(impl->session,
"adapter", "adapter",
&node->props->dict); &node->props->dict);
@ -517,11 +630,10 @@ static int update_device_props(struct device *device)
static void set_profile(struct device *device, int index) static void set_profile(struct device *device, int index)
{ {
struct impl *impl = device->impl;
char buf[1024]; char buf[1024];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
if (impl->use_acp) if (device->use_acp)
return; return;
pw_log_debug("%p: set profile %d id:%d", device, index, device->device_id); pw_log_debug("%p: set profile %d id:%d", device, index, device->device_id);
@ -795,7 +907,7 @@ static struct device *alsa_create_device(struct impl *impl, uint32_t id,
{ {
struct device *device; struct device *device;
int res; int res;
const char *str, *card, *factory_name, *name; const char *str, *card;
pw_log_debug("new device %u", id); pw_log_debug("new device %u", id);
@ -810,12 +922,6 @@ static struct device *alsa_create_device(struct impl *impl, uint32_t id,
goto exit; goto exit;
} }
if (impl->use_acp)
factory_name = SPA_NAME_API_ALSA_ACP_DEVICE;
else
factory_name = info->factory_name;
device->factory_name = strdup(factory_name);
device->impl = impl; device->impl = impl;
device->id = id; device->id = id;
device->props = pw_properties_new_dict(info->props); device->props = pw_properties_new_dict(info->props);
@ -826,23 +932,14 @@ static struct device *alsa_create_device(struct impl *impl, uint32_t id,
device->pending_profile = 1; device->pending_profile = 1;
spa_list_append(&impl->device_list, &device->link); spa_list_append(&impl->device_list, &device->link);
name = pw_properties_get(device->props, "device.name"); apply_matches(impl, device->props);
if ((str = pw_properties_get(impl->session->props, "alsa.soft-mixer")) != NULL && str = pw_properties_get(device->props, "api.alsa.use-acp");
(strcmp(str, "*") == 0 || device->use_acp = str ? pw_properties_parse_bool(str) : true;
(name != NULL && strstr(str, name) != NULL))) { if (device->use_acp)
pw_properties_set(device->props, "api.alsa.soft-mixer", "true"); device->factory_name = strdup(SPA_NAME_API_ALSA_ACP_DEVICE);
} else
if ((str = pw_properties_get(impl->session->props, "alsa.no-auto-port")) != NULL && device->factory_name = strdup(info->factory_name);
(strcmp(str, "*") == 0 ||
(name != NULL && strstr(str, name) != NULL))) {
pw_properties_set(device->props, "api.acp.auto-port", "false");
}
if ((str = pw_properties_get(impl->session->props, "alsa.no-auto-profile")) != NULL &&
(strcmp(str, "*") == 0 ||
(name != NULL && strstr(str, name) != NULL))) {
pw_properties_set(device->props, "api.acp.auto-profile", "false");
}
if (impl->conn && if (impl->conn &&
(card = spa_dict_lookup(info->props, SPA_KEY_API_ALSA_CARD)) != NULL) { (card = spa_dict_lookup(info->props, SPA_KEY_API_ALSA_CARD)) != NULL) {
@ -941,6 +1038,7 @@ static void session_destroy(void *data)
spa_hook_remove(&impl->listener); spa_hook_remove(&impl->listener);
pw_proxy_destroy(impl->jack_device); pw_proxy_destroy(impl->jack_device);
pw_unload_spa_handle(impl->handle); pw_unload_spa_handle(impl->handle);
pw_properties_free(impl->conf);
free(impl); free(impl);
} }
@ -954,7 +1052,6 @@ int sm_alsa_monitor_start(struct sm_media_session *session)
struct pw_context *context = session->context; struct pw_context *context = session->context;
struct impl *impl; struct impl *impl;
void *iface; void *iface;
const char *str;
int res; int res;
impl = calloc(1, sizeof(struct impl)); impl = calloc(1, sizeof(struct impl));
@ -962,9 +1059,15 @@ int sm_alsa_monitor_start(struct sm_media_session *session)
return -errno; return -errno;
impl->session = session; impl->session = session;
impl->conf = pw_properties_new(NULL, NULL);
if (impl->conf == NULL) {
free(impl);
return -ENOMEM;
}
if ((str = pw_properties_get(session->props, "alsa.use-acp")) != NULL) if ((res = sm_media_session_load_conf(impl->session,
impl->use_acp = pw_properties_parse_bool(str); SESSION_CONF, impl->conf)) < 0)
pw_log_info("can't load "SESSION_CONF" config: %s", spa_strerror(res));
if (session->dbus_connection) if (session->dbus_connection)
impl->conn = spa_dbus_connection_get(session->dbus_connection); impl->conn = spa_dbus_connection_get(session->dbus_connection);

View file

@ -61,6 +61,7 @@
#include "media-session.h" #include "media-session.h"
#define NAME "media-session" #define NAME "media-session"
#define SESSION_CONF "media-session.conf"
#define sm_object_emit(o,m,v,...) spa_hook_list_call(&(o)->hooks, struct sm_object_events, m, v, ##__VA_ARGS__) #define sm_object_emit(o,m,v,...) spa_hook_list_call(&(o)->hooks, struct sm_object_events, m, v, ##__VA_ARGS__)
@ -115,9 +116,8 @@ struct sync {
struct impl { struct impl {
struct sm_media_session this; struct sm_media_session this;
const char *opt_default; struct pw_properties *conf;
char *opt_enabled; struct pw_properties *modules;
char *opt_disabled;
struct pw_main_loop *loop; struct pw_main_loop *loop;
struct spa_dbus *dbus; struct spa_dbus *dbus;
@ -1776,6 +1776,44 @@ int sm_media_session_remove_links(struct sm_media_session *sess,
return 0; return 0;
} }
int sm_media_session_load_conf(struct sm_media_session *sess, const char *name,
struct pw_properties *conf)
{
const char *dir;
char path[PATH_MAX];
int count, fd;
struct stat sbuf;
char *data;
if ((dir = getenv("PIPEWIRE_CONFIG_DIR")) == NULL)
dir = PIPEWIRE_CONFIG_DIR;
if (dir == NULL)
return -ENOENT;
snprintf(path, sizeof(path)-1, "%s/media-session.d/%s", dir, name);
if ((fd = open(path, O_CLOEXEC | O_RDONLY)) < 0) {
pw_log_warn(NAME" %p: error loading config '%s': %m", sess, path);
return -errno;
}
pw_log_info(NAME" %p: loading config '%s'", sess, path);
if (fstat(fd, &sbuf) < 0)
goto error_close;
if ((data = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
goto error_close;
close(fd);
count = pw_properties_update_string(conf, data, sbuf.st_size);
munmap(data, sbuf.st_size);
return count;
error_close:
pw_log_debug("can't read file %s: %m", path);
close(fd);
return -errno;
}
static int state_dir(struct sm_media_session *sess) static int state_dir(struct sm_media_session *sess)
{ {
struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this); struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
@ -2093,55 +2131,78 @@ static void do_quit(void *data, int signal_number)
pw_main_loop_quit(impl->loop); pw_main_loop_quit(impl->loop);
} }
#define DEFAULT_ENABLED "flatpak," \ static int load_spa_libs(struct impl *impl, const char *str)
"portal," \
"v4l2," \
"suspend-node," \
"policy-node"
#define AUDIO_ENABLED DEFAULT_ENABLED"," \
"metadata," \
"default-nodes," \
"default-profile," \
"default-routes," \
"alsa-acp," \
"alsa-seq"
#define PULSE_ENABLED AUDIO_ENABLED"," \
"bluez5," \
"restore-stream"
#define EXTRA_ENABLED ""
#define EXTRA_DISABLED ""
static int check_default_enabled(struct impl *impl)
{ {
const char *dir; struct spa_json it[2];
char check_path[PATH_MAX]; char key[512], value[512];
uint32_t i;
struct stat statbuf; spa_json_init(&it[0], str, strlen(str));
struct modules { if (spa_json_enter_object(&it[0], &it[1]) < 0)
const char *file; return -EINVAL;
const char *name;
const char *options; while (spa_json_get_string(&it[1], key, sizeof(key)-1) > 0) {
} module_check[] = { const char *val;
{ "with-jack", "Audio", AUDIO_ENABLED }, if (key[0] == '#') {
{ "with-alsa", "Audio", AUDIO_ENABLED }, if (spa_json_next(&it[1], &val) <= 0)
{ "with-pulseaudio", "PulseAudio", PULSE_ENABLED }, break;
}; }
else if (spa_json_get_string(&it[1], value, sizeof(value)-1) > 0) {
pw_log_debug("spa-libs: '%s' -> '%s'", key, value);
pw_context_add_spa_lib(impl->this.context, key, value);
}
}
return 0;
}
static int collect_modules(struct impl *impl, const char *str)
{
struct spa_json it[3];
char key[512], value[512];
const char *dir, *val;
char check_path[PATH_MAX];
struct stat statbuf;
int count = 0;
impl->opt_default = DEFAULT_ENABLED;
if ((dir = getenv("PIPEWIRE_CONFIG_DIR")) == NULL) if ((dir = getenv("PIPEWIRE_CONFIG_DIR")) == NULL)
dir = PIPEWIRE_CONFIG_DIR; dir = PIPEWIRE_CONFIG_DIR;
if (dir == NULL) if (dir == NULL)
return -ENOENT; return -ENOENT;
for (i = 0; i < SPA_N_ELEMENTS(module_check); i++) { again:
spa_json_init(&it[0], str, strlen(str));
if (spa_json_enter_object(&it[0], &it[1]) < 0)
return -EINVAL;
while (spa_json_get_string(&it[1], key, sizeof(key)-1) > 0) {
bool add = false;
pw_log_info("%s", key);
if (key[0] == '#') {
add = false;
} else if (pw_properties_get(impl->modules, key) != NULL) {
add = true;
} else {
snprintf(check_path, sizeof(check_path), snprintf(check_path, sizeof(check_path),
"%s/media-session.d/%s", dir, module_check[i].file); "%s/media-session.d/%s", dir, key);
if (stat(check_path, &statbuf) == 0) { add = (stat(check_path, &statbuf) == 0);
pw_log_info("found %s, enable %s", check_path, }
module_check[i].name); if (add) {
impl->opt_default = module_check[i].options; if (spa_json_enter_array(&it[1], &it[2]) < 0)
continue;
while (spa_json_get_string(&it[2], value, sizeof(value)-1) > 0) {
if (value[0] == '#')
continue;
pw_properties_set(impl->modules, value, "true");
} }
} }
else if (spa_json_next(&it[1], &val) <= 0)
break;
}
/* twice to resolve groups in module list */
if (count++ == 0)
goto again;
return 0; return 0;
} }
@ -2160,8 +2221,7 @@ static const struct {
{ "default-routes", "restore default route", sm_default_routes_start, NULL }, { "default-routes", "restore default route", sm_default_routes_start, NULL },
{ "restore-stream", "restore stream settings", sm_restore_stream_start, NULL }, { "restore-stream", "restore stream settings", sm_restore_stream_start, NULL },
{ "alsa-seq", "alsa seq midi support", sm_alsa_midi_start, NULL }, { "alsa-seq", "alsa seq midi support", sm_alsa_midi_start, NULL },
{ "alsa-pcm", "alsa pcm udev detection", sm_alsa_monitor_start, NULL }, { "alsa-monitor", "alsa card udev detection", sm_alsa_monitor_start, NULL },
{ "alsa-acp", "alsa card profile udev detection", sm_alsa_monitor_start, "alsa.use-acp=true" },
{ "v4l2", "video for linux udev detection", sm_v4l2_monitor_start, NULL }, { "v4l2", "video for linux udev detection", sm_v4l2_monitor_start, NULL },
{ "libcamera", "libcamera udev detection", sm_libcamera_monitor_start, NULL }, { "libcamera", "libcamera udev detection", sm_libcamera_monitor_start, NULL },
{ "bluez5", "bluetooth support", sm_bluez5_monitor_start, NULL }, { "bluez5", "bluetooth support", sm_bluez5_monitor_start, NULL },
@ -2170,41 +2230,10 @@ static const struct {
{ "pulse-bridge", "accept pulseaudio clients", sm_pulse_bridge_start, NULL }, { "pulse-bridge", "accept pulseaudio clients", sm_pulse_bridge_start, NULL },
}; };
static int opt_contains(const char *opt, const char *val) static bool is_module_enabled(struct impl *impl, const char *val)
{ {
const char *s, *state = NULL; const char *str = pw_properties_get(impl->modules, val);
size_t len; return str ? pw_properties_parse_bool(str) : false;
while((s = pw_split_walk(opt, ",", &len, &state)) != NULL) {
if (strncmp(val, s, len) == 0)
return 1;
}
return 0;
}
static bool is_opt_enabled(struct impl *impl, const char *val)
{
return (opt_contains(impl->opt_default, val) || opt_contains(impl->opt_enabled, val)) &&
!opt_contains(impl->opt_disabled, val);
}
static int append_opt_str(char **p, char *sep, char *str)
{
char *buf;
size_t size = strlen(*p) + strlen(sep) + strlen(str) + 1;
if (**p == '\0') {
free(*p);
*p = strdup(str);
return 0;
}
if ((buf = malloc(size)) == NULL)
return -1;
snprintf(buf, size, "%s%s%s", *p, sep, str);
free(*p);
*p = buf;
return 0;
} }
static void show_help(const char *name, struct impl *impl) static void show_help(const char *name, struct impl *impl)
@ -2214,16 +2243,14 @@ static void show_help(const char *name, struct impl *impl)
fprintf(stdout, "%s [options]\n" fprintf(stdout, "%s [options]\n"
" -h, --help Show this help\n" " -h, --help Show this help\n"
" --version Show version\n" " --version Show version\n"
" -e, --enabled Extra comma separated enabled options ('%s')\n"
" -d, --disabled Extra comma separated disabled options ('%s')\n"
" -p, --properties Extra properties as 'key=value { key=value }'\n", " -p, --properties Extra properties as 'key=value { key=value }'\n",
name, impl->opt_enabled, impl->opt_disabled); name);
fprintf(stdout, fprintf(stdout,
"\noptions: (*=enabled)\n"); "\noptions: (*=enabled)\n");
for (i = 0; i < SPA_N_ELEMENTS(modules); i++) { for (i = 0; i < SPA_N_ELEMENTS(modules); i++) {
fprintf(stdout, "\t %c %-15.15s: %s\n", fprintf(stdout, "\t %c %-15.15s: %s\n",
is_opt_enabled(impl, modules[i].name) ? '*' : ' ', is_module_enabled(impl, modules[i].name) ? '*' : ' ',
modules[i].name, modules[i].desc); modules[i].name, modules[i].desc);
} }
} }
@ -2232,14 +2259,12 @@ int main(int argc, char *argv[])
{ {
struct impl impl = { 0, }; struct impl impl = { 0, };
const struct spa_support *support; const struct spa_support *support;
const char *str;
uint32_t n_support; uint32_t n_support;
int res = 0, c; int res = 0, c;
char *opt_properties;
static const struct option long_options[] = { static const struct option long_options[] = {
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
{ "enabled", required_argument, NULL, 'e' },
{ "disabled", required_argument, NULL, 'd' },
{ "properties", required_argument, NULL, 'p' }, { "properties", required_argument, NULL, 'p' },
{ NULL, 0, NULL, 0} { NULL, 0, NULL, 0}
}; };
@ -2248,13 +2273,20 @@ int main(int argc, char *argv[])
pw_init(&argc, &argv); pw_init(&argc, &argv);
check_default_enabled(&impl); if ((impl.conf = pw_properties_new(NULL, NULL)) == NULL)
return -1;
sm_media_session_load_conf(&impl.this, SESSION_CONF, impl.conf);
impl.opt_enabled = strdup(EXTRA_ENABLED); if ((impl.modules = pw_properties_new("default", "true", NULL)) == NULL)
impl.opt_disabled = strdup(EXTRA_DISABLED); return -1;
opt_properties = strdup(""); if ((str = pw_properties_get(impl.conf, "modules")) != NULL)
collect_modules(&impl, str);
while ((c = getopt_long(argc, argv, "hVe:d:p:", long_options, NULL)) != -1) { impl.this.props = pw_properties_new(NULL, NULL);
if (impl.this.props == NULL)
return -1;
while ((c = getopt_long(argc, argv, "hVp:", long_options, NULL)) != -1) {
switch (c) { switch (c) {
case 'h': case 'h':
show_help(argv[0], &impl); show_help(argv[0], &impl);
@ -2267,17 +2299,8 @@ int main(int argc, char *argv[])
pw_get_headers_version(), pw_get_headers_version(),
pw_get_library_version()); pw_get_library_version());
return 0; return 0;
case 'e':
if (append_opt_str(&impl.opt_enabled, ",", optarg))
return -1;
break;
case 'd':
if (append_opt_str(&impl.opt_disabled, ",", optarg))
return -1;
break;
case 'p': case 'p':
if (append_opt_str(&opt_properties, " ", optarg)) pw_properties_update_string(impl.this.props, optarg, strlen(optarg));
return -1;
break; break;
default: default:
return -1; return -1;
@ -2286,11 +2309,6 @@ int main(int argc, char *argv[])
impl.state_dir_fd = -1; impl.state_dir_fd = -1;
impl.this.props = pw_properties_new_string(opt_properties);
free(opt_properties);
if (impl.this.props == NULL)
return -1;
spa_dict_for_each(item, &impl.this.props->dict) spa_dict_for_each(item, &impl.this.props->dict)
pw_log_info(" '%s' = '%s'", item->key, item->value); pw_log_info(" '%s' = '%s'", item->key, item->value);
@ -2311,10 +2329,8 @@ int main(int argc, char *argv[])
if (impl.this.context == NULL) if (impl.this.context == NULL)
return -1; return -1;
pw_context_add_spa_lib(impl.this.context, "api.bluez5.*", "bluez5/libspa-bluez5"); if ((str = pw_properties_get(impl.conf, "spa-libs")) != NULL)
pw_context_add_spa_lib(impl.this.context, "api.alsa.*", "alsa/libspa-alsa"); load_spa_libs(&impl, str);
pw_context_add_spa_lib(impl.this.context, "api.v4l2.*", "v4l2/libspa-v4l2");
pw_context_add_spa_lib(impl.this.context, "api.libcamera.*", "libcamera/libspa-libcamera");
pw_context_set_object(impl.this.context, SM_TYPE_MEDIA_SESSION, &impl); pw_context_set_object(impl.this.context, SM_TYPE_MEDIA_SESSION, &impl);
@ -2343,15 +2359,7 @@ int main(int argc, char *argv[])
for (i = 0; i < SPA_N_ELEMENTS(modules); i++) { for (i = 0; i < SPA_N_ELEMENTS(modules); i++) {
const char *name = modules[i].name; const char *name = modules[i].name;
if (is_opt_enabled(&impl, name)) { if (is_module_enabled(&impl, name)) {
if (modules[i].props) {
struct pw_properties *props;
props = pw_properties_new_string(modules[i].props);
if (props) {
pw_properties_update(impl.this.props, &props->dict);
pw_properties_free(props);
}
}
pw_log_info("enable: %s", name); pw_log_info("enable: %s", name);
modules[i].start(&impl.this); modules[i].start(&impl.this);
} }
@ -2370,14 +2378,13 @@ exit:
pw_map_clear(&impl.endpoint_links); pw_map_clear(&impl.endpoint_links);
pw_map_clear(&impl.globals); pw_map_clear(&impl.globals);
pw_properties_free(impl.this.props); pw_properties_free(impl.this.props);
pw_properties_free(impl.conf);
pw_properties_free(impl.modules);
if (impl.state_dir_fd != -1) if (impl.state_dir_fd != -1)
close(impl.state_dir_fd); close(impl.state_dir_fd);
pw_deinit(); pw_deinit();
free(impl.opt_enabled);
free(impl.opt_disabled);
return res; return res;
} }

View file

@ -289,6 +289,9 @@ int sm_media_session_create_links(struct sm_media_session *sess,
int sm_media_session_remove_links(struct sm_media_session *sess, int sm_media_session_remove_links(struct sm_media_session *sess,
const struct spa_dict *dict); const struct spa_dict *dict);
int sm_media_session_load_conf(struct sm_media_session *sess,
const char *name, struct pw_properties *conf);
int sm_media_session_load_state(struct sm_media_session *sess, int sm_media_session_load_state(struct sm_media_session *sess,
const char *name, const char *prefix, struct pw_properties *props); const char *name, const char *prefix, struct pw_properties *props);
int sm_media_session_save_state(struct sm_media_session *sess, int sm_media_session_save_state(struct sm_media_session *sess,