common: Update config structures.

Match xml format style.
This commit is contained in:
Juho Hämäläinen 2022-02-23 10:44:09 +02:00
parent 40c320bc07
commit 9e4c6fa8f1
2 changed files with 336 additions and 208 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2018 Jolla Ltd.
* Copyright (C) 2013-2022 Jolla Ltd.
*
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
@ -26,6 +26,7 @@
#include "droid/version.h"
#include "droid/droid-config.h"
#include "droid/sllist.h"
#include "config-parser-xml.h"
#include <signal.h>
#include <stdio.h>
@ -36,52 +37,28 @@
#include <valgrind/memcheck.h>
#endif
#include <pulse/rtclock.h>
#include <pulse/timeval.h>
#include <pulse/volume.h>
#include <pulse/xmalloc.h>
#include <pulsecore/core.h>
#include <pulsecore/core-error.h>
#include <pulsecore/i18n.h>
#include <pulsecore/module.h>
#include <pulsecore/memchunk.h>
#include <pulsecore/sink.h>
#include <pulsecore/modargs.h>
#include <pulsecore/core-rtclock.h>
#include <pulsecore/core-util.h>
#include <pulsecore/sample-util.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/thread.h>
#include <pulsecore/thread-mq.h>
#include <pulsecore/rtpoll.h>
#include <pulsecore/time-smoother.h>
#include <pulsecore/refcnt.h>
#include <pulsecore/shared.h>
#include <pulsecore/mutex.h>
#include <pulsecore/strlist.h>
#include <pulsecore/atomic.h>
#include <pulsecore/modargs.h>
#include <hardware/audio.h>
#include <hardware_legacy/audio_policy_conf.h>
#define ODM_AUDIO_POLICY_CONFIG_XML_FILE "/odm/etc/audio_policy_configuration.xml"
#define VENDOR_AUDIO_AUDIO_POLICY_CONFIG_XML_FILE "/vendor/etc/audio/audio_policy_configuration.xml"
#define VENDOR_AUDIO_POLICY_CONFIG_XML_FILE "/vendor/etc/audio_policy_configuration.xml"
#define SYSTEM_AUDIO_POLICY_CONFIG_XML_FILE "/system/etc/audio_policy_configuration.xml"
#define ODM_AUDIO_POLICY_CONFIG_XML_FILE "/odm/etc/audio_policy_configuration.xml"
#define VENDOR_AUDIO_AUDIO_POLICY_CONFIG_XML_FILE "/vendor/etc/audio/audio_policy_configuration.xml"
#define VENDOR_AUDIO_POLICY_CONFIG_XML_FILE "/vendor/etc/audio_policy_configuration.xml"
#define SYSTEM_AUDIO_POLICY_CONFIG_XML_FILE "/system/etc/audio_policy_configuration.xml"
pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma) {
pa_droid_config_audio *config = NULL;
dm_config_device *dm_config_load(pa_modargs *ma) {
dm_config_device *config = NULL;
const char *manual_config;
const char *config_location[] = {
ODM_AUDIO_POLICY_CONFIG_XML_FILE,
VENDOR_AUDIO_AUDIO_POLICY_CONFIG_XML_FILE,
VENDOR_AUDIO_POLICY_CONFIG_XML_FILE,
AUDIO_POLICY_VENDOR_CONFIG_FILE,
SYSTEM_AUDIO_POLICY_CONFIG_XML_FILE,
AUDIO_POLICY_CONFIG_FILE,
NULL};
pa_assert(ma);
@ -106,92 +83,210 @@ pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma) {
return config;
}
pa_droid_config_audio *pa_droid_config_dup(const pa_droid_config_audio *config) {
pa_droid_config_audio *config_copy;
pa_droid_config_hw_module *module, *module_copy;
pa_droid_config_device *device, *device_copy;
static dm_config_profile *config_profile_dup(const dm_config_profile *profile) {
dm_config_profile *copy = pa_xnew0(dm_config_profile, 1);
copy->name = pa_xstrdup(profile->name);
copy->format = profile->format;
memcpy(copy->sampling_rates,
profile->sampling_rates,
sizeof(profile->sampling_rates));
memcpy(copy->channel_masks,
profile->channel_masks,
sizeof(profile->channel_masks));
return copy;
}
static dm_config_port *config_port_dup(const dm_config_port *port, dm_config_module *module) {
dm_config_port *copy = pa_xnew0(dm_config_port, 1);
const dm_list_entry *i;
copy->module = module;
copy->port_type = port->port_type;
copy->name = pa_xstrdup(port->name);
copy->role = port->role;
copy->profiles = dm_list_new();
DM_LIST_FOREACH(i, port->profiles)
dm_list_push_back(copy->profiles, config_profile_dup(i->data));
if (port->port_type == DM_CONFIG_TYPE_DEVICE_PORT) {
copy->type = port->type;
copy->address = pa_xstrdup(port->address);
}
if (port->port_type == DM_CONFIG_TYPE_MIX_PORT) {
copy->flags = port->flags;
copy->max_open_count = port->max_open_count;
copy->max_active_count = port->max_active_count;
}
return copy;
}
static dm_config_route *config_route_dup(const dm_config_route *route, dm_list *ports) {
dm_config_route *copy = pa_xnew0(dm_config_route, 1);
dm_config_port *port_copy, *port;
void *state, *state2;
copy->type = route->type;
copy->sources = dm_list_new();
DM_LIST_FOREACH_DATA(port, route->sources, state) {
DM_LIST_FOREACH_DATA(port_copy, ports, state2) {
if (dm_config_port_equal(port, port_copy)) {
dm_list_push_back(copy->sources, port_copy);
break;
}
}
}
DM_LIST_FOREACH_DATA(port_copy, ports, state) {
if (dm_config_port_equal(port_copy, route->sink)) {
copy->sink = port_copy;
break;
}
}
return copy;
}
static dm_config_module *config_module_dup(const dm_config_module *module) {
dm_config_module *copy = pa_xnew0(dm_config_module, 1);
dm_config_port *device_port, *attached_device, *mix_port;
dm_config_route *route;
void *state, *state2;
copy = pa_xnew0(dm_config_module, 1);
copy->name = pa_xstrdup(module->name);
copy->version_major = module->version_major;
copy->version_minor = module->version_minor;
copy->attached_devices = dm_list_new();
copy->default_output_device = NULL;
copy->mix_ports = dm_list_new();
copy->device_ports = dm_list_new();
copy->ports = dm_list_new();
copy->routes = dm_list_new();
DM_LIST_FOREACH_DATA(device_port, module->device_ports, state) {
dm_config_port *device_port_copy = config_port_dup(device_port, copy);
dm_list_push_back(copy->device_ports, device_port_copy);
dm_list_push_back(copy->ports, device_port_copy);
if (module->default_output_device == device_port)
copy->default_output_device = device_port_copy;
DM_LIST_FOREACH_DATA(attached_device, module->attached_devices, state2) {
if (attached_device == device_port) {
dm_list_push_back(copy->attached_devices, device_port_copy);
break;
}
}
}
DM_LIST_FOREACH_DATA(mix_port, module->mix_ports, state) {
dm_config_port *mix_port_copy = config_port_dup(mix_port, copy);
dm_list_push_back(copy->mix_ports, mix_port_copy);
dm_list_push_back(copy->ports, mix_port_copy);
}
DM_LIST_FOREACH_DATA(route, module->routes, state)
dm_list_push_back(copy->routes, config_route_dup(route, copy->ports));
return copy;
}
dm_config_device *dm_config_dup(const dm_config_device *config) {
dm_config_device *copy;
dm_config_module *module;
void *state;
pa_assert(config);
config_copy = pa_xnew0(pa_droid_config_audio, 1);
copy = pa_xnew0(dm_config_device, 1);
copy->global_config = dm_list_new();
copy->modules = dm_list_new();
if (config->global_config)
config_copy->global_config = pa_xmemdup(config->global_config, sizeof(*config->global_config));
if (config->global_config) {
dm_config_global *global, *global_copy;
SLLIST_FOREACH(module, config->hw_modules) {
module_copy = pa_droid_config_hw_module_new(config_copy, module->name);
if (module->global_config)
module_copy->global_config = pa_xmemdup(module->global_config, sizeof(*module->global_config));
SLLIST_FOREACH(device, module->outputs) {
device_copy = pa_xmemdup(device, sizeof(*device));
device_copy->module = module_copy;
device_copy->name = pa_xstrdup(device->name);
SLLIST_APPEND(pa_droid_config_device, module_copy->outputs, device_copy);
DM_LIST_FOREACH_DATA(global, config->global_config, state) {
global_copy = pa_xnew0(dm_config_global, 1);
global_copy->key = pa_xstrdup(global->key);
global_copy->value = pa_xstrdup(global->value);
dm_list_push_back(copy->global_config, global_copy);
}
SLLIST_FOREACH(device, module->inputs) {
device_copy = pa_xmemdup(device, sizeof(*device));
device_copy->module = module_copy;
device_copy->name = pa_xstrdup(device->name);
SLLIST_APPEND(pa_droid_config_device, module_copy->inputs, device_copy);
}
SLLIST_APPEND(pa_droid_config_hw_module, config_copy->hw_modules, module_copy);
}
return config_copy;
DM_LIST_FOREACH_DATA(module, config->modules, state)
dm_list_push_back(copy->modules, config_module_dup(module));
return copy;
}
pa_droid_config_audio *pa_parse_droid_audio_config(const char *filename) {
const char *suffix;
pa_assert(filename);
if ((suffix = rindex(filename, '.'))) {
if (strlen(suffix) == 4 && pa_streq(suffix, ".xml"))
return pa_parse_droid_audio_config_xml(filename);
else if (strlen(suffix) == 5 && pa_streq(suffix, ".conf"))
return pa_parse_droid_audio_config_legacy(filename);
}
return NULL;
dm_config_device *pa_parse_droid_audio_config(const char *filename) {
return pa_parse_droid_audio_config_xml(filename);
}
void pa_droid_config_free(pa_droid_config_audio *config) {
pa_droid_config_hw_module *module;
pa_droid_config_device *device;
static void config_global_free(void *data) {
dm_config_global *global = data;
pa_xfree(global->key);
pa_xfree(global->value);
pa_xfree(global);
}
static void config_profile_free(void *data) {
dm_config_profile *profile = data;
pa_xfree(profile->name);
pa_xfree(profile);
}
static void config_port_free(void *data) {
dm_config_port *port = data;
pa_xfree(port->name);
pa_xfree(port->address);
dm_list_free(port->profiles, config_profile_free);
pa_xfree(port);
}
static void config_route_free(void *data) {
dm_config_route *route = data;
dm_list_free(route->sources, NULL);
pa_xfree(route);
}
static void config_module_free(void *data) {
dm_config_module *module = data;
pa_xfree(module->name);
dm_list_free(module->attached_devices, NULL);
dm_list_free(module->ports, config_port_free);
dm_list_free(module->device_ports, NULL);
dm_list_free(module->mix_ports, NULL);
dm_list_free(module->routes, config_route_free);
pa_xfree(module);
}
void dm_config_free(dm_config_device *config) {
if (!config)
return;
while (config->hw_modules) {
SLLIST_STEAL_FIRST(module, config->hw_modules);
while (module->outputs) {
SLLIST_STEAL_FIRST(device, module->outputs);
pa_droid_config_device_free(device);
}
while (module->inputs) {
SLLIST_STEAL_FIRST(device, module->inputs);
pa_droid_config_device_free(device);
}
pa_droid_config_hw_module_free(module);
}
pa_xfree(config->global_config);
dm_list_free(config->global_config, config_global_free);
dm_list_free(config->modules, config_module_free);
pa_xfree(config);
}
const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_config_audio *config, const char* module_id) {
pa_droid_config_hw_module *module;
dm_config_module *dm_config_find_module(dm_config_device *config, const char* module_id) {
dm_config_module *module;
void *state;
pa_assert(config);
pa_assert(module_id);
SLLIST_FOREACH(module, config->hw_modules) {
DM_LIST_FOREACH_DATA(module, config->modules, state) {
if (pa_streq(module_id, module->name))
return module;
}
@ -199,71 +294,73 @@ const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_conf
return NULL;
}
static const pa_droid_config_device *find_device(const pa_droid_config_hw_module *module, bool output, const char* device_name) {
pa_droid_config_device *device;
dm_config_port *dm_config_find_port(dm_config_module *module, const char* name) {
dm_config_port *port;
void *state;
pa_assert(module);
pa_assert(device_name);
pa_assert(name);
SLLIST_FOREACH(device, output ? module->outputs : module->inputs) {
if (pa_streq(device_name, device->name))
return device;
DM_LIST_FOREACH_DATA(port, module->ports, state) {
if (pa_streq(name, port->name))
return port;
}
return NULL;
}
const pa_droid_config_device *pa_droid_config_find_output(const pa_droid_config_hw_module *module, const char* output_name) {
return find_device(module, true, output_name);
}
const pa_droid_config_device *pa_droid_config_find_input(const pa_droid_config_hw_module *module, const char* input_name) {
return find_device(module, false, input_name);
}
pa_droid_config_hw_module *pa_droid_config_hw_module_new(const pa_droid_config_audio *config, const char *name) {
pa_droid_config_hw_module *hw_module;
pa_assert(config);
pa_assert(name);
hw_module = pa_xnew0(pa_droid_config_hw_module, 1);
hw_module->config = config;
hw_module->name = pa_xstrndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN);
return hw_module;
}
void pa_droid_config_hw_module_free(pa_droid_config_hw_module *hw_module) {
if (!hw_module)
return;
pa_xfree(hw_module->name);
pa_xfree(hw_module->global_config);
pa_xfree(hw_module);
}
pa_droid_config_device *pa_droid_config_device_new(const pa_droid_config_hw_module *module,
pa_direction_t direction,
const char *name) {
pa_droid_config_device *device;
dm_config_port *dm_config_default_output_device(dm_config_module *module) {
pa_assert(module);
pa_assert(direction == PA_DIRECTION_OUTPUT || direction == PA_DIRECTION_INPUT);
pa_assert(name);
device = pa_xnew0(pa_droid_config_device, 1);
device->module = module;
device->direction = direction;
device->name = pa_replace(name, " ", "_");
return device;
if (module->default_output_device)
return module->default_output_device;
else {
pa_log("Module %s doesn't have default output device.", module->name);
return 0;
}
}
void pa_droid_config_device_free(pa_droid_config_device *device) {
if (!device)
return;
char *dm_config_escape_string(const char *string) {
if (!string)
return NULL;
pa_xfree(device->name);
pa_xfree(device);
/* Just replace whitespace with underscores for now. */
return pa_replace(string, " ", "_");
}
dm_config_port *dm_config_find_device_port(dm_config_port *port, audio_devices_t device) {
dm_config_port *device_port;
void *state;
pa_assert(port);
DM_LIST_FOREACH_DATA(device_port, port->module->device_ports, state) {
if (device_port->type == device)
return device_port;
}
return NULL;
}
bool dm_config_port_equal(const dm_config_port *a, const dm_config_port *b) {
if ((!a && b) || (a && !b))
return false;
else if (!a && !b)
return true;
return (pa_streq(a->name, b->name) && a->type == b->type);
}
dm_config_port *dm_config_find_mix_port(dm_config_module *module, const char *name) {
dm_config_port *mix_port = NULL;
void *state;
DM_LIST_FOREACH_DATA(mix_port, module->mix_ports, state) {
if (pa_streq(mix_port->name, name))
return mix_port;
}
return NULL;
}

View file

@ -2,7 +2,7 @@
#define foodroidconfigfoo
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018-2022 Jolla Ltd.
*
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
@ -30,75 +30,106 @@
#include <android-config.h>
#include <hardware/audio.h>
#include <droid/sllist.h>
#include <droid/version.h>
typedef struct pa_droid_config_audio pa_droid_config_audio;
typedef struct pa_droid_config_hw_module pa_droid_config_hw_module;
#define AUDIO_MAX_SAMPLING_RATES (32)
#define AUDIO_MAX_CHANNEL_MASKS (32)
#define AUDIO_MAX_SAMPLING_RATES (32)
typedef struct dm_config_global dm_config_global;
typedef struct dm_config_port dm_config_port;
typedef struct dm_config_route dm_config_route;
typedef struct dm_config_module dm_config_module;
typedef struct dm_config_device dm_config_device;
typedef struct dm_config_profile dm_config_profile;
typedef struct pa_droid_config_global {
uint32_t audio_hal_version;
audio_devices_t attached_output_devices;
audio_devices_t default_output_device;
audio_devices_t attached_input_devices;
} pa_droid_config_global;
typedef struct pa_droid_config_device {
const pa_droid_config_hw_module *module;
char *name;
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]; /* (uint32_t) -1 -> dynamic */
audio_channel_mask_t channel_masks; /* 0 -> dynamic */
audio_format_t formats; /* 0 -> dynamic */
audio_devices_t devices;
/* Instead of using audio_output_flags_t and audio_input_flags_t
* unify the flags as uint32_t so that we can have single struct for both
* output and input configurations.
* audio_input_flags_t was introduced in APIs 2 & 3, depending on adaptation,
* so having input flags as uint32_t is simpler from input implementation
* point of view as well. */
uint32_t flags;
pa_direction_t direction;
struct pa_droid_config_device *next;
} pa_droid_config_device;
struct pa_droid_config_hw_module {
const pa_droid_config_audio *config;
char *name;
/* If global config is not defined for module, use root global config. */
pa_droid_config_global *global_config;
pa_droid_config_device *outputs;
pa_droid_config_device *inputs;
struct pa_droid_config_hw_module *next;
struct dm_config_global {
char *key;
char *value;
};
struct pa_droid_config_audio {
pa_droid_config_global *global_config;
pa_droid_config_hw_module *hw_modules;
struct dm_config_profile {
char *name;
audio_format_t format; /* 0 -> dynamic TODO check that this is still true */
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]; /* sampling_rates[0] == 0 -> dynamic, otherwise 0 terminates list */
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]; /* channel_masks[0] == 0 -> dynamic */
};
typedef enum dm_config_role {
DM_CONFIG_ROLE_SINK,
DM_CONFIG_ROLE_SOURCE,
} dm_config_role_t;
typedef enum dm_config_type {
DM_CONFIG_TYPE_MIX,
DM_CONFIG_TYPE_DEVICE_PORT,
DM_CONFIG_TYPE_MIX_PORT,
} dm_config_type_t;
struct dm_config_port {
dm_config_module *module;
/* common values */
dm_config_type_t port_type; /* either mixPort or devicePort */
char *name;
dm_config_role_t role;
dm_list *profiles; /* dm_config_profile* */
/* devicePort specific values */
audio_devices_t type;
char *address;
/* mixPort specific values */
uint32_t flags; /* audio_output_flag_t or audio_input_flag_t */
int max_open_count; /* 0 == not defined */
int max_active_count; /* 0 == not defined */
};
struct dm_config_route {
dm_config_type_t type;
dm_config_port *sink;
dm_list *sources; /* dm_config_port* */
};
struct dm_config_module {
dm_config_device *config;
char *name;
int version_major;
int version_minor;
dm_list *attached_devices; /* dm_config_port* owned by device_ports list below */
dm_config_port *default_output_device; /* owned by device_ports list below */
dm_list *ports; /* dm_config_port* - for convenience port types are filtered to two lists below: */
dm_list *mix_ports; /* dm_config_port* */
dm_list *device_ports; /* dm_config_port* */
dm_list *routes; /* dm_config_route* */
};
struct dm_config_device {
dm_list *global_config; /* dm_config_global* */
dm_list *modules; /* dm_config_module* */
};
/* Config parser */
pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma);
pa_droid_config_audio *pa_droid_config_dup(const pa_droid_config_audio *config);
void pa_droid_config_free(pa_droid_config_audio *config);
pa_droid_config_audio *pa_parse_droid_audio_config_legacy(const char *filename);
pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename);
dm_config_device *dm_config_load(pa_modargs *ma);
dm_config_device *dm_config_dup(const dm_config_device *config);
void dm_config_free(dm_config_device *config);
/* autodetect config type from filename and parse */
pa_droid_config_audio *pa_parse_droid_audio_config(const char *filename);
dm_config_device *pa_parse_droid_audio_config(const char *filename);
const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_config_audio *config, const char* module_id);
const pa_droid_config_device *pa_droid_config_find_output(const pa_droid_config_hw_module *module, const char* output_name);
const pa_droid_config_device *pa_droid_config_find_input(const pa_droid_config_hw_module *module, const char* input_name);
dm_config_module *dm_config_find_module(dm_config_device *config, const char* module_id);
dm_config_port *dm_config_find_port(dm_config_module *module, const char* name);
dm_config_port *dm_config_default_output_device(dm_config_module *module);
dm_config_port *dm_config_find_device_port(dm_config_port *port, audio_devices_t device);
char *dm_config_escape_string(const char *string);
pa_droid_config_hw_module *pa_droid_config_hw_module_new(const pa_droid_config_audio *config, const char *name);
void pa_droid_config_hw_module_free(pa_droid_config_hw_module *hw_module);
pa_droid_config_device *pa_droid_config_device_new(const pa_droid_config_hw_module *module,
pa_direction_t direction,
const char *name);
void pa_droid_config_device_free(pa_droid_config_device *device);
bool dm_config_port_equal(const dm_config_port *a, const dm_config_port *b);
dm_config_port *dm_config_find_mix_port(dm_config_module *module, const char *name);
#endif