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