1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "audio_hw_acdb" 18 //#define LOG_NDEBUG 0 19 #define LOG_NDDEBUG 0 20 21 #include <stdlib.h> 22 #include <stdbool.h> 23 #include <dlfcn.h> 24 #include <cutils/log.h> 25 #include <cutils/str_parms.h> 26 #include <system/audio.h> 27 #include <tinyalsa/asoundlib.h> 28 #include "acdb.h" 29 #include <platform_api.h> 30 31 #define PLATFORM_CONFIG_KEY_SOUNDCARD_NAME "snd_card_name" 32 33 int acdb_init(int snd_card_num) 34 { 35 36 int result = -1; 37 char *cvd_version = NULL; 38 39 char *snd_card_name = NULL; 40 struct mixer *mixer = NULL; 41 struct acdb_platform_data *my_data = NULL; 42 43 if(snd_card_num < 0) { 44 ALOGE("invalid sound card number"); 45 return result; 46 } 47 48 mixer = mixer_open(snd_card_num); 49 if (!mixer) { 50 ALOGE("%s: Unable to open the mixer card: %d", __func__, 51 snd_card_num); 52 goto cleanup; 53 } 54 55 my_data = calloc(1, sizeof(struct acdb_platform_data)); 56 if (!my_data) { 57 ALOGE("failed to allocate acdb platform data"); 58 goto cleanup; 59 } 60 61 list_init(&my_data->acdb_meta_key_list); 62 63 my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW); 64 if (my_data->acdb_handle == NULL) { 65 ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER); 66 goto cleanup; 67 } 68 69 ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER); 70 71 my_data->acdb_init_v3 = (acdb_init_v3_t)dlsym(my_data->acdb_handle, 72 "acdb_loader_init_v3"); 73 if (my_data->acdb_init_v3 == NULL) 74 ALOGE("%s: dlsym error %s for acdb_loader_init_v3", __func__, dlerror()); 75 76 my_data->acdb_init_v2 = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle, 77 "acdb_loader_init_v2"); 78 if (my_data->acdb_init_v2 == NULL) 79 ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror()); 80 81 my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle, 82 "acdb_loader_init_ACDB"); 83 if (my_data->acdb_init == NULL && my_data->acdb_init_v2 == NULL 84 && my_data->acdb_init_v3 == NULL) { 85 ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror()); 86 goto cleanup; 87 } 88 89 /* Get CVD version */ 90 cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE); 91 if (!cvd_version) { 92 ALOGE("%s: Failed to allocate cvd version", __func__); 93 goto cleanup; 94 } else { 95 struct mixer_ctl *ctl = NULL; 96 int count = 0; 97 98 ctl = mixer_get_ctl_by_name(mixer, CVD_VERSION_MIXER_CTL); 99 if (!ctl) { 100 ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__, CVD_VERSION_MIXER_CTL); 101 goto cleanup; 102 } 103 mixer_ctl_update(ctl); 104 105 count = mixer_ctl_get_num_values(ctl); 106 if (count > MAX_CVD_VERSION_STRING_SIZE) 107 count = MAX_CVD_VERSION_STRING_SIZE; 108 109 result = mixer_ctl_get_array(ctl, cvd_version, count); 110 if (result != 0) { 111 ALOGE("%s: ERROR! mixer_ctl_get_array() failed to get CVD Version", __func__); 112 goto cleanup; 113 } 114 } 115 116 /* Get Sound card name */ 117 snd_card_name = strdup(mixer_get_name(mixer)); 118 if (!snd_card_name) { 119 ALOGE("failed to allocate memory for snd_card_name"); 120 result = -1; 121 goto cleanup; 122 } 123 124 if (my_data->acdb_init_v3) 125 result = my_data->acdb_init_v3(snd_card_name, cvd_version, 126 &my_data->acdb_meta_key_list); 127 else if (my_data->acdb_init_v2) 128 result = my_data->acdb_init_v2(snd_card_name, cvd_version, 0); 129 else 130 result = my_data->acdb_init(); 131 132 cleanup: 133 if (NULL != my_data) { 134 if (my_data->acdb_handle) 135 dlclose(my_data->acdb_handle); 136 137 struct listnode *node; 138 struct meta_key_list *key_info; 139 list_for_each(node, &my_data->acdb_meta_key_list) { 140 key_info = node_to_item(node, struct meta_key_list, list); 141 free(key_info); 142 } 143 free(my_data); 144 } 145 146 mixer_close(mixer); 147 free(cvd_version); 148 free(snd_card_name); 149 150 return result; 151 } 152 153 int acdb_set_parameters(void *platform, struct str_parms *parms) 154 { 155 struct acdb_platform_data *my_data = (struct acdb_platform_data *)platform; 156 char value[128]; 157 char *kv_pairs = str_parms_to_str(parms); 158 int ret = 0; 159 160 if (kv_pairs == NULL) { 161 ret = -EINVAL; 162 ALOGE("%s: key-value pair is NULL",__func__); 163 goto done; 164 } 165 166 ret = str_parms_get_str(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME, 167 value, sizeof(value)); 168 if (ret >= 0) { 169 str_parms_del(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME); 170 my_data->snd_card_name = strdup(value); 171 ALOGV("%s: sound card name %s", __func__, my_data->snd_card_name); 172 } 173 174 done: 175 free(kv_pairs); 176 177 return ret; 178 } 179