blob: 4a449079e02734ab5c430acaa0cfe8b984e67ce1 [file] [log] [blame]
Simon Wilsoncef93592013-01-15 16:35:46 -08001/*
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;
Simon Wilsoncef93592013-01-15 16:35:46 -080041};
42
43struct mixer_setting {
Simon Wilsonf3090fa2013-02-12 16:41:52 -080044 unsigned int ctl_index;
Simon Wilsoncef93592013-01-15 16:35:46 -080045 unsigned int num_values;
46 int *value;
Simon Wilsoncef93592013-01-15 16:35:46 -080047};
48
49struct mixer_value {
Simon Wilsonf3090fa2013-02-12 16:41:52 -080050 unsigned int ctl_index;
Simon Wilsoncef93592013-01-15 16:35:46 -080051 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
Simon Wilsonf3090fa2013-02-12 16:41:52 -080080static inline struct mixer_ctl *index_to_ctl(struct audio_route *ar,
81 unsigned int ctl_index)
82{
83 return ar->mixer_state[ctl_index].ctl;
84}
85
86static void path_print(struct audio_route *ar, struct mixer_path *path)
Simon Wilsoncef93592013-01-15 16:35:46 -080087{
88 unsigned int i;
89 unsigned int j;
90
91 ALOGE("Path: %s, length: %d", path->name, path->length);
92 for (i = 0; i < path->length; i++) {
Simon Wilsonf3090fa2013-02-12 16:41:52 -080093 struct mixer_ctl *ctl = index_to_ctl(ar, path->setting[i].ctl_index);
94
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -070095 ALOGE(" id=%d: ctl=%s", i, mixer_ctl_get_name(ctl));
Simon Wilsoncef93592013-01-15 16:35:46 -080096 for (j = 0; j < path->setting[i].num_values; j++)
97 ALOGE(" id=%d value=%d", j, path->setting[i].value[j]);
98 }
99}
100
101static void path_free(struct audio_route *ar)
102{
103 unsigned int i;
104
105 for (i = 0; i < ar->num_mixer_paths; i++) {
106 if (ar->mixer_path[i].name)
107 free(ar->mixer_path[i].name);
108 if (ar->mixer_path[i].setting) {
109 if (ar->mixer_path[i].setting->value)
110 free(ar->mixer_path[i].setting->value);
111 free(ar->mixer_path[i].setting);
112 }
113 }
114 free(ar->mixer_path);
115}
116
117static struct mixer_path *path_get_by_name(struct audio_route *ar,
118 const char *name)
119{
120 unsigned int i;
121
122 for (i = 0; i < ar->num_mixer_paths; i++)
123 if (strcmp(ar->mixer_path[i].name, name) == 0)
124 return &ar->mixer_path[i];
125
126 return NULL;
127}
128
129static struct mixer_path *path_create(struct audio_route *ar, const char *name)
130{
131 struct mixer_path *new_mixer_path = NULL;
132
133 if (path_get_by_name(ar, name)) {
134 ALOGE("Path name '%s' already exists", name);
135 return NULL;
136 }
137
138 /* check if we need to allocate more space for mixer paths */
139 if (ar->mixer_path_size <= ar->num_mixer_paths) {
140 if (ar->mixer_path_size == 0)
141 ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE;
142 else
143 ar->mixer_path_size *= 2;
144
145 new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size *
146 sizeof(struct mixer_path));
147 if (new_mixer_path == NULL) {
148 ALOGE("Unable to allocate more paths");
149 return NULL;
150 } else {
151 ar->mixer_path = new_mixer_path;
152 }
153 }
154
155 /* initialise the new mixer path */
156 ar->mixer_path[ar->num_mixer_paths].name = strdup(name);
157 ar->mixer_path[ar->num_mixer_paths].size = 0;
158 ar->mixer_path[ar->num_mixer_paths].length = 0;
159 ar->mixer_path[ar->num_mixer_paths].setting = NULL;
160
161 /* return the mixer path just added, then increment number of them */
162 return &ar->mixer_path[ar->num_mixer_paths++];
163}
164
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800165static int find_ctl_index_in_path(struct mixer_path *path,
166 unsigned int ctl_index)
Simon Wilsoncef93592013-01-15 16:35:46 -0800167{
168 unsigned int i;
169
170 for (i = 0; i < path->length; i++)
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800171 if (path->setting[i].ctl_index == ctl_index)
Simon Wilsoncef93592013-01-15 16:35:46 -0800172 return i;
173
174 return -1;
175}
176
177static int alloc_path_setting(struct mixer_path *path)
178{
179 struct mixer_setting *new_path_setting;
180 int path_index;
181
182 /* check if we need to allocate more space for path settings */
183 if (path->size <= path->length) {
184 if (path->size == 0)
185 path->size = INITIAL_MIXER_PATH_SIZE;
186 else
187 path->size *= 2;
188
189 new_path_setting = realloc(path->setting,
190 path->size * sizeof(struct mixer_setting));
191 if (new_path_setting == NULL) {
192 ALOGE("Unable to allocate more path settings");
193 return -1;
194 } else {
195 path->setting = new_path_setting;
196 }
197 }
198
199 path_index = path->length;
200 path->length++;
201
202 return path_index;
203}
204
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800205static int path_add_setting(struct audio_route *ar, struct mixer_path *path,
Simon Wilsoncef93592013-01-15 16:35:46 -0800206 struct mixer_setting *setting)
207{
Simon Wilsoncef93592013-01-15 16:35:46 -0800208 int path_index;
209
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800210 if (find_ctl_index_in_path(path, setting->ctl_index) != -1) {
211 struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index);
212
Simon Wilsoncef93592013-01-15 16:35:46 -0800213 ALOGE("Control '%s' already exists in path '%s'",
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800214 mixer_ctl_get_name(ctl), path->name);
Simon Wilsoncef93592013-01-15 16:35:46 -0800215 return -1;
216 }
217
218 path_index = alloc_path_setting(path);
219 if (path_index < 0)
220 return -1;
221
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800222 path->setting[path_index].ctl_index = setting->ctl_index;
Simon Wilsoncef93592013-01-15 16:35:46 -0800223 path->setting[path_index].num_values = setting->num_values;
224 path->setting[path_index].value = malloc(setting->num_values * sizeof(int));
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700225 /* copy all values */
226 memcpy(path->setting[path_index].value, setting->value,
227 setting->num_values * sizeof(int));
Simon Wilsoncef93592013-01-15 16:35:46 -0800228
229 return 0;
230}
231
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800232static int path_add_value(struct audio_route *ar, struct mixer_path *path,
Simon Wilsoncef93592013-01-15 16:35:46 -0800233 struct mixer_value *mixer_value)
234{
235 unsigned int i;
236 int path_index;
237 unsigned int num_values;
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800238 struct mixer_ctl *ctl;
Simon Wilsoncef93592013-01-15 16:35:46 -0800239
240 /* Check that mixer value index is within range */
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800241 ctl = index_to_ctl(ar, mixer_value->ctl_index);
242 num_values = mixer_ctl_get_num_values(ctl);
Simon Wilsoncef93592013-01-15 16:35:46 -0800243 if (mixer_value->index >= (int)num_values) {
244 ALOGE("mixer index %d is out of range for '%s'", mixer_value->index,
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800245 mixer_ctl_get_name(ctl));
Simon Wilsoncef93592013-01-15 16:35:46 -0800246 return -1;
247 }
248
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800249 path_index = find_ctl_index_in_path(path, mixer_value->ctl_index);
Simon Wilsoncef93592013-01-15 16:35:46 -0800250 if (path_index < 0) {
251 /* New path */
252
253 path_index = alloc_path_setting(path);
254 if (path_index < 0)
255 return -1;
256
257 /* initialise the new path setting */
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800258 path->setting[path_index].ctl_index = mixer_value->ctl_index;
Simon Wilsoncef93592013-01-15 16:35:46 -0800259 path->setting[path_index].num_values = num_values;
260 path->setting[path_index].value = malloc(num_values * sizeof(int));
Simon Wilsoncef93592013-01-15 16:35:46 -0800261 path->setting[path_index].value[0] = mixer_value->value;
262 }
263
264 if (mixer_value->index == -1) {
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700265 /* set all values the same */
266 for (i = 0; i < num_values; i++)
267 path->setting[path_index].value[i] = mixer_value->value;
Simon Wilsoncef93592013-01-15 16:35:46 -0800268 } else {
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700269 /* set only one value */
Simon Wilsoncef93592013-01-15 16:35:46 -0800270 path->setting[path_index].value[mixer_value->index] = mixer_value->value;
271 }
272
273 return 0;
274}
275
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800276static int path_add_path(struct audio_route *ar, struct mixer_path *path,
277 struct mixer_path *sub_path)
Simon Wilsoncef93592013-01-15 16:35:46 -0800278{
279 unsigned int i;
280
281 for (i = 0; i < sub_path->length; i++)
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800282 if (path_add_setting(ar, path, &sub_path->setting[i]) < 0)
Simon Wilsoncef93592013-01-15 16:35:46 -0800283 return -1;
284
285 return 0;
286}
287
288static int path_apply(struct audio_route *ar, struct mixer_path *path)
289{
290 unsigned int i;
Simon Wilsoncef93592013-01-15 16:35:46 -0800291 unsigned int ctl_index;
292
293 for (i = 0; i < path->length; i++) {
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800294 ctl_index = path->setting[i].ctl_index;
Simon Wilsoncef93592013-01-15 16:35:46 -0800295
296 /* apply the new value(s) */
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700297 memcpy(ar->mixer_state[ctl_index].new_value, path->setting[i].value,
298 path->setting[i].num_values * sizeof(int));
Simon Wilsoncef93592013-01-15 16:35:46 -0800299 }
300
301 return 0;
302}
303
Ravi Kumar Alamanda72c277e2013-02-08 07:41:07 -0800304static int path_reset(struct audio_route *ar, struct mixer_path *path)
305{
306 unsigned int i;
307 unsigned int j;
308 unsigned int ctl_index;
309
310 for (i = 0; i < path->length; i++) {
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800311 ctl_index = path->setting[i].ctl_index;
Ravi Kumar Alamanda72c277e2013-02-08 07:41:07 -0800312
313 /* reset the value(s) */
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700314 memcpy(ar->mixer_state[ctl_index].new_value,
315 ar->mixer_state[ctl_index].reset_value,
316 ar->mixer_state[ctl_index].num_values * sizeof(int));
Ravi Kumar Alamanda72c277e2013-02-08 07:41:07 -0800317 }
318
319 return 0;
320}
321
Simon Wilsoncef93592013-01-15 16:35:46 -0800322/* mixer helper function */
323static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string)
324{
325 unsigned int i;
326
327 /* Search the enum strings for a particular one */
328 for (i = 0; i < mixer_ctl_get_num_enums(ctl); i++) {
329 if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
330 break;
331 }
332
333 return i;
334}
335
336static void start_tag(void *data, const XML_Char *tag_name,
337 const XML_Char **attr)
338{
339 const XML_Char *attr_name = NULL;
340 const XML_Char *attr_id = NULL;
341 const XML_Char *attr_value = NULL;
342 struct config_parse_state *state = data;
343 struct audio_route *ar = state->ar;
344 unsigned int i;
345 unsigned int ctl_index;
346 struct mixer_ctl *ctl;
347 int value;
348 unsigned int id;
349 struct mixer_value mixer_value;
350
351 /* Get name, id and value attributes (these may be empty) */
352 for (i = 0; attr[i]; i += 2) {
353 if (strcmp(attr[i], "name") == 0)
354 attr_name = attr[i + 1];
355 if (strcmp(attr[i], "id") == 0)
356 attr_id = attr[i + 1];
357 else if (strcmp(attr[i], "value") == 0)
358 attr_value = attr[i + 1];
359 }
360
361 /* Look at tags */
362 if (strcmp(tag_name, "path") == 0) {
363 if (attr_name == NULL) {
364 ALOGE("Unnamed path!");
365 } else {
366 if (state->level == 1) {
367 /* top level path: create and stash the path */
368 state->path = path_create(ar, (char *)attr_name);
369 } else {
370 /* nested path */
371 struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800372 path_add_path(ar, state->path, sub_path);
Simon Wilsoncef93592013-01-15 16:35:46 -0800373 }
374 }
375 }
376
377 else if (strcmp(tag_name, "ctl") == 0) {
378 /* Obtain the mixer ctl and value */
379 ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);
Simon Wilsond35bd632013-05-13 12:47:41 -0700380 if (ctl == NULL) {
381 ALOGE("Control '%s' doesn't exist - skipping", attr_name);
382 goto done;
383 }
384
Simon Wilsoncef93592013-01-15 16:35:46 -0800385 switch (mixer_ctl_get_type(ctl)) {
386 case MIXER_CTL_TYPE_BOOL:
387 case MIXER_CTL_TYPE_INT:
388 value = atoi((char *)attr_value);
389 break;
390 case MIXER_CTL_TYPE_ENUM:
391 value = mixer_enum_string_to_value(ctl, (char *)attr_value);
392 break;
393 default:
394 value = 0;
395 break;
396 }
397
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800398 /* locate the mixer ctl in the list */
399 for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
400 if (ar->mixer_state[ctl_index].ctl == ctl)
401 break;
402 }
403
Simon Wilsoncef93592013-01-15 16:35:46 -0800404 if (state->level == 1) {
405 /* top level ctl (initial setting) */
406
Simon Wilsoncef93592013-01-15 16:35:46 -0800407 /* apply the new value */
408 if (attr_id) {
409 /* set only one value */
410 id = atoi((char *)attr_id);
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700411 if (id < ar->mixer_state[ctl_index].num_values)
Simon Wilsoncef93592013-01-15 16:35:46 -0800412 ar->mixer_state[ctl_index].new_value[id] = value;
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700413 else
Simon Wilsoncef93592013-01-15 16:35:46 -0800414 ALOGE("value id out of range for mixer ctl '%s'",
415 mixer_ctl_get_name(ctl));
Simon Wilsoncef93592013-01-15 16:35:46 -0800416 } else {
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700417 /* set all values the same */
418 for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++)
419 ar->mixer_state[ctl_index].new_value[i] = value;
Simon Wilsoncef93592013-01-15 16:35:46 -0800420 }
421 } else {
422 /* nested ctl (within a path) */
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800423 mixer_value.ctl_index = ctl_index;
Simon Wilsoncef93592013-01-15 16:35:46 -0800424 mixer_value.value = value;
425 if (attr_id)
426 mixer_value.index = atoi((char *)attr_id);
427 else
428 mixer_value.index = -1;
Simon Wilsonf3090fa2013-02-12 16:41:52 -0800429 path_add_value(ar, state->path, &mixer_value);
Simon Wilsoncef93592013-01-15 16:35:46 -0800430 }
431 }
432
Simon Wilsond35bd632013-05-13 12:47:41 -0700433done:
Simon Wilsoncef93592013-01-15 16:35:46 -0800434 state->level++;
435}
436
437static void end_tag(void *data, const XML_Char *tag_name)
438{
439 struct config_parse_state *state = data;
440
441 state->level--;
442}
443
444static int alloc_mixer_state(struct audio_route *ar)
445{
446 unsigned int i;
447 unsigned int j;
448 unsigned int num_values;
449 struct mixer_ctl *ctl;
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700450 enum mixer_ctl_type type;
Simon Wilsoncef93592013-01-15 16:35:46 -0800451
452 ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
453 ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state));
454 if (!ar->mixer_state)
455 return -1;
456
457 for (i = 0; i < ar->num_mixer_ctls; i++) {
458 ctl = mixer_get_ctl(ar->mixer, i);
459 num_values = mixer_ctl_get_num_values(ctl);
460
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700461 ar->mixer_state[i].ctl = ctl;
462 ar->mixer_state[i].num_values = num_values;
463
464 /* Skip unsupported types that are not supported yet in XML */
465 type = mixer_ctl_get_type(ctl);
466 if ((type != MIXER_CTL_TYPE_BOOL) && (type != MIXER_CTL_TYPE_INT) &&
467 (type != MIXER_CTL_TYPE_ENUM))
468 continue;
469
Simon Wilsoncef93592013-01-15 16:35:46 -0800470 ar->mixer_state[i].old_value = malloc(num_values * sizeof(int));
471 ar->mixer_state[i].new_value = malloc(num_values * sizeof(int));
472 ar->mixer_state[i].reset_value = malloc(num_values * sizeof(int));
473
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700474 if (type == MIXER_CTL_TYPE_ENUM)
475 ar->mixer_state[i].old_value[0] = mixer_ctl_get_value(ctl, 0);
476 else
477 mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value, num_values);
478 memcpy(ar->mixer_state[i].new_value, ar->mixer_state[i].old_value,
479 num_values * sizeof(int));
Simon Wilsoncef93592013-01-15 16:35:46 -0800480 }
481
482 return 0;
483}
484
485static void free_mixer_state(struct audio_route *ar)
486{
487 unsigned int i;
488
489 for (i = 0; i < ar->num_mixer_ctls; i++) {
490 free(ar->mixer_state[i].old_value);
491 free(ar->mixer_state[i].new_value);
492 free(ar->mixer_state[i].reset_value);
493 }
494
495 free(ar->mixer_state);
496 ar->mixer_state = NULL;
497}
498
499/* Update the mixer with any changed values */
500int audio_route_update_mixer(struct audio_route *ar)
501{
502 unsigned int i;
503 unsigned int j;
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700504 struct mixer_ctl *ctl;
Simon Wilsoncef93592013-01-15 16:35:46 -0800505
506 for (i = 0; i < ar->num_mixer_ctls; i++) {
507 unsigned int num_values = ar->mixer_state[i].num_values;
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700508 enum mixer_ctl_type type;
509
510 ctl = ar->mixer_state[i].ctl;
511
512 /* Skip unsupported types */
513 type = mixer_ctl_get_type(ctl);
514 if ((type != MIXER_CTL_TYPE_BOOL) && (type != MIXER_CTL_TYPE_INT) &&
515 (type != MIXER_CTL_TYPE_ENUM))
516 continue;
Simon Wilsoncef93592013-01-15 16:35:46 -0800517
518 /* if the value has changed, update the mixer */
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700519 bool changed = false;
520 for (j = 0; j < num_values; j++) {
521 if (ar->mixer_state[i].old_value[j] != ar->mixer_state[i].new_value[j]) {
522 changed = true;
523 break;
Simon Wilsoncef93592013-01-15 16:35:46 -0800524 }
525 }
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700526 if (changed) {
527 if (type == MIXER_CTL_TYPE_ENUM)
528 mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value[0]);
529 else
530 mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value, num_values);
531 memcpy(ar->mixer_state[i].old_value, ar->mixer_state[i].new_value,
532 num_values * sizeof(int));
533 }
Simon Wilsoncef93592013-01-15 16:35:46 -0800534 }
535
536 return 0;
537}
538
539/* saves the current state of the mixer, for resetting all controls */
540static void save_mixer_state(struct audio_route *ar)
541{
542 unsigned int i;
Simon Wilsoncef93592013-01-15 16:35:46 -0800543
544 for (i = 0; i < ar->num_mixer_ctls; i++) {
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700545 memcpy(ar->mixer_state[i].reset_value, ar->mixer_state[i].new_value,
546 ar->mixer_state[i].num_values * sizeof(int));
Simon Wilsoncef93592013-01-15 16:35:46 -0800547 }
548}
549
550/* Reset the audio routes back to the initial state */
551void audio_route_reset(struct audio_route *ar)
552{
553 unsigned int i;
Simon Wilsoncef93592013-01-15 16:35:46 -0800554
555 /* load all of the saved values */
556 for (i = 0; i < ar->num_mixer_ctls; i++) {
Ravi Kumar Alamanda63b31c12013-05-24 18:02:24 -0700557 memcpy(ar->mixer_state[i].new_value, ar->mixer_state[i].reset_value,
558 ar->mixer_state[i].num_values * sizeof(int));
Simon Wilsoncef93592013-01-15 16:35:46 -0800559 }
560}
561
562/* Apply an audio route path by name */
563int audio_route_apply_path(struct audio_route *ar, const char *name)
564{
565 struct mixer_path *path;
566
567 if (!ar) {
568 ALOGE("invalid audio_route");
569 return -1;
570 }
571
572 path = path_get_by_name(ar, name);
573 if (!path) {
574 ALOGE("unable to find path '%s'", name);
575 return -1;
576 }
577
578 path_apply(ar, path);
579
580 return 0;
581}
582
Ravi Kumar Alamanda72c277e2013-02-08 07:41:07 -0800583/* Reset an audio route path by name */
584int audio_route_reset_path(struct audio_route *ar, const char *name)
585{
586 struct mixer_path *path;
587
588 if (!ar) {
589 ALOGE("invalid audio_route");
590 return -1;
591 }
592
593 path = path_get_by_name(ar, name);
594 if (!path) {
595 ALOGE("unable to find path '%s'", name);
596 return -1;
597 }
598
599 path_reset(ar, path);
600
601 return 0;
602}
603
Simon Wilsoncef93592013-01-15 16:35:46 -0800604struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
605{
606 struct config_parse_state state;
607 XML_Parser parser;
608 FILE *file;
609 int bytes_read;
610 void *buf;
611 int i;
612 struct audio_route *ar;
613
614 ar = calloc(1, sizeof(struct audio_route));
615 if (!ar)
616 goto err_calloc;
617
618 ar->mixer = mixer_open(card);
619 if (!ar->mixer) {
620 ALOGE("Unable to open the mixer, aborting.");
621 goto err_mixer_open;
622 }
623
624 ar->mixer_path = NULL;
625 ar->mixer_path_size = 0;
626 ar->num_mixer_paths = 0;
627
628 /* allocate space for and read current mixer settings */
629 if (alloc_mixer_state(ar) < 0)
630 goto err_mixer_state;
631
632 /* use the default XML path if none is provided */
633 if (xml_path == NULL)
634 xml_path = MIXER_XML_PATH;
635
636 file = fopen(xml_path, "r");
637
638 if (!file) {
639 ALOGE("Failed to open %s", xml_path);
640 goto err_fopen;
641 }
642
643 parser = XML_ParserCreate(NULL);
644 if (!parser) {
645 ALOGE("Failed to create XML parser");
646 goto err_parser_create;
647 }
648
649 memset(&state, 0, sizeof(state));
650 state.ar = ar;
651 XML_SetUserData(parser, &state);
652 XML_SetElementHandler(parser, start_tag, end_tag);
653
654 for (;;) {
655 buf = XML_GetBuffer(parser, BUF_SIZE);
656 if (buf == NULL)
657 goto err_parse;
658
659 bytes_read = fread(buf, 1, BUF_SIZE, file);
660 if (bytes_read < 0)
661 goto err_parse;
662
663 if (XML_ParseBuffer(parser, bytes_read,
664 bytes_read == 0) == XML_STATUS_ERROR) {
665 ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
666 goto err_parse;
667 }
668
669 if (bytes_read == 0)
670 break;
671 }
672
673 /* apply the initial mixer values, and save them so we can reset the
674 mixer to the original values */
675 audio_route_update_mixer(ar);
676 save_mixer_state(ar);
677
678 XML_ParserFree(parser);
679 fclose(file);
680 return ar;
681
682err_parse:
683 XML_ParserFree(parser);
684err_parser_create:
685 fclose(file);
686err_fopen:
687 free_mixer_state(ar);
688err_mixer_state:
689 mixer_close(ar->mixer);
690err_mixer_open:
691 free(ar);
692 ar = NULL;
693err_calloc:
694 return NULL;
695}
696
697void audio_route_free(struct audio_route *ar)
698{
699 free_mixer_state(ar);
700 mixer_close(ar->mixer);
701 free(ar);
702}