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