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