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 for (i = 0; i < path->length; i++) { 382 ctl_index = path->setting[i].ctl_index; 383 ctl = index_to_ctl(ar, ctl_index); 384 type = mixer_ctl_get_type(ctl); 385 if (!is_supported_ctl_type(type)) 386 continue; 387 size_t value_sz = sizeof_ctl_type(type); 388 memcpy(ar->mixer_state[ctl_index].new_value.ptr, path->setting[i].value.ptr, 389 path->setting[i].num_values * value_sz); 390 } 391 392 return 0; 393 } 394 395 static int path_reset(struct audio_route *ar, struct mixer_path *path) 396 { 397 unsigned int i; 398 unsigned int ctl_index; 399 struct mixer_ctl *ctl; 400 enum mixer_ctl_type type; 401 402 for (i = 0; i < path->length; i++) { 403 ctl_index = path->setting[i].ctl_index; 404 ctl = index_to_ctl(ar, ctl_index); 405 type = mixer_ctl_get_type(ctl); 406 if (!is_supported_ctl_type(type)) 407 continue; 408 size_t value_sz = sizeof_ctl_type(type); 409 /* reset the value(s) */ 410 memcpy(ar->mixer_state[ctl_index].new_value.ptr, 411 ar->mixer_state[ctl_index].reset_value.ptr, 412 ar->mixer_state[ctl_index].num_values * value_sz); 413 } 414 415 return 0; 416 } 417 418 /* mixer helper function */ 419 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string) 420 { 421 unsigned int i; 422 unsigned int num_values = mixer_ctl_get_num_enums(ctl); 423 424 if (string == NULL) { 425 ALOGE("NULL enum value string passed to mixer_enum_string_to_value() for ctl %s", 426 mixer_ctl_get_name(ctl)); 427 return 0; 428 } 429 430 /* Search the enum strings for a particular one */ 431 for (i = 0; i < num_values; i++) { 432 if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0) 433 break; 434 } 435 if (i == num_values) { 436 ALOGE("unknown enum value string %s for ctl %s", 437 string, mixer_ctl_get_name(ctl)); 438 return 0; 439 } 440 return i; 441 } 442 443 static void start_tag(void *data, const XML_Char *tag_name, 444 const XML_Char **attr) 445 { 446 const XML_Char *attr_name = NULL; 447 const XML_Char *attr_id = NULL; 448 const XML_Char *attr_value = NULL; 449 struct config_parse_state *state = data; 450 struct audio_route *ar = state->ar; 451 unsigned int i; 452 unsigned int ctl_index; 453 struct mixer_ctl *ctl; 454 long value; 455 unsigned int id; 456 struct mixer_value mixer_value; 457 enum mixer_ctl_type type; 458 459 /* Get name, id and value attributes (these may be empty) */ 460 for (i = 0; attr[i]; i += 2) { 461 if (strcmp(attr[i], "name") == 0) 462 attr_name = attr[i + 1]; 463 if (strcmp(attr[i], "id") == 0) 464 attr_id = attr[i + 1]; 465 else if (strcmp(attr[i], "value") == 0) 466 attr_value = attr[i + 1]; 467 } 468 469 /* Look at tags */ 470 if (strcmp(tag_name, "path") == 0) { 471 if (attr_name == NULL) { 472 ALOGE("Unnamed path!"); 473 } else { 474 if (state->level == 1) { 475 /* top level path: create and stash the path */ 476 state->path = path_create(ar, (char *)attr_name); 477 } else { 478 /* nested path */ 479 struct mixer_path *sub_path = path_get_by_name(ar, attr_name); 480 if (!sub_path) { 481 ALOGE("unable to find sub path '%s'", attr_name); 482 } else { 483 path_add_path(ar, state->path, sub_path); 484 } 485 } 486 } 487 } 488 489 else if (strcmp(tag_name, "ctl") == 0) { 490 /* Obtain the mixer ctl and value */ 491 ctl = mixer_get_ctl_by_name(ar->mixer, attr_name); 492 if (ctl == NULL) { 493 ALOGE("Control '%s' doesn't exist - skipping", attr_name); 494 goto done; 495 } 496 497 switch (mixer_ctl_get_type(ctl)) { 498 case MIXER_CTL_TYPE_BOOL: 499 case MIXER_CTL_TYPE_INT: 500 value = strtol((char *)attr_value, NULL, 0); 501 break; 502 case MIXER_CTL_TYPE_BYTE: 503 value = (unsigned char) strtol((char *)attr_value, NULL, 16); 504 break; 505 case MIXER_CTL_TYPE_ENUM: 506 value = mixer_enum_string_to_value(ctl, (char *)attr_value); 507 break; 508 default: 509 value = 0; 510 break; 511 } 512 513 /* locate the mixer ctl in the list */ 514 for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) { 515 if (ar->mixer_state[ctl_index].ctl == ctl) 516 break; 517 } 518 519 if (state->level == 1) { 520 /* top level ctl (initial setting) */ 521 522 type = mixer_ctl_get_type(ctl); 523 if (is_supported_ctl_type(type)) { 524 /* apply the new value */ 525 if (attr_id) { 526 /* set only one value */ 527 id = atoi((char *)attr_id); 528 if (id < ar->mixer_state[ctl_index].num_values) 529 if (type == MIXER_CTL_TYPE_BYTE) 530 ar->mixer_state[ctl_index].new_value.bytes[id] = value; 531 else if (type == MIXER_CTL_TYPE_ENUM) 532 ar->mixer_state[ctl_index].new_value.enumerated[id] = value; 533 else 534 ar->mixer_state[ctl_index].new_value.integer[id] = value; 535 else 536 ALOGE("value id out of range for mixer ctl '%s'", 537 mixer_ctl_get_name(ctl)); 538 } else { 539 /* set all values the same */ 540 for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++) 541 if (type == MIXER_CTL_TYPE_BYTE) 542 ar->mixer_state[ctl_index].new_value.bytes[i] = value; 543 else if (type == MIXER_CTL_TYPE_ENUM) 544 ar->mixer_state[ctl_index].new_value.enumerated[i] = value; 545 else 546 ar->mixer_state[ctl_index].new_value.integer[i] = value; 547 } 548 } 549 } else { 550 /* nested ctl (within a path) */ 551 mixer_value.ctl_index = ctl_index; 552 mixer_value.value = value; 553 if (attr_id) 554 mixer_value.index = atoi((char *)attr_id); 555 else 556 mixer_value.index = -1; 557 path_add_value(ar, state->path, &mixer_value); 558 } 559 } 560 561 done: 562 state->level++; 563 } 564 565 static void end_tag(void *data, const XML_Char *tag_name) 566 { 567 struct config_parse_state *state = data; 568 (void)tag_name; 569 570 state->level--; 571 } 572 573 static int alloc_mixer_state(struct audio_route *ar) 574 { 575 unsigned int i; 576 unsigned int num_values; 577 struct mixer_ctl *ctl; 578 enum mixer_ctl_type type; 579 580 ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer); 581 ar->mixer_state = calloc(ar->num_mixer_ctls, sizeof(struct mixer_state)); 582 if (!ar->mixer_state) 583 return -1; 584 585 for (i = 0; i < ar->num_mixer_ctls; i++) { 586 ctl = mixer_get_ctl(ar->mixer, i); 587 num_values = mixer_ctl_get_num_values(ctl); 588 589 ar->mixer_state[i].ctl = ctl; 590 ar->mixer_state[i].num_values = num_values; 591 592 /* Skip unsupported types that are not supported yet in XML */ 593 type = mixer_ctl_get_type(ctl); 594 595 if (!is_supported_ctl_type(type)) 596 continue; 597 598 size_t value_sz = sizeof_ctl_type(type); 599 ar->mixer_state[i].old_value.ptr = calloc(num_values, value_sz); 600 ar->mixer_state[i].new_value.ptr = calloc(num_values, value_sz); 601 ar->mixer_state[i].reset_value.ptr = calloc(num_values, value_sz); 602 603 if (type == MIXER_CTL_TYPE_ENUM) 604 ar->mixer_state[i].old_value.enumerated[0] = mixer_ctl_get_value(ctl, 0); 605 else 606 mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value.ptr, num_values); 607 608 memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].old_value.ptr, 609 num_values * value_sz); 610 } 611 612 return 0; 613 } 614 615 static void free_mixer_state(struct audio_route *ar) 616 { 617 unsigned int i; 618 enum mixer_ctl_type type; 619 620 for (i = 0; i < ar->num_mixer_ctls; i++) { 621 type = mixer_ctl_get_type(ar->mixer_state[i].ctl); 622 if (!is_supported_ctl_type(type)) 623 continue; 624 625 free(ar->mixer_state[i].old_value.ptr); 626 free(ar->mixer_state[i].new_value.ptr); 627 free(ar->mixer_state[i].reset_value.ptr); 628 } 629 630 free(ar->mixer_state); 631 ar->mixer_state = NULL; 632 } 633 634 /* Update the mixer with any changed values */ 635 int audio_route_update_mixer(struct audio_route *ar) 636 { 637 unsigned int i; 638 unsigned int j; 639 struct mixer_ctl *ctl; 640 641 for (i = 0; i < ar->num_mixer_ctls; i++) { 642 unsigned int num_values = ar->mixer_state[i].num_values; 643 enum mixer_ctl_type type; 644 645 ctl = ar->mixer_state[i].ctl; 646 647 /* Skip unsupported types */ 648 type = mixer_ctl_get_type(ctl); 649 if (!is_supported_ctl_type(type)) 650 continue; 651 652 /* if the value has changed, update the mixer */ 653 bool changed = false; 654 if (type == MIXER_CTL_TYPE_BYTE) { 655 for (j = 0; j < num_values; j++) { 656 if (ar->mixer_state[i].old_value.bytes[j] != ar->mixer_state[i].new_value.bytes[j]) { 657 changed = true; 658 break; 659 } 660 } 661 } else if (type == MIXER_CTL_TYPE_ENUM) { 662 for (j = 0; j < num_values; j++) { 663 if (ar->mixer_state[i].old_value.enumerated[j] 664 != ar->mixer_state[i].new_value.enumerated[j]) { 665 changed = true; 666 break; 667 } 668 } 669 } else { 670 for (j = 0; j < num_values; j++) { 671 if (ar->mixer_state[i].old_value.integer[j] != ar->mixer_state[i].new_value.integer[j]) { 672 changed = true; 673 break; 674 } 675 } 676 } 677 if (changed) { 678 if (type == MIXER_CTL_TYPE_ENUM) 679 mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value.enumerated[0]); 680 else 681 mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value.ptr, num_values); 682 683 size_t value_sz = sizeof_ctl_type(type); 684 memcpy(ar->mixer_state[i].old_value.ptr, ar->mixer_state[i].new_value.ptr, 685 num_values * value_sz); 686 } 687 } 688 689 return 0; 690 } 691 692 /* saves the current state of the mixer, for resetting all controls */ 693 static void save_mixer_state(struct audio_route *ar) 694 { 695 unsigned int i; 696 enum mixer_ctl_type type; 697 698 for (i = 0; i < ar->num_mixer_ctls; i++) { 699 type = mixer_ctl_get_type(ar->mixer_state[i].ctl); 700 if (!is_supported_ctl_type(type)) 701 continue; 702 703 size_t value_sz = sizeof_ctl_type(type); 704 memcpy(ar->mixer_state[i].reset_value.ptr, ar->mixer_state[i].new_value.ptr, 705 ar->mixer_state[i].num_values * value_sz); 706 } 707 } 708 709 /* Reset the audio routes back to the initial state */ 710 void audio_route_reset(struct audio_route *ar) 711 { 712 unsigned int i; 713 enum mixer_ctl_type type; 714 715 /* load all of the saved values */ 716 for (i = 0; i < ar->num_mixer_ctls; i++) { 717 type = mixer_ctl_get_type(ar->mixer_state[i].ctl); 718 if (!is_supported_ctl_type(type)) 719 continue; 720 721 size_t value_sz = sizeof_ctl_type(type); 722 memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].reset_value.ptr, 723 ar->mixer_state[i].num_values * value_sz); 724 } 725 } 726 727 /* Apply an audio route path by name */ 728 int audio_route_apply_path(struct audio_route *ar, const char *name) 729 { 730 struct mixer_path *path; 731 732 if (!ar) { 733 ALOGE("invalid audio_route"); 734 return -1; 735 } 736 737 path = path_get_by_name(ar, name); 738 if (!path) { 739 ALOGE("unable to find path '%s'", name); 740 return -1; 741 } 742 743 path_apply(ar, path); 744 745 return 0; 746 } 747 748 /* Reset an audio route path by name */ 749 int audio_route_reset_path(struct audio_route *ar, const char *name) 750 { 751 struct mixer_path *path; 752 753 if (!ar) { 754 ALOGE("invalid audio_route"); 755 return -1; 756 } 757 758 path = path_get_by_name(ar, name); 759 if (!path) { 760 ALOGE("unable to find path '%s'", name); 761 return -1; 762 } 763 764 path_reset(ar, path); 765 766 return 0; 767 } 768 769 /* 770 * Operates on the specified path .. controls will be updated in the 771 * order listed in the XML file 772 */ 773 static int audio_route_update_path(struct audio_route *ar, const char *name, bool reverse) 774 { 775 struct mixer_path *path; 776 int32_t i, end; 777 unsigned int j; 778 779 if (!ar) { 780 ALOGE("invalid audio_route"); 781 return -1; 782 } 783 784 path = path_get_by_name(ar, name); 785 if (!path) { 786 ALOGE("unable to find path '%s'", name); 787 return -1; 788 } 789 790 i = reverse ? (path->length - 1) : 0; 791 end = reverse ? -1 : (int32_t)path->length; 792 793 while (i != end) { 794 unsigned int ctl_index; 795 enum mixer_ctl_type type; 796 797 ctl_index = path->setting[i].ctl_index; 798 799 struct mixer_state * ms = &ar->mixer_state[ctl_index]; 800 801 type = mixer_ctl_get_type(ms->ctl); 802 if (!is_supported_ctl_type(type)) { 803 continue; 804 } 805 806 size_t value_sz = sizeof_ctl_type(type); 807 /* if any value has changed, update the mixer */ 808 for (j = 0; j < ms->num_values; j++) { 809 if (type == MIXER_CTL_TYPE_BYTE) { 810 if (ms->old_value.bytes[j] != ms->new_value.bytes[j]) { 811 mixer_ctl_set_array(ms->ctl, ms->new_value.bytes, ms->num_values); 812 memcpy(ms->old_value.bytes, ms->new_value.bytes, ms->num_values * value_sz); 813 break; 814 } 815 } else if (type == MIXER_CTL_TYPE_ENUM) { 816 if (ms->old_value.enumerated[j] != ms->new_value.enumerated[j]) { 817 mixer_ctl_set_value(ms->ctl, 0, ms->new_value.enumerated[0]); 818 memcpy(ms->old_value.enumerated, ms->new_value.enumerated, 819 ms->num_values * value_sz); 820 break; 821 } 822 } else if (ms->old_value.integer[j] != ms->new_value.integer[j]) { 823 mixer_ctl_set_array(ms->ctl, ms->new_value.integer, ms->num_values); 824 memcpy(ms->old_value.integer, ms->new_value.integer, ms->num_values * value_sz); 825 break; 826 } 827 } 828 829 i = reverse ? (i - 1) : (i + 1); 830 } 831 return 0; 832 } 833 834 int audio_route_apply_and_update_path(struct audio_route *ar, const char *name) 835 { 836 if (audio_route_apply_path(ar, name) < 0) { 837 return -1; 838 } 839 return audio_route_update_path(ar, name, false /*reverse*/); 840 } 841 842 int audio_route_reset_and_update_path(struct audio_route *ar, const char *name) 843 { 844 if (audio_route_reset_path(ar, name) < 0) { 845 return -1; 846 } 847 return audio_route_update_path(ar, name, true /*reverse*/); 848 } 849 850 struct audio_route *audio_route_init(unsigned int card, const char *xml_path) 851 { 852 struct config_parse_state state; 853 XML_Parser parser; 854 FILE *file; 855 int bytes_read; 856 void *buf; 857 struct audio_route *ar; 858 859 ar = calloc(1, sizeof(struct audio_route)); 860 if (!ar) 861 goto err_calloc; 862 863 ar->mixer = mixer_open(card); 864 if (!ar->mixer) { 865 ALOGE("Unable to open the mixer, aborting."); 866 goto err_mixer_open; 867 } 868 869 ar->mixer_path = NULL; 870 ar->mixer_path_size = 0; 871 ar->num_mixer_paths = 0; 872 873 /* allocate space for and read current mixer settings */ 874 if (alloc_mixer_state(ar) < 0) 875 goto err_mixer_state; 876 877 /* use the default XML path if none is provided */ 878 if (xml_path == NULL) 879 xml_path = MIXER_XML_PATH; 880 881 file = fopen(xml_path, "r"); 882 883 if (!file) { 884 ALOGE("Failed to open %s: %s", xml_path, strerror(errno)); 885 goto err_fopen; 886 } 887 888 parser = XML_ParserCreate(NULL); 889 if (!parser) { 890 ALOGE("Failed to create XML parser"); 891 goto err_parser_create; 892 } 893 894 memset(&state, 0, sizeof(state)); 895 state.ar = ar; 896 XML_SetUserData(parser, &state); 897 XML_SetElementHandler(parser, start_tag, end_tag); 898 899 for (;;) { 900 buf = XML_GetBuffer(parser, BUF_SIZE); 901 if (buf == NULL) 902 goto err_parse; 903 904 bytes_read = fread(buf, 1, BUF_SIZE, file); 905 if (bytes_read < 0) 906 goto err_parse; 907 908 if (XML_ParseBuffer(parser, bytes_read, 909 bytes_read == 0) == XML_STATUS_ERROR) { 910 ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH); 911 goto err_parse; 912 } 913 914 if (bytes_read == 0) 915 break; 916 } 917 918 /* apply the initial mixer values, and save them so we can reset the 919 mixer to the original values */ 920 audio_route_update_mixer(ar); 921 save_mixer_state(ar); 922 923 XML_ParserFree(parser); 924 fclose(file); 925 return ar; 926 927 err_parse: 928 path_free(ar); 929 XML_ParserFree(parser); 930 err_parser_create: 931 fclose(file); 932 err_fopen: 933 free_mixer_state(ar); 934 err_mixer_state: 935 mixer_close(ar->mixer); 936 err_mixer_open: 937 free(ar); 938 ar = NULL; 939 err_calloc: 940 return NULL; 941 } 942 943 void audio_route_free(struct audio_route *ar) 944 { 945 free_mixer_state(ar); 946 mixer_close(ar->mixer); 947 path_free(ar); 948 free(ar); 949 } 950