OSDN Git Service

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