• 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 <log/log.h>
28 
29 #include <tinyalsa/asoundlib.h>
30 
31 #define BUF_SIZE 1024
32 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
33 #define INITIAL_MIXER_PATH_SIZE 8
34 
35 enum update_direction {
36     DIRECTION_FORWARD,
37     DIRECTION_REVERSE,
38     DIRECTION_REVERSE_RESET
39 };
40 
41 /*
42  "ctl_values" couples the buffer pointer with a variable "byte_size" to store
43  both types of ctl setting as below in respective ways.
44 
45                     | fixed-length            | tlv-typed byte ctl [note 1]
46                     | byte/int/enum ctl       |
47  -------------------+-------------------------+--------------------------------
48   alloc buffer size | num_values * size(type) | num_values * 1     [note 2]
49                     +                         +
50   stored value size | always as the full size | can be any size from 1 up to
51                     | of allocated buffer     | num_values
52                     +                         +
53   "byte_size" value | equal to buffer size,   | equal to stored value size,
54                     | fixed in runtime        | variable according to setting
55 
56  additional notes:
57  [1] tlv-typed read/write is not a byte-specific feature but by now it only
58      supports for byte ctls via Tinyalsa API
59  [2] num_values is obtained from mixer_ctl_get_num_values()
60  */
61 struct ctl_values {
62     /* anonymous union */
63     union {
64         int *enumerated;
65         long *integer;
66         void *ptr;
67         unsigned char *bytes;
68     };
69     unsigned int byte_size;
70 };
71 
72 struct mixer_state {
73     struct mixer_ctl *ctl;
74     unsigned int num_values;
75     struct ctl_values old_value;
76     struct ctl_values new_value;
77     struct ctl_values reset_value;
78     unsigned int active_count;
79 };
80 
81 struct mixer_setting {
82     unsigned int ctl_index;
83     unsigned int num_values;
84     unsigned int type;
85     struct ctl_values value;
86 };
87 
88 struct mixer_value {
89     unsigned int ctl_index;
90     int index;
91     long value;
92     /*
93      memory pointed by this is allocated in start_tag during parsing ctl of
94      MIXER_CTL_TYPE_BYTE or MIXER_CTL_TYPE_INT, and is released after the
95      parsed values are updated to either setting value within a path,
96      or top level initial setting value
97      */
98     long *values;
99     unsigned int num_values_in_array;
100 };
101 
102 struct mixer_path {
103     char *name;
104     unsigned int size;
105     unsigned int length;
106     struct mixer_setting *setting;
107 };
108 
109 struct audio_route {
110     struct mixer *mixer;
111     unsigned int num_mixer_ctls;
112     struct mixer_state *mixer_state;
113 
114     unsigned int mixer_path_size;
115     unsigned int num_mixer_paths;
116     struct mixer_path *mixer_path;
117 };
118 
119 struct config_parse_state {
120     struct audio_route *ar;
121     struct mixer_path *path;
122     int level;
123     bool enum_mixer_numeric_fallback;
124 };
125 
126 static size_t sizeof_ctl_type(enum mixer_ctl_type type);
127 
ctl_is_tlv_byte_type(struct mixer_ctl * ctl)128 static bool ctl_is_tlv_byte_type(struct mixer_ctl *ctl)
129 {
130     return mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_BYTE && mixer_ctl_is_access_tlv_rw(ctl);
131 }
132 
133 /* ctl_values helper functions */
134 
ctl_values_alloc(struct ctl_values * value,unsigned int num_values,enum mixer_ctl_type type)135 static int ctl_values_alloc(struct ctl_values *value, unsigned int num_values,
136                             enum mixer_ctl_type type)
137 {
138     void *ptr;
139     size_t value_sz = sizeof_ctl_type(type);
140 
141     ptr = calloc(num_values, value_sz);
142     if (!ptr)
143         return -1;
144 
145     value->ptr = ptr;
146     value->byte_size = num_values * value_sz;
147     return 0;
148 }
149 
ctl_values_copy(struct ctl_values * dst,const struct ctl_values * src)150 static void ctl_values_copy(struct ctl_values *dst, const struct ctl_values *src)
151 {
152     /*
153      this should only be used for copying among "ctl_values"-es of a "mixer_state", all of them
154      will be allocated the same size of buffers according to "num_values" obtained from mixer ctl.
155      */
156     memcpy(dst->ptr, src->ptr, src->byte_size);
157     dst->byte_size = src->byte_size;
158 }
159 
160 /* path functions */
161 
is_supported_ctl_type(enum mixer_ctl_type type)162 static bool is_supported_ctl_type(enum mixer_ctl_type type)
163 {
164     switch (type) {
165     case MIXER_CTL_TYPE_BOOL:
166     case MIXER_CTL_TYPE_INT:
167     case MIXER_CTL_TYPE_ENUM:
168     case MIXER_CTL_TYPE_BYTE:
169         return true;
170     default:
171         return false;
172     }
173 }
174 
175 /* as they match in alsa */
sizeof_ctl_type(enum mixer_ctl_type type)176 static size_t sizeof_ctl_type(enum mixer_ctl_type type) {
177     switch (type) {
178     case MIXER_CTL_TYPE_BOOL:
179     case MIXER_CTL_TYPE_INT:
180         return sizeof(long);
181     case MIXER_CTL_TYPE_ENUM:
182         return sizeof(int);
183     case MIXER_CTL_TYPE_BYTE:
184         return sizeof(unsigned char);
185     case MIXER_CTL_TYPE_INT64:
186     case MIXER_CTL_TYPE_IEC958:
187     case MIXER_CTL_TYPE_UNKNOWN:
188     default:
189         LOG_ALWAYS_FATAL("Unsupported mixer ctl type: %d, check type before calling", (int)type);
190         return 0;
191     }
192 }
193 
index_to_ctl(struct audio_route * ar,unsigned int ctl_index)194 static inline struct mixer_ctl *index_to_ctl(struct audio_route *ar,
195                                              unsigned int ctl_index)
196 {
197     return ar->mixer_state[ctl_index].ctl;
198 }
199 
200 #if 0
201 static void path_print(struct audio_route *ar, struct mixer_path *path)
202 {
203     unsigned int i;
204     unsigned int j;
205 
206     ALOGE("Path: %s, length: %d", path->name, path->length);
207     for (i = 0; i < path->length; i++) {
208         struct mixer_ctl *ctl = index_to_ctl(ar, path->setting[i].ctl_index);
209 
210         ALOGE("  id=%d: ctl=%s", i, mixer_ctl_get_name(ctl));
211         if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_BYTE) {
212             for (j = 0; j < path->setting[i].num_values; j++)
213                 ALOGE("    id=%d value=0x%02x", j, path->setting[i].value.bytes[j]);
214         } else if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_ENUM) {
215             for (j = 0; j < path->setting[i].num_values; j++)
216                 ALOGE("    id=%d value=%d", j, path->setting[i].value.enumerated[j]);
217         } else {
218             for (j = 0; j < path->setting[i].num_values; j++)
219                 ALOGE("    id=%d value=%ld", j, path->setting[i].value.integer[j]);
220         }
221     }
222 }
223 #endif
224 
path_free(struct audio_route * ar)225 static void path_free(struct audio_route *ar)
226 {
227     unsigned int i;
228 
229     for (i = 0; i < ar->num_mixer_paths; i++) {
230         free(ar->mixer_path[i].name);
231         if (ar->mixer_path[i].setting) {
232             size_t j;
233             for (j = 0; j < ar->mixer_path[i].length; j++) {
234                 free(ar->mixer_path[i].setting[j].value.ptr);
235             }
236             free(ar->mixer_path[i].setting);
237             ar->mixer_path[i].size = 0;
238             ar->mixer_path[i].length = 0;
239             ar->mixer_path[i].setting = NULL;
240         }
241     }
242     free(ar->mixer_path);
243     ar->mixer_path = NULL;
244     ar->mixer_path_size = 0;
245     ar->num_mixer_paths = 0;
246 }
247 
path_get_by_name(struct audio_route * ar,const char * name)248 static struct mixer_path *path_get_by_name(struct audio_route *ar,
249                                            const char *name)
250 {
251     unsigned int i;
252 
253     for (i = 0; i < ar->num_mixer_paths; i++)
254         if (strcmp(ar->mixer_path[i].name, name) == 0)
255             return &ar->mixer_path[i];
256 
257     return NULL;
258 }
259 
path_create(struct audio_route * ar,const char * name)260 static struct mixer_path *path_create(struct audio_route *ar, const char *name)
261 {
262     struct mixer_path *new_mixer_path = NULL;
263 
264     if (path_get_by_name(ar, name)) {
265         ALOGW("Path name '%s' already exists", name);
266         return NULL;
267     }
268 
269     /* check if we need to allocate more space for mixer paths */
270     if (ar->mixer_path_size <= ar->num_mixer_paths) {
271         if (ar->mixer_path_size == 0)
272             ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE;
273         else
274             ar->mixer_path_size *= 2;
275 
276         new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size *
277                                  sizeof(struct mixer_path));
278         if (new_mixer_path == NULL) {
279             ALOGE("Unable to allocate more paths");
280             return NULL;
281         } else {
282             ar->mixer_path = new_mixer_path;
283         }
284     }
285 
286     /* initialise the new mixer path */
287     ar->mixer_path[ar->num_mixer_paths].name = strdup(name);
288     ar->mixer_path[ar->num_mixer_paths].size = 0;
289     ar->mixer_path[ar->num_mixer_paths].length = 0;
290     ar->mixer_path[ar->num_mixer_paths].setting = NULL;
291 
292     /* return the mixer path just added, then increment number of them */
293     return &ar->mixer_path[ar->num_mixer_paths++];
294 }
295 
find_ctl_index_in_path(struct mixer_path * path,unsigned int ctl_index)296 static int find_ctl_index_in_path(struct mixer_path *path,
297                                   unsigned int ctl_index)
298 {
299     unsigned int i;
300 
301     for (i = 0; i < path->length; i++)
302         if (path->setting[i].ctl_index == ctl_index)
303             return i;
304 
305     return -1;
306 }
307 
alloc_path_setting(struct mixer_path * path)308 static int alloc_path_setting(struct mixer_path *path)
309 {
310     struct mixer_setting *new_path_setting;
311     int path_index;
312 
313     /* check if we need to allocate more space for path settings */
314     if (path->size <= path->length) {
315         if (path->size == 0)
316             path->size = INITIAL_MIXER_PATH_SIZE;
317         else
318             path->size *= 2;
319 
320         new_path_setting = realloc(path->setting,
321                                    path->size * sizeof(struct mixer_setting));
322         if (new_path_setting == NULL) {
323             ALOGE("Unable to allocate more path settings");
324             return -1;
325         } else {
326             path->setting = new_path_setting;
327         }
328     }
329 
330     path_index = path->length;
331     path->length++;
332 
333     return path_index;
334 }
335 
path_add_setting(struct audio_route * ar,struct mixer_path * path,struct mixer_setting * setting)336 static int path_add_setting(struct audio_route *ar, struct mixer_path *path,
337                             struct mixer_setting *setting)
338 {
339     int path_index;
340     int rc;
341 
342     if (find_ctl_index_in_path(path, setting->ctl_index) != -1) {
343         struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index);
344 
345         ALOGW("Control '%s' already exists in path '%s' - Ignore one in the new sub path",
346               mixer_ctl_get_name(ctl), path->name);
347         return -2;
348     }
349 
350     if (!is_supported_ctl_type(setting->type)) {
351         ALOGE("unsupported type %d", (int)setting->type);
352         return -1;
353     }
354 
355     path_index = alloc_path_setting(path);
356     if (path_index < 0)
357         return -1;
358 
359     path->setting[path_index].ctl_index = setting->ctl_index;
360     path->setting[path_index].type = setting->type;
361     path->setting[path_index].num_values = setting->num_values;
362 
363     rc = ctl_values_alloc(&path->setting[path_index].value, setting->num_values, setting->type);
364     if (rc < 0) {
365         ALOGE("failed to allocate mem for path setting");
366         return rc;
367     }
368     /* copy all values */
369     ctl_values_copy(&path->setting[path_index].value, &setting->value);
370 
371     return 0;
372 }
373 
path_add_value(struct audio_route * ar,struct mixer_path * path,struct mixer_value * mixer_value)374 static int path_add_value(struct audio_route *ar, struct mixer_path *path,
375                           struct mixer_value *mixer_value)
376 {
377     unsigned int i;
378     int path_index;
379     unsigned int num_values;
380     struct mixer_ctl *ctl;
381     int rc;
382 
383     /* Check that mixer value index is within range */
384     ctl = index_to_ctl(ar, mixer_value->ctl_index);
385     num_values = mixer_ctl_get_num_values(ctl);
386     if (mixer_value->index >= (int)num_values) {
387         ALOGE("mixer index %d is out of range for '%s'", mixer_value->index,
388               mixer_ctl_get_name(ctl));
389         return -1;
390     }
391 
392     path_index = find_ctl_index_in_path(path, mixer_value->ctl_index);
393     if (path_index < 0) {
394         /* New path */
395 
396         enum mixer_ctl_type type = mixer_ctl_get_type(ctl);
397         if (!is_supported_ctl_type(type)) {
398             ALOGE("unsupported type %d", (int)type);
399             return -1;
400         }
401         path_index = alloc_path_setting(path);
402         if (path_index < 0)
403             return -1;
404 
405         /* initialise the new path setting */
406         path->setting[path_index].ctl_index = mixer_value->ctl_index;
407         path->setting[path_index].num_values = num_values;
408         path->setting[path_index].type = type;
409 
410         rc = ctl_values_alloc(&path->setting[path_index].value, num_values, type);
411         if (rc < 0) {
412             ALOGE("failed to allocate mem for path setting");
413             return rc;
414         }
415         if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
416             path->setting[path_index].value.bytes[0] = mixer_value->value;
417         else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM)
418             path->setting[path_index].value.enumerated[0] = mixer_value->value;
419         else
420             path->setting[path_index].value.integer[0] = mixer_value->value;
421     }
422 
423     if (mixer_value->index == -1) {
424         /* set all values the same except for CTL_TYPE_BYTE and CTL_TYPE_INT */
425         if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE) {
426             /* update the number of values (bytes) from input "mixer_value" */
427             for (i = 0; i < mixer_value->num_values_in_array; i++)
428                 path->setting[path_index].value.bytes[i] = mixer_value->values[i];
429             path->setting[path_index].value.byte_size = mixer_value->num_values_in_array;
430         } else if (path->setting[path_index].type == MIXER_CTL_TYPE_INT) {
431             for (i = 0; i < num_values; i++)
432                 path->setting[path_index].value.integer[i] = mixer_value->values[i];
433         } else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM) {
434             for (i = 0; i < num_values; i++)
435                 path->setting[path_index].value.enumerated[i] = mixer_value->value;
436         } else {
437             for (i = 0; i < num_values; i++)
438                 path->setting[path_index].value.integer[i] = mixer_value->value;
439         }
440     } else {
441         /* set only one value */
442         if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
443             path->setting[path_index].value.bytes[mixer_value->index] = mixer_value->value;
444         else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM)
445             path->setting[path_index].value.enumerated[mixer_value->index] = mixer_value->value;
446         else
447             path->setting[path_index].value.integer[mixer_value->index] = mixer_value->value;
448     }
449 
450     return 0;
451 }
452 
path_add_path(struct audio_route * ar,struct mixer_path * path,struct mixer_path * sub_path)453 static int path_add_path(struct audio_route *ar, struct mixer_path *path,
454                          struct mixer_path *sub_path)
455 {
456     unsigned int i;
457 
458     for (i = 0; i < sub_path->length; i++) {
459         int retVal = path_add_setting(ar, path, &sub_path->setting[i]);
460         if (retVal < 0) {
461             if (retVal == -2)
462                 continue;
463             else
464                 return -1;
465         }
466     }
467     return 0;
468 }
469 
path_apply(struct audio_route * ar,struct mixer_path * path)470 static int path_apply(struct audio_route *ar, struct mixer_path *path)
471 {
472     unsigned int i;
473     unsigned int ctl_index;
474     struct mixer_ctl *ctl;
475     enum mixer_ctl_type type;
476 
477     ALOGD("Apply path: %s", path->name != NULL ? path->name : "none");
478     for (i = 0; i < path->length; i++) {
479         ctl_index = path->setting[i].ctl_index;
480         ctl = index_to_ctl(ar, ctl_index);
481         type = mixer_ctl_get_type(ctl);
482         if (!is_supported_ctl_type(type))
483             continue;
484         ctl_values_copy(&ar->mixer_state[ctl_index].new_value, &path->setting[i].value);
485     }
486 
487     return 0;
488 }
489 
path_reset(struct audio_route * ar,struct mixer_path * path)490 static int path_reset(struct audio_route *ar, struct mixer_path *path)
491 {
492     unsigned int i;
493     unsigned int ctl_index;
494     struct mixer_ctl *ctl;
495     enum mixer_ctl_type type;
496 
497     ALOGV("Reset path: %s", path->name != NULL ? path->name : "none");
498     for (i = 0; i < path->length; i++) {
499         ctl_index = path->setting[i].ctl_index;
500         ctl = index_to_ctl(ar, ctl_index);
501         type = mixer_ctl_get_type(ctl);
502         if (!is_supported_ctl_type(type))
503             continue;
504         /* reset the value(s) */
505         ctl_values_copy(&ar->mixer_state[ctl_index].new_value,
506                         &ar->mixer_state[ctl_index].reset_value);
507     }
508 
509     return 0;
510 }
511 
safe_strtol(const char * str,long * val)512 static bool safe_strtol(const char *str, long *val)
513 {
514     char *end;
515     long v;
516     if (str == NULL || strlen(str) == 0)
517         return false;
518     errno = 0;
519     v = strtol(str, &end, 0);
520     if (errno || *end)
521         return false;
522     *val = v;
523     return true;
524 }
525 
526 /* mixer helper function */
mixer_enum_string_to_value(struct mixer_ctl * ctl,const char * string,bool allow_numeric_fallback)527 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string,
528                                       bool allow_numeric_fallback)
529 {
530     unsigned int i;
531     unsigned int num_values = mixer_ctl_get_num_enums(ctl);
532 
533     if (string == NULL) {
534         ALOGE("NULL enum value string passed to mixer_enum_string_to_value() for ctl %s",
535               mixer_ctl_get_name(ctl));
536         return 0;
537     }
538 
539     /* Search the enum strings for a particular one */
540     for (i = 0; i < num_values; i++) {
541         if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
542             break;
543     }
544     if (i == num_values) {
545         /* No enum string match. Check the flag before numeric parsing. */
546         if (allow_numeric_fallback) {
547             long value = 0;
548             if (safe_strtol(string, &value) && value >= 0 && value < num_values) {
549                 return value;
550             }
551         }
552         ALOGW("unknown enum value string %s for ctl %s",
553               string, mixer_ctl_get_name(ctl));
554         return 0;
555     }
556     return i;
557 }
558 
mixer_get_bytes_from_file(long ** value_array,const char * filepath,unsigned int max_bytes)559 static int mixer_get_bytes_from_file(long **value_array, const char *filepath,
560                                      unsigned int max_bytes)
561 {
562     unsigned char *buf = NULL;
563     long *values = NULL;
564     int bytes_read = -1;
565     unsigned int i;
566 
567     FILE *file = fopen(filepath, "rb");
568     if (!file) {
569         ALOGE("Failed to open %s: %s", filepath, strerror(errno));
570         return -1;
571     }
572 
573     buf = calloc(max_bytes, 1);
574     if (!buf) {
575         ALOGE("failed to allocate mem for file read buffer");
576         goto exit;
577     }
578 
579     bytes_read = fread(buf, 1, max_bytes, file);
580     if (bytes_read < 0) {
581         ALOGE("failed to read data from file, rc: %d", bytes_read);
582         goto exit;
583     }
584 
585     values = calloc(bytes_read, sizeof(long));
586     if (!values) {
587         ALOGE("failed to allocate mem for values array");
588         bytes_read = -1;
589         goto exit;
590     }
591 
592     for (i = 0; i < bytes_read; i++) {
593         values[i] = (long)buf[i];
594     }
595     *value_array = values;
596 
597 exit:
598     free(buf);
599     fclose(file);
600     return bytes_read;
601 }
602 
start_tag(void * data,const XML_Char * tag_name,const XML_Char ** attr)603 static void start_tag(void *data, const XML_Char *tag_name,
604                       const XML_Char **attr)
605 {
606     const XML_Char *attr_name = NULL;
607     const XML_Char *attr_id = NULL;
608     const XML_Char *attr_value = NULL;
609     const XML_Char *attr_enum_mixer_numeric_fallback = NULL;
610     const XML_Char *attr_bin = NULL;
611     struct config_parse_state *state = data;
612     struct audio_route *ar = state->ar;
613     unsigned int i;
614     unsigned int ctl_index;
615     struct mixer_ctl *ctl;
616     long value;
617     unsigned int id;
618     struct mixer_value mixer_value;
619     enum mixer_ctl_type type;
620     long* value_array = NULL;
621     unsigned int num_values_in_array = 0;
622 
623     /* Get name, id and value attributes (these may be empty) */
624     for (i = 0; attr[i]; i += 2) {
625         if (strcmp(attr[i], "name") == 0)
626             attr_name = attr[i + 1];
627         else if (strcmp(attr[i], "id") == 0)
628             attr_id = attr[i + 1];
629         else if (strcmp(attr[i], "value") == 0)
630             attr_value = attr[i + 1];
631         else if (strcmp(attr[i], "enum_mixer_numeric_fallback") == 0)
632             attr_enum_mixer_numeric_fallback = attr[i + 1];
633         else if (strcmp(attr[i], "bin") == 0)
634             attr_bin = attr[i + 1];
635     }
636 
637     /* Look at tags */
638     if (strcmp(tag_name, "mixer") == 0) {
639         state->enum_mixer_numeric_fallback =
640                 attr_enum_mixer_numeric_fallback != NULL &&
641                 strcmp(attr_enum_mixer_numeric_fallback, "true") == 0 ;
642     } else if (strcmp(tag_name, "path") == 0) {
643         if (attr_name == NULL) {
644             ALOGE("Unnamed path!");
645         } else {
646             if (state->level == 1) {
647                 /* top level path: create and stash the path */
648                 state->path = path_create(ar, (char *)attr_name);
649                 if (state->path == NULL)
650                     ALOGW("path creation failed, please check if the path exists");
651             } else {
652                 /* nested path */
653                 struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
654                 if (!sub_path) {
655                     ALOGW("unable to find sub path '%s'", attr_name);
656                 } else if (state->path != NULL) {
657                     path_add_path(ar, state->path, sub_path);
658                 }
659             }
660         }
661     } else if (strcmp(tag_name, "ctl") == 0) {
662         /* Obtain the mixer ctl and value */
663         ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);
664         if (ctl == NULL) {
665             ALOGW("Control '%s' doesn't exist - skipping", attr_name);
666             goto done;
667         }
668 
669         switch (mixer_ctl_get_type(ctl)) {
670         case MIXER_CTL_TYPE_BOOL:
671             if (attr_value == NULL) {
672                 ALOGE("No value specified for ctl %s", attr_name);
673                 goto done;
674             }
675             value = strtol((char *)attr_value, NULL, 0);
676             break;
677         case MIXER_CTL_TYPE_INT:
678         case MIXER_CTL_TYPE_BYTE: {
679                 char *attr_sub_value, *test_r;
680                 unsigned int num_values = mixer_ctl_get_num_values(ctl);
681 
682                 if (attr_bin && mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_BYTE) {
683                     /* get byte values from binfile */
684                     int bytes_read = mixer_get_bytes_from_file(&value_array, attr_bin, num_values);
685                     if (bytes_read <= 0) {
686                         ALOGE("failed to get bytes from file '%s'", attr_bin);
687                         goto done;
688                     }
689                     if (bytes_read < num_values && mixer_ctl_is_access_tlv_rw(ctl) == 0) {
690                         ALOGE("expect %d values but only %d specified for ctl %s",
691                               num_values, bytes_read, attr_name);
692                         goto done;
693                     }
694                     num_values_in_array = bytes_read;
695                     break;
696                 }
697 
698                 if (attr_value == NULL) {
699                     ALOGE("No value specified for ctl %s", attr_name);
700                     goto done;
701                 }
702                 value_array = calloc(num_values, sizeof(long));
703                 if (!value_array) {
704                     ALOGE("failed to allocate mem for ctl %s", attr_name);
705                     goto done;
706                 }
707                 for (i = 0; i < num_values; i++) {
708                     attr_sub_value = strtok_r((char *)attr_value, " ", &test_r);
709                     if (attr_sub_value == NULL) {
710                         /* the length of setting for tlv-typed byte control
711                            can be any size up to num_value; break the loop so
712                            the current count of values will be recorded */
713                         if (ctl_is_tlv_byte_type(ctl))
714                             break;
715 
716                         ALOGE("expect %d values but only %d specified for ctl %s",
717                             num_values, i, attr_name);
718                         goto done;
719                     }
720                     if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_INT)
721                         value_array[i] = strtol((char *)attr_sub_value, NULL, 0);
722                     else
723                         value_array[i] =
724                            (unsigned char) strtol((char *)attr_sub_value, NULL, 16);
725 
726                     /* count the number of values written in array */
727                     num_values_in_array++;
728 
729                     if (attr_id)
730                         break;
731 
732                     attr_value = NULL;
733                 }
734             } break;
735         case MIXER_CTL_TYPE_ENUM:
736             if (attr_value == NULL) {
737                 ALOGE("No value specified for ctl %s", attr_name);
738                 goto done;
739             }
740             value = mixer_enum_string_to_value(ctl, (char *)attr_value,
741                                                state->enum_mixer_numeric_fallback);
742             break;
743         default:
744             value = 0;
745             break;
746         }
747 
748         /* locate the mixer ctl in the list */
749         for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
750             if (ar->mixer_state[ctl_index].ctl == ctl)
751                 break;
752         }
753 
754         if (state->level == 1) {
755             /* top level ctl (initial setting) */
756 
757             type = mixer_ctl_get_type(ctl);
758             if (is_supported_ctl_type(type)) {
759                 /* apply the new value */
760                 if (attr_id) {
761                     /* set only one value */
762                     id = atoi((char *)attr_id);
763                     if (id < ar->mixer_state[ctl_index].num_values)
764                         if (type == MIXER_CTL_TYPE_BYTE)
765                             ar->mixer_state[ctl_index].new_value.bytes[id] = value_array[0];
766                         else if (type == MIXER_CTL_TYPE_INT)
767                             ar->mixer_state[ctl_index].new_value.integer[id] = value_array[0];
768                         else if (type == MIXER_CTL_TYPE_ENUM)
769                             ar->mixer_state[ctl_index].new_value.enumerated[id] = value;
770                         else
771                             ar->mixer_state[ctl_index].new_value.integer[id] = value;
772                     else
773                         ALOGW("value id out of range for mixer ctl '%s'",
774                               mixer_ctl_get_name(ctl));
775                 } else if (ctl_is_tlv_byte_type(ctl)) {
776                     /* for tlv-typed ctl, only set the number of values (bytes) carried by array,
777                        and update the number of bytes */
778                     for (i = 0; i < num_values_in_array; i++)
779                         ar->mixer_state[ctl_index].new_value.bytes[i] = value_array[i];
780                     ar->mixer_state[ctl_index].new_value.byte_size = num_values_in_array;
781                 } else {
782                     /* set all values the same except for CTL_TYPE_BYTE and CTL_TYPE_INT */
783                     for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++)
784                         if (type == MIXER_CTL_TYPE_BYTE)
785                             ar->mixer_state[ctl_index].new_value.bytes[i] = value_array[i];
786                         else if (type == MIXER_CTL_TYPE_INT)
787                             ar->mixer_state[ctl_index].new_value.integer[i] = value_array[i];
788                         else if (type == MIXER_CTL_TYPE_ENUM)
789                             ar->mixer_state[ctl_index].new_value.enumerated[i] = value;
790                         else
791                             ar->mixer_state[ctl_index].new_value.integer[i] = value;
792                 }
793             }
794         } else {
795             /* nested ctl (within a path) */
796             mixer_value.ctl_index = ctl_index;
797             if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_BYTE ||
798                 mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_INT) {
799                 mixer_value.values = value_array;
800                 mixer_value.value = value_array[0];
801                 mixer_value.num_values_in_array = num_values_in_array;
802             } else {
803                 mixer_value.value = value;
804             }
805             if (attr_id)
806                 mixer_value.index = atoi((char *)attr_id);
807             else
808                 mixer_value.index = -1;
809             if (state->path != NULL)
810                 path_add_value(ar, state->path, &mixer_value);
811         }
812     }
813 
814 done:
815     free(value_array);
816     state->level++;
817 }
818 
end_tag(void * data,const XML_Char * tag_name)819 static void end_tag(void *data, const XML_Char *tag_name)
820 {
821     struct config_parse_state *state = data;
822     (void)tag_name;
823 
824     state->level--;
825 }
826 
alloc_mixer_state(struct audio_route * ar)827 static int alloc_mixer_state(struct audio_route *ar)
828 {
829     unsigned int i;
830     unsigned int num_values;
831     struct mixer_ctl *ctl;
832     enum mixer_ctl_type type;
833 
834     ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
835     ar->mixer_state = calloc(ar->num_mixer_ctls, sizeof(struct mixer_state));
836     if (!ar->mixer_state)
837         return -1;
838 
839     for (i = 0; i < ar->num_mixer_ctls; i++) {
840         ctl = mixer_get_ctl(ar->mixer, i);
841         num_values = mixer_ctl_get_num_values(ctl);
842 
843         ar->mixer_state[i].ctl = ctl;
844         ar->mixer_state[i].num_values = num_values;
845         ar->mixer_state[i].active_count = 0;
846 
847         /* Skip unsupported types that are not supported yet in XML */
848         type = mixer_ctl_get_type(ctl);
849 
850         if (!is_supported_ctl_type(type))
851             continue;
852 
853         /*
854          for tlv-typed ctl, "mixer_ctl_get_num_values()" returns the max length of a
855          setting data. The buffer size allocated per mixer setting should align the
856          max length to be capable of carrying any length of data.
857          */
858         ctl_values_alloc(&ar->mixer_state[i].old_value, num_values, type);
859         ctl_values_alloc(&ar->mixer_state[i].new_value, num_values, type);
860         ctl_values_alloc(&ar->mixer_state[i].reset_value, num_values, type);
861 
862         if (type == MIXER_CTL_TYPE_ENUM)
863             ar->mixer_state[i].old_value.enumerated[0] = mixer_ctl_get_value(ctl, 0);
864         else
865             mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value.ptr, num_values);
866 
867         ctl_values_copy(&ar->mixer_state[i].new_value, &ar->mixer_state[i].old_value);
868     }
869 
870     return 0;
871 }
872 
free_mixer_state(struct audio_route * ar)873 static void free_mixer_state(struct audio_route *ar)
874 {
875     unsigned int i;
876     enum mixer_ctl_type type;
877 
878     for (i = 0; i < ar->num_mixer_ctls; i++) {
879         type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
880         if (!is_supported_ctl_type(type))
881             continue;
882 
883         free(ar->mixer_state[i].old_value.ptr);
884         free(ar->mixer_state[i].new_value.ptr);
885         free(ar->mixer_state[i].reset_value.ptr);
886     }
887 
888     free(ar->mixer_state);
889     ar->mixer_state = NULL;
890 }
891 
mixer_set_value_if_changed(struct mixer_state * ms)892 static void mixer_set_value_if_changed(struct mixer_state *ms)
893 {
894     unsigned int i;
895     struct mixer_ctl *ctl = ms->ctl;
896     enum mixer_ctl_type type = mixer_ctl_get_type(ctl);
897 
898     if (type == MIXER_CTL_TYPE_BYTE) {
899         unsigned int num_bytes;
900         /*
901          for tlv-typed ctl, "mixer_ctl_set_array()" should specify the length of data to
902          be set, thus the data can be wrapped into tlv format correctly by Tinyalsa.
903          */
904         num_bytes = ctl_is_tlv_byte_type(ctl) ? ms->new_value.byte_size : ms->num_values;
905         for (i = 0; i < num_bytes; i++) {
906             if (ms->old_value.bytes[i] != ms->new_value.bytes[i]) {
907                 mixer_ctl_set_array(ctl, ms->new_value.ptr, num_bytes);
908                 ctl_values_copy(&ms->old_value, &ms->new_value);
909                 return;
910             }
911         }
912     } else if (type == MIXER_CTL_TYPE_ENUM) {
913         for (i = 0; i < ms->num_values; i++) {
914             if (ms->old_value.enumerated[i] != ms->new_value.enumerated[i]) {
915                 mixer_ctl_set_value(ctl, 0, ms->new_value.enumerated[0]);
916                 ctl_values_copy(&ms->old_value, &ms->new_value);
917                 return;
918             }
919         }
920     } else {
921         for (i = 0; i < ms->num_values; i++) {
922             if (ms->old_value.integer[i] != ms->new_value.integer[i]) {
923                 mixer_ctl_set_array(ctl, ms->new_value.ptr, ms->num_values);
924                 ctl_values_copy(&ms->old_value, &ms->new_value);
925                 return;
926             }
927         }
928     }
929 }
930 
931 /* Update the mixer with any changed values */
audio_route_update_mixer(struct audio_route * ar)932 int audio_route_update_mixer(struct audio_route *ar)
933 {
934     unsigned int i;
935     struct mixer_ctl *ctl;
936 
937     for (i = 0; i < ar->num_mixer_ctls; i++) {
938         enum mixer_ctl_type type;
939 
940         ctl = ar->mixer_state[i].ctl;
941 
942         /* Skip unsupported types */
943         type = mixer_ctl_get_type(ctl);
944         if (!is_supported_ctl_type(type))
945             continue;
946 
947         /* if the value has changed, update the mixer */
948         mixer_set_value_if_changed(&ar->mixer_state[i]);
949     }
950 
951     return 0;
952 }
953 
954 /* saves the current state of the mixer, for resetting all controls */
save_mixer_state(struct audio_route * ar)955 static void save_mixer_state(struct audio_route *ar)
956 {
957     unsigned int i;
958     enum mixer_ctl_type type;
959 
960     for (i = 0; i < ar->num_mixer_ctls; i++) {
961         type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
962         if (!is_supported_ctl_type(type))
963             continue;
964 
965         ctl_values_copy(&ar->mixer_state[i].reset_value, &ar->mixer_state[i].new_value);
966     }
967 }
968 
969 /* Reset the audio routes back to the initial state */
audio_route_reset(struct audio_route * ar)970 void audio_route_reset(struct audio_route *ar)
971 {
972     unsigned int i;
973     enum mixer_ctl_type type;
974 
975     /* load all of the saved values */
976     for (i = 0; i < ar->num_mixer_ctls; i++) {
977         type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
978         if (!is_supported_ctl_type(type))
979             continue;
980 
981         ctl_values_copy(&ar->mixer_state[i].new_value, &ar->mixer_state[i].reset_value);
982     }
983 }
984 
985 /* Apply an audio route path by name */
audio_route_apply_path(struct audio_route * ar,const char * name)986 int audio_route_apply_path(struct audio_route *ar, const char *name)
987 {
988     struct mixer_path *path;
989 
990     if (!ar) {
991         ALOGE("invalid audio_route");
992         return -1;
993     }
994 
995     path = path_get_by_name(ar, name);
996     if (!path) {
997         ALOGE("unable to find path '%s'", name);
998         return -1;
999     }
1000 
1001     path_apply(ar, path);
1002 
1003     return 0;
1004 }
1005 
1006 /* Reset an audio route path by name */
audio_route_reset_path(struct audio_route * ar,const char * name)1007 int audio_route_reset_path(struct audio_route *ar, const char *name)
1008 {
1009     struct mixer_path *path;
1010 
1011     if (!ar) {
1012         ALOGE("invalid audio_route");
1013         return -1;
1014     }
1015 
1016     path = path_get_by_name(ar, name);
1017     if (!path) {
1018         ALOGE("unable to find path '%s'", name);
1019         return -1;
1020     }
1021 
1022     path_reset(ar, path);
1023 
1024     return 0;
1025 }
1026 
1027 /*
1028  * Operates on the specified path .. controls will be updated in the
1029  * order listed in the XML file
1030  */
audio_route_update_path(struct audio_route * ar,const char * name,int direction)1031 static int audio_route_update_path(struct audio_route *ar, const char *name, int direction)
1032 {
1033     struct mixer_path *path;
1034     unsigned int j;
1035     bool reverse = direction != DIRECTION_FORWARD;
1036     bool force_reset = direction == DIRECTION_REVERSE_RESET;
1037 
1038     if (!ar) {
1039         ALOGE("invalid audio_route");
1040         return -1;
1041     }
1042 
1043     path = path_get_by_name(ar, name);
1044     if (!path) {
1045         ALOGE("unable to find path '%s'", name);
1046         return -1;
1047     }
1048 
1049     for (size_t i = 0; i < path->length; ++i) {
1050         unsigned int ctl_index;
1051         enum mixer_ctl_type type;
1052 
1053         ctl_index = path->setting[reverse ? path->length - 1 - i : i].ctl_index;
1054 
1055         struct mixer_state * ms = &ar->mixer_state[ctl_index];
1056 
1057         type = mixer_ctl_get_type(ms->ctl);
1058         if (!is_supported_ctl_type(type)) {
1059             continue;
1060         }
1061 
1062         if (reverse && ms->active_count > 0) {
1063             if (force_reset) {
1064                 ms->active_count = 0;
1065             } else if (--ms->active_count > 0) {
1066                 ALOGD("%s: skip to reset mixer control '%s' in path '%s' "
1067                     "because it is still needed by other paths", __func__,
1068                     mixer_ctl_get_name(ms->ctl), name);
1069                 ctl_values_copy(&ms->new_value, &ms->old_value);
1070                 continue;
1071             }
1072         } else if (!reverse) {
1073             ms->active_count++;
1074         }
1075 
1076         /* if any value has changed, update the mixer */
1077         mixer_set_value_if_changed(ms);
1078     }
1079     return 0;
1080 }
1081 
audio_route_apply_and_update_path(struct audio_route * ar,const char * name)1082 int audio_route_apply_and_update_path(struct audio_route *ar, const char *name)
1083 {
1084     if (audio_route_apply_path(ar, name) < 0) {
1085         return -1;
1086     }
1087     return audio_route_update_path(ar, name, DIRECTION_FORWARD);
1088 }
1089 
audio_route_reset_and_update_path(struct audio_route * ar,const char * name)1090 int audio_route_reset_and_update_path(struct audio_route *ar, const char *name)
1091 {
1092     if (audio_route_reset_path(ar, name) < 0) {
1093         return -1;
1094     }
1095     return audio_route_update_path(ar, name, DIRECTION_REVERSE);
1096 }
1097 
audio_route_force_reset_and_update_path(struct audio_route * ar,const char * name)1098 int audio_route_force_reset_and_update_path(struct audio_route *ar, const char *name)
1099 {
1100     if (audio_route_reset_path(ar, name) < 0) {
1101         return -1;
1102     }
1103 
1104     return audio_route_update_path(ar, name, DIRECTION_REVERSE_RESET);
1105 }
1106 
audio_route_supports_path(struct audio_route * ar,const char * name)1107 int audio_route_supports_path(struct audio_route *ar, const char *name)
1108 {
1109     if (!path_get_by_name(ar, name)) {
1110         return -1;
1111     }
1112 
1113     return 0;
1114 }
1115 
audio_route_init(unsigned int card,const char * xml_path)1116 struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
1117 {
1118     struct config_parse_state state;
1119     XML_Parser parser;
1120     FILE *file;
1121     int bytes_read;
1122     void *buf;
1123     struct audio_route *ar;
1124 
1125     ar = calloc(1, sizeof(struct audio_route));
1126     if (!ar)
1127         goto err_calloc;
1128 
1129     ar->mixer = mixer_open(card);
1130     if (!ar->mixer) {
1131         ALOGE("Unable to open the mixer, aborting.");
1132         goto err_mixer_open;
1133     }
1134 
1135     ar->mixer_path = NULL;
1136     ar->mixer_path_size = 0;
1137     ar->num_mixer_paths = 0;
1138 
1139     /* allocate space for and read current mixer settings */
1140     if (alloc_mixer_state(ar) < 0)
1141         goto err_mixer_state;
1142 
1143     /* use the default XML path if none is provided */
1144     if (xml_path == NULL)
1145         xml_path = MIXER_XML_PATH;
1146 
1147     file = fopen(xml_path, "r");
1148 
1149     if (!file) {
1150         ALOGE("Failed to open %s: %s", xml_path, strerror(errno));
1151         goto err_fopen;
1152     }
1153 
1154     parser = XML_ParserCreate(NULL);
1155     if (!parser) {
1156         ALOGE("Failed to create XML parser");
1157         goto err_parser_create;
1158     }
1159 
1160     memset(&state, 0, sizeof(state));
1161     state.ar = ar;
1162     XML_SetUserData(parser, &state);
1163     XML_SetElementHandler(parser, start_tag, end_tag);
1164 
1165     for (;;) {
1166         buf = XML_GetBuffer(parser, BUF_SIZE);
1167         if (buf == NULL)
1168             goto err_parse;
1169 
1170         bytes_read = fread(buf, 1, BUF_SIZE, file);
1171         if (bytes_read < 0)
1172             goto err_parse;
1173 
1174         if (XML_ParseBuffer(parser, bytes_read,
1175                             bytes_read == 0) == XML_STATUS_ERROR) {
1176             ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
1177             goto err_parse;
1178         }
1179 
1180         if (bytes_read == 0)
1181             break;
1182     }
1183 
1184     /* apply the initial mixer values, and save them so we can reset the
1185        mixer to the original values */
1186     audio_route_update_mixer(ar);
1187     save_mixer_state(ar);
1188 
1189     XML_ParserFree(parser);
1190     fclose(file);
1191     return ar;
1192 
1193 err_parse:
1194     path_free(ar);
1195     XML_ParserFree(parser);
1196 err_parser_create:
1197     fclose(file);
1198 err_fopen:
1199     free_mixer_state(ar);
1200 err_mixer_state:
1201     mixer_close(ar->mixer);
1202 err_mixer_open:
1203     free(ar);
1204     ar = NULL;
1205 err_calloc:
1206     return NULL;
1207 }
1208 
audio_route_free(struct audio_route * ar)1209 void audio_route_free(struct audio_route *ar)
1210 {
1211     free_mixer_state(ar);
1212     mixer_close(ar->mixer);
1213     path_free(ar);
1214     free(ar);
1215 }
1216