switch: explicit route support
[staging/agl-audio-plugin.git] / config.c
1 /*
2  * module-agl-audio -- PulseAudio module for providing audio routing support
3  * (forked from "module-murphy-ivi" - https://github.com/otcshare )
4  * Copyright (c) 2012, Intel Corporation.
5  * Copyright (c) 2016, IoT.bzh
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms and conditions of the GNU Lesser General Public License,
9  * version 2.1, as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
19  * MA 02110-1301 USA.
20  *
21  */
22 #include "config.h"
23 #include "zone.h"
24
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <json-c/json.h>
29
30 #include <pulsecore/core-util.h>
31 #include <pulsecore/pulsecore-config.h>
32
33 bool use_default_configuration (struct userdata *);
34
35 const char *agl_config_file_get_path (const char *dir, const char *file, char *buf, size_t len)
36 {
37         pa_assert (file);
38         pa_assert (buf);
39         pa_assert (len > 0);
40
41         snprintf (buf, len, "%s/%s", dir, file);
42
43         return buf;
44 }
45
46 bool agl_config_parse_file (struct userdata *u, const char *path)
47 {
48         bool success;
49
50         pa_assert (u);
51
52         if (!path)
53                 return false;
54         else {
55                 pa_log_info ("parsing configuration file '%s'", path);
56                 success = agl_config_dofile (u, path);
57         }
58
59         if (!success) {
60                 pa_log_info ("applying builtin default configuration");
61                 success = use_default_configuration (u);
62         }
63
64         return success;
65 }
66
67 bool agl_config_dofile (struct userdata *u, const char *path)
68 {
69         int filefd;
70         struct stat filestat;
71         void *filemap;
72         struct json_object *fjson, *root, *sct, *elt, *selt;
73         const char *val;
74         int len, i;
75
76         pa_assert (u);
77         pa_assert (path);
78
79         filefd = open (path, O_RDONLY);
80         if (filefd == -1) {
81                 pa_log_info ("could not find configuration file '%s'", path);
82                 return false;
83         }
84         fstat (filefd, &filestat);
85
86         filemap = mmap (NULL, filestat.st_size, PROT_READ, MAP_PRIVATE, filefd, 0);
87         if (filemap == MAP_FAILED) {
88                 pa_log_info ("could not map configuration file in memory");
89                 return false;
90         }
91
92          /* is the file a JSON file, and if it is, does it have a "config" root ? */
93         fjson = json_tokener_parse (filemap);
94         root = json_object_object_get (fjson, "config");
95         if (!fjson || !root) {
96                 pa_log_info ("could not parse JSON configuration file");
97                 return false;
98         }
99
100          /* [zones] section */
101         sct = json_object_object_get (root, "zones");
102         if (!sct) return false;
103         len = json_object_array_length (sct);
104         for (i = 0; i < len; i++) {
105                 elt = json_object_array_get_idx (sct, i);
106                 val = json_object_get_string (elt);
107                 agl_zoneset_add_zone (u, val, (uint32_t)i);
108         }
109
110          /* [rtgroups] section */
111         sct = json_object_object_get (root, "rtgroups");
112         if (!sct) return false;
113         len = json_object_array_length (sct);
114         for (i = 0; i < len; i++) {
115                 const char *name, *type, *card, *accept_fct, *effect_fct;
116                 elt = json_object_array_get_idx (sct, i);
117                  name = json_object_get_string (json_object_object_get (elt, "name"));
118                  type = json_object_get_string (json_object_object_get (elt, "type"));
119                  card = json_object_get_string (json_object_object_get (elt, "card"));
120                  accept_fct = json_object_get_string (json_object_object_get (elt, "accept_fct"));
121                  effect_fct = json_object_get_string (json_object_object_get (elt, "effect_fct"));
122                 agl_router_create_rtgroup (u, pa_streq(type, "OUTPUT") ? agl_output : agl_input,
123                                               name, card,
124                                               pa_streq(name, "phone") ? agl_router_phone_accept : NULL,
125                                               pa_streq(name, "phone") ? agl_router_phone_effect : NULL);
126         }
127
128          /* [classmap] section */
129         sct = json_object_object_get (root, "classmap");
130         if (!sct) return false;
131         len = json_object_array_length (sct);
132         for (i = 0; i < len; i++) {
133                 const char *class, *type, *rtgroup;
134                 int zone;
135                 elt = json_object_array_get_idx (sct, i);
136                  class = json_object_get_string (json_object_object_get (elt, "class"));
137                  type = json_object_get_string (json_object_object_get (elt, "type"));
138                  zone = json_object_get_int (json_object_object_get (elt, "zone"));
139                  rtgroup = json_object_get_string (json_object_object_get (elt, "rtgroup"));
140                 agl_router_assign_class_to_rtgroup (u, agl_node_type_from_str (class),
141                                                        zone,
142                                                        pa_streq(type, "OUTPUT") ? agl_output : agl_input,
143                                                        rtgroup);
144         }
145
146          /* [typemap] section */
147         sct = json_object_object_get (root, "typemap");
148         if (!sct) return false;
149         len = json_object_array_length (sct);
150         for (i = 0; i < len; i++) {
151                 const char *id, *type;
152                 elt = json_object_array_get_idx (sct, i);
153                  id = json_object_get_string (json_object_object_get (elt, "id"));
154                  type = json_object_get_string (json_object_object_get (elt, "type"));
155                 agl_nodeset_add_role (u, id, agl_node_type_from_str (type), NULL);
156         }
157
158          /* [priormap] section */
159         sct = json_object_object_get (root, "priormap");
160         if (!sct) return false;
161         len = json_object_array_length (sct);
162         for (i = 0; i < len; i++) {
163                 const char *class;
164                 int priority;
165                 elt = json_object_array_get_idx (sct, i);
166                  class = json_object_get_string (json_object_object_get (elt, "class"));
167                  priority = json_object_get_int (json_object_object_get (elt, "priority"));
168                 agl_router_assign_class_priority (u, agl_node_type_from_str (class), priority);
169         }
170
171         json_object_object_del (fjson, "");
172         munmap (filemap, filestat.st_size);
173         close (filefd);
174
175         return true;
176 }
177
178
179  /* DEFAULT CONFIGURATION PART */
180
181 static zone_def zones[] = {
182         { "driver" },
183         { "passenger1" },
184         { "passenger2" },
185         { "passenger3" },
186         { "passenger4" },
187         { NULL }
188 };
189
190 static rtgroup_def rtgroups[] = {
191         { agl_input,
192           "Phone",
193           "PhoneCard",
194           agl_router_phone_accept,
195           agl_router_phone_effect
196         },
197
198         { agl_input,
199           "default",
200           "pci",
201           NULL,
202           NULL
203         },
204
205         { 0, NULL, NULL, NULL, NULL }
206 };
207
208 static classmap_def classmap[] = {
209         { agl_phone,    0, agl_input, "Phone" },
210         { agl_player,   0, agl_input, "default" },
211         { agl_radio,    0, agl_input, "default" },
212         { agl_navigator,0, agl_input, "default" },
213         { agl_event,    0, agl_input, "default" },
214         { agl_node_type_unknown, 0, agl_direction_unknown, NULL }
215 };
216
217 static typemap_def typemap[] = {
218         { "phone", agl_phone },
219         { "music", agl_player },
220         { "radio", agl_radio },
221         { "navi", agl_navigator },
222         { "event", agl_event },
223         { NULL, agl_node_type_unknown }
224 };
225
226 static prior_def priormap[] = {
227         { agl_event,     5 },
228         { agl_phone,     4 },
229         { agl_navigator, 2 },
230         { agl_radio,     1 },
231         { agl_player,    1 },
232         { agl_node_type_unknown, 0}
233 };
234
235 bool use_default_configuration (struct userdata *u)
236 {
237         zone_def *z;
238         rtgroup_def *r;
239         classmap_def *c;
240         typemap_def *t;
241         prior_def *p;
242
243         pa_assert (u);
244
245         for (z = zones; z->name; z++)
246                 agl_zoneset_add_zone (u, z->name, (uint32_t)(z - zones));
247
248         for (r = rtgroups; r->name; r++)
249                 agl_router_create_rtgroup (u, r->type, r->name, r->node_desc,
250                                               r->accept, r->effect);
251
252         for (c = classmap; c->rtgroup; c++)
253                 agl_router_assign_class_to_rtgroup (u, c->class, c->zone,
254                                                        c->type, c->rtgroup);
255
256         for (t = typemap; t->id; t++) 
257                 agl_nodeset_add_role (u, t->id, t->type, NULL);
258
259         for (p = priormap; p->class; p++)
260                 agl_router_assign_class_priority (u, p->class, p->priority);
261
262         return true;
263 }