OSDN Git Service

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