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