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