blob: ca5d3bbf9ee852942823196855ff22b7f7e8632e [file] [log] [blame]
Trinath Thammishettyf3f53472020-09-02 12:14:57 +05301/* Copyright (c) 2012-2021, 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"
Trinath Thammishettyf3f53472020-09-02 12:14:57 +053053#define AUDIO_PARAMETER_HFP_VOL_MIXER_CTL "hfp_vol_mixer_ctl"
54#define AUDIO_PARAMETER_HFP_VALUE_MAX 128
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080055
Aalique Grahame22e49102018-12-18 14:23:57 -080056#define AUDIO_PARAMETER_KEY_HFP_MIC_VOLUME "hfp_mic_volume"
57#define PLAYBACK_VOLUME_MAX 0x2000
58#define CAPTURE_VOLUME_DEFAULT (15.0)
59
Sudheer Papothi19e43d02014-07-16 02:34:41 +053060#ifdef PLATFORM_MSM8994
61#define HFP_RX_VOLUME "SEC AUXPCM LOOPBACK Volume"
Aalique Grahame22e49102018-12-18 14:23:57 -080062#elif defined (PLATFORM_MSM8996) || defined (EXTERNAL_BT_SUPPORTED)
Banajit Goswamida77c452015-10-14 20:45:22 -070063#define HFP_RX_VOLUME "PRI AUXPCM LOOPBACK Volume"
Derek Chen3e5b30a2018-10-24 01:04:25 -070064#elif defined PLATFORM_AUTO
65#define HFP_RX_VOLUME "Playback 36 Volume"
Meng Wangef2f6e12018-10-08 13:06:05 +080066#elif defined (PLATFORM_MSM8998) || defined (PLATFORM_MSMFALCON) || \
67 defined (PLATFORM_SDM845) || defined (PLATFORM_SDM710) || \
68 defined (PLATFORM_QCS605) || defined (PLATFORM_MSMNILE) || \
69 defined (PLATFORM_KONA) || defined (PLATFORM_MSMSTEPPE) || \
Manisha Agarwal888e9762019-02-27 22:18:49 +053070 defined (PLATFORM_QCS405) || defined (PLATFORM_TRINKET) || \
Jaideep Sharmade870aa2019-09-26 10:54:04 +053071 defined (PLATFORM_LITO) || defined(PLATFORM_ATOLL) || \
Mingshu Pang2c3f3642020-09-18 21:19:45 +080072 defined (PLATFORM_BENGAL) || defined (PLATFORM_LAHAINA)
Banajit Goswami4c0dff22016-03-04 18:31:22 -080073#define HFP_RX_VOLUME "SLIMBUS_7 LOOPBACK Volume"
Sudheer Papothi19e43d02014-07-16 02:34:41 +053074#else
75#define HFP_RX_VOLUME "Internal HFP RX Volume"
76#endif
77
Vimal Puthanveed584048b2013-12-11 17:00:50 -080078static int32_t start_hfp(struct audio_device *adev,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080079 struct str_parms *parms);
80
Vimal Puthanveed584048b2013-12-11 17:00:50 -080081static int32_t stop_hfp(struct audio_device *adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080082
83struct hfp_module {
84 struct pcm *hfp_sco_rx;
85 struct pcm *hfp_sco_tx;
86 struct pcm *hfp_pcm_rx;
87 struct pcm *hfp_pcm_tx;
88 bool is_hfp_running;
Amit Shekhar967cab32014-02-07 17:03:21 -080089 float hfp_volume;
Trinath Thammishettyf3f53472020-09-02 12:14:57 +053090 char hfp_vol_mixer_ctl[AUDIO_PARAMETER_HFP_VALUE_MAX];
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +053091 int32_t hfp_pcm_dev_id;
Vimal Puthanveed47e64852013-12-20 13:23:39 -080092 audio_usecase_t ucid;
Aalique Grahame22e49102018-12-18 14:23:57 -080093 float mic_volume;
94 bool mic_mute;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080095};
96
97static struct hfp_module hfpmod = {
98 .hfp_sco_rx = NULL,
99 .hfp_sco_tx = NULL,
100 .hfp_pcm_rx = NULL,
101 .hfp_pcm_tx = NULL,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800102 .is_hfp_running = 0,
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530103 .hfp_volume = 0,
Trinath Thammishettyf3f53472020-09-02 12:14:57 +0530104 .hfp_vol_mixer_ctl = {0, },
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530105 .hfp_pcm_dev_id = HFP_ASM_RX_TX,
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800106 .ucid = USECASE_AUDIO_HFP_SCO,
Aalique Grahame22e49102018-12-18 14:23:57 -0800107 .mic_volume = CAPTURE_VOLUME_DEFAULT,
108 .mic_mute = 0,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800109};
Aalique Grahame22e49102018-12-18 14:23:57 -0800110
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800111static struct pcm_config pcm_config_hfp = {
112 .channels = 1,
113 .rate = 8000,
114 .period_size = 240,
115 .period_count = 2,
116 .format = PCM_FORMAT_S16_LE,
117 .start_threshold = 0,
118 .stop_threshold = INT_MAX,
119 .avail_min = 0,
120};
121
Arun Mirpurie008ed22019-03-21 11:21:04 -0700122//external feature dependency
123static fp_platform_set_mic_mute_t fp_platform_set_mic_mute;
124static fp_platform_get_pcm_device_id_t fp_platform_get_pcm_device_id;
125static fp_platform_set_echo_reference_t fp_platform_set_echo_reference;
126static fp_select_devices_t fp_select_devices;
127static fp_audio_extn_ext_hw_plugin_usecase_start_t fp_audio_extn_ext_hw_plugin_usecase_start;
128static fp_audio_extn_ext_hw_plugin_usecase_stop_t fp_audio_extn_ext_hw_plugin_usecase_stop;
129static fp_get_usecase_from_list_t fp_get_usecase_from_list;
130static fp_disable_audio_route_t fp_disable_audio_route;
131static fp_disable_snd_device_t fp_disable_snd_device;
132static fp_voice_get_mic_mute_t fp_voice_get_mic_mute;
Derek Chenf7092792017-05-23 12:23:53 -0400133static fp_audio_extn_auto_hal_start_hfp_downlink_t fp_audio_extn_auto_hal_start_hfp_downlink;
134static fp_audio_extn_auto_hal_stop_hfp_downlink_t fp_audio_extn_auto_hal_stop_hfp_downlink;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700135
Amit Shekhar967cab32014-02-07 17:03:21 -0800136static int32_t hfp_set_volume(struct audio_device *adev, float value)
137{
138 int32_t vol, ret = 0;
139 struct mixer_ctl *ctl;
Sudheer Papothi19e43d02014-07-16 02:34:41 +0530140 const char *mixer_ctl_name = HFP_RX_VOLUME;
Amit Shekhar967cab32014-02-07 17:03:21 -0800141
142 ALOGV("%s: entry", __func__);
143 ALOGD("%s: (%f)\n", __func__, value);
144
Satya Krishna Pindiproli3ed6d792014-09-09 15:32:25 +0530145 hfpmod.hfp_volume = value;
Aalique Grahame22e49102018-12-18 14:23:57 -0800146
Amit Shekhar967cab32014-02-07 17:03:21 -0800147 if (value < 0.0) {
148 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
149 value = 0.0;
150 } else {
151 value = ((value > 15.000000) ? 1.0 : (value / 15));
152 ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
153 }
154 vol = lrint((value * 0x2000) + 0.5);
Amit Shekhar967cab32014-02-07 17:03:21 -0800155
156 if (!hfpmod.is_hfp_running) {
157 ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
158 return -EIO;
159 }
160
161 ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
Trinath Thammishettyf3f53472020-09-02 12:14:57 +0530162
163 if (0 == hfpmod.hfp_vol_mixer_ctl[0])
164 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
165 else
166 ctl = mixer_get_ctl_by_name(adev->mixer, hfpmod.hfp_vol_mixer_ctl);
167
168 if(!ctl) {
Amit Shekhar967cab32014-02-07 17:03:21 -0800169 ALOGE("%s: Could not get ctl for mixer cmd - %s",
170 __func__, mixer_ctl_name);
171 return -EINVAL;
172 }
173 if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
174 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
175 return -EINVAL;
176 }
177
178 ALOGV("%s: exit", __func__);
179 return ret;
180}
181
Aalique Grahame22e49102018-12-18 14:23:57 -0800182/*Set mic volume to value.
183*
184* This interface is used for mic volume control, set mic volume as value(range 0 ~ 15).
185*/
186static int hfp_set_mic_volume(struct audio_device *adev, float value)
187{
188 int volume, ret = 0;
189 char mixer_ctl_name[128];
190 struct mixer_ctl *ctl;
191 int pcm_device_id = HFP_ASM_RX_TX;
192
Arun Mirpurie008ed22019-03-21 11:21:04 -0700193 ALOGD("%s: enter, value=%f", __func__, value);
194
Aalique Grahame22e49102018-12-18 14:23:57 -0800195 if (!hfpmod.is_hfp_running) {
196 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
197 return -EIO;
198 }
199
200 if (value < 0.0) {
201 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
202 value = 0.0;
203 } else if (value > CAPTURE_VOLUME_DEFAULT) {
204 value = CAPTURE_VOLUME_DEFAULT;
205 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
206 }
207
208 value = value / CAPTURE_VOLUME_DEFAULT;
209 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
210 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
211 "Playback %d Volume", pcm_device_id);
212 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
213 if (!ctl) {
214 ALOGE("%s: Could not get ctl for mixer cmd - %s",
215 __func__, mixer_ctl_name);
216 return -EINVAL;
217 }
218 volume = (int)(value * PLAYBACK_VOLUME_MAX);
219
220 ALOGD("%s: Setting volume to %d (%s)\n", __func__, volume, mixer_ctl_name);
221 if (mixer_ctl_set_value(ctl, 0, volume) < 0) {
222 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
223 return -EINVAL;
224 }
225
226 return ret;
227}
228
229static float hfp_get_mic_volume(struct audio_device *adev)
230{
231 int volume;
232 char mixer_ctl_name[128];
233 struct mixer_ctl *ctl;
234 int pcm_device_id = HFP_ASM_RX_TX;
235 float value = 0.0;
236
Arun Mirpurie008ed22019-03-21 11:21:04 -0700237 ALOGD("%s: enter", __func__);
238
Aalique Grahame22e49102018-12-18 14:23:57 -0800239 if (!hfpmod.is_hfp_running) {
240 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
241 return -EIO;
242 }
243
244 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
245 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
246 "Playback %d Volume", pcm_device_id);
247 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
248 if (!ctl) {
249 ALOGE("%s: Could not get ctl for mixer cmd - %s",
250 __func__, mixer_ctl_name);
251 return -EINVAL;
252 }
253
254 volume = mixer_ctl_get_value(ctl, 0);
255 if ( volume < 0) {
256 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
257 return -EINVAL;
258 }
259 ALOGD("%s: getting mic volume %d \n", __func__, volume);
260
261 value = (volume / PLAYBACK_VOLUME_MAX) * CAPTURE_VOLUME_DEFAULT;
262 if (value < 0.0) {
263 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
264 value = 0.0;
265 } else if (value > CAPTURE_VOLUME_DEFAULT) {
266 value = CAPTURE_VOLUME_DEFAULT;
267 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
268 }
269
270 return value;
271}
272
273/*Set mic mute state.
274*
275* This interface is used for mic mute state control
276*/
Arun Mirpurie008ed22019-03-21 11:21:04 -0700277int hfp_set_mic_mute(struct audio_device *adev, bool state)
Aalique Grahame22e49102018-12-18 14:23:57 -0800278{
279 int rc = 0;
280
281 if (state == hfpmod.mic_mute)
282 return rc;
283
284 if (state == true) {
285 hfpmod.mic_volume = hfp_get_mic_volume(adev);
286 }
287 rc = hfp_set_mic_volume(adev, (state == true) ? 0.0 : hfpmod.mic_volume);
288 adev->voice.mic_mute = state;
289 hfpmod.mic_mute = state;
290 ALOGD("%s: Setting mute state %d, rc %d\n", __func__, state, rc);
291 return rc;
292}
293
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800294static int32_t start_hfp(struct audio_device *adev,
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700295 struct str_parms *parms __unused)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800296{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530297 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800298 struct audio_usecase *uc_info;
299 int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
300
301 ALOGD("%s: enter", __func__);
302
Aalique Grahame22e49102018-12-18 14:23:57 -0800303 if (adev->enable_hfp == true) {
304 ALOGD("%s: HFP is already active!\n", __func__);
305 return 0;
306 }
307 adev->enable_hfp = true;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700308 fp_platform_set_mic_mute(adev->platform, false);
Aalique Grahame22e49102018-12-18 14:23:57 -0800309
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800310 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700311
312 if (!uc_info)
313 return -ENOMEM;
314
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800315 uc_info->id = hfpmod.ucid;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800316 uc_info->type = PCM_HFP_CALL;
317 uc_info->stream.out = adev->primary_output;
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -0800318 list_init(&uc_info->device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800319 assign_devices(&uc_info->device_list, &adev->primary_output->device_list);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800320 uc_info->in_snd_device = SND_DEVICE_NONE;
321 uc_info->out_snd_device = SND_DEVICE_NONE;
322
323 list_add_tail(&adev->usecase_list, &uc_info->list);
324
Arun Mirpurie008ed22019-03-21 11:21:04 -0700325 fp_select_devices(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800326
Derek Chend2530072014-11-24 12:39:14 -0800327 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
328 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
Arun Mirpurie008ed22019-03-21 11:21:04 -0700329 if (fp_audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
Derek Chend2530072014-11-24 12:39:14 -0800330 ALOGE("%s: failed to start ext hw plugin", __func__);
331 }
332
Arun Mirpurie008ed22019-03-21 11:21:04 -0700333 pcm_dev_rx_id = fp_platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
334 pcm_dev_tx_id = fp_platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530335 pcm_dev_asm_rx_id = hfpmod.hfp_pcm_dev_id;
336 pcm_dev_asm_tx_id = hfpmod.hfp_pcm_dev_id;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800337 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
338 pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
339 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
340 __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
341 ret = -EIO;
342 goto exit;
343 }
344
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530345 ALOGD("%s: HFP PCM devices (rx: %d tx: %d pcm dev id: %d) usecase(%d)",
346 __func__, pcm_dev_rx_id, pcm_dev_tx_id, hfpmod.hfp_pcm_dev_id, uc_info->id);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800347
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800348 hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800349 pcm_dev_rx_id,
350 PCM_OUT, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800351 if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
352 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
353 ret = -EIO;
354 goto exit;
355 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530356
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800357 hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800358 pcm_dev_tx_id,
359 PCM_IN, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800360 if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
361 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
362 ret = -EIO;
363 goto exit;
364 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530365
Satya Krishna Pindiprolice903a02014-07-28 12:40:56 +0530366 if (pcm_start(hfpmod.hfp_pcm_rx) < 0) {
367 ALOGE("%s: pcm start for hfp pcm rx failed", __func__);
368 ret = -EINVAL;
369 goto exit;
370 }
371 if (pcm_start(hfpmod.hfp_pcm_tx) < 0) {
372 ALOGE("%s: pcm start for hfp pcm tx failed", __func__);
373 ret = -EINVAL;
374 goto exit;
375 }
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800376
Derek Chenf7092792017-05-23 12:23:53 -0400377 if (fp_audio_extn_auto_hal_start_hfp_downlink(adev, uc_info))
378 ALOGE("%s: start hfp downlink failed", __func__);
379
380 hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
381 pcm_dev_asm_rx_id,
382 PCM_OUT, &pcm_config_hfp);
383 if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
384 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
385 ret = -EIO;
386 goto exit;
387 }
388
389 hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
390 pcm_dev_asm_tx_id,
391 PCM_IN, &pcm_config_hfp);
392 if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
393 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
394 ret = -EIO;
395 goto exit;
396 }
397
398 if (pcm_start(hfpmod.hfp_sco_rx) < 0) {
399 ALOGE("%s: pcm start for hfp sco rx failed", __func__);
400 ret = -EINVAL;
401 goto exit;
402 }
403 if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
404 ALOGE("%s: pcm start for hfp sco tx failed", __func__);
405 ret = -EINVAL;
406 goto exit;
407 }
408
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800409 hfpmod.is_hfp_running = true;
Amit Shekhar967cab32014-02-07 17:03:21 -0800410 hfp_set_volume(adev, hfpmod.hfp_volume);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800411
Aalique Grahame22e49102018-12-18 14:23:57 -0800412 /* Set mic volume by mute status, we don't provide set mic volume in phone app, only
413 provide mute and unmute. */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700414 hfp_set_mic_mute(adev, adev->mic_muted);
Aalique Grahame22e49102018-12-18 14:23:57 -0800415
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800416 ALOGD("%s: exit: status(%d)", __func__, ret);
417 return 0;
418
419exit:
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800420 stop_hfp(adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800421 ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
422 return ret;
423}
424
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800425static int32_t stop_hfp(struct audio_device *adev)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800426{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530427 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800428 struct audio_usecase *uc_info;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800429 struct listnode *node;
430 struct audio_device_info *item = NULL;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800431
432 ALOGD("%s: enter", __func__);
433 hfpmod.is_hfp_running = false;
434
435 /* 1. Close the PCM devices */
436 if (hfpmod.hfp_sco_rx) {
437 pcm_close(hfpmod.hfp_sco_rx);
438 hfpmod.hfp_sco_rx = NULL;
439 }
440 if (hfpmod.hfp_sco_tx) {
441 pcm_close(hfpmod.hfp_sco_tx);
442 hfpmod.hfp_sco_tx = NULL;
443 }
444 if (hfpmod.hfp_pcm_rx) {
445 pcm_close(hfpmod.hfp_pcm_rx);
446 hfpmod.hfp_pcm_rx = NULL;
447 }
448 if (hfpmod.hfp_pcm_tx) {
449 pcm_close(hfpmod.hfp_pcm_tx);
450 hfpmod.hfp_pcm_tx = NULL;
451 }
452
Arun Mirpurie008ed22019-03-21 11:21:04 -0700453 uc_info = fp_get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800454 if (uc_info == NULL) {
455 ALOGE("%s: Could not find the usecase (%d) in the list",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800456 __func__, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800457 return -EINVAL;
458 }
459
Derek Chend2530072014-11-24 12:39:14 -0800460 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
461 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
Arun Mirpurie008ed22019-03-21 11:21:04 -0700462 if (fp_audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
Derek Chend2530072014-11-24 12:39:14 -0800463 ALOGE("%s: failed to stop ext hw plugin", __func__);
464 }
465
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530466 /* 2. Disable echo reference while stopping hfp */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800467 fp_platform_set_echo_reference(adev, false, &uc_info->device_list);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530468
469 /* 3. Get and set stream specific mixer controls */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700470 fp_disable_audio_route(adev, uc_info);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800471
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530472 /* 4. Disable the rx and tx devices */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700473 fp_disable_snd_device(adev, uc_info->out_snd_device);
474 fp_disable_snd_device(adev, uc_info->in_snd_device);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800475
Derek Chenf7092792017-05-23 12:23:53 -0400476 if (fp_audio_extn_auto_hal_stop_hfp_downlink(adev, uc_info))
477 ALOGE("%s: stop hfp downlink failed", __func__);
478
Aalique Grahame22e49102018-12-18 14:23:57 -0800479 /* Set the unmute Tx mixer control */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700480 if (fp_voice_get_mic_mute(adev)) {
481 fp_platform_set_mic_mute(adev->platform, false);
Aalique Grahame22e49102018-12-18 14:23:57 -0800482 ALOGD("%s: unMute HFP Tx", __func__);
483 }
484 adev->enable_hfp = false;
485
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800486 list_remove(&uc_info->list);
487 free(uc_info);
488
489 ALOGD("%s: exit: status(%d)", __func__, ret);
490 return ret;
491}
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800492
Arun Mirpurie008ed22019-03-21 11:21:04 -0700493void hfp_init(hfp_init_config_t init_config)
494{
495 fp_platform_set_mic_mute = init_config.fp_platform_set_mic_mute;
496 fp_platform_get_pcm_device_id = init_config.fp_platform_get_pcm_device_id;
497 fp_platform_set_echo_reference = init_config.fp_platform_set_echo_reference;
498 fp_select_devices = init_config.fp_select_devices;
499 fp_audio_extn_ext_hw_plugin_usecase_start =
500 init_config.fp_audio_extn_ext_hw_plugin_usecase_start;
501 fp_audio_extn_ext_hw_plugin_usecase_stop =
502 init_config.fp_audio_extn_ext_hw_plugin_usecase_stop;
503 fp_get_usecase_from_list = init_config.fp_get_usecase_from_list;
504 fp_disable_audio_route = init_config.fp_disable_audio_route;
505 fp_disable_snd_device = init_config.fp_disable_snd_device;
506 fp_voice_get_mic_mute = init_config.fp_voice_get_mic_mute;
Derek Chenf7092792017-05-23 12:23:53 -0400507 fp_audio_extn_auto_hal_start_hfp_downlink =
508 init_config.fp_audio_extn_auto_hal_start_hfp_downlink;
509 fp_audio_extn_auto_hal_stop_hfp_downlink =
510 init_config.fp_audio_extn_auto_hal_stop_hfp_downlink;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700511}
512
513bool hfp_is_active(struct audio_device *adev)
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800514{
515 struct audio_usecase *hfp_usecase = NULL;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700516 hfp_usecase = fp_get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800517
518 if (hfp_usecase != NULL)
519 return true;
520 else
521 return false;
522}
523
Arun Mirpurie008ed22019-03-21 11:21:04 -0700524int hfp_set_mic_mute2(struct audio_device *adev, bool state)
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530525{
526 struct mixer_ctl *ctl;
527 const char *mixer_ctl_name = "HFP TX Mute";
Manish Dewangan338c50a2017-09-12 15:22:03 +0530528 long set_values[ ] = {0};
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530529
Arun Mirpurie008ed22019-03-21 11:21:04 -0700530 ALOGD("%s: enter, state=%d", __func__, state);
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530531
532 set_values[0] = state;
533 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
534 if (!ctl) {
535 ALOGE("%s: Could not get ctl for mixer cmd - %s",
536 __func__, mixer_ctl_name);
537 return -EINVAL;
538 }
539 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
540 ALOGV("%s: exit", __func__);
541 return 0;
542}
543
Arun Mirpurie008ed22019-03-21 11:21:04 -0700544audio_usecase_t hfp_get_usecase()
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800545{
546 return hfpmod.ucid;
547}
548
Arun Mirpurie008ed22019-03-21 11:21:04 -0700549void hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800550{
551 int ret;
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800552 int rate;
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800553 int val;
Amit Shekhar967cab32014-02-07 17:03:21 -0800554 float vol;
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800555 char value[32]={0};
556
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700557 ALOGV("%s: enter", __func__);
Arun Mirpurie008ed22019-03-21 11:21:04 -0700558
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800559 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
560 sizeof(value));
561 if (ret >= 0) {
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530562 if (!strncmp(value, "true", sizeof(value)) && !hfpmod.is_hfp_running)
563 ret = start_hfp(adev,parms);
564 else if (!strncmp(value, "false", sizeof(value)) && hfpmod.is_hfp_running)
565 stop_hfp(adev);
566 else
567 ALOGE("hfp_enable=%s is unsupported", value);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800568 }
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800569 memset(value, 0, sizeof(value));
570 ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
571 sizeof(value));
572 if (ret >= 0) {
573 rate = atoi(value);
574 if (rate == 8000){
575 hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
576 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700577 } else if (rate == 16000){
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800578 hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
579 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700580 } else
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800581 ALOGE("Unsupported rate..");
582 }
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800583
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700584 if (hfpmod.is_hfp_running) {
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800585 memset(value, 0, sizeof(value));
586 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
587 value, sizeof(value));
588 if (ret >= 0) {
589 val = atoi(value);
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700590 if (val > 0)
Arun Mirpurie008ed22019-03-21 11:21:04 -0700591 fp_select_devices(adev, hfpmod.ucid);
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800592 }
593 }
Amit Shekhar967cab32014-02-07 17:03:21 -0800594
595 memset(value, 0, sizeof(value));
Trinath Thammishettyf3f53472020-09-02 12:14:57 +0530596 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_VOL_MIXER_CTL,
597 value, sizeof(value));
598 if (ret >= 0) {
599 ALOGD("%s: mixer ctl name: %s", __func__, value);
600 strlcpy(hfpmod.hfp_vol_mixer_ctl, value, sizeof(value));
601 str_parms_del(parms, AUDIO_PARAMETER_HFP_VOL_MIXER_CTL);
602 }
603
604 memset(value, 0, sizeof(value));
Amit Shekhar967cab32014-02-07 17:03:21 -0800605 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
606 value, sizeof(value));
607 if (ret >= 0) {
608 if (sscanf(value, "%f", &vol) != 1){
609 ALOGE("%s: error in retrieving hfp volume", __func__);
610 ret = -EIO;
611 goto exit;
612 }
613 ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
614 hfp_set_volume(adev, vol);
615 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530616
617 memset(value, 0, sizeof(value));
618 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID, value, sizeof(value));
619 if (ret >= 0) {
620 hfpmod.hfp_pcm_dev_id = atoi(value);
621 ALOGD("Updating HFP_PCM_DEV_ID as %d from platform XML", hfpmod.hfp_pcm_dev_id);
622 str_parms_del(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID);
623 }
624
Aalique Grahame22e49102018-12-18 14:23:57 -0800625 memset(value, 0, sizeof(value));
626 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_MIC_VOLUME,
627 value, sizeof(value));
628 if (ret >= 0) {
629 if (sscanf(value, "%f", &vol) != 1){
630 ALOGE("%s: error in retrieving hfp mic volume", __func__);
631 ret = -EIO;
632 goto exit;
633 }
634 ALOGD("%s: set_hfp_mic_volume usecase, Vol: [%f]", __func__, vol);
635 hfp_set_mic_volume(adev, vol);
636 }
637
Amit Shekhar967cab32014-02-07 17:03:21 -0800638exit:
639 ALOGV("%s Exit",__func__);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800640}