• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  * Inspired by TinyHW, written by Mark Brown at Wolfson Micro
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #define LOG_TAG "audio_route"
19 /*#define LOG_NDEBUG 0*/
20 
21 #include <errno.h>
22 #include <expat.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include <log/log.h>
28 
29 #include <tinyalsa/asoundlib.h>
30 
31 #define BUF_SIZE 1024
32 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
33 #define INITIAL_MIXER_PATH_SIZE 8
34 
35 union ctl_values {
36     int *enumerated;
37     long *integer;
38     void *ptr;
39     unsigned char *bytes;
40 };
41 
42 struct mixer_state {
43     struct mixer_ctl *ctl;
44     unsigned int num_values;
45     union ctl_values old_value;
46     union ctl_values new_value;
47     union ctl_values reset_value;
48     unsigned int active_count;
49 };
50 
51 struct mixer_setting {
52     unsigned int ctl_index;
53     unsigned int num_values;
54     unsigned int type;
55     union ctl_values value;
56 };
57 
58 struct mixer_value {
59     unsigned int ctl_index;
60     int index;
61     long value;
62 };
63 
64 struct mixer_path {
65     char *name;
66     unsigned int size;
67     unsigned int length;
68     struct mixer_setting *setting;
69 };
70 
71 struct audio_route {
72     struct mixer *mixer;
73     unsigned int num_mixer_ctls;
74     struct mixer_state *mixer_state;
75 
76     unsigned int mixer_path_size;
77     unsigned int num_mixer_paths;
78     struct mixer_path *mixer_path;
79 };
80 
81 struct config_parse_state {
82     struct audio_route *ar;
83     struct mixer_path *path;
84     int level;
85 };
86 
87 /* path functions */
88 
is_supported_ctl_type(enum mixer_ctl_type type)89 static bool is_supported_ctl_type(enum mixer_ctl_type type)
90 {
91     switch (type) {
92     case MIXER_CTL_TYPE_BOOL:
93     case MIXER_CTL_TYPE_INT:
94     case MIXER_CTL_TYPE_ENUM:
95     case MIXER_CTL_TYPE_BYTE:
96         return true;
97     default:
98         return false;
99     }
100 }
101 
102 /* as they match in alsa */
sizeof_ctl_type(enum mixer_ctl_type type)103 static size_t sizeof_ctl_type(enum mixer_ctl_type type) {
104     switch (type) {
105     case MIXER_CTL_TYPE_BOOL:
106     case MIXER_CTL_TYPE_INT:
107         return sizeof(long);
108     case MIXER_CTL_TYPE_ENUM:
109         return sizeof(int);
110     case MIXER_CTL_TYPE_BYTE:
111         return sizeof(unsigned char);
112     case MIXER_CTL_TYPE_INT64:
113     case MIXER_CTL_TYPE_IEC958:
114     case MIXER_CTL_TYPE_UNKNOWN:
115     default:
116         LOG_ALWAYS_FATAL("Unsupported mixer ctl type: %d, check type before calling", (int)type);
117         return 0;
118     }
119 }
120 
index_to_ctl(struct audio_route * ar,unsigned int ctl_index)121 static inline struct mixer_ctl *index_to_ctl(struct audio_route *ar,
122                                              unsigned int ctl_index)
123 {
124     return ar->mixer_state[ctl_index].ctl;
125 }
126 
127 #if 0
128 static void path_print(struct audio_route *ar, struct mixer_path *path)
129 {
130     unsigned int i;
131     unsigned int j;
132 
133     ALOGE("Path: %s, length: %d", path->name, path->length);
134     for (i = 0; i < path->length; i++) {
135         struct mixer_ctl *ctl = index_to_ctl(ar, path->setting[i].ctl_index);
136 
137         ALOGE("  id=%d: ctl=%s", i, mixer_ctl_get_name(ctl));
138         if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_BYTE) {
139             for (j = 0; j < path->setting[i].num_values; j++)
140                 ALOGE("    id=%d value=0x%02x", j, path->setting[i].value.bytes[j]);
141         } else if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_ENUM) {
142             for (j = 0; j < path->setting[i].num_values; j++)
143                 ALOGE("    id=%d value=%d", j, path->setting[i].value.enumerated[j]);
144         } else {
145             for (j = 0; j < path->setting[i].num_values; j++)
146                 ALOGE("    id=%d value=%ld", j, path->setting[i].value.integer[j]);
147         }
148     }
149 }
150 #endif
151 
path_free(struct audio_route * ar)152 static void path_free(struct audio_route *ar)
153 {
154     unsigned int i;
155 
156     for (i = 0; i < ar->num_mixer_paths; i++) {
157         free(ar->mixer_path[i].name);
158         if (ar->mixer_path[i].setting) {
159             size_t j;
160             for (j = 0; j < ar->mixer_path[i].length; j++) {
161                 free(ar->mixer_path[i].setting[j].value.ptr);
162             }
163             free(ar->mixer_path[i].setting);
164             ar->mixer_path[i].size = 0;
165             ar->mixer_path[i].length = 0;
166             ar->mixer_path[i].setting = NULL;
167         }
168     }
169     free(ar->mixer_path);
170     ar->mixer_path = NULL;
171     ar->mixer_path_size = 0;
172     ar->num_mixer_paths = 0;
173 }
174 
path_get_by_name(struct audio_route * ar,const char * name)175 static struct mixer_path *path_get_by_name(struct audio_route *ar,
176                                            const char *name)
177 {
178     unsigned int i;
179 
180     for (i = 0; i < ar->num_mixer_paths; i++)
181         if (strcmp(ar->mixer_path[i].name, name) == 0)
182             return &ar->mixer_path[i];
183 
184     return NULL;
185 }
186 
path_create(struct audio_route * ar,const char * name)187 static struct mixer_path *path_create(struct audio_route *ar, const char *name)
188 {
189     struct mixer_path *new_mixer_path = NULL;
190 
191     if (path_get_by_name(ar, name)) {
192         ALOGE("Path name '%s' already exists", name);
193         return NULL;
194     }
195 
196     /* check if we need to allocate more space for mixer paths */
197     if (ar->mixer_path_size <= ar->num_mixer_paths) {
198         if (ar->mixer_path_size == 0)
199             ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE;
200         else
201             ar->mixer_path_size *= 2;
202 
203         new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size *
204                                  sizeof(struct mixer_path));
205         if (new_mixer_path == NULL) {
206             ALOGE("Unable to allocate more paths");
207             return NULL;
208         } else {
209             ar->mixer_path = new_mixer_path;
210         }
211     }
212 
213     /* initialise the new mixer path */
214     ar->mixer_path[ar->num_mixer_paths].name = strdup(name);
215     ar->mixer_path[ar->num_mixer_paths].size = 0;
216     ar->mixer_path[ar->num_mixer_paths].length = 0;
217     ar->mixer_path[ar->num_mixer_paths].setting = NULL;
218 
219     /* return the mixer path just added, then increment number of them */
220     return &ar->mixer_path[ar->num_mixer_paths++];
221 }
222 
find_ctl_index_in_path(struct mixer_path * path,unsigned int ctl_index)223 static int find_ctl_index_in_path(struct mixer_path *path,
224                                   unsigned int ctl_index)
225 {
226     unsigned int i;
227 
228     for (i = 0; i < path->length; i++)
229         if (path->setting[i].ctl_index == ctl_index)
230             return i;
231 
232     return -1;
233 }
234 
alloc_path_setting(struct mixer_path * path)235 static int alloc_path_setting(struct mixer_path *path)
236 {
237     struct mixer_setting *new_path_setting;
238     int path_index;
239 
240     /* check if we need to allocate more space for path settings */
241     if (path->size <= path->length) {
242         if (path->size == 0)
243             path->size = INITIAL_MIXER_PATH_SIZE;
244         else
245             path->size *= 2;
246 
247         new_path_setting = realloc(path->setting,
248                                    path->size * sizeof(struct mixer_setting));
249         if (new_path_setting == NULL) {
250             ALOGE("Unable to allocate more path settings");
251             return -1;
252         } else {
253             path->setting = new_path_setting;
254         }
255     }
256 
257     path_index = path->length;
258     path->length++;
259 
260     return path_index;
261 }
262 
path_add_setting(struct audio_route * ar,struct mixer_path * path,struct mixer_setting * setting)263 static int path_add_setting(struct audio_route *ar, struct mixer_path *path,
264                             struct mixer_setting *setting)
265 {
266     int path_index;
267 
268     if (find_ctl_index_in_path(path, setting->ctl_index) != -1) {
269         struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index);
270 
271         ALOGE("Control '%s' already exists in path '%s'",
272               mixer_ctl_get_name(ctl), path->name);
273         return -1;
274     }
275 
276     if (!is_supported_ctl_type(setting->type)) {
277         ALOGE("unsupported type %d", (int)setting->type);
278         return -1;
279     }
280 
281     path_index = alloc_path_setting(path);
282     if (path_index < 0)
283         return -1;
284 
285     path->setting[path_index].ctl_index = setting->ctl_index;
286     path->setting[path_index].type = setting->type;
287     path->setting[path_index].num_values = setting->num_values;
288 
289     size_t value_sz = sizeof_ctl_type(setting->type);
290 
291     path->setting[path_index].value.ptr = calloc(setting->num_values, value_sz);
292     /* copy all values */
293     memcpy(path->setting[path_index].value.ptr, setting->value.ptr,
294            setting->num_values * value_sz);
295 
296     return 0;
297 }
298 
path_add_value(struct audio_route * ar,struct mixer_path * path,struct mixer_value * mixer_value)299 static int path_add_value(struct audio_route *ar, struct mixer_path *path,
300                           struct mixer_value *mixer_value)
301 {
302     unsigned int i;
303     int path_index;
304     unsigned int num_values;
305     struct mixer_ctl *ctl;
306 
307     /* Check that mixer value index is within range */
308     ctl = index_to_ctl(ar, mixer_value->ctl_index);
309     num_values = mixer_ctl_get_num_values(ctl);
310     if (mixer_value->index >= (int)num_values) {
311         ALOGE("mixer index %d is out of range for '%s'", mixer_value->index,
312               mixer_ctl_get_name(ctl));
313         return -1;
314     }
315 
316     path_index = find_ctl_index_in_path(path, mixer_value->ctl_index);
317     if (path_index < 0) {
318         /* New path */
319 
320         enum mixer_ctl_type type = mixer_ctl_get_type(ctl);
321         if (!is_supported_ctl_type(type)) {
322             ALOGE("unsupported type %d", (int)type);
323             return -1;
324         }
325         path_index = alloc_path_setting(path);
326         if (path_index < 0)
327             return -1;
328 
329         /* initialise the new path setting */
330         path->setting[path_index].ctl_index = mixer_value->ctl_index;
331         path->setting[path_index].num_values = num_values;
332         path->setting[path_index].type = type;
333 
334         size_t value_sz = sizeof_ctl_type(type);
335         path->setting[path_index].value.ptr = calloc(num_values, value_sz);
336         if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
337             path->setting[path_index].value.bytes[0] = mixer_value->value;
338         else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM)
339             path->setting[path_index].value.enumerated[0] = mixer_value->value;
340         else
341             path->setting[path_index].value.integer[0] = mixer_value->value;
342     }
343 
344     if (mixer_value->index == -1) {
345         /* set all values the same */
346         if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE) {
347             for (i = 0; i < num_values; i++)
348                 path->setting[path_index].value.bytes[i] = mixer_value->value;
349         } else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM) {
350             for (i = 0; i < num_values; i++)
351                 path->setting[path_index].value.enumerated[i] = mixer_value->value;
352         } else {
353             for (i = 0; i < num_values; i++)
354                 path->setting[path_index].value.integer[i] = mixer_value->value;
355         }
356     } else {
357         /* set only one value */
358         if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
359             path->setting[path_index].value.bytes[mixer_value->index] = mixer_value->value;
360         else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM)
361             path->setting[path_index].value.enumerated[mixer_value->index] = mixer_value->value;
362         else
363             path->setting[path_index].value.integer[mixer_value->index] = mixer_value->value;
364     }
365 
366     return 0;
367 }
368 
path_add_path(struct audio_route * ar,struct mixer_path * path,struct mixer_path * sub_path)369 static int path_add_path(struct audio_route *ar, struct mixer_path *path,
370                          struct mixer_path *sub_path)
371 {
372     unsigned int i;
373 
374     for (i = 0; i < sub_path->length; i++)
375         if (path_add_setting(ar, path, &sub_path->setting[i]) < 0)
376             return -1;
377 
378     return 0;
379 }
380 
path_apply(struct audio_route * ar,struct mixer_path * path)381 static int path_apply(struct audio_route *ar, struct mixer_path *path)
382 {
383     unsigned int i;
384     unsigned int ctl_index;
385     struct mixer_ctl *ctl;
386     enum mixer_ctl_type type;
387 
388     ALOGD("Apply path: %s", path->name != NULL ? path->name : "none");
389     for (i = 0; i < path->length; i++) {
390         ctl_index = path->setting[i].ctl_index;
391         ctl = index_to_ctl(ar, ctl_index);
392         type = mixer_ctl_get_type(ctl);
393         if (!is_supported_ctl_type(type))
394             continue;
395         size_t value_sz = sizeof_ctl_type(type);
396         memcpy(ar->mixer_state[ctl_index].new_value.ptr, path->setting[i].value.ptr,
397                    path->setting[i].num_values * value_sz);
398     }
399 
400     return 0;
401 }
402 
path_reset(struct audio_route * ar,struct mixer_path * path)403 static int path_reset(struct audio_route *ar, struct mixer_path *path)
404 {
405     unsigned int i;
406     unsigned int ctl_index;
407     struct mixer_ctl *ctl;
408     enum mixer_ctl_type type;
409 
410     ALOGV("Reset path: %s", path->name != NULL ? path->name : "none");
411     for (i = 0; i < path->length; i++) {
412         ctl_index = path->setting[i].ctl_index;
413         ctl = index_to_ctl(ar, ctl_index);
414         type = mixer_ctl_get_type(ctl);
415         if (!is_supported_ctl_type(type))
416             continue;
417         size_t value_sz = sizeof_ctl_type(type);
418         /* reset the value(s) */
419         memcpy(ar->mixer_state[ctl_index].new_value.ptr,
420                ar->mixer_state[ctl_index].reset_value.ptr,
421                ar->mixer_state[ctl_index].num_values * value_sz);
422     }
423 
424     return 0;
425 }
426 
427 /* mixer helper function */
mixer_enum_string_to_value(struct mixer_ctl * ctl,const char * string)428 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string)
429 {
430     unsigned int i;
431     unsigned int num_values = mixer_ctl_get_num_enums(ctl);
432 
433     if (string == NULL) {
434         ALOGE("NULL enum value string passed to mixer_enum_string_to_value() for ctl %s",
435               mixer_ctl_get_name(ctl));
436         return 0;
437     }
438 
439     /* Search the enum strings for a particular one */
440     for (i = 0; i < num_values; i++) {
441         if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
442             break;
443     }
444     if (i == num_values) {
445         ALOGE("unknown enum value string %s for ctl %s",
446               string, mixer_ctl_get_name(ctl));
447         return 0;
448     }
449     return i;
450 }
451 
start_tag(void * data,const XML_Char * tag_name,const XML_Char ** attr)452 static void start_tag(void *data, const XML_Char *tag_name,
453                       const XML_Char **attr)
454 {
455     const XML_Char *attr_name = NULL;
456     const XML_Char *attr_id = NULL;
457     const XML_Char *attr_value = NULL;
458     struct config_parse_state *state = data;
459     struct audio_route *ar = state->ar;
460     unsigned int i;
461     unsigned int ctl_index;
462     struct mixer_ctl *ctl;
463     long value;
464     unsigned int id;
465     struct mixer_value mixer_value;
466     enum mixer_ctl_type type;
467 
468     /* Get name, id and value attributes (these may be empty) */
469     for (i = 0; attr[i]; i += 2) {
470         if (strcmp(attr[i], "name") == 0)
471             attr_name = attr[i + 1];
472         if (strcmp(attr[i], "id") == 0)
473             attr_id = attr[i + 1];
474         else if (strcmp(attr[i], "value") == 0)
475             attr_value = attr[i + 1];
476     }
477 
478     /* Look at tags */
479     if (strcmp(tag_name, "path") == 0) {
480         if (attr_name == NULL) {
481             ALOGE("Unnamed path!");
482         } else {
483             if (state->level == 1) {
484                 /* top level path: create and stash the path */
485                 state->path = path_create(ar, (char *)attr_name);
486                 if (state->path == NULL)
487                     ALOGE("path created failed, please check the path if existed");
488             } else {
489                 /* nested path */
490                 struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
491                 if (!sub_path) {
492                     ALOGE("unable to find sub path '%s'", attr_name);
493                 } else if (state->path != NULL) {
494                     path_add_path(ar, state->path, sub_path);
495                 }
496             }
497         }
498     }
499 
500     else if (strcmp(tag_name, "ctl") == 0) {
501         /* Obtain the mixer ctl and value */
502         ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);
503         if (ctl == NULL) {
504             ALOGE("Control '%s' doesn't exist - skipping", attr_name);
505             goto done;
506         }
507 
508         switch (mixer_ctl_get_type(ctl)) {
509         case MIXER_CTL_TYPE_BOOL:
510         case MIXER_CTL_TYPE_INT:
511             value = strtol((char *)attr_value, NULL, 0);
512             break;
513         case MIXER_CTL_TYPE_BYTE:
514             value = (unsigned char) strtol((char *)attr_value, NULL, 16);
515             break;
516         case MIXER_CTL_TYPE_ENUM:
517             value = mixer_enum_string_to_value(ctl, (char *)attr_value);
518             break;
519         default:
520             value = 0;
521             break;
522         }
523 
524         /* locate the mixer ctl in the list */
525         for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
526             if (ar->mixer_state[ctl_index].ctl == ctl)
527                 break;
528         }
529 
530         if (state->level == 1) {
531             /* top level ctl (initial setting) */
532 
533             type = mixer_ctl_get_type(ctl);
534             if (is_supported_ctl_type(type)) {
535                 /* apply the new value */
536                 if (attr_id) {
537                     /* set only one value */
538                     id = atoi((char *)attr_id);
539                     if (id < ar->mixer_state[ctl_index].num_values)
540                         if (type == MIXER_CTL_TYPE_BYTE)
541                             ar->mixer_state[ctl_index].new_value.bytes[id] = value;
542                         else if (type == MIXER_CTL_TYPE_ENUM)
543                             ar->mixer_state[ctl_index].new_value.enumerated[id] = value;
544                         else
545                             ar->mixer_state[ctl_index].new_value.integer[id] = value;
546                     else
547                         ALOGE("value id out of range for mixer ctl '%s'",
548                               mixer_ctl_get_name(ctl));
549                 } else {
550                     /* set all values the same */
551                     for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++)
552                         if (type == MIXER_CTL_TYPE_BYTE)
553                             ar->mixer_state[ctl_index].new_value.bytes[i] = value;
554                         else if (type == MIXER_CTL_TYPE_ENUM)
555                             ar->mixer_state[ctl_index].new_value.enumerated[i] = value;
556                         else
557                             ar->mixer_state[ctl_index].new_value.integer[i] = value;
558                 }
559             }
560         } else {
561             /* nested ctl (within a path) */
562             mixer_value.ctl_index = ctl_index;
563             mixer_value.value = value;
564             if (attr_id)
565                 mixer_value.index = atoi((char *)attr_id);
566             else
567                 mixer_value.index = -1;
568             if (state->path != NULL)
569                 path_add_value(ar, state->path, &mixer_value);
570         }
571     }
572 
573 done:
574     state->level++;
575 }
576 
end_tag(void * data,const XML_Char * tag_name)577 static void end_tag(void *data, const XML_Char *tag_name)
578 {
579     struct config_parse_state *state = data;
580     (void)tag_name;
581 
582     state->level--;
583 }
584 
alloc_mixer_state(struct audio_route * ar)585 static int alloc_mixer_state(struct audio_route *ar)
586 {
587     unsigned int i;
588     unsigned int num_values;
589     struct mixer_ctl *ctl;
590     enum mixer_ctl_type type;
591 
592     ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
593     ar->mixer_state = calloc(ar->num_mixer_ctls, sizeof(struct mixer_state));
594     if (!ar->mixer_state)
595         return -1;
596 
597     for (i = 0; i < ar->num_mixer_ctls; i++) {
598         ctl = mixer_get_ctl(ar->mixer, i);
599         num_values = mixer_ctl_get_num_values(ctl);
600 
601         ar->mixer_state[i].ctl = ctl;
602         ar->mixer_state[i].num_values = num_values;
603         ar->mixer_state[i].active_count = 0;
604 
605         /* Skip unsupported types that are not supported yet in XML */
606         type = mixer_ctl_get_type(ctl);
607 
608         if (!is_supported_ctl_type(type))
609             continue;
610 
611         size_t value_sz = sizeof_ctl_type(type);
612         ar->mixer_state[i].old_value.ptr = calloc(num_values, value_sz);
613         ar->mixer_state[i].new_value.ptr = calloc(num_values, value_sz);
614         ar->mixer_state[i].reset_value.ptr = calloc(num_values, value_sz);
615 
616         if (type == MIXER_CTL_TYPE_ENUM)
617             ar->mixer_state[i].old_value.enumerated[0] = mixer_ctl_get_value(ctl, 0);
618         else
619             mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value.ptr, num_values);
620 
621         memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].old_value.ptr,
622                num_values * value_sz);
623     }
624 
625     return 0;
626 }
627 
free_mixer_state(struct audio_route * ar)628 static void free_mixer_state(struct audio_route *ar)
629 {
630     unsigned int i;
631     enum mixer_ctl_type type;
632 
633     for (i = 0; i < ar->num_mixer_ctls; i++) {
634         type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
635         if (!is_supported_ctl_type(type))
636             continue;
637 
638         free(ar->mixer_state[i].old_value.ptr);
639         free(ar->mixer_state[i].new_value.ptr);
640         free(ar->mixer_state[i].reset_value.ptr);
641     }
642 
643     free(ar->mixer_state);
644     ar->mixer_state = NULL;
645 }
646 
647 /* Update the mixer with any changed values */
audio_route_update_mixer(struct audio_route * ar)648 int audio_route_update_mixer(struct audio_route *ar)
649 {
650     unsigned int i;
651     unsigned int j;
652     struct mixer_ctl *ctl;
653 
654     for (i = 0; i < ar->num_mixer_ctls; i++) {
655         unsigned int num_values = ar->mixer_state[i].num_values;
656         enum mixer_ctl_type type;
657 
658         ctl = ar->mixer_state[i].ctl;
659 
660         /* Skip unsupported types */
661         type = mixer_ctl_get_type(ctl);
662         if (!is_supported_ctl_type(type))
663             continue;
664 
665         /* if the value has changed, update the mixer */
666         bool changed = false;
667         if (type == MIXER_CTL_TYPE_BYTE) {
668             for (j = 0; j < num_values; j++) {
669                 if (ar->mixer_state[i].old_value.bytes[j] != ar->mixer_state[i].new_value.bytes[j]) {
670                     changed = true;
671                     break;
672                 }
673             }
674          } else if (type == MIXER_CTL_TYPE_ENUM) {
675              for (j = 0; j < num_values; j++) {
676                  if (ar->mixer_state[i].old_value.enumerated[j]
677                          != ar->mixer_state[i].new_value.enumerated[j]) {
678                      changed = true;
679                      break;
680                  }
681              }
682          } else {
683             for (j = 0; j < num_values; j++) {
684                 if (ar->mixer_state[i].old_value.integer[j] != ar->mixer_state[i].new_value.integer[j]) {
685                     changed = true;
686                     break;
687                 }
688             }
689         }
690         if (changed) {
691             if (type == MIXER_CTL_TYPE_ENUM)
692                 mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value.enumerated[0]);
693             else
694                 mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value.ptr, num_values);
695 
696             size_t value_sz = sizeof_ctl_type(type);
697             memcpy(ar->mixer_state[i].old_value.ptr, ar->mixer_state[i].new_value.ptr,
698                    num_values * value_sz);
699         }
700     }
701 
702     return 0;
703 }
704 
705 /* saves the current state of the mixer, for resetting all controls */
save_mixer_state(struct audio_route * ar)706 static void save_mixer_state(struct audio_route *ar)
707 {
708     unsigned int i;
709     enum mixer_ctl_type type;
710 
711     for (i = 0; i < ar->num_mixer_ctls; i++) {
712         type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
713         if (!is_supported_ctl_type(type))
714             continue;
715 
716         size_t value_sz = sizeof_ctl_type(type);
717         memcpy(ar->mixer_state[i].reset_value.ptr, ar->mixer_state[i].new_value.ptr,
718                ar->mixer_state[i].num_values * value_sz);
719     }
720 }
721 
722 /* Reset the audio routes back to the initial state */
audio_route_reset(struct audio_route * ar)723 void audio_route_reset(struct audio_route *ar)
724 {
725     unsigned int i;
726     enum mixer_ctl_type type;
727 
728     /* load all of the saved values */
729     for (i = 0; i < ar->num_mixer_ctls; i++) {
730         type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
731         if (!is_supported_ctl_type(type))
732             continue;
733 
734         size_t value_sz = sizeof_ctl_type(type);
735         memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].reset_value.ptr,
736             ar->mixer_state[i].num_values * value_sz);
737     }
738 }
739 
740 /* Apply an audio route path by name */
audio_route_apply_path(struct audio_route * ar,const char * name)741 int audio_route_apply_path(struct audio_route *ar, const char *name)
742 {
743     struct mixer_path *path;
744 
745     if (!ar) {
746         ALOGE("invalid audio_route");
747         return -1;
748     }
749 
750     path = path_get_by_name(ar, name);
751     if (!path) {
752         ALOGE("unable to find path '%s'", name);
753         return -1;
754     }
755 
756     path_apply(ar, path);
757 
758     return 0;
759 }
760 
761 /* Reset an audio route path by name */
audio_route_reset_path(struct audio_route * ar,const char * name)762 int audio_route_reset_path(struct audio_route *ar, const char *name)
763 {
764     struct mixer_path *path;
765 
766     if (!ar) {
767         ALOGE("invalid audio_route");
768         return -1;
769     }
770 
771     path = path_get_by_name(ar, name);
772     if (!path) {
773         ALOGE("unable to find path '%s'", name);
774         return -1;
775     }
776 
777     path_reset(ar, path);
778 
779     return 0;
780 }
781 
782 /*
783  * Operates on the specified path .. controls will be updated in the
784  * order listed in the XML file
785  */
audio_route_update_path(struct audio_route * ar,const char * name,bool reverse)786 static int audio_route_update_path(struct audio_route *ar, const char *name, bool reverse)
787 {
788     struct mixer_path *path;
789     unsigned int j;
790 
791     if (!ar) {
792         ALOGE("invalid audio_route");
793         return -1;
794     }
795 
796     path = path_get_by_name(ar, name);
797     if (!path) {
798         ALOGE("unable to find path '%s'", name);
799         return -1;
800     }
801 
802     for (size_t i = 0; i < path->length; ++i) {
803         unsigned int ctl_index;
804         enum mixer_ctl_type type;
805 
806         ctl_index = path->setting[reverse ? path->length - 1 - i : i].ctl_index;
807 
808         struct mixer_state * ms = &ar->mixer_state[ctl_index];
809 
810         type = mixer_ctl_get_type(ms->ctl);
811         if (!is_supported_ctl_type(type)) {
812             continue;
813         }
814 
815         if (reverse && ms->active_count > 0) {
816             ms->active_count--;
817         } else if (!reverse) {
818             ms->active_count++;
819         }
820 
821        size_t value_sz = sizeof_ctl_type(type);
822         /* if any value has changed, update the mixer */
823         for (j = 0; j < ms->num_values; j++) {
824             if (type == MIXER_CTL_TYPE_BYTE) {
825                 if (ms->old_value.bytes[j] != ms->new_value.bytes[j]) {
826                     if (reverse && ms->active_count > 0) {
827                         ALOGD("%s: skip to reset mixer control '%s' in path '%s' "
828                             "because it is still needed by other paths", __func__,
829                             mixer_ctl_get_name(ms->ctl), name);
830                         memcpy(ms->new_value.bytes, ms->old_value.bytes,
831                             ms->num_values * value_sz);
832                         break;
833                     }
834                     mixer_ctl_set_array(ms->ctl, ms->new_value.bytes, ms->num_values);
835                     memcpy(ms->old_value.bytes, ms->new_value.bytes, ms->num_values * value_sz);
836                     break;
837                 }
838             } else if (type == MIXER_CTL_TYPE_ENUM) {
839                 if (ms->old_value.enumerated[j] != ms->new_value.enumerated[j]) {
840                     if (reverse && ms->active_count > 0) {
841                         ALOGD("%s: skip to reset mixer control '%s' in path '%s' "
842                             "because it is still needed by other paths", __func__,
843                             mixer_ctl_get_name(ms->ctl), name);
844                         memcpy(ms->new_value.enumerated, ms->old_value.enumerated,
845                             ms->num_values * value_sz);
846                         break;
847                     }
848                     mixer_ctl_set_value(ms->ctl, 0, ms->new_value.enumerated[0]);
849                     memcpy(ms->old_value.enumerated, ms->new_value.enumerated,
850                             ms->num_values * value_sz);
851                     break;
852                 }
853             } else if (ms->old_value.integer[j] != ms->new_value.integer[j]) {
854                 if (reverse && ms->active_count > 0) {
855                     ALOGD("%s: skip to reset mixer control '%s' in path '%s' "
856                         "because it is still needed by other paths", __func__,
857                         mixer_ctl_get_name(ms->ctl), name);
858                     memcpy(ms->new_value.integer, ms->old_value.integer,
859                         ms->num_values * value_sz);
860                     break;
861                 }
862                 mixer_ctl_set_array(ms->ctl, ms->new_value.integer, ms->num_values);
863                 memcpy(ms->old_value.integer, ms->new_value.integer, ms->num_values * value_sz);
864                 break;
865             }
866         }
867     }
868     return 0;
869 }
870 
audio_route_apply_and_update_path(struct audio_route * ar,const char * name)871 int audio_route_apply_and_update_path(struct audio_route *ar, const char *name)
872 {
873     if (audio_route_apply_path(ar, name) < 0) {
874         return -1;
875     }
876     return audio_route_update_path(ar, name, false /*reverse*/);
877 }
878 
audio_route_reset_and_update_path(struct audio_route * ar,const char * name)879 int audio_route_reset_and_update_path(struct audio_route *ar, const char *name)
880 {
881     if (audio_route_reset_path(ar, name) < 0) {
882         return -1;
883     }
884     return audio_route_update_path(ar, name, true /*reverse*/);
885 }
886 
audio_route_init(unsigned int card,const char * xml_path)887 struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
888 {
889     struct config_parse_state state;
890     XML_Parser parser;
891     FILE *file;
892     int bytes_read;
893     void *buf;
894     struct audio_route *ar;
895 
896     ar = calloc(1, sizeof(struct audio_route));
897     if (!ar)
898         goto err_calloc;
899 
900     ar->mixer = mixer_open(card);
901     if (!ar->mixer) {
902         ALOGE("Unable to open the mixer, aborting.");
903         goto err_mixer_open;
904     }
905 
906     ar->mixer_path = NULL;
907     ar->mixer_path_size = 0;
908     ar->num_mixer_paths = 0;
909 
910     /* allocate space for and read current mixer settings */
911     if (alloc_mixer_state(ar) < 0)
912         goto err_mixer_state;
913 
914     /* use the default XML path if none is provided */
915     if (xml_path == NULL)
916         xml_path = MIXER_XML_PATH;
917 
918     file = fopen(xml_path, "r");
919 
920     if (!file) {
921         ALOGE("Failed to open %s: %s", xml_path, strerror(errno));
922         goto err_fopen;
923     }
924 
925     parser = XML_ParserCreate(NULL);
926     if (!parser) {
927         ALOGE("Failed to create XML parser");
928         goto err_parser_create;
929     }
930 
931     memset(&state, 0, sizeof(state));
932     state.ar = ar;
933     XML_SetUserData(parser, &state);
934     XML_SetElementHandler(parser, start_tag, end_tag);
935 
936     for (;;) {
937         buf = XML_GetBuffer(parser, BUF_SIZE);
938         if (buf == NULL)
939             goto err_parse;
940 
941         bytes_read = fread(buf, 1, BUF_SIZE, file);
942         if (bytes_read < 0)
943             goto err_parse;
944 
945         if (XML_ParseBuffer(parser, bytes_read,
946                             bytes_read == 0) == XML_STATUS_ERROR) {
947             ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
948             goto err_parse;
949         }
950 
951         if (bytes_read == 0)
952             break;
953     }
954 
955     /* apply the initial mixer values, and save them so we can reset the
956        mixer to the original values */
957     audio_route_update_mixer(ar);
958     save_mixer_state(ar);
959 
960     XML_ParserFree(parser);
961     fclose(file);
962     return ar;
963 
964 err_parse:
965     path_free(ar);
966     XML_ParserFree(parser);
967 err_parser_create:
968     fclose(file);
969 err_fopen:
970     free_mixer_state(ar);
971 err_mixer_state:
972     mixer_close(ar->mixer);
973 err_mixer_open:
974     free(ar);
975     ar = NULL;
976 err_calloc:
977     return NULL;
978 }
979 
audio_route_free(struct audio_route * ar)980 void audio_route_free(struct audio_route *ar)
981 {
982     free_mixer_state(ar);
983     mixer_close(ar->mixer);
984     path_free(ar);
985     free(ar);
986 }
987