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