blob: bbdbfb537e6f42a775dc2122f47121b86c5ff42d [file] [log] [blame]
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -08002
3Redistribution and use in source and binary forms, with or without
4modification, are permitted provided that the following conditions are
5met:
6 * Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above
9 copyright notice, this list of conditions and the following
10 disclaimer in the documentation and/or other materials provided
11 with the distribution.
12 * Neither the name of The Linux Foundation nor the names of its
13 contributors may be used to endorse or promote products derived
14 from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
27
28#define LOG_TAG "audio_hw_hfp"
29/*#define LOG_NDEBUG 0*/
30#define LOG_NDDEBUG 0
31
32#include <errno.h>
33#include <math.h>
Aalique Grahame22e49102018-12-18 14:23:57 -080034#include <log/log.h>
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080035
36#include "audio_hw.h"
37#include "platform.h"
38#include "platform_api.h"
39#include <stdlib.h>
40#include <cutils/str_parms.h>
Derek Chend2530072014-11-24 12:39:14 -080041#include "audio_extn.h"
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080042
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +053043#ifdef DYNAMIC_LOG_ENABLED
44#include <log_xml_parser.h>
45#define LOG_MASK HAL_MOD_FILE_HFP
46#include <log_utils.h>
47#endif
48
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080049#define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable"
Vimal Puthanveed47e64852013-12-20 13:23:39 -080050#define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate"
Amit Shekhar967cab32014-02-07 17:03:21 -080051#define AUDIO_PARAMETER_KEY_HFP_VOLUME "hfp_volume"
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +053052#define AUDIO_PARAMETER_HFP_PCM_DEV_ID "hfp_pcm_dev_id"
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080053
Aalique Grahame22e49102018-12-18 14:23:57 -080054#define AUDIO_PARAMETER_KEY_HFP_MIC_VOLUME "hfp_mic_volume"
55#define PLAYBACK_VOLUME_MAX 0x2000
56#define CAPTURE_VOLUME_DEFAULT (15.0)
57
Sudheer Papothi19e43d02014-07-16 02:34:41 +053058#ifdef PLATFORM_MSM8994
59#define HFP_RX_VOLUME "SEC AUXPCM LOOPBACK Volume"
Aalique Grahame22e49102018-12-18 14:23:57 -080060#elif defined (PLATFORM_MSM8996) || defined (EXTERNAL_BT_SUPPORTED)
Banajit Goswamida77c452015-10-14 20:45:22 -070061#define HFP_RX_VOLUME "PRI AUXPCM LOOPBACK Volume"
Derek Chen3e5b30a2018-10-24 01:04:25 -070062#elif defined PLATFORM_AUTO
63#define HFP_RX_VOLUME "Playback 36 Volume"
Meng Wangef2f6e12018-10-08 13:06:05 +080064#elif defined (PLATFORM_MSM8998) || defined (PLATFORM_MSMFALCON) || \
65 defined (PLATFORM_SDM845) || defined (PLATFORM_SDM710) || \
66 defined (PLATFORM_QCS605) || defined (PLATFORM_MSMNILE) || \
67 defined (PLATFORM_KONA) || defined (PLATFORM_MSMSTEPPE) || \
Manisha Agarwal888e9762019-02-27 22:18:49 +053068 defined (PLATFORM_QCS405) || defined (PLATFORM_TRINKET) || \
Jaideep Sharmade870aa2019-09-26 10:54:04 +053069 defined (PLATFORM_LITO) || defined(PLATFORM_ATOLL) || \
70 defined (PLATFORM_BENGAL)
Banajit Goswami4c0dff22016-03-04 18:31:22 -080071#define HFP_RX_VOLUME "SLIMBUS_7 LOOPBACK Volume"
Sudheer Papothi19e43d02014-07-16 02:34:41 +053072#else
73#define HFP_RX_VOLUME "Internal HFP RX Volume"
74#endif
75
Vimal Puthanveed584048b2013-12-11 17:00:50 -080076static int32_t start_hfp(struct audio_device *adev,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080077 struct str_parms *parms);
78
Vimal Puthanveed584048b2013-12-11 17:00:50 -080079static int32_t stop_hfp(struct audio_device *adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080080
81struct hfp_module {
82 struct pcm *hfp_sco_rx;
83 struct pcm *hfp_sco_tx;
84 struct pcm *hfp_pcm_rx;
85 struct pcm *hfp_pcm_tx;
86 bool is_hfp_running;
Amit Shekhar967cab32014-02-07 17:03:21 -080087 float hfp_volume;
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +053088 int32_t hfp_pcm_dev_id;
Vimal Puthanveed47e64852013-12-20 13:23:39 -080089 audio_usecase_t ucid;
Aalique Grahame22e49102018-12-18 14:23:57 -080090 float mic_volume;
91 bool mic_mute;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080092};
93
94static struct hfp_module hfpmod = {
95 .hfp_sco_rx = NULL,
96 .hfp_sco_tx = NULL,
97 .hfp_pcm_rx = NULL,
98 .hfp_pcm_tx = NULL,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080099 .is_hfp_running = 0,
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530100 .hfp_volume = 0,
101 .hfp_pcm_dev_id = HFP_ASM_RX_TX,
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800102 .ucid = USECASE_AUDIO_HFP_SCO,
Aalique Grahame22e49102018-12-18 14:23:57 -0800103 .mic_volume = CAPTURE_VOLUME_DEFAULT,
104 .mic_mute = 0,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800105};
Aalique Grahame22e49102018-12-18 14:23:57 -0800106
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800107static struct pcm_config pcm_config_hfp = {
108 .channels = 1,
109 .rate = 8000,
110 .period_size = 240,
111 .period_count = 2,
112 .format = PCM_FORMAT_S16_LE,
113 .start_threshold = 0,
114 .stop_threshold = INT_MAX,
115 .avail_min = 0,
116};
117
Arun Mirpurie008ed22019-03-21 11:21:04 -0700118//external feature dependency
119static fp_platform_set_mic_mute_t fp_platform_set_mic_mute;
120static fp_platform_get_pcm_device_id_t fp_platform_get_pcm_device_id;
121static fp_platform_set_echo_reference_t fp_platform_set_echo_reference;
122static fp_select_devices_t fp_select_devices;
123static fp_audio_extn_ext_hw_plugin_usecase_start_t fp_audio_extn_ext_hw_plugin_usecase_start;
124static fp_audio_extn_ext_hw_plugin_usecase_stop_t fp_audio_extn_ext_hw_plugin_usecase_stop;
125static fp_get_usecase_from_list_t fp_get_usecase_from_list;
126static fp_disable_audio_route_t fp_disable_audio_route;
127static fp_disable_snd_device_t fp_disable_snd_device;
128static fp_voice_get_mic_mute_t fp_voice_get_mic_mute;
Derek Chenf7092792017-05-23 12:23:53 -0400129static fp_audio_extn_auto_hal_start_hfp_downlink_t fp_audio_extn_auto_hal_start_hfp_downlink;
130static fp_audio_extn_auto_hal_stop_hfp_downlink_t fp_audio_extn_auto_hal_stop_hfp_downlink;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700131
Amit Shekhar967cab32014-02-07 17:03:21 -0800132static int32_t hfp_set_volume(struct audio_device *adev, float value)
133{
134 int32_t vol, ret = 0;
135 struct mixer_ctl *ctl;
Sudheer Papothi19e43d02014-07-16 02:34:41 +0530136 const char *mixer_ctl_name = HFP_RX_VOLUME;
Amit Shekhar967cab32014-02-07 17:03:21 -0800137
138 ALOGV("%s: entry", __func__);
139 ALOGD("%s: (%f)\n", __func__, value);
140
Satya Krishna Pindiproli3ed6d792014-09-09 15:32:25 +0530141 hfpmod.hfp_volume = value;
Aalique Grahame22e49102018-12-18 14:23:57 -0800142
Amit Shekhar967cab32014-02-07 17:03:21 -0800143 if (value < 0.0) {
144 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
145 value = 0.0;
146 } else {
147 value = ((value > 15.000000) ? 1.0 : (value / 15));
148 ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
149 }
150 vol = lrint((value * 0x2000) + 0.5);
Amit Shekhar967cab32014-02-07 17:03:21 -0800151
152 if (!hfpmod.is_hfp_running) {
153 ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
154 return -EIO;
155 }
156
157 ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
158 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
159 if (!ctl) {
160 ALOGE("%s: Could not get ctl for mixer cmd - %s",
161 __func__, mixer_ctl_name);
162 return -EINVAL;
163 }
164 if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
165 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
166 return -EINVAL;
167 }
168
169 ALOGV("%s: exit", __func__);
170 return ret;
171}
172
Aalique Grahame22e49102018-12-18 14:23:57 -0800173/*Set mic volume to value.
174*
175* This interface is used for mic volume control, set mic volume as value(range 0 ~ 15).
176*/
177static int hfp_set_mic_volume(struct audio_device *adev, float value)
178{
179 int volume, ret = 0;
180 char mixer_ctl_name[128];
181 struct mixer_ctl *ctl;
182 int pcm_device_id = HFP_ASM_RX_TX;
183
Arun Mirpurie008ed22019-03-21 11:21:04 -0700184 ALOGD("%s: enter, value=%f", __func__, value);
185
Aalique Grahame22e49102018-12-18 14:23:57 -0800186 if (!hfpmod.is_hfp_running) {
187 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
188 return -EIO;
189 }
190
191 if (value < 0.0) {
192 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
193 value = 0.0;
194 } else if (value > CAPTURE_VOLUME_DEFAULT) {
195 value = CAPTURE_VOLUME_DEFAULT;
196 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
197 }
198
199 value = value / CAPTURE_VOLUME_DEFAULT;
200 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
201 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
202 "Playback %d Volume", pcm_device_id);
203 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
204 if (!ctl) {
205 ALOGE("%s: Could not get ctl for mixer cmd - %s",
206 __func__, mixer_ctl_name);
207 return -EINVAL;
208 }
209 volume = (int)(value * PLAYBACK_VOLUME_MAX);
210
211 ALOGD("%s: Setting volume to %d (%s)\n", __func__, volume, mixer_ctl_name);
212 if (mixer_ctl_set_value(ctl, 0, volume) < 0) {
213 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
214 return -EINVAL;
215 }
216
217 return ret;
218}
219
220static float hfp_get_mic_volume(struct audio_device *adev)
221{
222 int volume;
223 char mixer_ctl_name[128];
224 struct mixer_ctl *ctl;
225 int pcm_device_id = HFP_ASM_RX_TX;
226 float value = 0.0;
227
Arun Mirpurie008ed22019-03-21 11:21:04 -0700228 ALOGD("%s: enter", __func__);
229
Aalique Grahame22e49102018-12-18 14:23:57 -0800230 if (!hfpmod.is_hfp_running) {
231 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
232 return -EIO;
233 }
234
235 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
236 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
237 "Playback %d Volume", pcm_device_id);
238 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
239 if (!ctl) {
240 ALOGE("%s: Could not get ctl for mixer cmd - %s",
241 __func__, mixer_ctl_name);
242 return -EINVAL;
243 }
244
245 volume = mixer_ctl_get_value(ctl, 0);
246 if ( volume < 0) {
247 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
248 return -EINVAL;
249 }
250 ALOGD("%s: getting mic volume %d \n", __func__, volume);
251
252 value = (volume / PLAYBACK_VOLUME_MAX) * CAPTURE_VOLUME_DEFAULT;
253 if (value < 0.0) {
254 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
255 value = 0.0;
256 } else if (value > CAPTURE_VOLUME_DEFAULT) {
257 value = CAPTURE_VOLUME_DEFAULT;
258 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
259 }
260
261 return value;
262}
263
264/*Set mic mute state.
265*
266* This interface is used for mic mute state control
267*/
Arun Mirpurie008ed22019-03-21 11:21:04 -0700268int hfp_set_mic_mute(struct audio_device *adev, bool state)
Aalique Grahame22e49102018-12-18 14:23:57 -0800269{
270 int rc = 0;
271
272 if (state == hfpmod.mic_mute)
273 return rc;
274
275 if (state == true) {
276 hfpmod.mic_volume = hfp_get_mic_volume(adev);
277 }
278 rc = hfp_set_mic_volume(adev, (state == true) ? 0.0 : hfpmod.mic_volume);
279 adev->voice.mic_mute = state;
280 hfpmod.mic_mute = state;
281 ALOGD("%s: Setting mute state %d, rc %d\n", __func__, state, rc);
282 return rc;
283}
284
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800285static int32_t start_hfp(struct audio_device *adev,
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700286 struct str_parms *parms __unused)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800287{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530288 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800289 struct audio_usecase *uc_info;
290 int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
291
292 ALOGD("%s: enter", __func__);
293
Aalique Grahame22e49102018-12-18 14:23:57 -0800294 if (adev->enable_hfp == true) {
295 ALOGD("%s: HFP is already active!\n", __func__);
296 return 0;
297 }
298 adev->enable_hfp = true;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700299 fp_platform_set_mic_mute(adev->platform, false);
Aalique Grahame22e49102018-12-18 14:23:57 -0800300
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800301 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700302
303 if (!uc_info)
304 return -ENOMEM;
305
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800306 uc_info->id = hfpmod.ucid;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800307 uc_info->type = PCM_HFP_CALL;
308 uc_info->stream.out = adev->primary_output;
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -0800309 list_init(&uc_info->device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800310 assign_devices(&uc_info->device_list, &adev->primary_output->device_list);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800311 uc_info->in_snd_device = SND_DEVICE_NONE;
312 uc_info->out_snd_device = SND_DEVICE_NONE;
313
314 list_add_tail(&adev->usecase_list, &uc_info->list);
315
Arun Mirpurie008ed22019-03-21 11:21:04 -0700316 fp_select_devices(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800317
Derek Chend2530072014-11-24 12:39:14 -0800318 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
319 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
Arun Mirpurie008ed22019-03-21 11:21:04 -0700320 if (fp_audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
Derek Chend2530072014-11-24 12:39:14 -0800321 ALOGE("%s: failed to start ext hw plugin", __func__);
322 }
323
Arun Mirpurie008ed22019-03-21 11:21:04 -0700324 pcm_dev_rx_id = fp_platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
325 pcm_dev_tx_id = fp_platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530326 pcm_dev_asm_rx_id = hfpmod.hfp_pcm_dev_id;
327 pcm_dev_asm_tx_id = hfpmod.hfp_pcm_dev_id;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800328 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
329 pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
330 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
331 __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
332 ret = -EIO;
333 goto exit;
334 }
335
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530336 ALOGD("%s: HFP PCM devices (rx: %d tx: %d pcm dev id: %d) usecase(%d)",
337 __func__, pcm_dev_rx_id, pcm_dev_tx_id, hfpmod.hfp_pcm_dev_id, uc_info->id);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800338
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800339 hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800340 pcm_dev_rx_id,
341 PCM_OUT, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800342 if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
343 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
344 ret = -EIO;
345 goto exit;
346 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530347
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800348 hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800349 pcm_dev_tx_id,
350 PCM_IN, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800351 if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
352 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
353 ret = -EIO;
354 goto exit;
355 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530356
Satya Krishna Pindiprolice903a02014-07-28 12:40:56 +0530357 if (pcm_start(hfpmod.hfp_pcm_rx) < 0) {
358 ALOGE("%s: pcm start for hfp pcm rx failed", __func__);
359 ret = -EINVAL;
360 goto exit;
361 }
362 if (pcm_start(hfpmod.hfp_pcm_tx) < 0) {
363 ALOGE("%s: pcm start for hfp pcm tx failed", __func__);
364 ret = -EINVAL;
365 goto exit;
366 }
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800367
Derek Chenf7092792017-05-23 12:23:53 -0400368 if (fp_audio_extn_auto_hal_start_hfp_downlink(adev, uc_info))
369 ALOGE("%s: start hfp downlink failed", __func__);
370
371 hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
372 pcm_dev_asm_rx_id,
373 PCM_OUT, &pcm_config_hfp);
374 if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
375 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
376 ret = -EIO;
377 goto exit;
378 }
379
380 hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
381 pcm_dev_asm_tx_id,
382 PCM_IN, &pcm_config_hfp);
383 if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
384 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
385 ret = -EIO;
386 goto exit;
387 }
388
389 if (pcm_start(hfpmod.hfp_sco_rx) < 0) {
390 ALOGE("%s: pcm start for hfp sco rx failed", __func__);
391 ret = -EINVAL;
392 goto exit;
393 }
394 if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
395 ALOGE("%s: pcm start for hfp sco tx failed", __func__);
396 ret = -EINVAL;
397 goto exit;
398 }
399
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800400 hfpmod.is_hfp_running = true;
Amit Shekhar967cab32014-02-07 17:03:21 -0800401 hfp_set_volume(adev, hfpmod.hfp_volume);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800402
Aalique Grahame22e49102018-12-18 14:23:57 -0800403 /* Set mic volume by mute status, we don't provide set mic volume in phone app, only
404 provide mute and unmute. */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700405 hfp_set_mic_mute(adev, adev->mic_muted);
Aalique Grahame22e49102018-12-18 14:23:57 -0800406
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800407 ALOGD("%s: exit: status(%d)", __func__, ret);
408 return 0;
409
410exit:
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800411 stop_hfp(adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800412 ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
413 return ret;
414}
415
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800416static int32_t stop_hfp(struct audio_device *adev)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800417{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530418 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800419 struct audio_usecase *uc_info;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800420 struct listnode *node;
421 struct audio_device_info *item = NULL;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800422
423 ALOGD("%s: enter", __func__);
424 hfpmod.is_hfp_running = false;
425
426 /* 1. Close the PCM devices */
427 if (hfpmod.hfp_sco_rx) {
428 pcm_close(hfpmod.hfp_sco_rx);
429 hfpmod.hfp_sco_rx = NULL;
430 }
431 if (hfpmod.hfp_sco_tx) {
432 pcm_close(hfpmod.hfp_sco_tx);
433 hfpmod.hfp_sco_tx = NULL;
434 }
435 if (hfpmod.hfp_pcm_rx) {
436 pcm_close(hfpmod.hfp_pcm_rx);
437 hfpmod.hfp_pcm_rx = NULL;
438 }
439 if (hfpmod.hfp_pcm_tx) {
440 pcm_close(hfpmod.hfp_pcm_tx);
441 hfpmod.hfp_pcm_tx = NULL;
442 }
443
Arun Mirpurie008ed22019-03-21 11:21:04 -0700444 uc_info = fp_get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800445 if (uc_info == NULL) {
446 ALOGE("%s: Could not find the usecase (%d) in the list",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800447 __func__, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800448 return -EINVAL;
449 }
450
Derek Chend2530072014-11-24 12:39:14 -0800451 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
452 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
Arun Mirpurie008ed22019-03-21 11:21:04 -0700453 if (fp_audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
Derek Chend2530072014-11-24 12:39:14 -0800454 ALOGE("%s: failed to stop ext hw plugin", __func__);
455 }
456
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530457 /* 2. Disable echo reference while stopping hfp */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800458 fp_platform_set_echo_reference(adev, false, &uc_info->device_list);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530459
460 /* 3. Get and set stream specific mixer controls */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700461 fp_disable_audio_route(adev, uc_info);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800462
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530463 /* 4. Disable the rx and tx devices */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700464 fp_disable_snd_device(adev, uc_info->out_snd_device);
465 fp_disable_snd_device(adev, uc_info->in_snd_device);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800466
Derek Chenf7092792017-05-23 12:23:53 -0400467 if (fp_audio_extn_auto_hal_stop_hfp_downlink(adev, uc_info))
468 ALOGE("%s: stop hfp downlink failed", __func__);
469
Aalique Grahame22e49102018-12-18 14:23:57 -0800470 /* Set the unmute Tx mixer control */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700471 if (fp_voice_get_mic_mute(adev)) {
472 fp_platform_set_mic_mute(adev->platform, false);
Aalique Grahame22e49102018-12-18 14:23:57 -0800473 ALOGD("%s: unMute HFP Tx", __func__);
474 }
475 adev->enable_hfp = false;
476
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800477 list_remove(&uc_info->list);
478 free(uc_info);
479
480 ALOGD("%s: exit: status(%d)", __func__, ret);
481 return ret;
482}
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800483
Arun Mirpurie008ed22019-03-21 11:21:04 -0700484void hfp_init(hfp_init_config_t init_config)
485{
486 fp_platform_set_mic_mute = init_config.fp_platform_set_mic_mute;
487 fp_platform_get_pcm_device_id = init_config.fp_platform_get_pcm_device_id;
488 fp_platform_set_echo_reference = init_config.fp_platform_set_echo_reference;
489 fp_select_devices = init_config.fp_select_devices;
490 fp_audio_extn_ext_hw_plugin_usecase_start =
491 init_config.fp_audio_extn_ext_hw_plugin_usecase_start;
492 fp_audio_extn_ext_hw_plugin_usecase_stop =
493 init_config.fp_audio_extn_ext_hw_plugin_usecase_stop;
494 fp_get_usecase_from_list = init_config.fp_get_usecase_from_list;
495 fp_disable_audio_route = init_config.fp_disable_audio_route;
496 fp_disable_snd_device = init_config.fp_disable_snd_device;
497 fp_voice_get_mic_mute = init_config.fp_voice_get_mic_mute;
Derek Chenf7092792017-05-23 12:23:53 -0400498 fp_audio_extn_auto_hal_start_hfp_downlink =
499 init_config.fp_audio_extn_auto_hal_start_hfp_downlink;
500 fp_audio_extn_auto_hal_stop_hfp_downlink =
501 init_config.fp_audio_extn_auto_hal_stop_hfp_downlink;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700502}
503
504bool hfp_is_active(struct audio_device *adev)
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800505{
506 struct audio_usecase *hfp_usecase = NULL;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700507 hfp_usecase = fp_get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800508
509 if (hfp_usecase != NULL)
510 return true;
511 else
512 return false;
513}
514
Arun Mirpurie008ed22019-03-21 11:21:04 -0700515int hfp_set_mic_mute2(struct audio_device *adev, bool state)
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530516{
517 struct mixer_ctl *ctl;
518 const char *mixer_ctl_name = "HFP TX Mute";
Manish Dewangan338c50a2017-09-12 15:22:03 +0530519 long set_values[ ] = {0};
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530520
Arun Mirpurie008ed22019-03-21 11:21:04 -0700521 ALOGD("%s: enter, state=%d", __func__, state);
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530522
523 set_values[0] = state;
524 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
525 if (!ctl) {
526 ALOGE("%s: Could not get ctl for mixer cmd - %s",
527 __func__, mixer_ctl_name);
528 return -EINVAL;
529 }
530 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
531 ALOGV("%s: exit", __func__);
532 return 0;
533}
534
Arun Mirpurie008ed22019-03-21 11:21:04 -0700535audio_usecase_t hfp_get_usecase()
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800536{
537 return hfpmod.ucid;
538}
539
Arun Mirpurie008ed22019-03-21 11:21:04 -0700540void hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800541{
542 int ret;
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800543 int rate;
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800544 int val;
Amit Shekhar967cab32014-02-07 17:03:21 -0800545 float vol;
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800546 char value[32]={0};
547
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700548 ALOGV("%s: enter", __func__);
Arun Mirpurie008ed22019-03-21 11:21:04 -0700549
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800550 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
551 sizeof(value));
552 if (ret >= 0) {
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530553 if (!strncmp(value, "true", sizeof(value)) && !hfpmod.is_hfp_running)
554 ret = start_hfp(adev,parms);
555 else if (!strncmp(value, "false", sizeof(value)) && hfpmod.is_hfp_running)
556 stop_hfp(adev);
557 else
558 ALOGE("hfp_enable=%s is unsupported", value);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800559 }
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800560 memset(value, 0, sizeof(value));
561 ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
562 sizeof(value));
563 if (ret >= 0) {
564 rate = atoi(value);
565 if (rate == 8000){
566 hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
567 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700568 } else if (rate == 16000){
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800569 hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
570 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700571 } else
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800572 ALOGE("Unsupported rate..");
573 }
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800574
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700575 if (hfpmod.is_hfp_running) {
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800576 memset(value, 0, sizeof(value));
577 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
578 value, sizeof(value));
579 if (ret >= 0) {
580 val = atoi(value);
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700581 if (val > 0)
Arun Mirpurie008ed22019-03-21 11:21:04 -0700582 fp_select_devices(adev, hfpmod.ucid);
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800583 }
584 }
Amit Shekhar967cab32014-02-07 17:03:21 -0800585
586 memset(value, 0, sizeof(value));
587 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
588 value, sizeof(value));
589 if (ret >= 0) {
590 if (sscanf(value, "%f", &vol) != 1){
591 ALOGE("%s: error in retrieving hfp volume", __func__);
592 ret = -EIO;
593 goto exit;
594 }
595 ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
596 hfp_set_volume(adev, vol);
597 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530598
599 memset(value, 0, sizeof(value));
600 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID, value, sizeof(value));
601 if (ret >= 0) {
602 hfpmod.hfp_pcm_dev_id = atoi(value);
603 ALOGD("Updating HFP_PCM_DEV_ID as %d from platform XML", hfpmod.hfp_pcm_dev_id);
604 str_parms_del(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID);
605 }
606
Aalique Grahame22e49102018-12-18 14:23:57 -0800607 memset(value, 0, sizeof(value));
608 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_MIC_VOLUME,
609 value, sizeof(value));
610 if (ret >= 0) {
611 if (sscanf(value, "%f", &vol) != 1){
612 ALOGE("%s: error in retrieving hfp mic volume", __func__);
613 ret = -EIO;
614 goto exit;
615 }
616 ALOGD("%s: set_hfp_mic_volume usecase, Vol: [%f]", __func__, vol);
617 hfp_set_mic_volume(adev, vol);
618 }
619
Amit Shekhar967cab32014-02-07 17:03:21 -0800620exit:
621 ALOGV("%s Exit",__func__);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800622}