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
35union ctl_values {
36    int *enumerated;
37    long *integer;
38    void *ptr;
39    unsigned char *bytes;
40};
41
42struct 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
50struct mixer_setting {
51    unsigned int ctl_index;
52    unsigned int num_values;
53    unsigned int type;
54    union ctl_values value;
55};
56
57struct mixer_value {
58    unsigned int ctl_index;
59    int index;
60    long value;
61};
62
63struct mixer_path {
64    char *name;
65    unsigned int size;
66    unsigned int length;
67    struct mixer_setting *setting;
68};
69
70struct 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
80struct config_parse_state {
81    struct audio_route *ar;
82    struct mixer_path *path;
83    int level;
84};
85
86/* path functions */
87
88static 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 */
102static 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
120static 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
127static 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
151static 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
174static 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
186static 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
222static 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
234static 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
262static 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
298static 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
368static 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
380static 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
402static 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 */
427static 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
451static 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
572done:
573    state->level++;
574}
575
576static 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
584static 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
626static 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 */
646int 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 */
704static 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 */
721void 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 */
739int 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 */
760int 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 */
784static 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
840int 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
848int 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
856struct 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
933err_parse:
934    path_free(ar);
935    XML_ParserFree(parser);
936err_parser_create:
937    fclose(file);
938err_fopen:
939    free_mixer_state(ar);
940err_mixer_state:
941    mixer_close(ar->mixer);
942err_mixer_open:
943    free(ar);
944    ar = NULL;
945err_calloc:
946    return NULL;
947}
948
949void 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}
956