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