diff options
author | Manuel Bachmann <manuel.bachmann@iot.bzh> | 2016-07-08 16:31:01 +0200 |
---|---|---|
committer | Yannick Gicquel <yannick.gicquel@iot.bzh> | 2016-10-11 17:09:07 +0200 |
commit | 2de141b9a3145a4a8edf2e310adfa8d425637e53 (patch) | |
tree | 9ecf1291300fdc2a1a2915e3ce18a6b5c6a15181 | |
parent | cc70e0ae30920ca835bf011f8040afb6fea43f45 (diff) |
Implement JSON configuration file
A JSON configuration file can now be read as "/etc/
pulseaudio-agl.cfg", and a sample one is provided by the
package. If it exists and is valid, it will override the
default configuration.
As a result, the module now depends on json-c.
Change-Id: I3f5deccc6f9b89cbd54bea7004271b8aec727538
Signed-off-by: Manuel Bachmann <manuel.bachmann@iot.bzh>
-rw-r--r-- | CMakeLists.txt | 14 | ||||
-rw-r--r-- | config.c | 124 | ||||
-rw-r--r-- | node.c | 35 | ||||
-rw-r--r-- | node.h | 1 |
4 files changed, 166 insertions, 8 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f1ce33..f03a65d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,18 +27,18 @@ add_compile_options(-ffunction-sections -fdata-sections) ########################################################################### -PKG_CHECK_MODULES(pulseaudio-module-devel REQUIRED pulseaudio-module-devel) +PKG_CHECK_MODULES(dependencies REQUIRED json-c pulseaudio-module-devel) -ADD_DEFINITIONS(${pulseaudio-module-devel_CFLAGS}) -SET(include_dirs ${INCLUDE_DIRS} ${pulseaudio-module-devel_INCLUDE_DIRS}) -SET(link_libraries ${LINK_LIBRARIES} ${pulseaudio-module-devel_LIBRARIES}) -STRING(REGEX REPLACE ";" " " link_flags "${pulseaudio-module-devel_LDFLAGS}" "") +ADD_DEFINITIONS(${dependencies_CFLAGS}) +SET(include_dirs ${INCLUDE_DIRS} ${dependencies_INCLUDE_DIRS}) +SET(link_libraries ${LINK_LIBRARIES} ${dependencies_LIBRARIES}) +STRING(REGEX REPLACE ";" " " link_flags "${dependencies_LDFLAGS}" "") SET(plugin_install_dir ${CMAKE_INSTALL_LIBDIR}/pulse-6.0/modules) ############################################################ -ADD_LIBRARY(agl-audio-plugin MODULE module.c audiomgr.c classify.c config.c discover.c loopback.c node.c router.c socketif.c switch.c tracker.c utils.c zone.c) +ADD_LIBRARY(agl-audio-plugin MODULE module.c audiomgr.c classify.c config.c discover.c loopback.c node.c router.c socketif.c switch.c tracker.c utils.c zone.c pulseaudio-agl.cfg) INCLUDE_DIRECTORIES(${include_dirs}) TARGET_LINK_LIBRARIES(agl-audio-plugin ${link_libraries}) SET_TARGET_PROPERTIES(agl-audio-plugin PROPERTIES PREFIX "" @@ -46,3 +46,5 @@ SET_TARGET_PROPERTIES(agl-audio-plugin PROPERTIES PREFIX "" INSTALL(TARGETS agl-audio-plugin LIBRARY DESTINATION ${plugin_install_dir}) +INSTALL(FILES pulseaudio-agl.cfg + DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/pulse) @@ -22,6 +22,14 @@ #include "config.h" #include "zone.h" +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <json/json.h> + +#include <pulsecore/core-util.h> +#include <pulsecore/pulsecore-config.h> + bool use_default_configuration (struct userdata *); const char *agl_config_file_get_path (const char *dir, const char *file, char *buf, size_t len) @@ -58,8 +66,113 @@ bool agl_config_parse_file (struct userdata *u, const char *path) bool agl_config_dofile (struct userdata *u, const char *path) { - /* TODO */ - return false; + int filefd; + struct stat filestat; + void *filemap; + struct json_object *fjson, *root, *sct, *elt, *selt; + const char *val; + int len, i; + + pa_assert (u); + pa_assert (path); + + filefd = open (path, O_RDONLY); + if (filefd == -1) { + pa_log_info ("could not find configuration file '%s'", path); + return false; + } + fstat (filefd, &filestat); + + filemap = mmap (NULL, filestat.st_size, PROT_READ, MAP_PRIVATE, filefd, 0); + if (filemap == MAP_FAILED) { + pa_log_info ("could not map configuration file in memory"); + return false; + } + + /* is the file a JSON file, and if it is, does it have a "config" root ? */ + fjson = json_tokener_parse (filemap); + root = json_object_object_get (fjson, "config"); + if (!fjson || !root) { + pa_log_info ("could not parse JSON configuration file"); + return false; + } + + /* [zones] section */ + sct = json_object_object_get (root, "zones"); + if (!sct) return false; + len = json_object_array_length (sct); + for (i = 0; i < len; i++) { + elt = json_object_array_get_idx (sct, i); + val = json_object_get_string (elt); + agl_zoneset_add_zone (u, val, (uint32_t)i); + } + + /* [rtgroups] section */ + sct = json_object_object_get (root, "rtgroups"); + if (!sct) return false; + len = json_object_array_length (sct); + for (i = 0; i < len; i++) { + const char *name, *type, *card, *accept_fct, *effect_fct; + elt = json_object_array_get_idx (sct, i); + name = json_object_get_string (json_object_object_get (elt, "name")); + type = json_object_get_string (json_object_object_get (elt, "type")); + card = json_object_get_string (json_object_object_get (elt, "card")); + accept_fct = json_object_get_string (json_object_object_get (elt, "accept_fct")); + effect_fct = json_object_get_string (json_object_object_get (elt, "effect_fct")); + agl_router_create_rtgroup (u, pa_streq(type, "OUTPUT") ? agl_output : agl_input, + name, card, + pa_streq(type, "phone") ? agl_router_phone_accept : NULL, + pa_streq(type, "phone") ? agl_router_phone_effect : NULL); + } + + /* [classmap] section */ + sct = json_object_object_get (root, "classmap"); + if (!sct) return false; + len = json_object_array_length (sct); + for (i = 0; i < len; i++) { + const char *class, *type, *rtgroup; + int zone; + elt = json_object_array_get_idx (sct, i); + class = json_object_get_string (json_object_object_get (elt, "class")); + type = json_object_get_string (json_object_object_get (elt, "type")); + zone = json_object_get_int (json_object_object_get (elt, "zone")); + rtgroup = json_object_get_string (json_object_object_get (elt, "rtgroup")); + agl_router_assign_class_to_rtgroup (u, agl_node_type_from_str (class), + zone, + pa_streq(type, "OUTPUT") ? agl_output : agl_input, + rtgroup); + } + + /* [typemap] section */ + sct = json_object_object_get (root, "typemap"); + if (!sct) return false; + len = json_object_array_length (sct); + for (i = 0; i < len; i++) { + const char *id, *type; + elt = json_object_array_get_idx (sct, i); + id = json_object_get_string (json_object_object_get (elt, "id")); + type = json_object_get_string (json_object_object_get (elt, "type")); + agl_nodeset_add_role (u, id, agl_node_type_from_str (type), NULL); + } + + /* [priormap] section */ + sct = json_object_object_get (root, "priormap"); + if (!sct) return false; + len = json_object_array_length (sct); + for (i = 0; i < len; i++) { + const char *class; + int priority; + elt = json_object_array_get_idx (sct, i); + class = json_object_get_string (json_object_object_get (elt, "class")); + priority = json_object_get_int (json_object_object_get (elt, "priority")); + agl_router_assign_class_priority (u, agl_node_type_from_str (class), priority); + } + + json_object_object_del (fjson, ""); + munmap (filemap, filestat.st_size); + close (filefd); + + return true; } @@ -82,6 +195,13 @@ static rtgroup_def rtgroups[] = { agl_router_phone_effect }, + { agl_input, + "default", + "pci", + NULL, + NULL + }, + { 0, NULL, NULL, NULL, NULL } }; @@ -23,6 +23,8 @@ #include "router.h" #include <pulsecore/idxset.h> +#include <pulsecore/core-util.h> +#include <pulsecore/pulsecore-config.h> agl_nodeset *agl_nodeset_init (struct userdata *u) { @@ -146,6 +148,39 @@ void agl_node_destroy (struct userdata *u, agl_node *node) pa_xfree (node); } + +agl_node_type agl_node_type_from_str (const char *str) +{ + agl_node_type type; + + pa_assert (str); + + if (pa_streq (str, "agl_radio")) + type = agl_radio; + else if (pa_streq (str, "agl_music")) + type = agl_player; + else if (pa_streq (str, "agl_navigator")) + type = agl_navigator; + else if (pa_streq (str, "agl_game")) + type = agl_game; + else if (pa_streq (str, "agl_browser")) + type = agl_browser; + else if (pa_streq (str, "agl_camera")) + type = agl_camera; + else if (pa_streq (str, "agl_phone")) + type = agl_phone; + else if (pa_streq (str, "agl_alert")) + type = agl_alert; + else if (pa_streq (str, "agl_event")) + type = agl_event; + else if (pa_streq (str, "agl_system")) + type = agl_system; + else + type = agl_node_type_unknown; + + return type; +} + const char *agl_node_type_str (agl_node_type type) { switch (type) { @@ -105,6 +105,7 @@ int agl_nodeset_add_role (struct userdata *, const char *, agl_node_type, agl_no agl_node *agl_node_create (struct userdata *, agl_node *); void agl_node_destroy (struct userdata *, agl_node *); +agl_node_type agl_node_type_from_str (const char *); const char *agl_node_type_str (agl_node_type); const char *agl_node_direction_str (agl_direction); |