1 /* 2 * Copyright (C) 2014 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_hfp" 18 /*#define LOG_NDEBUG 0*/ 19 #define LOG_NDDEBUG 0 20 21 #include <errno.h> 22 #include <math.h> 23 #include <cutils/log.h> 24 25 #include "audio_hw.h" 26 #include "platform.h" 27 #include "platform_api.h" 28 #include <stdlib.h> 29 #include <cutils/str_parms.h> 30 31 #define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable" 32 #define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate" 33 #define AUDIO_PARAMETER_KEY_HFP_VOLUME "hfp_volume" 34 35 static int32_t start_hfp(struct audio_device *adev, 36 struct str_parms *parms); 37 38 static int32_t stop_hfp(struct audio_device *adev); 39 40 struct hfp_module { 41 struct pcm *hfp_sco_rx; 42 struct pcm *hfp_sco_tx; 43 struct pcm *hfp_pcm_rx; 44 struct pcm *hfp_pcm_tx; 45 float hfp_volume; 46 bool is_hfp_running; 47 audio_usecase_t ucid; 48 }; 49 50 static struct hfp_module hfpmod = { 51 .hfp_sco_rx = NULL, 52 .hfp_sco_tx = NULL, 53 .hfp_pcm_rx = NULL, 54 .hfp_pcm_tx = NULL, 55 .hfp_volume = 0, 56 .is_hfp_running = 0, 57 .ucid = USECASE_AUDIO_HFP_SCO, 58 }; 59 static struct pcm_config pcm_config_hfp = { 60 .channels = 1, 61 .rate = 8000, 62 .period_size = 240, 63 .period_count = 2, 64 .format = PCM_FORMAT_S16_LE, 65 .start_threshold = 0, 66 .stop_threshold = INT_MAX, 67 .avail_min = 0, 68 }; 69 70 static int32_t hfp_set_volume(struct audio_device *adev, float value) 71 { 72 int32_t vol, ret = 0; 73 struct mixer_ctl *ctl; 74 const char *mixer_ctl_name = "Internal HFP RX Volume"; 75 76 ALOGV("%s: entry", __func__); 77 ALOGD("%s: (%f)\n", __func__, value); 78 79 if (value < 0.0) { 80 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value); 81 value = 0.0; 82 } else { 83 value = ((value > 15.000000) ? 1.0 : (value / 15)); 84 ALOGW("%s: Volume brought with in range (%f)\n", __func__, value); 85 } 86 vol = lrint((value * 0x2000) + 0.5); 87 hfpmod.hfp_volume = value; 88 89 if (!hfpmod.is_hfp_running) { 90 ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__); 91 return -EIO; 92 } 93 94 ALOGD("%s: Setting HFP volume to %d \n", __func__, vol); 95 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); 96 if (!ctl) { 97 ALOGE("%s: Could not get ctl for mixer cmd - %s", 98 __func__, mixer_ctl_name); 99 return -EINVAL; 100 } 101 if(mixer_ctl_set_value(ctl, 0, vol) < 0) { 102 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol); 103 return -EINVAL; 104 } 105 106 ALOGV("%s: exit", __func__); 107 return ret; 108 } 109 110 static int32_t start_hfp(struct audio_device *adev, 111 struct str_parms *parms __unused) 112 { 113 int32_t i, ret = 0; 114 struct audio_usecase *uc_info; 115 int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id; 116 117 ALOGD("%s: enter", __func__); 118 119 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); 120 uc_info->id = hfpmod.ucid; 121 uc_info->type = PCM_HFP_CALL; 122 uc_info->stream.out = adev->primary_output; 123 uc_info->devices = adev->primary_output->devices; 124 uc_info->in_snd_device = SND_DEVICE_NONE; 125 uc_info->out_snd_device = SND_DEVICE_NONE; 126 127 list_add_tail(&adev->usecase_list, &uc_info->list); 128 129 select_devices(adev, hfpmod.ucid); 130 131 pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); 132 pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); 133 pcm_dev_asm_rx_id = HFP_ASM_RX_TX; 134 pcm_dev_asm_tx_id = HFP_ASM_RX_TX; 135 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 || 136 pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) { 137 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)", 138 __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id); 139 ret = -EIO; 140 goto exit; 141 } 142 143 ALOGV("%s: HFP PCM devices (hfp rx tx: %d pcm rx tx: %d) for the usecase(%d)", 144 __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id); 145 146 ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)", 147 __func__, adev->snd_card, pcm_dev_rx_id); 148 hfpmod.hfp_sco_rx = pcm_open(adev->snd_card, 149 pcm_dev_asm_rx_id, 150 PCM_OUT, &pcm_config_hfp); 151 if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) { 152 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx)); 153 ret = -EIO; 154 goto exit; 155 } 156 ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)", 157 __func__, adev->snd_card, pcm_dev_tx_id); 158 hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card, 159 pcm_dev_rx_id, 160 PCM_OUT, &pcm_config_hfp); 161 if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) { 162 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx)); 163 ret = -EIO; 164 goto exit; 165 } 166 hfpmod.hfp_sco_tx = pcm_open(adev->snd_card, 167 pcm_dev_asm_tx_id, 168 PCM_IN, &pcm_config_hfp); 169 if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) { 170 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx)); 171 ret = -EIO; 172 goto exit; 173 } 174 ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)", 175 __func__, adev->snd_card, pcm_dev_tx_id); 176 hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card, 177 pcm_dev_tx_id, 178 PCM_IN, &pcm_config_hfp); 179 if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) { 180 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx)); 181 ret = -EIO; 182 goto exit; 183 } 184 pcm_start(hfpmod.hfp_sco_rx); 185 pcm_start(hfpmod.hfp_sco_tx); 186 pcm_start(hfpmod.hfp_pcm_rx); 187 pcm_start(hfpmod.hfp_pcm_tx); 188 189 hfpmod.is_hfp_running = true; 190 hfp_set_volume(adev, hfpmod.hfp_volume); 191 192 ALOGD("%s: exit: status(%d)", __func__, ret); 193 return 0; 194 195 exit: 196 stop_hfp(adev); 197 ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret); 198 return ret; 199 } 200 201 static int32_t stop_hfp(struct audio_device *adev) 202 { 203 int32_t i, ret = 0; 204 struct audio_usecase *uc_info; 205 206 ALOGD("%s: enter", __func__); 207 hfpmod.is_hfp_running = false; 208 209 /* 1. Close the PCM devices */ 210 if (hfpmod.hfp_sco_rx) { 211 pcm_close(hfpmod.hfp_sco_rx); 212 hfpmod.hfp_sco_rx = NULL; 213 } 214 if (hfpmod.hfp_sco_tx) { 215 pcm_close(hfpmod.hfp_sco_tx); 216 hfpmod.hfp_sco_tx = NULL; 217 } 218 if (hfpmod.hfp_pcm_rx) { 219 pcm_close(hfpmod.hfp_pcm_rx); 220 hfpmod.hfp_pcm_rx = NULL; 221 } 222 if (hfpmod.hfp_pcm_tx) { 223 pcm_close(hfpmod.hfp_pcm_tx); 224 hfpmod.hfp_pcm_tx = NULL; 225 } 226 227 uc_info = get_usecase_from_list(adev, hfpmod.ucid); 228 if (uc_info == NULL) { 229 ALOGE("%s: Could not find the usecase (%d) in the list", 230 __func__, hfpmod.ucid); 231 return -EINVAL; 232 } 233 234 /* 2. Get and set stream specific mixer controls */ 235 disable_audio_route(adev, uc_info); 236 237 /* 3. Disable the rx and tx devices */ 238 disable_snd_device(adev, uc_info->out_snd_device); 239 disable_snd_device(adev, uc_info->in_snd_device); 240 241 list_remove(&uc_info->list); 242 free(uc_info); 243 244 ALOGD("%s: exit: status(%d)", __func__, ret); 245 return ret; 246 } 247 248 bool audio_extn_hfp_is_active(struct audio_device *adev) 249 { 250 struct audio_usecase *hfp_usecase = NULL; 251 hfp_usecase = get_usecase_from_list(adev, hfpmod.ucid); 252 253 if (hfp_usecase != NULL) 254 return true; 255 else 256 return false; 257 } 258 259 audio_usecase_t audio_extn_hfp_get_usecase() 260 { 261 return hfpmod.ucid; 262 } 263 264 void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms) 265 { 266 int ret; 267 int rate; 268 int val; 269 float vol; 270 char value[32]={0}; 271 272 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value, 273 sizeof(value)); 274 if (ret >= 0) { 275 if (!strncmp(value,"true",sizeof(value))) 276 ret = start_hfp(adev,parms); 277 else 278 stop_hfp(adev); 279 } 280 memset(value, 0, sizeof(value)); 281 ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value, 282 sizeof(value)); 283 if (ret >= 0) { 284 rate = atoi(value); 285 if (rate == 8000){ 286 hfpmod.ucid = USECASE_AUDIO_HFP_SCO; 287 pcm_config_hfp.rate = rate; 288 } else if (rate == 16000){ 289 hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB; 290 pcm_config_hfp.rate = rate; 291 } else 292 ALOGE("Unsupported rate.."); 293 } 294 295 if (hfpmod.is_hfp_running) { 296 memset(value, 0, sizeof(value)); 297 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, 298 value, sizeof(value)); 299 if (ret >= 0) { 300 val = atoi(value); 301 if (val > 0) 302 select_devices(adev, hfpmod.ucid); 303 } 304 } 305 306 memset(value, 0, sizeof(value)); 307 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME, 308 value, sizeof(value)); 309 if (ret >= 0) { 310 if (sscanf(value, "%f", &vol) != 1){ 311 ALOGE("%s: error in retrieving hfp volume", __func__); 312 ret = -EIO; 313 goto exit; 314 } 315 ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol); 316 hfp_set_volume(adev, vol); 317 } 318 exit: 319 ALOGV("%s Exit",__func__); 320 } 321