OSDN Git Service

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