1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * Inspired by TinyHW, written by Mark Brown at Wolfson Micro 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #define LOG_TAG "audio_route" 19 /*#define LOG_NDEBUG 0*/ 20 21 #include <errno.h> 22 #include <expat.h> 23 #include <stdbool.h> 24 #include <stdio.h> 25 #include <string.h> 26 27 #include <cutils/log.h> 28 29 #include <tinyalsa/asoundlib.h> 30 31 #define BUF_SIZE 1024 32 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml" 33 #define INITIAL_MIXER_PATH_SIZE 8 34 35 union ctl_values { 36 int *enumerated; 37 long *integer; 38 void *ptr; 39 unsigned char *bytes; 40 }; 41 42 struct 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 50 struct mixer_setting { 51 unsigned int ctl_index; 52 unsigned int num_values; 53 unsigned int type; 54 union ctl_values value; 55 }; 56 57 struct mixer_value { 58 unsigned int ctl_index; 59 int index; 60 long value; 61 }; 62 63 struct mixer_path { 64 char *name; 65 unsigned int size; 66 unsigned int length; 67 struct mixer_setting *setting; 68 }; 69 70 struct 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 80 struct config_parse_state { 81 struct audio_route *ar; 82 struct mixer_path *path; 83 int level; 84 }; 85 86 /* path functions */ 87 88 static 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 */ 102 static 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 120 static 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 127 static 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 151 static void path_free(struct audio_route *ar) 152 { 153 unsigned int i; 154 155 for (i = 0; i < ar->num_mixer_paths; i++) { 156 if (ar->mixer_path[i].name) 157 free(ar->mixer_path[i].name); 158 if (ar->mixer_path[i].setting) { 159 if (ar->mixer_path[i].setting->value.ptr) 160 free(ar->mixer_path[i].setting->value.ptr); 161 free(ar->mixer_path[i].setting); 162 } 163 } 164 free(ar->mixer_path); 165 ar->mixer_path = NULL; 166 ar->mixer_path_size = 0; 167 } 168 169 static struct mixer_path *path_get_by_name(struct audio_route *ar, 170 const char *name) 171 { 172 unsigned int i; 173 174 for (i = 0; i < ar->num_mixer_paths; i++) 175 if (strcmp(ar->mixer_path[i].name, name) == 0) 176 return &ar->mixer_path[i]; 177 178 return NULL; 179 } 180 181 static struct mixer_path *path_create(struct audio_route *ar, const char *name) 182 { 183 struct mixer_path *new_mixer_path = NULL; 184 185 if (path_get_by_name(ar, name)) { 186 ALOGE("Path name '%s' already exists", name); 187 return NULL; 188 } 189 190 /* check if we need to allocate more space for mixer paths */ 191 if (ar->mixer_path_size <= ar->num_mixer_paths) { 192 if (ar->mixer_path_size == 0) 193 ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE; 194 else 195 ar->mixer_path_size *= 2; 196 197 new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size * 198 sizeof(struct mixer_path)); 199 if (new_mixer_path == NULL) { 200 ALOGE("Unable to allocate more paths"); 201 return NULL; 202 } else { 203 ar->mixer_path = new_mixer_path; 204 } 205 } 206 207 /* initialise the new mixer path */ 208 ar->mixer_path[ar->num_mixer_paths].name = strdup(name); 209 ar->mixer_path[ar->num_mixer_paths].size = 0; 210 ar->mixer_path[ar->num_mixer_paths].length = 0; 211 ar->mixer_path[ar->num_mixer_paths].setting = NULL; 212 213 /* return the mixer path just added, then increment number of them */ 214 return &ar->mixer_path[ar->num_mixer_paths++]; 215 } 216 217 static int find_ctl_index_in_path(struct mixer_path *path, 218 unsigned int ctl_index) 219 { 220 unsigned int i; 221 222 for (i = 0; i < path->length; i++) 223 if (path->setting[i].ctl_index == ctl_index) 224 return i; 225 226 return -1; 227 } 228 229 static int alloc_path_setting(struct mixer_path *path) 230 { 231 struct mixer_setting *new_path_setting; 232 int path_index; 233 234 /* check if we need to allocate more space for path settings */ 235 if (path->size <= path->length) { 236 if (path->size == 0) 237 path->size = INITIAL_MIXER_PATH_SIZE; 238 else 239 path->size *= 2; 240 241 new_path_setting = realloc(path->setting, 242 path->size * sizeof(struct mixer_setting)); 243 if (new_path_setting == NULL) { 244 ALOGE("Unable to allocate more path settings"); 245 return -1; 246 } else { 247 path->setting = new_path_setting; 248 } 249 } 250 251 path_index = path->length; 252 path->length++; 253 254 return path_index; 255 } 256 257 static int path_add_setting(struct audio_route *ar, struct mixer_path *path, 258 struct mixer_setting *setting) 259 { 260 int path_index; 261 262 if (find_ctl_index_in_path(path, setting->ctl_index) != -1) { 263 struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index); 264 265 ALOGE("Control '%s' already exists in path '%s'", 266 mixer_ctl_get_name(ctl), path->name); 267 return -1; 268 } 269 270 if (!is_supported_ctl_type(setting->type)) { 271 ALOGE("unsupported type %d", (int)setting->type); 272 return -1; 273 } 274 275 path_index = alloc_path_setting(path); 276 if (path_index < 0) 277 return -1; 278 279 path->setting[path_index].ctl_index = setting->ctl_index; 280 path->setting[path_index].type = setting->type; 281 path->setting[path_index].num_values = setting->num_values; 282 283 size_t value_sz = sizeof_ctl_type(setting->type); 284 285 path->setting[path_index].value.ptr = calloc(setting->num_values, value_sz); 286 /* copy all values */ 287 memcpy(path->setting[path_index].value.ptr, setting->value.ptr, 288 setting->num_values * value_sz); 289 290 return 0; 291 } 292 293 static int path_add_value(struct audio_route *ar, struct mixer_path *path, 294 struct mixer_value *mixer_value) 295 { 296 unsigned int i; 297 int path_index; 298 unsigned int num_values; 299 struct mixer_ctl *ctl; 300 301 /* Check that mixer value index is within range */ 302 ctl = index_to_ctl(ar, mixer_value->ctl_index); 303 num_values = mixer_ctl_get_num_values(ctl); 304 if (mixer_value->index >= (int)num_values) { 305 ALOGE("mixer index %d is out of range for '%s'", mixer_value->index, 306 mixer_ctl_get_name(ctl)); 307 return -1; 308 } 309 310 path_index = find_ctl_index_in_path(path, mixer_value->ctl_index); 311 if (path_index < 0) { 312 /* New path */ 313 314 enum mixer_ctl_type type = mixer_ctl_get_type(ctl); 315 if (!is_supported_ctl_type(type)) { 316 ALOGE("unsupported type %d", (int)type); 317 return -1; 318 } 319 path_index = alloc_path_setting(path); 320 if (path_index < 0) 321 return -1; 322 323 /* initialise the new path setting */ 324 path->setting[path_index].ctl_index = mixer_value->ctl_index; 325 path->setting[path_index].num_values = num_values; 326 path->setting[path_index].type = type; 327 328 size_t value_sz = sizeof_ctl_type(type); 329 path->setting[path_index].value.ptr = calloc(num_values, value_sz); 330 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE) 331 path->setting[path_index].value.bytes[0] = mixer_value->value; 332 else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM) 333 path->setting[path_index].value.enumerated[0] = mixer_value->value; 334 else 335 path->setting[path_index].value.integer[0] = mixer_value->value; 336 } 337 338 if (mixer_value->index == -1) { 339 /* set all values the same */ 340 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE) { 341 for (i = 0; i < num_values; i++) 342 path->setting[path_index].value.bytes[i] = mixer_value->value; 343 } else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM) { 344 for (i = 0; i < num_values; i++) 345 path->setting[path_index].value.enumerated[i] = mixer_value->value; 346 } else { 347 for (i = 0; i < num_values; i++) 348 path->setting[path_index].value.integer[i] = mixer_value->value; 349 } 350 } else { 351 /* set only one value */ 352 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE) 353 path->setting[path_index].value.bytes[mixer_value->index] = mixer_value->value; 354 else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM) 355 path->setting[path_index].value.enumerated[mixer_value->index] = mixer_value->value; 356 else 357 path->setting[path_index].value.integer[mixer_value->index] = mixer_value->value; 358 } 359 360 return 0; 361 } 362 363 static int path_add_path(struct audio_route *ar, struct mixer_path *path, 364 struct mixer_path *sub_path) 365 { 366 unsigned int i; 367 368 for (i = 0; i < sub_path->length; i++) 369 if (path_add_setting(ar, path, &sub_path->setting[i]) < 0) 370 return -1; 371 372 return 0; 373 } 374 375 static int path_apply(struct audio_route *ar, struct mixer_path *path) 376 { 377 unsigned int i; 378 unsigned int ctl_index; 379 struct mixer_ctl *ctl; 380 enum mixer_ctl_type type; 381 382 for (i = 0; i < path->length; i++) { 383 ctl_index = path->setting[i].ctl_index; 384 ctl = index_to_ctl(ar, ctl_index); 385 type = mixer_ctl_get_type(ctl); 386 if (!is_supported_ctl_type(type)) 387 continue; 388 size_t value_sz = sizeof_ctl_type(type); 389 memcpy(ar->mixer_state[ctl_index].new_value.ptr, path->setting[i].value.ptr, 390 path->setting[i].num_values * value_sz); 391 } 392 393 return 0; 394 } 395 396 static int path_reset(struct audio_route *ar, struct mixer_path *path) 397 { 398 unsigned int i; 399 unsigned int ctl_index; 400 struct mixer_ctl *ctl; 401 enum mixer_ctl_type type; 402 403 for (i = 0; i < path->length; i++) { 404 ctl_index = path->setting[i].ctl_index; 405 ctl = index_to_ctl(ar, ctl_index); 406 type = mixer_ctl_get_type(ctl); 407 if (!is_supported_ctl_type(type)) 408 continue; 409 size_t value_sz = sizeof_ctl_type(type); 410 /* reset the value(s) */ 411 memcpy(ar->mixer_state[ctl_index].new_value.ptr, 412 ar->mixer_state[ctl_index].reset_value.ptr, 413 ar->mixer_state[ctl_index].num_values * value_sz); 414 } 415 416 return 0; 417 } 418 419 /* mixer helper function */ 420 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string) 421 { 422 unsigned int i; 423 unsigned int num_values = mixer_ctl_get_num_enums(ctl); 424 425 if (string == NULL) { 426 ALOGE("NULL enum value string passed to mixer_enum_string_to_value() for ctl %s", 427 mixer_ctl_get_name(ctl)); 428 return 0; 429 } 430 431 /* Search the enum strings for a particular one */ 432 for (i = 0; i < num_values; i++) { 433 if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0) 434 break; 435 } 436 if (i == num_values) { 437 ALOGE("unknown enum value string %s for ctl %s", 438 string, mixer_ctl_get_name(ctl)); 439 return 0; 440 } 441 return i; 442 } 443 444 static void start_tag(void *data, const XML_Char *tag_name, 445 const XML_Char **attr) 446 { 447 const XML_Char *attr_name = NULL; 448 const XML_Char *attr_id = NULL; 449 const XML_Char *attr_value = NULL; 450 struct config_parse_state *state = data; 451 struct audio_route *ar = state->ar; 452 unsigned int i; 453 unsigned int ctl_index; 454 struct mixer_ctl *ctl; 455 long value; 456 unsigned int id; 457 struct mixer_value mixer_value; 458 enum mixer_ctl_type type; 459 460 /* Get name, id and value attributes (these may be empty) */ 461 for (i = 0; attr[i]; i += 2) { 462 if (strcmp(attr[i], "name") == 0) 463 attr_name = attr[i + 1]; 464 if (strcmp(attr[i], "id") == 0) 465 attr_id = attr[i + 1]; 466 else if (strcmp(attr[i], "value") == 0) 467 attr_value = attr[i + 1]; 468 } 469 470 /* Look at tags */ 471 if (strcmp(tag_name, "path") == 0) { 472 if (attr_name == NULL) { 473 ALOGE("Unnamed path!"); 474 } else { 475 if (state->level == 1) { 476 /* top level path: create and stash the path */ 477 state->path = path_create(ar, (char *)attr_name); 478 } else { 479 /* nested path */ 480 struct mixer_path *sub_path = path_get_by_name(ar, attr_name); 481 path_add_path(ar, state->path, sub_path); 482 } 483 } 484 } 485 486 else if (strcmp(tag_name, "ctl") == 0) { 487 /* Obtain the mixer ctl and value */ 488 ctl = mixer_get_ctl_by_name(ar->mixer, attr_name); 489 if (ctl == NULL) { 490 ALOGE("Control '%s' doesn't exist - skipping", attr_name); 491 goto done; 492 } 493 494 switch (mixer_ctl_get_type(ctl)) { 495 case MIXER_CTL_TYPE_BOOL: 496 case MIXER_CTL_TYPE_INT: 497 value = strtol((char *)attr_value, NULL, 0); 498 break; 499 case MIXER_CTL_TYPE_BYTE: 500 value = (unsigned char) strtol((char *)attr_value, NULL, 16); 501 break; 502 case MIXER_CTL_TYPE_ENUM: 503 value = mixer_enum_string_to_value(ctl, (char *)attr_value); 504 break; 505 default: 506 value = 0; 507 break; 508 } 509 510 /* locate the mixer ctl in the list */ 511 for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) { 512 if (ar->mixer_state[ctl_index].ctl == ctl) 513 break; 514 } 515 516 if (state->level == 1) { 517 /* top level ctl (initial setting) */ 518 519 type = mixer_ctl_get_type(ctl); 520 if (is_supported_ctl_type(type)) { 521 /* apply the new value */ 522 if (attr_id) { 523 /* set only one value */ 524 id = atoi((char *)attr_id); 525 if (id < ar->mixer_state[ctl_index].num_values) 526 if (type == MIXER_CTL_TYPE_BYTE) 527 ar->mixer_state[ctl_index].new_value.bytes[id] = value; 528 else if (type == MIXER_CTL_TYPE_ENUM) 529 ar->mixer_state[ctl_index].new_value.enumerated[id] = value; 530 else 531 ar->mixer_state[ctl_index].new_value.integer[id] = value; 532 else 533 ALOGE("value id out of range for mixer ctl '%s'", 534 mixer_ctl_get_name(ctl)); 535 } else { 536 /* set all values the same */ 537 for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++) 538 if (type == MIXER_CTL_TYPE_BYTE) 539 ar->mixer_state[ctl_index].new_value.bytes[i] = value; 540 else if (type == MIXER_CTL_TYPE_ENUM) 541 ar->mixer_state[ctl_index].new_value.enumerated[i] = value; 542 else 543 ar->mixer_state[ctl_index].new_value.integer[i] = value; 544 } 545 } 546 } else { 547 /* nested ctl (within a path) */ 548 mixer_value.ctl_index = ctl_index; 549 mixer_value.value = value; 550 if (attr_id) 551 mixer_value.index = atoi((char *)attr_id); 552 else 553 mixer_value.index = -1; 554 path_add_value(ar, state->path, &mixer_value); 555 } 556 } 557 558 done: 559 state->level++; 560 } 561 562 static void end_tag(void *data, const XML_Char *tag_name) 563 { 564 struct config_parse_state *state = data; 565 (void)tag_name; 566 567 state->level--; 568 } 569 570 static int alloc_mixer_state(struct audio_route *ar) 571 { 572 unsigned int i; 573 unsigned int num_values; 574 struct mixer_ctl *ctl; 575 enum mixer_ctl_type type; 576 577 ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer); 578 ar->mixer_state = calloc(ar->num_mixer_ctls, sizeof(struct mixer_state)); 579 if (!ar->mixer_state) 580 return -1; 581 582 for (i = 0; i < ar->num_mixer_ctls; i++) { 583 ctl = mixer_get_ctl(ar->mixer, i); 584 num_values = mixer_ctl_get_num_values(ctl); 585 586 ar->mixer_state[i].ctl = ctl; 587 ar->mixer_state[i].num_values = num_values; 588 589 /* Skip unsupported types that are not supported yet in XML */ 590 type = mixer_ctl_get_type(ctl); 591 592 if (!is_supported_ctl_type(type)) 593 continue; 594 595 size_t value_sz = sizeof_ctl_type(type); 596 ar->mixer_state[i].old_value.ptr = calloc(num_values, value_sz); 597 ar->mixer_state[i].new_value.ptr = calloc(num_values, value_sz); 598 ar->mixer_state[i].reset_value.ptr = calloc(num_values, value_sz); 599 600 if (type == MIXER_CTL_TYPE_ENUM) 601 ar->mixer_state[i].old_value.enumerated[0] = mixer_ctl_get_value(ctl, 0); 602 else 603 mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value.ptr, num_values); 604 605 memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].old_value.ptr, 606 num_values * value_sz); 607 } 608 609 return 0; 610 } 611 612 static void free_mixer_state(struct audio_route *ar) 613 { 614 unsigned int i; 615 enum mixer_ctl_type type; 616 617 for (i = 0; i < ar->num_mixer_ctls; i++) { 618 type = mixer_ctl_get_type(ar->mixer_state[i].ctl); 619 if (!is_supported_ctl_type(type)) 620 continue; 621 622 free(ar->mixer_state[i].old_value.ptr); 623 free(ar->mixer_state[i].new_value.ptr); 624 free(ar->mixer_state[i].reset_value.ptr); 625 } 626 627 free(ar->mixer_state); 628 ar->mixer_state = NULL; 629 } 630 631 /* Update the mixer with any changed values */ 632 int audio_route_update_mixer(struct audio_route *ar) 633 { 634 unsigned int i; 635 unsigned int j; 636 struct mixer_ctl *ctl; 637 638 for (i = 0; i < ar->num_mixer_ctls; i++) { 639 unsigned int num_values = ar->mixer_state[i].num_values; 640 enum mixer_ctl_type type; 641 642 ctl = ar->mixer_state[i].ctl; 643 644 /* Skip unsupported types */ 645 type = mixer_ctl_get_type(ctl); 646 if (!is_supported_ctl_type(type)) 647 continue; 648 649 /* if the value has changed, update the mixer */ 650 bool changed = false; 651 if (type == MIXER_CTL_TYPE_BYTE) { 652 for (j = 0; j < num_values; j++) { 653 if (ar->mixer_state[i].old_value.bytes[j] != ar->mixer_state[i].new_value.bytes[j]) { 654 changed = true; 655 break; 656 } 657 } 658 } else if (type == MIXER_CTL_TYPE_ENUM) { 659 for (j = 0; j < num_values; j++) { 660 if (ar->mixer_state[i].old_value.enumerated[j] 661 != ar->mixer_state[i].new_value.enumerated[j]) { 662 changed = true; 663 break; 664 } 665 } 666 } else { 667 for (j = 0; j < num_values; j++) { 668 if (ar->mixer_state[i].old_value.integer[j] != ar->mixer_state[i].new_value.integer[j]) { 669 changed = true; 670 break; 671 } 672 } 673 } 674 if (changed) { 675 if (type == MIXER_CTL_TYPE_ENUM) 676 mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value.enumerated[0]); 677 else 678 mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value.ptr, num_values); 679 680 size_t value_sz = sizeof_ctl_type(type); 681 memcpy(ar->mixer_state[i].old_value.ptr, ar->mixer_state[i].new_value.ptr, 682 num_values * value_sz); 683 } 684 } 685 686 return 0; 687 } 688 689 /* saves the current state of the mixer, for resetting all controls */ 690 static void save_mixer_state(struct audio_route *ar) 691 { 692 unsigned int i; 693 enum mixer_ctl_type type; 694 695 for (i = 0; i < ar->num_mixer_ctls; i++) { 696 type = mixer_ctl_get_type(ar->mixer_state[i].ctl); 697 if (!is_supported_ctl_type(type)) 698 continue; 699 700 size_t value_sz = sizeof_ctl_type(type); 701 memcpy(ar->mixer_state[i].reset_value.ptr, ar->mixer_state[i].new_value.ptr, 702 ar->mixer_state[i].num_values * value_sz); 703 } 704 } 705 706 /* Reset the audio routes back to the initial state */ 707 void audio_route_reset(struct audio_route *ar) 708 { 709 unsigned int i; 710 enum mixer_ctl_type type; 711 712 /* load all of the saved values */ 713 for (i = 0; i < ar->num_mixer_ctls; i++) { 714 type = mixer_ctl_get_type(ar->mixer_state[i].ctl); 715 if (!is_supported_ctl_type(type)) 716 continue; 717 718 size_t value_sz = sizeof_ctl_type(type); 719 memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].reset_value.ptr, 720 ar->mixer_state[i].num_values * value_sz); 721 } 722 } 723 724 /* Apply an audio route path by name */ 725 int audio_route_apply_path(struct audio_route *ar, const char *name) 726 { 727 struct mixer_path *path; 728 729 if (!ar) { 730 ALOGE("invalid audio_route"); 731 return -1; 732 } 733 734 path = path_get_by_name(ar, name); 735 if (!path) { 736 ALOGE("unable to find path '%s'", name); 737 return -1; 738 } 739 740 path_apply(ar, path); 741 742 return 0; 743 } 744 745 /* Reset an audio route path by name */ 746 int audio_route_reset_path(struct audio_route *ar, const char *name) 747 { 748 struct mixer_path *path; 749 750 if (!ar) { 751 ALOGE("invalid audio_route"); 752 return -1; 753 } 754 755 path = path_get_by_name(ar, name); 756 if (!path) { 757 ALOGE("unable to find path '%s'", name); 758 return -1; 759 } 760 761 path_reset(ar, path); 762 763 return 0; 764 } 765 766 /* 767 * Operates on the specified path .. controls will be updated in the 768 * order listed in the XML file 769 */ 770 static int audio_route_update_path(struct audio_route *ar, const char *name, bool reverse) 771 { 772 struct mixer_path *path; 773 int32_t i, end; 774 unsigned int j; 775 776 if (!ar) { 777 ALOGE("invalid audio_route"); 778 return -1; 779 } 780 781 path = path_get_by_name(ar, name); 782 if (!path) { 783 ALOGE("unable to find path '%s'", name); 784 return -1; 785 } 786 787 i = reverse ? (path->length - 1) : 0; 788 end = reverse ? -1 : (int32_t)path->length; 789 790 while (i != end) { 791 unsigned int ctl_index; 792 enum mixer_ctl_type type; 793 794 ctl_index = path->setting[i].ctl_index; 795 796 struct mixer_state * ms = &ar->mixer_state[ctl_index]; 797 798 type = mixer_ctl_get_type(ms->ctl); 799 if (!is_supported_ctl_type(type)) { 800 continue; 801 } 802 803 size_t value_sz = sizeof_ctl_type(type); 804 /* if any value has changed, update the mixer */ 805 for (j = 0; j < ms->num_values; j++) { 806 if (type == MIXER_CTL_TYPE_BYTE) { 807 if (ms->old_value.bytes[j] != ms->new_value.bytes[j]) { 808 mixer_ctl_set_array(ms->ctl, ms->new_value.bytes, ms->num_values); 809 memcpy(ms->old_value.bytes, ms->new_value.bytes, ms->num_values * value_sz); 810 break; 811 } 812 } else if (type == MIXER_CTL_TYPE_ENUM) { 813 if (ms->old_value.enumerated[j] != ms->new_value.enumerated[j]) { 814 mixer_ctl_set_value(ms->ctl, 0, ms->new_value.enumerated[0]); 815 memcpy(ms->old_value.enumerated, ms->new_value.enumerated, 816 ms->num_values * value_sz); 817 break; 818 } 819 } else if (ms->old_value.integer[j] != ms->new_value.integer[j]) { 820 mixer_ctl_set_array(ms->ctl, ms->new_value.integer, ms->num_values); 821 memcpy(ms->old_value.integer, ms->new_value.integer, ms->num_values * value_sz); 822 break; 823 } 824 } 825 826 i = reverse ? (i - 1) : (i + 1); 827 } 828 return 0; 829 } 830 831 int audio_route_apply_and_update_path(struct audio_route *ar, const char *name) 832 { 833 if (audio_route_apply_path(ar, name) < 0) { 834 return -1; 835 } 836 return audio_route_update_path(ar, name, false /*reverse*/); 837 } 838 839 int audio_route_reset_and_update_path(struct audio_route *ar, const char *name) 840 { 841 if (audio_route_reset_path(ar, name) < 0) { 842 return -1; 843 } 844 return audio_route_update_path(ar, name, true /*reverse*/); 845 } 846 847 struct audio_route *audio_route_init(unsigned int card, const char *xml_path) 848 { 849 struct config_parse_state state; 850 XML_Parser parser; 851 FILE *file; 852 int bytes_read; 853 void *buf; 854 struct audio_route *ar; 855 856 ar = calloc(1, sizeof(struct audio_route)); 857 if (!ar) 858 goto err_calloc; 859 860 ar->mixer = mixer_open(card); 861 if (!ar->mixer) { 862 ALOGE("Unable to open the mixer, aborting."); 863 goto err_mixer_open; 864 } 865 866 ar->mixer_path = NULL; 867 ar->mixer_path_size = 0; 868 ar->num_mixer_paths = 0; 869 870 /* allocate space for and read current mixer settings */ 871 if (alloc_mixer_state(ar) < 0) 872 goto err_mixer_state; 873 874 /* use the default XML path if none is provided */ 875 if (xml_path == NULL) 876 xml_path = MIXER_XML_PATH; 877 878 file = fopen(xml_path, "r"); 879 880 if (!file) { 881 ALOGE("Failed to open %s", xml_path); 882 goto err_fopen; 883 } 884 885 parser = XML_ParserCreate(NULL); 886 if (!parser) { 887 ALOGE("Failed to create XML parser"); 888 goto err_parser_create; 889 } 890 891 memset(&state, 0, sizeof(state)); 892 state.ar = ar; 893 XML_SetUserData(parser, &state); 894 XML_SetElementHandler(parser, start_tag, end_tag); 895 896 for (;;) { 897 buf = XML_GetBuffer(parser, BUF_SIZE); 898 if (buf == NULL) 899 goto err_parse; 900 901 bytes_read = fread(buf, 1, BUF_SIZE, file); 902 if (bytes_read < 0) 903 goto err_parse; 904 905 if (XML_ParseBuffer(parser, bytes_read, 906 bytes_read == 0) == XML_STATUS_ERROR) { 907 ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH); 908 goto err_parse; 909 } 910 911 if (bytes_read == 0) 912 break; 913 } 914 915 /* apply the initial mixer values, and save them so we can reset the 916 mixer to the original values */ 917 audio_route_update_mixer(ar); 918 save_mixer_state(ar); 919 920 XML_ParserFree(parser); 921 fclose(file); 922 return ar; 923 924 err_parse: 925 path_free(ar); 926 XML_ParserFree(parser); 927 err_parser_create: 928 fclose(file); 929 err_fopen: 930 free_mixer_state(ar); 931 err_mixer_state: 932 mixer_close(ar->mixer); 933 err_mixer_open: 934 free(ar); 935 ar = NULL; 936 err_calloc: 937 return NULL; 938 } 939 940 void audio_route_free(struct audio_route *ar) 941 { 942 free_mixer_state(ar); 943 mixer_close(ar->mixer); 944 path_free(ar); 945 free(ar); 946 } 947