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