mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
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:
parent
389a125488
commit
24c68b0067
6 changed files with 383 additions and 154 deletions
57
src/daemon/media-session.d/alsa-monitor.conf
Normal file
57
src/daemon/media-session.d/alsa-monitor.conf
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
55
src/daemon/media-session.d/media-session.conf
Normal file
55
src/daemon/media-session.d/media-session.conf
Normal 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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -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')
|
||||
|
||||
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'))
|
||||
|
||||
conf_config_uninstalled = conf_config
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
|
@ -40,6 +41,7 @@
|
|||
#include <spa/utils/hook.h>
|
||||
#include <spa/utils/names.h>
|
||||
#include <spa/utils/keys.h>
|
||||
#include <spa/utils/json.h>
|
||||
#include <spa/param/props.h>
|
||||
#include <spa/pod/builder.h>
|
||||
#include <spa/pod/parser.h>
|
||||
|
|
@ -55,6 +57,8 @@
|
|||
|
||||
#include "reserve.c"
|
||||
|
||||
#define SESSION_CONF "alsa-monitor.conf"
|
||||
|
||||
#define DEFAULT_JACK_SECONDS 1
|
||||
|
||||
struct node {
|
||||
|
|
@ -102,6 +106,7 @@ struct device {
|
|||
unsigned int first:1;
|
||||
unsigned int appeared:1;
|
||||
unsigned int probed:1;
|
||||
unsigned int use_acp:1;
|
||||
struct spa_list node_list;
|
||||
};
|
||||
|
||||
|
|
@ -109,6 +114,8 @@ struct impl {
|
|||
struct sm_media_session *session;
|
||||
struct spa_hook session_listener;
|
||||
|
||||
struct pw_properties *conf;
|
||||
|
||||
DBusConnection *conn;
|
||||
|
||||
struct spa_handle *handle;
|
||||
|
|
@ -120,8 +127,6 @@ struct impl {
|
|||
|
||||
struct spa_source *jack_timeout;
|
||||
struct pw_proxy *jack_device;
|
||||
|
||||
unsigned int use_acp:1;
|
||||
};
|
||||
|
||||
#undef NAME
|
||||
|
|
@ -192,6 +197,111 @@ static const struct sm_object_methods node_methods = {
|
|||
.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,
|
||||
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->device = device;
|
||||
node->id = id;
|
||||
|
||||
apply_matches(impl, node->props);
|
||||
|
||||
node->snode = sm_media_session_create_node(impl->session,
|
||||
"adapter",
|
||||
&node->props->dict);
|
||||
|
|
@ -517,11 +630,10 @@ static int update_device_props(struct device *device)
|
|||
|
||||
static void set_profile(struct device *device, int index)
|
||||
{
|
||||
struct impl *impl = device->impl;
|
||||
char buf[1024];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
|
||||
|
||||
if (impl->use_acp)
|
||||
if (device->use_acp)
|
||||
return;
|
||||
|
||||
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;
|
||||
int res;
|
||||
const char *str, *card, *factory_name, *name;
|
||||
const char *str, *card;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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->id = id;
|
||||
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;
|
||||
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 &&
|
||||
(strcmp(str, "*") == 0 ||
|
||||
(name != NULL && strstr(str, name) != NULL))) {
|
||||
pw_properties_set(device->props, "api.alsa.soft-mixer", "true");
|
||||
}
|
||||
if ((str = pw_properties_get(impl->session->props, "alsa.no-auto-port")) != NULL &&
|
||||
(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");
|
||||
}
|
||||
str = pw_properties_get(device->props, "api.alsa.use-acp");
|
||||
device->use_acp = str ? pw_properties_parse_bool(str) : true;
|
||||
if (device->use_acp)
|
||||
device->factory_name = strdup(SPA_NAME_API_ALSA_ACP_DEVICE);
|
||||
else
|
||||
device->factory_name = strdup(info->factory_name);
|
||||
|
||||
if (impl->conn &&
|
||||
(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);
|
||||
pw_proxy_destroy(impl->jack_device);
|
||||
pw_unload_spa_handle(impl->handle);
|
||||
pw_properties_free(impl->conf);
|
||||
free(impl);
|
||||
}
|
||||
|
||||
|
|
@ -954,7 +1052,6 @@ int sm_alsa_monitor_start(struct sm_media_session *session)
|
|||
struct pw_context *context = session->context;
|
||||
struct impl *impl;
|
||||
void *iface;
|
||||
const char *str;
|
||||
int res;
|
||||
|
||||
impl = calloc(1, sizeof(struct impl));
|
||||
|
|
@ -962,9 +1059,15 @@ int sm_alsa_monitor_start(struct sm_media_session *session)
|
|||
return -errno;
|
||||
|
||||
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)
|
||||
impl->use_acp = pw_properties_parse_bool(str);
|
||||
if ((res = sm_media_session_load_conf(impl->session,
|
||||
SESSION_CONF, impl->conf)) < 0)
|
||||
pw_log_info("can't load "SESSION_CONF" config: %s", spa_strerror(res));
|
||||
|
||||
if (session->dbus_connection)
|
||||
impl->conn = spa_dbus_connection_get(session->dbus_connection);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@
|
|||
|
||||
#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__)
|
||||
|
||||
|
|
@ -115,9 +116,8 @@ struct sync {
|
|||
struct impl {
|
||||
struct sm_media_session this;
|
||||
|
||||
const char *opt_default;
|
||||
char *opt_enabled;
|
||||
char *opt_disabled;
|
||||
struct pw_properties *conf;
|
||||
struct pw_properties *modules;
|
||||
|
||||
struct pw_main_loop *loop;
|
||||
struct spa_dbus *dbus;
|
||||
|
|
@ -1776,6 +1776,44 @@ int sm_media_session_remove_links(struct sm_media_session *sess,
|
|||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
#define DEFAULT_ENABLED "flatpak," \
|
||||
"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)
|
||||
static int load_spa_libs(struct impl *impl, const char *str)
|
||||
{
|
||||
const char *dir;
|
||||
char check_path[PATH_MAX];
|
||||
uint32_t i;
|
||||
struct stat statbuf;
|
||||
struct modules {
|
||||
const char *file;
|
||||
const char *name;
|
||||
const char *options;
|
||||
} module_check[] = {
|
||||
{ "with-jack", "Audio", AUDIO_ENABLED },
|
||||
{ "with-alsa", "Audio", AUDIO_ENABLED },
|
||||
{ "with-pulseaudio", "PulseAudio", PULSE_ENABLED },
|
||||
};
|
||||
struct spa_json it[2];
|
||||
char key[512], value[512];
|
||||
|
||||
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) {
|
||||
const char *val;
|
||||
if (key[0] == '#') {
|
||||
if (spa_json_next(&it[1], &val) <= 0)
|
||||
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)
|
||||
dir = PIPEWIRE_CONFIG_DIR;
|
||||
if (dir == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
for (i = 0; i < SPA_N_ELEMENTS(module_check); i++) {
|
||||
snprintf(check_path, sizeof(check_path),
|
||||
"%s/media-session.d/%s", dir, module_check[i].file);
|
||||
if (stat(check_path, &statbuf) == 0) {
|
||||
pw_log_info("found %s, enable %s", check_path,
|
||||
module_check[i].name);
|
||||
impl->opt_default = module_check[i].options;
|
||||
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),
|
||||
"%s/media-session.d/%s", dir, key);
|
||||
add = (stat(check_path, &statbuf) == 0);
|
||||
}
|
||||
if (add) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -2160,8 +2221,7 @@ static const struct {
|
|||
{ "default-routes", "restore default route", sm_default_routes_start, NULL },
|
||||
{ "restore-stream", "restore stream settings", sm_restore_stream_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-acp", "alsa card profile udev detection", sm_alsa_monitor_start, "alsa.use-acp=true" },
|
||||
{ "alsa-monitor", "alsa card udev detection", sm_alsa_monitor_start, NULL },
|
||||
{ "v4l2", "video for linux udev detection", sm_v4l2_monitor_start, NULL },
|
||||
{ "libcamera", "libcamera udev detection", sm_libcamera_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 },
|
||||
};
|
||||
|
||||
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;
|
||||
size_t len;
|
||||
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;
|
||||
const char *str = pw_properties_get(impl->modules, val);
|
||||
return str ? pw_properties_parse_bool(str) : false;
|
||||
}
|
||||
|
||||
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"
|
||||
" -h, --help Show this help\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",
|
||||
name, impl->opt_enabled, impl->opt_disabled);
|
||||
name);
|
||||
|
||||
fprintf(stdout,
|
||||
"\noptions: (*=enabled)\n");
|
||||
for (i = 0; i < SPA_N_ELEMENTS(modules); i++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -2232,14 +2259,12 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
struct impl impl = { 0, };
|
||||
const struct spa_support *support;
|
||||
const char *str;
|
||||
uint32_t n_support;
|
||||
int res = 0, c;
|
||||
char *opt_properties;
|
||||
static const struct option long_options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "enabled", required_argument, NULL, 'e' },
|
||||
{ "disabled", required_argument, NULL, 'd' },
|
||||
{ "properties", required_argument, NULL, 'p' },
|
||||
{ NULL, 0, NULL, 0}
|
||||
};
|
||||
|
|
@ -2248,13 +2273,20 @@ int main(int argc, char *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);
|
||||
impl.opt_disabled = strdup(EXTRA_DISABLED);
|
||||
opt_properties = strdup("");
|
||||
if ((impl.modules = pw_properties_new("default", "true", NULL)) == NULL)
|
||||
return -1;
|
||||
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) {
|
||||
case 'h':
|
||||
show_help(argv[0], &impl);
|
||||
|
|
@ -2267,17 +2299,8 @@ int main(int argc, char *argv[])
|
|||
pw_get_headers_version(),
|
||||
pw_get_library_version());
|
||||
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':
|
||||
if (append_opt_str(&opt_properties, " ", optarg))
|
||||
return -1;
|
||||
pw_properties_update_string(impl.this.props, optarg, strlen(optarg));
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
|
|
@ -2286,11 +2309,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
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)
|
||||
pw_log_info(" '%s' = '%s'", item->key, item->value);
|
||||
|
||||
|
|
@ -2311,10 +2329,8 @@ int main(int argc, char *argv[])
|
|||
if (impl.this.context == NULL)
|
||||
return -1;
|
||||
|
||||
pw_context_add_spa_lib(impl.this.context, "api.bluez5.*", "bluez5/libspa-bluez5");
|
||||
pw_context_add_spa_lib(impl.this.context, "api.alsa.*", "alsa/libspa-alsa");
|
||||
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");
|
||||
if ((str = pw_properties_get(impl.conf, "spa-libs")) != NULL)
|
||||
load_spa_libs(&impl, str);
|
||||
|
||||
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++) {
|
||||
const char *name = modules[i].name;
|
||||
if (is_opt_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);
|
||||
}
|
||||
}
|
||||
if (is_module_enabled(&impl, name)) {
|
||||
pw_log_info("enable: %s", name);
|
||||
modules[i].start(&impl.this);
|
||||
}
|
||||
|
|
@ -2370,14 +2378,13 @@ exit:
|
|||
pw_map_clear(&impl.endpoint_links);
|
||||
pw_map_clear(&impl.globals);
|
||||
pw_properties_free(impl.this.props);
|
||||
pw_properties_free(impl.conf);
|
||||
pw_properties_free(impl.modules);
|
||||
|
||||
if (impl.state_dir_fd != -1)
|
||||
close(impl.state_dir_fd);
|
||||
|
||||
pw_deinit();
|
||||
|
||||
free(impl.opt_enabled);
|
||||
free(impl.opt_disabled);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
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,
|
||||
const char *name, const char *prefix, struct pw_properties *props);
|
||||
int sm_media_session_save_state(struct sm_media_session *sess,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue