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
35struct 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
43struct mixer_setting {
44    unsigned int ctl_index;
45    unsigned int num_values;
46    int *value;
47};
48
49struct mixer_value {
50    unsigned int ctl_index;
51    int index;
52    int value;
53};
54
55struct mixer_path {
56    char *name;
57    unsigned int size;
58    unsigned int length;
59    struct mixer_setting *setting;
60};
61
62struct 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
72struct config_parse_state {
73    struct audio_route *ar;
74    struct mixer_path *path;
75    int level;
76};
77
78/* path functions */
79
80static 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
92static 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
98static 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
113static 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
129static 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
141static 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
177static 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
189static 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
217static 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
244static 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
288static 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
300static 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
322static 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 */
347static 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
360static 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 = (int) strtol((char *)attr_value, NULL, 0);
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
461done:
462    state->level++;
463}
464
465static 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
473static 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
514static 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 */
534int 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 */
573static 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 */
589void 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 */
606int 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 */
627int 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
647/*
648 * Operates on the specified path .. controls will be updated in the
649 * order listed in the XML file
650 */
651static int audio_route_update_path(struct audio_route *ar, const char *name, bool reverse)
652{
653    struct mixer_path *path;
654    int32_t i, end;
655    unsigned int j;
656
657    if (!ar) {
658        ALOGE("invalid audio_route");
659        return -1;
660    }
661
662    path = path_get_by_name(ar, name);
663    if (!path) {
664        ALOGE("unable to find path '%s'", name);
665        return -1;
666    }
667
668    i = reverse ? (path->length - 1) : 0;
669    end = reverse ? -1 : (int32_t)path->length;
670
671    while (i != end) {
672        unsigned int ctl_index;
673        enum mixer_ctl_type type;
674
675        ctl_index = path->setting[i].ctl_index;
676
677        struct mixer_state * ms = &ar->mixer_state[ctl_index];
678
679        type = mixer_ctl_get_type(ms->ctl);
680        if (!is_supported_ctl_type(type)) {
681            continue;
682        }
683
684        /* if any value has changed, update the mixer */
685        for (j = 0; j < ms->num_values; j++) {
686            if (ms->old_value[j] != ms->new_value[j]) {
687                if (type == MIXER_CTL_TYPE_ENUM)
688                    mixer_ctl_set_value(ms->ctl, 0, ms->new_value[0]);
689                else
690                    mixer_ctl_set_array(ms->ctl, ms->new_value, ms->num_values);
691                memcpy(ms->old_value, ms->new_value, ms->num_values * sizeof(int));
692                break;
693            }
694        }
695
696        i = reverse ? (i - 1) : (i + 1);
697    }
698    return 0;
699}
700
701int audio_route_apply_and_update_path(struct audio_route *ar, const char *name)
702{
703    if (audio_route_apply_path(ar, name) < 0) {
704        return -1;
705    }
706    return audio_route_update_path(ar, name, false /*reverse*/);
707}
708
709int audio_route_reset_and_update_path(struct audio_route *ar, const char *name)
710{
711    if (audio_route_reset_path(ar, name) < 0) {
712        return -1;
713    }
714    return audio_route_update_path(ar, name, true /*reverse*/);
715}
716
717struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
718{
719    struct config_parse_state state;
720    XML_Parser parser;
721    FILE *file;
722    int bytes_read;
723    void *buf;
724    int i;
725    struct audio_route *ar;
726
727    ar = calloc(1, sizeof(struct audio_route));
728    if (!ar)
729        goto err_calloc;
730
731    ar->mixer = mixer_open(card);
732    if (!ar->mixer) {
733        ALOGE("Unable to open the mixer, aborting.");
734        goto err_mixer_open;
735    }
736
737    ar->mixer_path = NULL;
738    ar->mixer_path_size = 0;
739    ar->num_mixer_paths = 0;
740
741    /* allocate space for and read current mixer settings */
742    if (alloc_mixer_state(ar) < 0)
743        goto err_mixer_state;
744
745    /* use the default XML path if none is provided */
746    if (xml_path == NULL)
747        xml_path = MIXER_XML_PATH;
748
749    file = fopen(xml_path, "r");
750
751    if (!file) {
752        ALOGE("Failed to open %s", xml_path);
753        goto err_fopen;
754    }
755
756    parser = XML_ParserCreate(NULL);
757    if (!parser) {
758        ALOGE("Failed to create XML parser");
759        goto err_parser_create;
760    }
761
762    memset(&state, 0, sizeof(state));
763    state.ar = ar;
764    XML_SetUserData(parser, &state);
765    XML_SetElementHandler(parser, start_tag, end_tag);
766
767    for (;;) {
768        buf = XML_GetBuffer(parser, BUF_SIZE);
769        if (buf == NULL)
770            goto err_parse;
771
772        bytes_read = fread(buf, 1, BUF_SIZE, file);
773        if (bytes_read < 0)
774            goto err_parse;
775
776        if (XML_ParseBuffer(parser, bytes_read,
777                            bytes_read == 0) == XML_STATUS_ERROR) {
778            ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
779            goto err_parse;
780        }
781
782        if (bytes_read == 0)
783            break;
784    }
785
786    /* apply the initial mixer values, and save them so we can reset the
787       mixer to the original values */
788    audio_route_update_mixer(ar);
789    save_mixer_state(ar);
790
791    XML_ParserFree(parser);
792    fclose(file);
793    return ar;
794
795err_parse:
796    XML_ParserFree(parser);
797err_parser_create:
798    fclose(file);
799err_fopen:
800    free_mixer_state(ar);
801err_mixer_state:
802    mixer_close(ar->mixer);
803err_mixer_open:
804    free(ar);
805    ar = NULL;
806err_calloc:
807    return NULL;
808}
809
810void audio_route_free(struct audio_route *ar)
811{
812    free_mixer_state(ar);
813    mixer_close(ar->mixer);
814    free(ar);
815}
816