• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  * Inspired by TinyHW, written by Mark Brown at Wolfson Micro
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #define LOG_TAG "audio_route"
19 /*#define LOG_NDEBUG 0*/
20 
21 #include <errno.h>
22 #include <expat.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include <cutils/log.h>
28 
29 #include <tinyalsa/asoundlib.h>
30 
31 #define BUF_SIZE 1024
32 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
33 #define INITIAL_MIXER_PATH_SIZE 8
34 
35 struct mixer_state {
36     struct mixer_ctl *ctl;
37     unsigned int num_values;
38     int *old_value;
39     int *new_value;
40     int *reset_value;
41     /* If linked is true, only the first element in each array is valid */
42     bool old_linked;
43     bool new_linked;
44     bool reset_linked;
45 };
46 
47 struct mixer_setting {
48     struct mixer_ctl *ctl;
49     unsigned int num_values;
50     int *value;
51     /* If linked is true, only the first element in each array is valid */
52     bool linked;
53 };
54 
55 struct mixer_value {
56     struct mixer_ctl *ctl;
57     int index;
58     int value;
59 };
60 
61 struct mixer_path {
62     char *name;
63     unsigned int size;
64     unsigned int length;
65     struct mixer_setting *setting;
66 };
67 
68 struct audio_route {
69     struct mixer *mixer;
70     unsigned int num_mixer_ctls;
71     struct mixer_state *mixer_state;
72 
73     unsigned int mixer_path_size;
74     unsigned int num_mixer_paths;
75     struct mixer_path *mixer_path;
76 };
77 
78 struct config_parse_state {
79     struct audio_route *ar;
80     struct mixer_path *path;
81     int level;
82 };
83 
84 /* path functions */
85 
path_print(struct mixer_path * path)86 static void path_print(struct mixer_path *path)
87 {
88     unsigned int i;
89     unsigned int j;
90 
91     ALOGE("Path: %s, length: %d", path->name, path->length);
92     for (i = 0; i < path->length; i++) {
93         ALOGE("  id=%d: ctl=%s linked=%c", i,
94               mixer_ctl_get_name(path->setting[i].ctl),
95               path->setting[i].linked ? 'y' : 'n');
96         for (j = 0; j < path->setting[i].num_values; j++)
97             ALOGE("    id=%d value=%d", j, path->setting[i].value[j]);
98     }
99 }
100 
path_free(struct audio_route * ar)101 static void path_free(struct audio_route *ar)
102 {
103     unsigned int i;
104 
105     for (i = 0; i < ar->num_mixer_paths; i++) {
106         if (ar->mixer_path[i].name)
107             free(ar->mixer_path[i].name);
108         if (ar->mixer_path[i].setting) {
109             if (ar->mixer_path[i].setting->value)
110                 free(ar->mixer_path[i].setting->value);
111             free(ar->mixer_path[i].setting);
112         }
113     }
114     free(ar->mixer_path);
115 }
116 
path_get_by_name(struct audio_route * ar,const char * name)117 static struct mixer_path *path_get_by_name(struct audio_route *ar,
118                                            const char *name)
119 {
120     unsigned int i;
121 
122     for (i = 0; i < ar->num_mixer_paths; i++)
123         if (strcmp(ar->mixer_path[i].name, name) == 0)
124             return &ar->mixer_path[i];
125 
126     return NULL;
127 }
128 
path_create(struct audio_route * ar,const char * name)129 static struct mixer_path *path_create(struct audio_route *ar, const char *name)
130 {
131     struct mixer_path *new_mixer_path = NULL;
132 
133     if (path_get_by_name(ar, name)) {
134         ALOGE("Path name '%s' already exists", name);
135         return NULL;
136     }
137 
138     /* check if we need to allocate more space for mixer paths */
139     if (ar->mixer_path_size <= ar->num_mixer_paths) {
140         if (ar->mixer_path_size == 0)
141             ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE;
142         else
143             ar->mixer_path_size *= 2;
144 
145         new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size *
146                                  sizeof(struct mixer_path));
147         if (new_mixer_path == NULL) {
148             ALOGE("Unable to allocate more paths");
149             return NULL;
150         } else {
151             ar->mixer_path = new_mixer_path;
152         }
153     }
154 
155     /* initialise the new mixer path */
156     ar->mixer_path[ar->num_mixer_paths].name = strdup(name);
157     ar->mixer_path[ar->num_mixer_paths].size = 0;
158     ar->mixer_path[ar->num_mixer_paths].length = 0;
159     ar->mixer_path[ar->num_mixer_paths].setting = NULL;
160 
161     /* return the mixer path just added, then increment number of them */
162     return &ar->mixer_path[ar->num_mixer_paths++];
163 }
164 
find_ctl_in_path(struct mixer_path * path,struct mixer_ctl * ctl)165 static int find_ctl_in_path(struct mixer_path *path, struct mixer_ctl *ctl)
166 {
167     unsigned int i;
168 
169     for (i = 0; i < path->length; i++)
170         if (path->setting[i].ctl == ctl)
171             return i;
172 
173     return -1;
174 }
175 
alloc_path_setting(struct mixer_path * path)176 static int alloc_path_setting(struct mixer_path *path)
177 {
178     struct mixer_setting *new_path_setting;
179     int path_index;
180 
181     /* check if we need to allocate more space for path settings */
182     if (path->size <= path->length) {
183         if (path->size == 0)
184             path->size = INITIAL_MIXER_PATH_SIZE;
185         else
186             path->size *= 2;
187 
188         new_path_setting = realloc(path->setting,
189                                    path->size * sizeof(struct mixer_setting));
190         if (new_path_setting == NULL) {
191             ALOGE("Unable to allocate more path settings");
192             return -1;
193         } else {
194             path->setting = new_path_setting;
195         }
196     }
197 
198     path_index = path->length;
199     path->length++;
200 
201     return path_index;
202 }
203 
path_add_setting(struct mixer_path * path,struct mixer_setting * setting)204 static int path_add_setting(struct mixer_path *path,
205                             struct mixer_setting *setting)
206 {
207     unsigned int i;
208     int path_index;
209 
210     if (find_ctl_in_path(path, setting->ctl) != -1) {
211         ALOGE("Control '%s' already exists in path '%s'",
212               mixer_ctl_get_name(setting->ctl), path->name);
213         return -1;
214     }
215 
216     path_index = alloc_path_setting(path);
217     if (path_index < 0)
218         return -1;
219 
220     path->setting[path_index].ctl = setting->ctl;
221     path->setting[path_index].num_values = setting->num_values;
222     path->setting[path_index].value = malloc(setting->num_values * sizeof(int));
223     path->setting[path_index].linked = setting->linked;
224     if (setting->linked) {
225         path->setting[path_index].value[0] = setting->value[0];
226     } else {
227         for (i = 0; i < setting->num_values; i++)
228             path->setting[path_index].value[i] = setting->value[i];
229     }
230 
231     return 0;
232 }
233 
path_add_value(struct mixer_path * path,struct mixer_value * mixer_value)234 static int path_add_value(struct mixer_path *path,
235                           struct mixer_value *mixer_value)
236 {
237     unsigned int i;
238     int path_index;
239     unsigned int num_values;
240 
241     /* Check that mixer value index is within range */
242     num_values = mixer_ctl_get_num_values(mixer_value->ctl);
243     if (mixer_value->index >= (int)num_values) {
244         ALOGE("mixer index %d is out of range for '%s'", mixer_value->index,
245               mixer_ctl_get_name(mixer_value->ctl));
246         return -1;
247     }
248 
249     path_index = find_ctl_in_path(path, mixer_value->ctl);
250     if (path_index < 0) {
251         /* New path */
252 
253         path_index = alloc_path_setting(path);
254         if (path_index < 0)
255             return -1;
256 
257         /* initialise the new path setting */
258         path->setting[path_index].ctl = mixer_value->ctl;
259         path->setting[path_index].num_values = num_values;
260         path->setting[path_index].value = malloc(num_values * sizeof(int));
261         path->setting[path_index].linked = true;
262         path->setting[path_index].value[0] = mixer_value->value;
263     }
264 
265     if (mixer_value->index == -1) {
266         /* Linked, so only set the first value */
267         path->setting[path_index].linked = true;
268         path->setting[path_index].value[0] = mixer_value->value;
269     } else {
270         if (path->setting[path_index].linked && (num_values > 1)) {
271             /* Unlinking the values, so duplicate them across */
272             for (i = 1; i < num_values; i++) {
273                 path->setting[path_index].value[i] =
274                         path->setting[path_index].value[0];
275             }
276             path->setting[path_index].linked = false;
277         }
278         path->setting[path_index].value[mixer_value->index] = mixer_value->value;
279     }
280 
281     return 0;
282 }
283 
path_add_path(struct mixer_path * path,struct mixer_path * sub_path)284 static int path_add_path(struct mixer_path *path, struct mixer_path *sub_path)
285 {
286     unsigned int i;
287 
288     for (i = 0; i < sub_path->length; i++)
289         if (path_add_setting(path, &sub_path->setting[i]) < 0)
290             return -1;
291 
292     return 0;
293 }
294 
path_apply(struct audio_route * ar,struct mixer_path * path)295 static int path_apply(struct audio_route *ar, struct mixer_path *path)
296 {
297     unsigned int i;
298     unsigned int j;
299     unsigned int ctl_index;
300 
301     for (i = 0; i < path->length; i++) {
302         struct mixer_ctl *ctl = path->setting[i].ctl;
303 
304         /* locate the mixer ctl in the list */
305         for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++)
306             if (ar->mixer_state[ctl_index].ctl == ctl)
307                 break;
308 
309         /* apply the new value(s) */
310         for (j = 0; j < ar->mixer_state[ctl_index].num_values; j++) {
311             ar->mixer_state[ctl_index].new_value[j] = path->setting[i].value[j];
312             if (path->setting[i].linked)
313                 break;
314         }
315         ar->mixer_state[ctl_index].new_linked = path->setting[i].linked;
316     }
317 
318     return 0;
319 }
320 
path_reset(struct audio_route * ar,struct mixer_path * path)321 static int path_reset(struct audio_route *ar, struct mixer_path *path)
322 {
323     unsigned int i;
324     unsigned int j;
325     unsigned int ctl_index;
326 
327     for (i = 0; i < path->length; i++) {
328         struct mixer_ctl *ctl = path->setting[i].ctl;
329 
330         /* locate the mixer ctl in the list */
331         for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
332             if (ar->mixer_state[ctl_index].ctl == ctl)
333                 break;
334         }
335 
336         /* reset the value(s) */
337         for (j = 0; j < ar->mixer_state[ctl_index].num_values; j++) {
338             ar->mixer_state[ctl_index].new_value[j] = ar->mixer_state[ctl_index].reset_value[j];
339             if (ar->mixer_state[ctl_index].reset_linked)
340                 break;
341         }
342         ar->mixer_state[ctl_index].new_linked = ar->mixer_state[ctl_index].reset_linked;
343     }
344 
345     return 0;
346 }
347 
348 /* mixer helper function */
mixer_enum_string_to_value(struct mixer_ctl * ctl,const char * string)349 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string)
350 {
351     unsigned int i;
352 
353     /* Search the enum strings for a particular one */
354     for (i = 0; i < mixer_ctl_get_num_enums(ctl); i++) {
355         if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
356             break;
357     }
358 
359     return i;
360 }
361 
start_tag(void * data,const XML_Char * tag_name,const XML_Char ** attr)362 static void start_tag(void *data, const XML_Char *tag_name,
363                       const XML_Char **attr)
364 {
365     const XML_Char *attr_name = NULL;
366     const XML_Char *attr_id = NULL;
367     const XML_Char *attr_value = NULL;
368     struct config_parse_state *state = data;
369     struct audio_route *ar = state->ar;
370     unsigned int i;
371     unsigned int ctl_index;
372     struct mixer_ctl *ctl;
373     int value;
374     unsigned int id;
375     struct mixer_value mixer_value;
376 
377     /* Get name, id and value attributes (these may be empty) */
378     for (i = 0; attr[i]; i += 2) {
379         if (strcmp(attr[i], "name") == 0)
380             attr_name = attr[i + 1];
381         if (strcmp(attr[i], "id") == 0)
382             attr_id = attr[i + 1];
383         else if (strcmp(attr[i], "value") == 0)
384             attr_value = attr[i + 1];
385     }
386 
387     /* Look at tags */
388     if (strcmp(tag_name, "path") == 0) {
389         if (attr_name == NULL) {
390             ALOGE("Unnamed path!");
391         } else {
392             if (state->level == 1) {
393                 /* top level path: create and stash the path */
394                 state->path = path_create(ar, (char *)attr_name);
395             } else {
396                 /* nested path */
397                 struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
398                 path_add_path(state->path, sub_path);
399             }
400         }
401     }
402 
403     else if (strcmp(tag_name, "ctl") == 0) {
404         /* Obtain the mixer ctl and value */
405         ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);
406         switch (mixer_ctl_get_type(ctl)) {
407         case MIXER_CTL_TYPE_BOOL:
408         case MIXER_CTL_TYPE_INT:
409             value = atoi((char *)attr_value);
410             break;
411         case MIXER_CTL_TYPE_ENUM:
412             value = mixer_enum_string_to_value(ctl, (char *)attr_value);
413             break;
414         default:
415             value = 0;
416             break;
417         }
418 
419         if (state->level == 1) {
420             /* top level ctl (initial setting) */
421 
422             /* locate the mixer ctl in the list */
423             for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
424                 if (ar->mixer_state[ctl_index].ctl == ctl)
425                     break;
426             }
427 
428             /* apply the new value */
429             if (attr_id) {
430                 /* set only one value */
431                 id = atoi((char *)attr_id);
432                 if (id < ar->mixer_state[ctl_index].num_values) {
433                     if (ar->mixer_state[ctl_index].new_linked) {
434                         /*
435                          * We're unlinking the values, so copy old_value[0] into
436                          * all the new_value elements.
437                          */
438                         for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++) {
439                             ar->mixer_state[ctl_index].new_value[i] =
440                                     ar->mixer_state[ctl_index].old_value[0];
441                         }
442                         ar->mixer_state[ctl_index].new_linked = false;
443                     }
444                     ar->mixer_state[ctl_index].new_value[id] = value;
445                 } else {
446                     ALOGE("value id out of range for mixer ctl '%s'",
447                           mixer_ctl_get_name(ctl));
448                 }
449             } else {
450                 ar->mixer_state[ctl_index].new_value[0] = value;
451                 ar->mixer_state[ctl_index].new_linked = true;
452             }
453         } else {
454             /* nested ctl (within a path) */
455             mixer_value.ctl = ctl;
456             mixer_value.value = value;
457             if (attr_id)
458                 mixer_value.index = atoi((char *)attr_id);
459             else
460                 mixer_value.index = -1;
461             path_add_value(state->path, &mixer_value);
462         }
463     }
464 
465     state->level++;
466 }
467 
end_tag(void * data,const XML_Char * tag_name)468 static void end_tag(void *data, const XML_Char *tag_name)
469 {
470     struct config_parse_state *state = data;
471 
472     state->level--;
473 }
474 
alloc_mixer_state(struct audio_route * ar)475 static int alloc_mixer_state(struct audio_route *ar)
476 {
477     unsigned int i;
478     unsigned int j;
479     unsigned int num_values;
480     struct mixer_ctl *ctl;
481     bool linked;
482 
483     ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
484     ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state));
485     if (!ar->mixer_state)
486         return -1;
487 
488     for (i = 0; i < ar->num_mixer_ctls; i++) {
489         ctl = mixer_get_ctl(ar->mixer, i);
490         num_values = mixer_ctl_get_num_values(ctl);
491 
492         ar->mixer_state[i].old_value = malloc(num_values * sizeof(int));
493         ar->mixer_state[i].new_value = malloc(num_values * sizeof(int));
494         ar->mixer_state[i].reset_value = malloc(num_values * sizeof(int));
495 
496         /*
497          * Get all mixer values for controls with multiple values. If all
498          * values are the same, set the linked flag.
499          */
500         linked = true;
501         for (j = 0; j < num_values; j++) {
502             ar->mixer_state[i].old_value[j] = mixer_ctl_get_value(ctl, j);
503             ar->mixer_state[i].new_value[j] = ar->mixer_state[i].old_value[j];
504 
505             /*
506              * If the next value is different from the last, set linked to
507              * false.
508              */
509             if ((j > 0) && (ar->mixer_state[i].old_value[j - 1] !=
510                             ar->mixer_state[i].old_value[j])) {
511                 linked = false;
512             }
513         }
514         ar->mixer_state[i].ctl = ctl;
515         ar->mixer_state[i].old_linked = linked;
516         ar->mixer_state[i].new_linked = linked;
517         ar->mixer_state[i].num_values = num_values;
518     }
519 
520     return 0;
521 }
522 
free_mixer_state(struct audio_route * ar)523 static void free_mixer_state(struct audio_route *ar)
524 {
525     unsigned int i;
526 
527     for (i = 0; i < ar->num_mixer_ctls; i++) {
528         free(ar->mixer_state[i].old_value);
529         free(ar->mixer_state[i].new_value);
530         free(ar->mixer_state[i].reset_value);
531     }
532 
533     free(ar->mixer_state);
534     ar->mixer_state = NULL;
535 }
536 
537 /* Update the mixer with any changed values */
audio_route_update_mixer(struct audio_route * ar)538 int audio_route_update_mixer(struct audio_route *ar)
539 {
540     unsigned int i;
541     unsigned int j;
542 
543     for (i = 0; i < ar->num_mixer_ctls; i++) {
544         unsigned int num_values = ar->mixer_state[i].num_values;
545 
546         /* if the value has changed, update the mixer */
547         if (ar->mixer_state[i].new_linked) {
548             if (ar->mixer_state[i].old_value[0] != ar->mixer_state[i].new_value[0]) {
549                 /* linked ctl, so set all ctl values the same */
550                 for (j = 0; j < num_values; j++)
551                     mixer_ctl_set_value(ar->mixer_state[i].ctl, j,
552                                         ar->mixer_state[i].new_value[0]);
553                 ar->mixer_state[i].old_value[0] = ar->mixer_state[i].new_value[0];
554             }
555         } else {
556             for (j = 0; j < num_values; j++) {
557                 /*
558                  * unlinked ctl, so set each value if necessary.
559                  * Note that if the new value is unlinked but the old is
560                  * linked, only value 0 is valid, so we always have to
561                  * update the mixer for the other values.
562                  */
563                 if (ar->mixer_state[i].old_linked ||
564                     (ar->mixer_state[i].old_value[j] !=
565                             ar->mixer_state[i].new_value[j])) {
566                     mixer_ctl_set_value(ar->mixer_state[i].ctl, j,
567                                         ar->mixer_state[i].new_value[j]);
568                     ar->mixer_state[i].old_value[j] = ar->mixer_state[i].new_value[j];
569                 }
570             }
571         }
572         ar->mixer_state[i].old_linked = ar->mixer_state[i].new_linked;
573     }
574 
575     return 0;
576 }
577 
578 /* saves the current state of the mixer, for resetting all controls */
save_mixer_state(struct audio_route * ar)579 static void save_mixer_state(struct audio_route *ar)
580 {
581     unsigned int i;
582     unsigned int j;
583 
584     for (i = 0; i < ar->num_mixer_ctls; i++) {
585         for (j = 0; j < ar->mixer_state[i].num_values; j++) {
586             ar->mixer_state[i].reset_value[j] = ar->mixer_state[i].new_value[j];
587 
588             /* if the values are linked, only need to save value 0 */
589             if (ar->mixer_state[i].new_linked)
590                 break;
591         }
592         ar->mixer_state[i].reset_linked = ar->mixer_state[i].new_linked;
593     }
594 }
595 
596 /* Reset the audio routes back to the initial state */
audio_route_reset(struct audio_route * ar)597 void audio_route_reset(struct audio_route *ar)
598 {
599     unsigned int i;
600     unsigned int j;
601 
602     /* load all of the saved values */
603     for (i = 0; i < ar->num_mixer_ctls; i++) {
604         for (j = 0; j < ar->mixer_state[i].num_values; j++) {
605             ar->mixer_state[i].new_value[j] = ar->mixer_state[i].reset_value[j];
606 
607             /* if the values are linked, only need to save value 0 */
608             if (ar->mixer_state[i].reset_linked)
609                 break;
610         }
611         ar->mixer_state[i].new_linked = ar->mixer_state[i].reset_linked;
612     }
613 }
614 
615 /* Apply an audio route path by name */
audio_route_apply_path(struct audio_route * ar,const char * name)616 int audio_route_apply_path(struct audio_route *ar, const char *name)
617 {
618     struct mixer_path *path;
619 
620     if (!ar) {
621         ALOGE("invalid audio_route");
622         return -1;
623     }
624 
625     path = path_get_by_name(ar, name);
626     if (!path) {
627         ALOGE("unable to find path '%s'", name);
628         return -1;
629     }
630 
631     path_apply(ar, path);
632 
633     return 0;
634 }
635 
636 /* Reset an audio route path by name */
audio_route_reset_path(struct audio_route * ar,const char * name)637 int audio_route_reset_path(struct audio_route *ar, const char *name)
638 {
639     struct mixer_path *path;
640 
641     if (!ar) {
642         ALOGE("invalid audio_route");
643         return -1;
644     }
645 
646     path = path_get_by_name(ar, name);
647     if (!path) {
648         ALOGE("unable to find path '%s'", name);
649         return -1;
650     }
651 
652     path_reset(ar, path);
653 
654     return 0;
655 }
656 
audio_route_init(unsigned int card,const char * xml_path)657 struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
658 {
659     struct config_parse_state state;
660     XML_Parser parser;
661     FILE *file;
662     int bytes_read;
663     void *buf;
664     int i;
665     struct audio_route *ar;
666 
667     ar = calloc(1, sizeof(struct audio_route));
668     if (!ar)
669         goto err_calloc;
670 
671     ar->mixer = mixer_open(card);
672     if (!ar->mixer) {
673         ALOGE("Unable to open the mixer, aborting.");
674         goto err_mixer_open;
675     }
676 
677     ar->mixer_path = NULL;
678     ar->mixer_path_size = 0;
679     ar->num_mixer_paths = 0;
680 
681     /* allocate space for and read current mixer settings */
682     if (alloc_mixer_state(ar) < 0)
683         goto err_mixer_state;
684 
685     /* use the default XML path if none is provided */
686     if (xml_path == NULL)
687         xml_path = MIXER_XML_PATH;
688 
689     file = fopen(xml_path, "r");
690 
691     if (!file) {
692         ALOGE("Failed to open %s", xml_path);
693         goto err_fopen;
694     }
695 
696     parser = XML_ParserCreate(NULL);
697     if (!parser) {
698         ALOGE("Failed to create XML parser");
699         goto err_parser_create;
700     }
701 
702     memset(&state, 0, sizeof(state));
703     state.ar = ar;
704     XML_SetUserData(parser, &state);
705     XML_SetElementHandler(parser, start_tag, end_tag);
706 
707     for (;;) {
708         buf = XML_GetBuffer(parser, BUF_SIZE);
709         if (buf == NULL)
710             goto err_parse;
711 
712         bytes_read = fread(buf, 1, BUF_SIZE, file);
713         if (bytes_read < 0)
714             goto err_parse;
715 
716         if (XML_ParseBuffer(parser, bytes_read,
717                             bytes_read == 0) == XML_STATUS_ERROR) {
718             ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
719             goto err_parse;
720         }
721 
722         if (bytes_read == 0)
723             break;
724     }
725 
726     /* apply the initial mixer values, and save them so we can reset the
727        mixer to the original values */
728     audio_route_update_mixer(ar);
729     save_mixer_state(ar);
730 
731     XML_ParserFree(parser);
732     fclose(file);
733     return ar;
734 
735 err_parse:
736     XML_ParserFree(parser);
737 err_parser_create:
738     fclose(file);
739 err_fopen:
740     free_mixer_state(ar);
741 err_mixer_state:
742     mixer_close(ar->mixer);
743 err_mixer_open:
744     free(ar);
745     ar = NULL;
746 err_calloc:
747     return NULL;
748 }
749 
audio_route_free(struct audio_route * ar)750 void audio_route_free(struct audio_route *ar)
751 {
752     free_mixer_state(ar);
753     mixer_close(ar->mixer);
754     free(ar);
755 }
756