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