• 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         ALOGE("Control '%s' already exists in path '%s'",
285               mixer_ctl_get_name(ctl), path->name);
286         return -1;
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         if (path_add_setting(ar, path, &sub_path->setting[i]) < 0)
392             return -1;
393 
394     return 0;
395 }
396 
path_apply(struct audio_route * ar,struct mixer_path * path)397 static int path_apply(struct audio_route *ar, struct mixer_path *path)
398 {
399     unsigned int i;
400     unsigned int ctl_index;
401     struct mixer_ctl *ctl;
402     enum mixer_ctl_type type;
403 
404     ALOGD("Apply path: %s", path->name != NULL ? path->name : "none");
405     for (i = 0; i < path->length; i++) {
406         ctl_index = path->setting[i].ctl_index;
407         ctl = index_to_ctl(ar, ctl_index);
408         type = mixer_ctl_get_type(ctl);
409         if (!is_supported_ctl_type(type))
410             continue;
411         size_t value_sz = sizeof_ctl_type(type);
412         memcpy(ar->mixer_state[ctl_index].new_value.ptr, path->setting[i].value.ptr,
413                    path->setting[i].num_values * value_sz);
414     }
415 
416     return 0;
417 }
418 
path_reset(struct audio_route * ar,struct mixer_path * path)419 static int path_reset(struct audio_route *ar, struct mixer_path *path)
420 {
421     unsigned int i;
422     unsigned int ctl_index;
423     struct mixer_ctl *ctl;
424     enum mixer_ctl_type type;
425 
426     ALOGV("Reset path: %s", path->name != NULL ? path->name : "none");
427     for (i = 0; i < path->length; i++) {
428         ctl_index = path->setting[i].ctl_index;
429         ctl = index_to_ctl(ar, ctl_index);
430         type = mixer_ctl_get_type(ctl);
431         if (!is_supported_ctl_type(type))
432             continue;
433         size_t value_sz = sizeof_ctl_type(type);
434         /* reset the value(s) */
435         memcpy(ar->mixer_state[ctl_index].new_value.ptr,
436                ar->mixer_state[ctl_index].reset_value.ptr,
437                ar->mixer_state[ctl_index].num_values * value_sz);
438     }
439 
440     return 0;
441 }
442 
443 /* mixer helper function */
mixer_enum_string_to_value(struct mixer_ctl * ctl,const char * string)444 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string)
445 {
446     unsigned int i;
447     unsigned int num_values = mixer_ctl_get_num_enums(ctl);
448 
449     if (string == NULL) {
450         ALOGE("NULL enum value string passed to mixer_enum_string_to_value() for ctl %s",
451               mixer_ctl_get_name(ctl));
452         return 0;
453     }
454 
455     /* Search the enum strings for a particular one */
456     for (i = 0; i < num_values; i++) {
457         if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
458             break;
459     }
460     if (i == num_values) {
461         ALOGW("unknown enum value string %s for ctl %s",
462               string, mixer_ctl_get_name(ctl));
463         return 0;
464     }
465     return i;
466 }
467 
start_tag(void * data,const XML_Char * tag_name,const XML_Char ** attr)468 static void start_tag(void *data, const XML_Char *tag_name,
469                       const XML_Char **attr)
470 {
471     const XML_Char *attr_name = NULL;
472     const XML_Char *attr_id = NULL;
473     const XML_Char *attr_value = NULL;
474     struct config_parse_state *state = data;
475     struct audio_route *ar = state->ar;
476     unsigned int i;
477     unsigned int ctl_index;
478     struct mixer_ctl *ctl;
479     long value;
480     unsigned int id;
481     struct mixer_value mixer_value;
482     enum mixer_ctl_type type;
483     long* value_array = NULL;
484 
485     /* Get name, id and value attributes (these may be empty) */
486     for (i = 0; attr[i]; i += 2) {
487         if (strcmp(attr[i], "name") == 0)
488             attr_name = attr[i + 1];
489         else if (strcmp(attr[i], "id") == 0)
490             attr_id = attr[i + 1];
491         else if (strcmp(attr[i], "value") == 0)
492             attr_value = attr[i + 1];
493     }
494 
495     /* Look at tags */
496     if (strcmp(tag_name, "path") == 0) {
497         if (attr_name == NULL) {
498             ALOGE("Unnamed path!");
499         } else {
500             if (state->level == 1) {
501                 /* top level path: create and stash the path */
502                 state->path = path_create(ar, (char *)attr_name);
503                 if (state->path == NULL)
504                     ALOGW("path creation failed, please check if the path exists");
505             } else {
506                 /* nested path */
507                 struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
508                 if (!sub_path) {
509                     ALOGW("unable to find sub path '%s'", attr_name);
510                 } else if (state->path != NULL) {
511                     path_add_path(ar, state->path, sub_path);
512                 }
513             }
514         }
515     } else if (strcmp(tag_name, "ctl") == 0) {
516         /* Obtain the mixer ctl and value */
517         ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);
518         if (ctl == NULL) {
519             ALOGW("Control '%s' doesn't exist - skipping", attr_name);
520             goto done;
521         }
522 
523         switch (mixer_ctl_get_type(ctl)) {
524         case MIXER_CTL_TYPE_BOOL:
525             if (attr_value == NULL) {
526                 ALOGE("No value specified for ctl %s", attr_name);
527                 goto done;
528             }
529             value = strtol((char *)attr_value, NULL, 0);
530             break;
531         case MIXER_CTL_TYPE_INT:
532         case MIXER_CTL_TYPE_BYTE: {
533                 char *attr_sub_value, *test_r;
534 
535                 if (attr_value == NULL) {
536                     ALOGE("No value specified for ctl %s", attr_name);
537                     goto done;
538                 }
539                 unsigned int num_values = mixer_ctl_get_num_values(ctl);
540                 value_array = calloc(num_values, sizeof(long));
541                 if (!value_array) {
542                     ALOGE("failed to allocate mem for ctl %s", attr_name);
543                     goto done;
544                 }
545                 for (i = 0; i < num_values; i++) {
546                     attr_sub_value = strtok_r((char *)attr_value, " ", &test_r);
547                     if (attr_sub_value == NULL) {
548                         ALOGE("expect %d values but only %d specified for ctl %s",
549                             num_values, i, attr_name);
550                         goto done;
551                     }
552                     if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_INT)
553                         value_array[i] = strtol((char *)attr_sub_value, NULL, 0);
554                     else
555                         value_array[i] =
556                            (unsigned char) strtol((char *)attr_sub_value, NULL, 16);
557 
558                     if (attr_id)
559                         break;
560 
561                     attr_value = NULL;
562                 }
563             } break;
564         case MIXER_CTL_TYPE_ENUM:
565             if (attr_value == NULL) {
566                 ALOGE("No value specified for ctl %s", attr_name);
567                 goto done;
568             }
569             value = mixer_enum_string_to_value(ctl, (char *)attr_value);
570             break;
571         default:
572             value = 0;
573             break;
574         }
575 
576         /* locate the mixer ctl in the list */
577         for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
578             if (ar->mixer_state[ctl_index].ctl == ctl)
579                 break;
580         }
581 
582         if (state->level == 1) {
583             /* top level ctl (initial setting) */
584 
585             type = mixer_ctl_get_type(ctl);
586             if (is_supported_ctl_type(type)) {
587                 /* apply the new value */
588                 if (attr_id) {
589                     /* set only one value */
590                     id = atoi((char *)attr_id);
591                     if (id < ar->mixer_state[ctl_index].num_values)
592                         if (type == MIXER_CTL_TYPE_BYTE)
593                             ar->mixer_state[ctl_index].new_value.bytes[id] = value_array[0];
594                         else if (type == MIXER_CTL_TYPE_INT)
595                             ar->mixer_state[ctl_index].new_value.integer[id] = value_array[0];
596                         else if (type == MIXER_CTL_TYPE_ENUM)
597                             ar->mixer_state[ctl_index].new_value.enumerated[id] = value;
598                         else
599                             ar->mixer_state[ctl_index].new_value.integer[id] = value;
600                     else
601                         ALOGW("value id out of range for mixer ctl '%s'",
602                               mixer_ctl_get_name(ctl));
603                 } else {
604                     /* set all values the same except for CTL_TYPE_BYTE and CTL_TYPE_INT */
605                     for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++)
606                         if (type == MIXER_CTL_TYPE_BYTE)
607                             ar->mixer_state[ctl_index].new_value.bytes[i] = value_array[i];
608                         else if (type == MIXER_CTL_TYPE_INT)
609                             ar->mixer_state[ctl_index].new_value.integer[i] = value_array[i];
610                         else if (type == MIXER_CTL_TYPE_ENUM)
611                             ar->mixer_state[ctl_index].new_value.enumerated[i] = value;
612                         else
613                             ar->mixer_state[ctl_index].new_value.integer[i] = value;
614                 }
615             }
616         } else {
617             /* nested ctl (within a path) */
618             mixer_value.ctl_index = ctl_index;
619             if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_BYTE ||
620                 mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_INT) {
621                 mixer_value.values = value_array;
622                 mixer_value.value = value_array[0];
623             } else {
624                 mixer_value.value = value;
625             }
626             if (attr_id)
627                 mixer_value.index = atoi((char *)attr_id);
628             else
629                 mixer_value.index = -1;
630             if (state->path != NULL)
631                 path_add_value(ar, state->path, &mixer_value);
632         }
633     }
634 
635 done:
636     free(value_array);
637     state->level++;
638 }
639 
end_tag(void * data,const XML_Char * tag_name)640 static void end_tag(void *data, const XML_Char *tag_name)
641 {
642     struct config_parse_state *state = data;
643     (void)tag_name;
644 
645     state->level--;
646 }
647 
alloc_mixer_state(struct audio_route * ar)648 static int alloc_mixer_state(struct audio_route *ar)
649 {
650     unsigned int i;
651     unsigned int num_values;
652     struct mixer_ctl *ctl;
653     enum mixer_ctl_type type;
654 
655     ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
656     ar->mixer_state = calloc(ar->num_mixer_ctls, sizeof(struct mixer_state));
657     if (!ar->mixer_state)
658         return -1;
659 
660     for (i = 0; i < ar->num_mixer_ctls; i++) {
661         ctl = mixer_get_ctl(ar->mixer, i);
662         num_values = mixer_ctl_get_num_values(ctl);
663 
664         ar->mixer_state[i].ctl = ctl;
665         ar->mixer_state[i].num_values = num_values;
666         ar->mixer_state[i].active_count = 0;
667 
668         /* Skip unsupported types that are not supported yet in XML */
669         type = mixer_ctl_get_type(ctl);
670 
671         if (!is_supported_ctl_type(type))
672             continue;
673 
674         size_t value_sz = sizeof_ctl_type(type);
675         ar->mixer_state[i].old_value.ptr = calloc(num_values, value_sz);
676         ar->mixer_state[i].new_value.ptr = calloc(num_values, value_sz);
677         ar->mixer_state[i].reset_value.ptr = calloc(num_values, value_sz);
678 
679         if (type == MIXER_CTL_TYPE_ENUM)
680             ar->mixer_state[i].old_value.enumerated[0] = mixer_ctl_get_value(ctl, 0);
681         else
682             mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value.ptr, num_values);
683 
684         memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].old_value.ptr,
685                num_values * value_sz);
686     }
687 
688     return 0;
689 }
690 
free_mixer_state(struct audio_route * ar)691 static void free_mixer_state(struct audio_route *ar)
692 {
693     unsigned int i;
694     enum mixer_ctl_type type;
695 
696     for (i = 0; i < ar->num_mixer_ctls; i++) {
697         type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
698         if (!is_supported_ctl_type(type))
699             continue;
700 
701         free(ar->mixer_state[i].old_value.ptr);
702         free(ar->mixer_state[i].new_value.ptr);
703         free(ar->mixer_state[i].reset_value.ptr);
704     }
705 
706     free(ar->mixer_state);
707     ar->mixer_state = NULL;
708 }
709 
710 /* Update the mixer with any changed values */
audio_route_update_mixer(struct audio_route * ar)711 int audio_route_update_mixer(struct audio_route *ar)
712 {
713     unsigned int i;
714     unsigned int j;
715     struct mixer_ctl *ctl;
716 
717     for (i = 0; i < ar->num_mixer_ctls; i++) {
718         unsigned int num_values = ar->mixer_state[i].num_values;
719         enum mixer_ctl_type type;
720 
721         ctl = ar->mixer_state[i].ctl;
722 
723         /* Skip unsupported types */
724         type = mixer_ctl_get_type(ctl);
725         if (!is_supported_ctl_type(type))
726             continue;
727 
728         /* if the value has changed, update the mixer */
729         bool changed = false;
730         if (type == MIXER_CTL_TYPE_BYTE) {
731             for (j = 0; j < num_values; j++) {
732                 if (ar->mixer_state[i].old_value.bytes[j] != ar->mixer_state[i].new_value.bytes[j]) {
733                     changed = true;
734                     break;
735                 }
736             }
737          } else if (type == MIXER_CTL_TYPE_ENUM) {
738              for (j = 0; j < num_values; j++) {
739                  if (ar->mixer_state[i].old_value.enumerated[j]
740                          != ar->mixer_state[i].new_value.enumerated[j]) {
741                      changed = true;
742                      break;
743                  }
744              }
745          } else {
746             for (j = 0; j < num_values; j++) {
747                 if (ar->mixer_state[i].old_value.integer[j] != ar->mixer_state[i].new_value.integer[j]) {
748                     changed = true;
749                     break;
750                 }
751             }
752         }
753         if (changed) {
754             if (type == MIXER_CTL_TYPE_ENUM)
755                 mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value.enumerated[0]);
756             else
757                 mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value.ptr, num_values);
758 
759             size_t value_sz = sizeof_ctl_type(type);
760             memcpy(ar->mixer_state[i].old_value.ptr, ar->mixer_state[i].new_value.ptr,
761                    num_values * value_sz);
762         }
763     }
764 
765     return 0;
766 }
767 
768 /* saves the current state of the mixer, for resetting all controls */
save_mixer_state(struct audio_route * ar)769 static void save_mixer_state(struct audio_route *ar)
770 {
771     unsigned int i;
772     enum mixer_ctl_type type;
773 
774     for (i = 0; i < ar->num_mixer_ctls; i++) {
775         type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
776         if (!is_supported_ctl_type(type))
777             continue;
778 
779         size_t value_sz = sizeof_ctl_type(type);
780         memcpy(ar->mixer_state[i].reset_value.ptr, ar->mixer_state[i].new_value.ptr,
781                ar->mixer_state[i].num_values * value_sz);
782     }
783 }
784 
785 /* Reset the audio routes back to the initial state */
audio_route_reset(struct audio_route * ar)786 void audio_route_reset(struct audio_route *ar)
787 {
788     unsigned int i;
789     enum mixer_ctl_type type;
790 
791     /* load all of the saved values */
792     for (i = 0; i < ar->num_mixer_ctls; i++) {
793         type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
794         if (!is_supported_ctl_type(type))
795             continue;
796 
797         size_t value_sz = sizeof_ctl_type(type);
798         memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].reset_value.ptr,
799             ar->mixer_state[i].num_values * value_sz);
800     }
801 }
802 
803 /* Apply an audio route path by name */
audio_route_apply_path(struct audio_route * ar,const char * name)804 int audio_route_apply_path(struct audio_route *ar, const char *name)
805 {
806     struct mixer_path *path;
807 
808     if (!ar) {
809         ALOGE("invalid audio_route");
810         return -1;
811     }
812 
813     path = path_get_by_name(ar, name);
814     if (!path) {
815         ALOGE("unable to find path '%s'", name);
816         return -1;
817     }
818 
819     path_apply(ar, path);
820 
821     return 0;
822 }
823 
824 /* Reset an audio route path by name */
audio_route_reset_path(struct audio_route * ar,const char * name)825 int audio_route_reset_path(struct audio_route *ar, const char *name)
826 {
827     struct mixer_path *path;
828 
829     if (!ar) {
830         ALOGE("invalid audio_route");
831         return -1;
832     }
833 
834     path = path_get_by_name(ar, name);
835     if (!path) {
836         ALOGE("unable to find path '%s'", name);
837         return -1;
838     }
839 
840     path_reset(ar, path);
841 
842     return 0;
843 }
844 
845 /*
846  * Operates on the specified path .. controls will be updated in the
847  * order listed in the XML file
848  */
audio_route_update_path(struct audio_route * ar,const char * name,int direction)849 static int audio_route_update_path(struct audio_route *ar, const char *name, int direction)
850 {
851     struct mixer_path *path;
852     unsigned int j;
853     bool reverse = direction != DIRECTION_FORWARD;
854     bool force_reset = direction == DIRECTION_REVERSE_RESET;
855 
856     if (!ar) {
857         ALOGE("invalid audio_route");
858         return -1;
859     }
860 
861     path = path_get_by_name(ar, name);
862     if (!path) {
863         ALOGE("unable to find path '%s'", name);
864         return -1;
865     }
866 
867     for (size_t i = 0; i < path->length; ++i) {
868         unsigned int ctl_index;
869         enum mixer_ctl_type type;
870 
871         ctl_index = path->setting[reverse ? path->length - 1 - i : i].ctl_index;
872 
873         struct mixer_state * ms = &ar->mixer_state[ctl_index];
874 
875         type = mixer_ctl_get_type(ms->ctl);
876         if (!is_supported_ctl_type(type)) {
877             continue;
878         }
879 
880         if (reverse && ms->active_count > 0) {
881             if (force_reset)
882                 ms->active_count = 0;
883             else
884                 ms->active_count--;
885         } else if (!reverse) {
886             ms->active_count++;
887         }
888 
889        size_t value_sz = sizeof_ctl_type(type);
890         /* if any value has changed, update the mixer */
891         for (j = 0; j < ms->num_values; j++) {
892             if (type == MIXER_CTL_TYPE_BYTE) {
893                 if (ms->old_value.bytes[j] != ms->new_value.bytes[j]) {
894                     if (reverse && ms->active_count > 0) {
895                         ALOGD("%s: skip to reset mixer control '%s' in path '%s' "
896                             "because it is still needed by other paths", __func__,
897                             mixer_ctl_get_name(ms->ctl), name);
898                         memcpy(ms->new_value.bytes, ms->old_value.bytes,
899                             ms->num_values * value_sz);
900                         break;
901                     }
902                     mixer_ctl_set_array(ms->ctl, ms->new_value.bytes, ms->num_values);
903                     memcpy(ms->old_value.bytes, ms->new_value.bytes, ms->num_values * value_sz);
904                     break;
905                 }
906             } else if (type == MIXER_CTL_TYPE_ENUM) {
907                 if (ms->old_value.enumerated[j] != ms->new_value.enumerated[j]) {
908                     if (reverse && ms->active_count > 0) {
909                         ALOGD("%s: skip to reset mixer control '%s' in path '%s' "
910                             "because it is still needed by other paths", __func__,
911                             mixer_ctl_get_name(ms->ctl), name);
912                         memcpy(ms->new_value.enumerated, ms->old_value.enumerated,
913                             ms->num_values * value_sz);
914                         break;
915                     }
916                     mixer_ctl_set_value(ms->ctl, 0, ms->new_value.enumerated[0]);
917                     memcpy(ms->old_value.enumerated, ms->new_value.enumerated,
918                             ms->num_values * value_sz);
919                     break;
920                 }
921             } else if (ms->old_value.integer[j] != ms->new_value.integer[j]) {
922                 if (reverse && ms->active_count > 0) {
923                     ALOGD("%s: skip to reset mixer control '%s' in path '%s' "
924                         "because it is still needed by other paths", __func__,
925                         mixer_ctl_get_name(ms->ctl), name);
926                     memcpy(ms->new_value.integer, ms->old_value.integer,
927                         ms->num_values * value_sz);
928                     break;
929                 }
930                 mixer_ctl_set_array(ms->ctl, ms->new_value.integer, ms->num_values);
931                 memcpy(ms->old_value.integer, ms->new_value.integer, ms->num_values * value_sz);
932                 break;
933             }
934         }
935     }
936     return 0;
937 }
938 
audio_route_apply_and_update_path(struct audio_route * ar,const char * name)939 int audio_route_apply_and_update_path(struct audio_route *ar, const char *name)
940 {
941     if (audio_route_apply_path(ar, name) < 0) {
942         return -1;
943     }
944     return audio_route_update_path(ar, name, DIRECTION_FORWARD);
945 }
946 
audio_route_reset_and_update_path(struct audio_route * ar,const char * name)947 int audio_route_reset_and_update_path(struct audio_route *ar, const char *name)
948 {
949     if (audio_route_reset_path(ar, name) < 0) {
950         return -1;
951     }
952     return audio_route_update_path(ar, name, DIRECTION_REVERSE);
953 }
954 
audio_route_force_reset_and_update_path(struct audio_route * ar,const char * name)955 int audio_route_force_reset_and_update_path(struct audio_route *ar, const char *name)
956 {
957     if (audio_route_reset_path(ar, name) < 0) {
958         return -1;
959     }
960 
961     return audio_route_update_path(ar, name, DIRECTION_REVERSE_RESET);
962 }
963 
audio_route_init(unsigned int card,const char * xml_path)964 struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
965 {
966     struct config_parse_state state;
967     XML_Parser parser;
968     FILE *file;
969     int bytes_read;
970     void *buf;
971     struct audio_route *ar;
972 
973     ar = calloc(1, sizeof(struct audio_route));
974     if (!ar)
975         goto err_calloc;
976 
977     ar->mixer = mixer_open(card);
978     if (!ar->mixer) {
979         ALOGE("Unable to open the mixer, aborting.");
980         goto err_mixer_open;
981     }
982 
983     ar->mixer_path = NULL;
984     ar->mixer_path_size = 0;
985     ar->num_mixer_paths = 0;
986 
987     /* allocate space for and read current mixer settings */
988     if (alloc_mixer_state(ar) < 0)
989         goto err_mixer_state;
990 
991     /* use the default XML path if none is provided */
992     if (xml_path == NULL)
993         xml_path = MIXER_XML_PATH;
994 
995     file = fopen(xml_path, "r");
996 
997     if (!file) {
998         ALOGE("Failed to open %s: %s", xml_path, strerror(errno));
999         goto err_fopen;
1000     }
1001 
1002     parser = XML_ParserCreate(NULL);
1003     if (!parser) {
1004         ALOGE("Failed to create XML parser");
1005         goto err_parser_create;
1006     }
1007 
1008     memset(&state, 0, sizeof(state));
1009     state.ar = ar;
1010     XML_SetUserData(parser, &state);
1011     XML_SetElementHandler(parser, start_tag, end_tag);
1012 
1013     for (;;) {
1014         buf = XML_GetBuffer(parser, BUF_SIZE);
1015         if (buf == NULL)
1016             goto err_parse;
1017 
1018         bytes_read = fread(buf, 1, BUF_SIZE, file);
1019         if (bytes_read < 0)
1020             goto err_parse;
1021 
1022         if (XML_ParseBuffer(parser, bytes_read,
1023                             bytes_read == 0) == XML_STATUS_ERROR) {
1024             ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
1025             goto err_parse;
1026         }
1027 
1028         if (bytes_read == 0)
1029             break;
1030     }
1031 
1032     /* apply the initial mixer values, and save them so we can reset the
1033        mixer to the original values */
1034     audio_route_update_mixer(ar);
1035     save_mixer_state(ar);
1036 
1037     XML_ParserFree(parser);
1038     fclose(file);
1039     return ar;
1040 
1041 err_parse:
1042     path_free(ar);
1043     XML_ParserFree(parser);
1044 err_parser_create:
1045     fclose(file);
1046 err_fopen:
1047     free_mixer_state(ar);
1048 err_mixer_state:
1049     mixer_close(ar->mixer);
1050 err_mixer_open:
1051     free(ar);
1052     ar = NULL;
1053 err_calloc:
1054     return NULL;
1055 }
1056 
audio_route_free(struct audio_route * ar)1057 void audio_route_free(struct audio_route *ar)
1058 {
1059     free_mixer_state(ar);
1060     mixer_close(ar->mixer);
1061     path_free(ar);
1062     free(ar);
1063 }
1064