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 struct mixer_state { 36 struct mixer_ctl *ctl; 37 unsigned int num_values; 38 int *old_value; 39 int *new_value; 40 int *reset_value; 41 }; 42 43 struct mixer_setting { 44 unsigned int ctl_index; 45 unsigned int num_values; 46 int *value; 47 }; 48 49 struct mixer_value { 50 unsigned int ctl_index; 51 int index; 52 int value; 53 }; 54 55 struct mixer_path { 56 char *name; 57 unsigned int size; 58 unsigned int length; 59 struct mixer_setting *setting; 60 }; 61 62 struct audio_route { 63 struct mixer *mixer; 64 unsigned int num_mixer_ctls; 65 struct mixer_state *mixer_state; 66 67 unsigned int mixer_path_size; 68 unsigned int num_mixer_paths; 69 struct mixer_path *mixer_path; 70 }; 71 72 struct config_parse_state { 73 struct audio_route *ar; 74 struct mixer_path *path; 75 int level; 76 }; 77 78 /* path functions */ 79 80 static inline struct mixer_ctl *index_to_ctl(struct audio_route *ar, 81 unsigned int ctl_index) 82 { 83 return ar->mixer_state[ctl_index].ctl; 84 } 85 86 static void path_print(struct audio_route *ar, struct mixer_path *path) 87 { 88 unsigned int i; 89 unsigned int j; 90 91 ALOGE("Path: %s, length: %d", path->name, path->length); 92 for (i = 0; i < path->length; i++) { 93 struct mixer_ctl *ctl = index_to_ctl(ar, path->setting[i].ctl_index); 94 95 ALOGE(" id=%d: ctl=%s", i, mixer_ctl_get_name(ctl)); 96 for (j = 0; j < path->setting[i].num_values; j++) 97 ALOGE(" id=%d value=%d", j, path->setting[i].value[j]); 98 } 99 } 100 101 static void path_free(struct audio_route *ar) 102 { 103 unsigned int i; 104 105 for (i = 0; i < ar->num_mixer_paths; i++) { 106 if (ar->mixer_path[i].name) 107 free(ar->mixer_path[i].name); 108 if (ar->mixer_path[i].setting) { 109 if (ar->mixer_path[i].setting->value) 110 free(ar->mixer_path[i].setting->value); 111 free(ar->mixer_path[i].setting); 112 } 113 } 114 free(ar->mixer_path); 115 } 116 117 static struct mixer_path *path_get_by_name(struct audio_route *ar, 118 const char *name) 119 { 120 unsigned int i; 121 122 for (i = 0; i < ar->num_mixer_paths; i++) 123 if (strcmp(ar->mixer_path[i].name, name) == 0) 124 return &ar->mixer_path[i]; 125 126 return NULL; 127 } 128 129 static struct mixer_path *path_create(struct audio_route *ar, const char *name) 130 { 131 struct mixer_path *new_mixer_path = NULL; 132 133 if (path_get_by_name(ar, name)) { 134 ALOGE("Path name '%s' already exists", name); 135 return NULL; 136 } 137 138 /* check if we need to allocate more space for mixer paths */ 139 if (ar->mixer_path_size <= ar->num_mixer_paths) { 140 if (ar->mixer_path_size == 0) 141 ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE; 142 else 143 ar->mixer_path_size *= 2; 144 145 new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size * 146 sizeof(struct mixer_path)); 147 if (new_mixer_path == NULL) { 148 ALOGE("Unable to allocate more paths"); 149 return NULL; 150 } else { 151 ar->mixer_path = new_mixer_path; 152 } 153 } 154 155 /* initialise the new mixer path */ 156 ar->mixer_path[ar->num_mixer_paths].name = strdup(name); 157 ar->mixer_path[ar->num_mixer_paths].size = 0; 158 ar->mixer_path[ar->num_mixer_paths].length = 0; 159 ar->mixer_path[ar->num_mixer_paths].setting = NULL; 160 161 /* return the mixer path just added, then increment number of them */ 162 return &ar->mixer_path[ar->num_mixer_paths++]; 163 } 164 165 static int find_ctl_index_in_path(struct mixer_path *path, 166 unsigned int ctl_index) 167 { 168 unsigned int i; 169 170 for (i = 0; i < path->length; i++) 171 if (path->setting[i].ctl_index == ctl_index) 172 return i; 173 174 return -1; 175 } 176 177 static int alloc_path_setting(struct mixer_path *path) 178 { 179 struct mixer_setting *new_path_setting; 180 int path_index; 181 182 /* check if we need to allocate more space for path settings */ 183 if (path->size <= path->length) { 184 if (path->size == 0) 185 path->size = INITIAL_MIXER_PATH_SIZE; 186 else 187 path->size *= 2; 188 189 new_path_setting = realloc(path->setting, 190 path->size * sizeof(struct mixer_setting)); 191 if (new_path_setting == NULL) { 192 ALOGE("Unable to allocate more path settings"); 193 return -1; 194 } else { 195 path->setting = new_path_setting; 196 } 197 } 198 199 path_index = path->length; 200 path->length++; 201 202 return path_index; 203 } 204 205 static int path_add_setting(struct audio_route *ar, struct mixer_path *path, 206 struct mixer_setting *setting) 207 { 208 int path_index; 209 210 if (find_ctl_index_in_path(path, setting->ctl_index) != -1) { 211 struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index); 212 213 ALOGE("Control '%s' already exists in path '%s'", 214 mixer_ctl_get_name(ctl), path->name); 215 return -1; 216 } 217 218 path_index = alloc_path_setting(path); 219 if (path_index < 0) 220 return -1; 221 222 path->setting[path_index].ctl_index = setting->ctl_index; 223 path->setting[path_index].num_values = setting->num_values; 224 path->setting[path_index].value = malloc(setting->num_values * sizeof(int)); 225 /* copy all values */ 226 memcpy(path->setting[path_index].value, setting->value, 227 setting->num_values * sizeof(int)); 228 229 return 0; 230 } 231 232 static int path_add_value(struct audio_route *ar, struct mixer_path *path, 233 struct mixer_value *mixer_value) 234 { 235 unsigned int i; 236 int path_index; 237 unsigned int num_values; 238 struct mixer_ctl *ctl; 239 240 /* Check that mixer value index is within range */ 241 ctl = index_to_ctl(ar, mixer_value->ctl_index); 242 num_values = mixer_ctl_get_num_values(ctl); 243 if (mixer_value->index >= (int)num_values) { 244 ALOGE("mixer index %d is out of range for '%s'", mixer_value->index, 245 mixer_ctl_get_name(ctl)); 246 return -1; 247 } 248 249 path_index = find_ctl_index_in_path(path, mixer_value->ctl_index); 250 if (path_index < 0) { 251 /* New path */ 252 253 path_index = alloc_path_setting(path); 254 if (path_index < 0) 255 return -1; 256 257 /* initialise the new path setting */ 258 path->setting[path_index].ctl_index = mixer_value->ctl_index; 259 path->setting[path_index].num_values = num_values; 260 path->setting[path_index].value = malloc(num_values * sizeof(int)); 261 path->setting[path_index].value[0] = mixer_value->value; 262 } 263 264 if (mixer_value->index == -1) { 265 /* set all values the same */ 266 for (i = 0; i < num_values; i++) 267 path->setting[path_index].value[i] = mixer_value->value; 268 } else { 269 /* set only one value */ 270 path->setting[path_index].value[mixer_value->index] = mixer_value->value; 271 } 272 273 return 0; 274 } 275 276 static int path_add_path(struct audio_route *ar, struct mixer_path *path, 277 struct mixer_path *sub_path) 278 { 279 unsigned int i; 280 281 for (i = 0; i < sub_path->length; i++) 282 if (path_add_setting(ar, path, &sub_path->setting[i]) < 0) 283 return -1; 284 285 return 0; 286 } 287 288 static int path_apply(struct audio_route *ar, struct mixer_path *path) 289 { 290 unsigned int i; 291 unsigned int ctl_index; 292 293 for (i = 0; i < path->length; i++) { 294 ctl_index = path->setting[i].ctl_index; 295 296 /* apply the new value(s) */ 297 memcpy(ar->mixer_state[ctl_index].new_value, path->setting[i].value, 298 path->setting[i].num_values * sizeof(int)); 299 } 300 301 return 0; 302 } 303 304 static int path_reset(struct audio_route *ar, struct mixer_path *path) 305 { 306 unsigned int i; 307 unsigned int j; 308 unsigned int ctl_index; 309 310 for (i = 0; i < path->length; i++) { 311 ctl_index = path->setting[i].ctl_index; 312 313 /* reset the value(s) */ 314 memcpy(ar->mixer_state[ctl_index].new_value, 315 ar->mixer_state[ctl_index].reset_value, 316 ar->mixer_state[ctl_index].num_values * sizeof(int)); 317 } 318 319 return 0; 320 } 321 322 /* mixer helper function */ 323 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string) 324 { 325 unsigned int i; 326 327 /* Search the enum strings for a particular one */ 328 for (i = 0; i < mixer_ctl_get_num_enums(ctl); i++) { 329 if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0) 330 break; 331 } 332 333 return i; 334 } 335 336 static void start_tag(void *data, const XML_Char *tag_name, 337 const XML_Char **attr) 338 { 339 const XML_Char *attr_name = NULL; 340 const XML_Char *attr_id = NULL; 341 const XML_Char *attr_value = NULL; 342 struct config_parse_state *state = data; 343 struct audio_route *ar = state->ar; 344 unsigned int i; 345 unsigned int ctl_index; 346 struct mixer_ctl *ctl; 347 int value; 348 unsigned int id; 349 struct mixer_value mixer_value; 350 351 /* Get name, id and value attributes (these may be empty) */ 352 for (i = 0; attr[i]; i += 2) { 353 if (strcmp(attr[i], "name") == 0) 354 attr_name = attr[i + 1]; 355 if (strcmp(attr[i], "id") == 0) 356 attr_id = attr[i + 1]; 357 else if (strcmp(attr[i], "value") == 0) 358 attr_value = attr[i + 1]; 359 } 360 361 /* Look at tags */ 362 if (strcmp(tag_name, "path") == 0) { 363 if (attr_name == NULL) { 364 ALOGE("Unnamed path!"); 365 } else { 366 if (state->level == 1) { 367 /* top level path: create and stash the path */ 368 state->path = path_create(ar, (char *)attr_name); 369 } else { 370 /* nested path */ 371 struct mixer_path *sub_path = path_get_by_name(ar, attr_name); 372 path_add_path(ar, state->path, sub_path); 373 } 374 } 375 } 376 377 else if (strcmp(tag_name, "ctl") == 0) { 378 /* Obtain the mixer ctl and value */ 379 ctl = mixer_get_ctl_by_name(ar->mixer, attr_name); 380 if (ctl == NULL) { 381 ALOGE("Control '%s' doesn't exist - skipping", attr_name); 382 goto done; 383 } 384 385 switch (mixer_ctl_get_type(ctl)) { 386 case MIXER_CTL_TYPE_BOOL: 387 case MIXER_CTL_TYPE_INT: 388 value = atoi((char *)attr_value); 389 break; 390 case MIXER_CTL_TYPE_ENUM: 391 value = mixer_enum_string_to_value(ctl, (char *)attr_value); 392 break; 393 default: 394 value = 0; 395 break; 396 } 397 398 /* locate the mixer ctl in the list */ 399 for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) { 400 if (ar->mixer_state[ctl_index].ctl == ctl) 401 break; 402 } 403 404 if (state->level == 1) { 405 /* top level ctl (initial setting) */ 406 407 /* apply the new value */ 408 if (attr_id) { 409 /* set only one value */ 410 id = atoi((char *)attr_id); 411 if (id < ar->mixer_state[ctl_index].num_values) 412 ar->mixer_state[ctl_index].new_value[id] = value; 413 else 414 ALOGE("value id out of range for mixer ctl '%s'", 415 mixer_ctl_get_name(ctl)); 416 } else { 417 /* set all values the same */ 418 for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++) 419 ar->mixer_state[ctl_index].new_value[i] = value; 420 } 421 } else { 422 /* nested ctl (within a path) */ 423 mixer_value.ctl_index = ctl_index; 424 mixer_value.value = value; 425 if (attr_id) 426 mixer_value.index = atoi((char *)attr_id); 427 else 428 mixer_value.index = -1; 429 path_add_value(ar, state->path, &mixer_value); 430 } 431 } 432 433 done: 434 state->level++; 435 } 436 437 static void end_tag(void *data, const XML_Char *tag_name) 438 { 439 struct config_parse_state *state = data; 440 441 state->level--; 442 } 443 444 static int alloc_mixer_state(struct audio_route *ar) 445 { 446 unsigned int i; 447 unsigned int j; 448 unsigned int num_values; 449 struct mixer_ctl *ctl; 450 enum mixer_ctl_type type; 451 452 ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer); 453 ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state)); 454 if (!ar->mixer_state) 455 return -1; 456 457 for (i = 0; i < ar->num_mixer_ctls; i++) { 458 ctl = mixer_get_ctl(ar->mixer, i); 459 num_values = mixer_ctl_get_num_values(ctl); 460 461 ar->mixer_state[i].ctl = ctl; 462 ar->mixer_state[i].num_values = num_values; 463 464 /* Skip unsupported types that are not supported yet in XML */ 465 type = mixer_ctl_get_type(ctl); 466 if ((type != MIXER_CTL_TYPE_BOOL) && (type != MIXER_CTL_TYPE_INT) && 467 (type != MIXER_CTL_TYPE_ENUM)) 468 continue; 469 470 ar->mixer_state[i].old_value = malloc(num_values * sizeof(int)); 471 ar->mixer_state[i].new_value = malloc(num_values * sizeof(int)); 472 ar->mixer_state[i].reset_value = malloc(num_values * sizeof(int)); 473 474 if (type == MIXER_CTL_TYPE_ENUM) 475 ar->mixer_state[i].old_value[0] = mixer_ctl_get_value(ctl, 0); 476 else 477 mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value, num_values); 478 memcpy(ar->mixer_state[i].new_value, ar->mixer_state[i].old_value, 479 num_values * sizeof(int)); 480 } 481 482 return 0; 483 } 484 485 static void free_mixer_state(struct audio_route *ar) 486 { 487 unsigned int i; 488 489 for (i = 0; i < ar->num_mixer_ctls; i++) { 490 free(ar->mixer_state[i].old_value); 491 free(ar->mixer_state[i].new_value); 492 free(ar->mixer_state[i].reset_value); 493 } 494 495 free(ar->mixer_state); 496 ar->mixer_state = NULL; 497 } 498 499 /* Update the mixer with any changed values */ 500 int audio_route_update_mixer(struct audio_route *ar) 501 { 502 unsigned int i; 503 unsigned int j; 504 struct mixer_ctl *ctl; 505 506 for (i = 0; i < ar->num_mixer_ctls; i++) { 507 unsigned int num_values = ar->mixer_state[i].num_values; 508 enum mixer_ctl_type type; 509 510 ctl = ar->mixer_state[i].ctl; 511 512 /* Skip unsupported types */ 513 type = mixer_ctl_get_type(ctl); 514 if ((type != MIXER_CTL_TYPE_BOOL) && (type != MIXER_CTL_TYPE_INT) && 515 (type != MIXER_CTL_TYPE_ENUM)) 516 continue; 517 518 /* if the value has changed, update the mixer */ 519 bool changed = false; 520 for (j = 0; j < num_values; j++) { 521 if (ar->mixer_state[i].old_value[j] != ar->mixer_state[i].new_value[j]) { 522 changed = true; 523 break; 524 } 525 } 526 if (changed) { 527 if (type == MIXER_CTL_TYPE_ENUM) 528 mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value[0]); 529 else 530 mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value, num_values); 531 memcpy(ar->mixer_state[i].old_value, ar->mixer_state[i].new_value, 532 num_values * sizeof(int)); 533 } 534 } 535 536 return 0; 537 } 538 539 /* saves the current state of the mixer, for resetting all controls */ 540 static void save_mixer_state(struct audio_route *ar) 541 { 542 unsigned int i; 543 544 for (i = 0; i < ar->num_mixer_ctls; i++) { 545 memcpy(ar->mixer_state[i].reset_value, ar->mixer_state[i].new_value, 546 ar->mixer_state[i].num_values * sizeof(int)); 547 } 548 } 549 550 /* Reset the audio routes back to the initial state */ 551 void audio_route_reset(struct audio_route *ar) 552 { 553 unsigned int i; 554 555 /* load all of the saved values */ 556 for (i = 0; i < ar->num_mixer_ctls; i++) { 557 memcpy(ar->mixer_state[i].new_value, ar->mixer_state[i].reset_value, 558 ar->mixer_state[i].num_values * sizeof(int)); 559 } 560 } 561 562 /* Apply an audio route path by name */ 563 int audio_route_apply_path(struct audio_route *ar, const char *name) 564 { 565 struct mixer_path *path; 566 567 if (!ar) { 568 ALOGE("invalid audio_route"); 569 return -1; 570 } 571 572 path = path_get_by_name(ar, name); 573 if (!path) { 574 ALOGE("unable to find path '%s'", name); 575 return -1; 576 } 577 578 path_apply(ar, path); 579 580 return 0; 581 } 582 583 /* Reset an audio route path by name */ 584 int audio_route_reset_path(struct audio_route *ar, const char *name) 585 { 586 struct mixer_path *path; 587 588 if (!ar) { 589 ALOGE("invalid audio_route"); 590 return -1; 591 } 592 593 path = path_get_by_name(ar, name); 594 if (!path) { 595 ALOGE("unable to find path '%s'", name); 596 return -1; 597 } 598 599 path_reset(ar, path); 600 601 return 0; 602 } 603 604 struct audio_route *audio_route_init(unsigned int card, const char *xml_path) 605 { 606 struct config_parse_state state; 607 XML_Parser parser; 608 FILE *file; 609 int bytes_read; 610 void *buf; 611 int i; 612 struct audio_route *ar; 613 614 ar = calloc(1, sizeof(struct audio_route)); 615 if (!ar) 616 goto err_calloc; 617 618 ar->mixer = mixer_open(card); 619 if (!ar->mixer) { 620 ALOGE("Unable to open the mixer, aborting."); 621 goto err_mixer_open; 622 } 623 624 ar->mixer_path = NULL; 625 ar->mixer_path_size = 0; 626 ar->num_mixer_paths = 0; 627 628 /* allocate space for and read current mixer settings */ 629 if (alloc_mixer_state(ar) < 0) 630 goto err_mixer_state; 631 632 /* use the default XML path if none is provided */ 633 if (xml_path == NULL) 634 xml_path = MIXER_XML_PATH; 635 636 file = fopen(xml_path, "r"); 637 638 if (!file) { 639 ALOGE("Failed to open %s", xml_path); 640 goto err_fopen; 641 } 642 643 parser = XML_ParserCreate(NULL); 644 if (!parser) { 645 ALOGE("Failed to create XML parser"); 646 goto err_parser_create; 647 } 648 649 memset(&state, 0, sizeof(state)); 650 state.ar = ar; 651 XML_SetUserData(parser, &state); 652 XML_SetElementHandler(parser, start_tag, end_tag); 653 654 for (;;) { 655 buf = XML_GetBuffer(parser, BUF_SIZE); 656 if (buf == NULL) 657 goto err_parse; 658 659 bytes_read = fread(buf, 1, BUF_SIZE, file); 660 if (bytes_read < 0) 661 goto err_parse; 662 663 if (XML_ParseBuffer(parser, bytes_read, 664 bytes_read == 0) == XML_STATUS_ERROR) { 665 ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH); 666 goto err_parse; 667 } 668 669 if (bytes_read == 0) 670 break; 671 } 672 673 /* apply the initial mixer values, and save them so we can reset the 674 mixer to the original values */ 675 audio_route_update_mixer(ar); 676 save_mixer_state(ar); 677 678 XML_ParserFree(parser); 679 fclose(file); 680 return ar; 681 682 err_parse: 683 XML_ParserFree(parser); 684 err_parser_create: 685 fclose(file); 686 err_fopen: 687 free_mixer_state(ar); 688 err_mixer_state: 689 mixer_close(ar->mixer); 690 err_mixer_open: 691 free(ar); 692 ar = NULL; 693 err_calloc: 694 return NULL; 695 } 696 697 void audio_route_free(struct audio_route *ar) 698 { 699 free_mixer_state(ar); 700 mixer_close(ar->mixer); 701 free(ar); 702 } 703