blob: 697a5076bf45e398ed9b48b7866cef46f144ec53 [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
ronghuiz98dbc492021-02-19 20:06:22 +080055#define AUDIO_PARAMETER_HFP_FORCE_ROUTE_SPEAKER "hfp_route_spkr"
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080056
Aalique Grahame22e49102018-12-18 14:23:57 -080057#define AUDIO_PARAMETER_KEY_HFP_MIC_VOLUME "hfp_mic_volume"
58#define PLAYBACK_VOLUME_MAX 0x2000
59#define CAPTURE_VOLUME_DEFAULT (15.0)
60
Sudheer Papothi19e43d02014-07-16 02:34:41 +053061#ifdef PLATFORM_MSM8994
62#define HFP_RX_VOLUME "SEC AUXPCM LOOPBACK Volume"
Aalique Grahame22e49102018-12-18 14:23:57 -080063#elif defined (PLATFORM_MSM8996) || defined (EXTERNAL_BT_SUPPORTED)
Banajit Goswamida77c452015-10-14 20:45:22 -070064#define HFP_RX_VOLUME "PRI AUXPCM LOOPBACK Volume"
Derek Chen3e5b30a2018-10-24 01:04:25 -070065#elif defined PLATFORM_AUTO
66#define HFP_RX_VOLUME "Playback 36 Volume"
Meng Wangef2f6e12018-10-08 13:06:05 +080067#elif defined (PLATFORM_MSM8998) || defined (PLATFORM_MSMFALCON) || \
68 defined (PLATFORM_SDM845) || defined (PLATFORM_SDM710) || \
69 defined (PLATFORM_QCS605) || defined (PLATFORM_MSMNILE) || \
70 defined (PLATFORM_KONA) || defined (PLATFORM_MSMSTEPPE) || \
Manisha Agarwal888e9762019-02-27 22:18:49 +053071 defined (PLATFORM_QCS405) || defined (PLATFORM_TRINKET) || \
Jaideep Sharmade870aa2019-09-26 10:54:04 +053072 defined (PLATFORM_LITO) || defined(PLATFORM_ATOLL) || \
Mingshu Pang2c3f3642020-09-18 21:19:45 +080073 defined (PLATFORM_BENGAL) || defined (PLATFORM_LAHAINA)
Banajit Goswami4c0dff22016-03-04 18:31:22 -080074#define HFP_RX_VOLUME "SLIMBUS_7 LOOPBACK Volume"
Sudheer Papothi19e43d02014-07-16 02:34:41 +053075#else
76#define HFP_RX_VOLUME "Internal HFP RX Volume"
77#endif
78
Vimal Puthanveed584048b2013-12-11 17:00:50 -080079static int32_t start_hfp(struct audio_device *adev,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080080 struct str_parms *parms);
81
Vimal Puthanveed584048b2013-12-11 17:00:50 -080082static int32_t stop_hfp(struct audio_device *adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080083
84struct hfp_module {
85 struct pcm *hfp_sco_rx;
86 struct pcm *hfp_sco_tx;
87 struct pcm *hfp_pcm_rx;
88 struct pcm *hfp_pcm_tx;
89 bool is_hfp_running;
Amit Shekhar967cab32014-02-07 17:03:21 -080090 float hfp_volume;
Trinath Thammishettyf3f53472020-09-02 12:14:57 +053091 char hfp_vol_mixer_ctl[AUDIO_PARAMETER_HFP_VALUE_MAX];
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +053092 int32_t hfp_pcm_dev_id;
Vimal Puthanveed47e64852013-12-20 13:23:39 -080093 audio_usecase_t ucid;
Aalique Grahame22e49102018-12-18 14:23:57 -080094 float mic_volume;
95 bool mic_mute;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080096};
97
98static struct hfp_module hfpmod = {
99 .hfp_sco_rx = NULL,
100 .hfp_sco_tx = NULL,
101 .hfp_pcm_rx = NULL,
102 .hfp_pcm_tx = NULL,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800103 .is_hfp_running = 0,
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530104 .hfp_volume = 0,
Trinath Thammishettyf3f53472020-09-02 12:14:57 +0530105 .hfp_vol_mixer_ctl = {0, },
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530106 .hfp_pcm_dev_id = HFP_ASM_RX_TX,
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800107 .ucid = USECASE_AUDIO_HFP_SCO,
Aalique Grahame22e49102018-12-18 14:23:57 -0800108 .mic_volume = CAPTURE_VOLUME_DEFAULT,
109 .mic_mute = 0,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800110};
Aalique Grahame22e49102018-12-18 14:23:57 -0800111
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800112static struct pcm_config pcm_config_hfp = {
113 .channels = 1,
114 .rate = 8000,
115 .period_size = 240,
116 .period_count = 2,
117 .format = PCM_FORMAT_S16_LE,
118 .start_threshold = 0,
119 .stop_threshold = INT_MAX,
120 .avail_min = 0,
121};
ronghuiz98dbc492021-02-19 20:06:22 +0800122static bool route_spkr = false;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800123
Arun Mirpurie008ed22019-03-21 11:21:04 -0700124//external feature dependency
125static fp_platform_set_mic_mute_t fp_platform_set_mic_mute;
126static fp_platform_get_pcm_device_id_t fp_platform_get_pcm_device_id;
127static fp_platform_set_echo_reference_t fp_platform_set_echo_reference;
128static fp_select_devices_t fp_select_devices;
129static fp_audio_extn_ext_hw_plugin_usecase_start_t fp_audio_extn_ext_hw_plugin_usecase_start;
130static fp_audio_extn_ext_hw_plugin_usecase_stop_t fp_audio_extn_ext_hw_plugin_usecase_stop;
131static fp_get_usecase_from_list_t fp_get_usecase_from_list;
132static fp_disable_audio_route_t fp_disable_audio_route;
133static fp_disable_snd_device_t fp_disable_snd_device;
134static fp_voice_get_mic_mute_t fp_voice_get_mic_mute;
Derek Chenf7092792017-05-23 12:23:53 -0400135static fp_audio_extn_auto_hal_start_hfp_downlink_t fp_audio_extn_auto_hal_start_hfp_downlink;
136static fp_audio_extn_auto_hal_stop_hfp_downlink_t fp_audio_extn_auto_hal_stop_hfp_downlink;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700137
Amit Shekhar967cab32014-02-07 17:03:21 -0800138static int32_t hfp_set_volume(struct audio_device *adev, float value)
139{
140 int32_t vol, ret = 0;
141 struct mixer_ctl *ctl;
Sudheer Papothi19e43d02014-07-16 02:34:41 +0530142 const char *mixer_ctl_name = HFP_RX_VOLUME;
Amit Shekhar967cab32014-02-07 17:03:21 -0800143
144 ALOGV("%s: entry", __func__);
145 ALOGD("%s: (%f)\n", __func__, value);
146
Satya Krishna Pindiproli3ed6d792014-09-09 15:32:25 +0530147 hfpmod.hfp_volume = value;
Aalique Grahame22e49102018-12-18 14:23:57 -0800148
Amit Shekhar967cab32014-02-07 17:03:21 -0800149 if (value < 0.0) {
150 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
151 value = 0.0;
152 } else {
153 value = ((value > 15.000000) ? 1.0 : (value / 15));
154 ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
155 }
156 vol = lrint((value * 0x2000) + 0.5);
Amit Shekhar967cab32014-02-07 17:03:21 -0800157
158 if (!hfpmod.is_hfp_running) {
159 ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
160 return -EIO;
161 }
162
163 ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
Trinath Thammishettyf3f53472020-09-02 12:14:57 +0530164
165 if (0 == hfpmod.hfp_vol_mixer_ctl[0])
166 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
167 else
168 ctl = mixer_get_ctl_by_name(adev->mixer, hfpmod.hfp_vol_mixer_ctl);
169
170 if(!ctl) {
Amit Shekhar967cab32014-02-07 17:03:21 -0800171 ALOGE("%s: Could not get ctl for mixer cmd - %s",
172 __func__, mixer_ctl_name);
173 return -EINVAL;
174 }
175 if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
176 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
177 return -EINVAL;
178 }
179
180 ALOGV("%s: exit", __func__);
181 return ret;
182}
183
Aalique Grahame22e49102018-12-18 14:23:57 -0800184/*Set mic volume to value.
185*
186* This interface is used for mic volume control, set mic volume as value(range 0 ~ 15).
187*/
188static int hfp_set_mic_volume(struct audio_device *adev, float value)
189{
190 int volume, ret = 0;
191 char mixer_ctl_name[128];
192 struct mixer_ctl *ctl;
193 int pcm_device_id = HFP_ASM_RX_TX;
194
Arun Mirpurie008ed22019-03-21 11:21:04 -0700195 ALOGD("%s: enter, value=%f", __func__, value);
196
Aalique Grahame22e49102018-12-18 14:23:57 -0800197 if (!hfpmod.is_hfp_running) {
198 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
199 return -EIO;
200 }
201
202 if (value < 0.0) {
203 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
204 value = 0.0;
205 } else if (value > CAPTURE_VOLUME_DEFAULT) {
206 value = CAPTURE_VOLUME_DEFAULT;
207 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
208 }
209
210 value = value / CAPTURE_VOLUME_DEFAULT;
211 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
212 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
213 "Playback %d Volume", pcm_device_id);
214 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
215 if (!ctl) {
216 ALOGE("%s: Could not get ctl for mixer cmd - %s",
217 __func__, mixer_ctl_name);
218 return -EINVAL;
219 }
220 volume = (int)(value * PLAYBACK_VOLUME_MAX);
221
222 ALOGD("%s: Setting volume to %d (%s)\n", __func__, volume, mixer_ctl_name);
223 if (mixer_ctl_set_value(ctl, 0, volume) < 0) {
224 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
225 return -EINVAL;
226 }
227
228 return ret;
229}
230
231static float hfp_get_mic_volume(struct audio_device *adev)
232{
233 int volume;
234 char mixer_ctl_name[128];
235 struct mixer_ctl *ctl;
236 int pcm_device_id = HFP_ASM_RX_TX;
237 float value = 0.0;
238
Arun Mirpurie008ed22019-03-21 11:21:04 -0700239 ALOGD("%s: enter", __func__);
240
Aalique Grahame22e49102018-12-18 14:23:57 -0800241 if (!hfpmod.is_hfp_running) {
242 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
243 return -EIO;
244 }
245
246 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
247 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
248 "Playback %d Volume", pcm_device_id);
249 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
250 if (!ctl) {
251 ALOGE("%s: Could not get ctl for mixer cmd - %s",
252 __func__, mixer_ctl_name);
253 return -EINVAL;
254 }
255
256 volume = mixer_ctl_get_value(ctl, 0);
257 if ( volume < 0) {
258 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
259 return -EINVAL;
260 }
261 ALOGD("%s: getting mic volume %d \n", __func__, volume);
262
263 value = (volume / PLAYBACK_VOLUME_MAX) * CAPTURE_VOLUME_DEFAULT;
264 if (value < 0.0) {
265 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
266 value = 0.0;
267 } else if (value > CAPTURE_VOLUME_DEFAULT) {
268 value = CAPTURE_VOLUME_DEFAULT;
269 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
270 }
271
272 return value;
273}
274
275/*Set mic mute state.
276*
277* This interface is used for mic mute state control
278*/
Arun Mirpurie008ed22019-03-21 11:21:04 -0700279int hfp_set_mic_mute(struct audio_device *adev, bool state)
Aalique Grahame22e49102018-12-18 14:23:57 -0800280{
281 int rc = 0;
282
283 if (state == hfpmod.mic_mute)
284 return rc;
285
286 if (state == true) {
287 hfpmod.mic_volume = hfp_get_mic_volume(adev);
288 }
289 rc = hfp_set_mic_volume(adev, (state == true) ? 0.0 : hfpmod.mic_volume);
290 adev->voice.mic_mute = state;
291 hfpmod.mic_mute = state;
292 ALOGD("%s: Setting mute state %d, rc %d\n", __func__, state, rc);
293 return rc;
294}
295
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800296static int32_t start_hfp(struct audio_device *adev,
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700297 struct str_parms *parms __unused)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800298{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530299 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800300 struct audio_usecase *uc_info;
301 int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
302
303 ALOGD("%s: enter", __func__);
304
Aalique Grahame22e49102018-12-18 14:23:57 -0800305 if (adev->enable_hfp == true) {
306 ALOGD("%s: HFP is already active!\n", __func__);
307 return 0;
308 }
309 adev->enable_hfp = true;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700310 fp_platform_set_mic_mute(adev->platform, false);
Aalique Grahame22e49102018-12-18 14:23:57 -0800311
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800312 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700313
314 if (!uc_info)
315 return -ENOMEM;
316
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800317 uc_info->id = hfpmod.ucid;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800318 uc_info->type = PCM_HFP_CALL;
319 uc_info->stream.out = adev->primary_output;
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -0800320 list_init(&uc_info->device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800321 assign_devices(&uc_info->device_list, &adev->primary_output->device_list);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800322 uc_info->in_snd_device = SND_DEVICE_NONE;
323 uc_info->out_snd_device = SND_DEVICE_NONE;
324
ronghuiz98dbc492021-02-19 20:06:22 +0800325 if (route_spkr) {
326 reassign_device_list(&uc_info->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
327 reassign_device_list(&uc_info->stream.out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
328 }
329
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800330 list_add_tail(&adev->usecase_list, &uc_info->list);
331
Arun Mirpurie008ed22019-03-21 11:21:04 -0700332 fp_select_devices(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800333
Derek Chend2530072014-11-24 12:39:14 -0800334 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
335 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
Arun Mirpurie008ed22019-03-21 11:21:04 -0700336 if (fp_audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
Derek Chend2530072014-11-24 12:39:14 -0800337 ALOGE("%s: failed to start ext hw plugin", __func__);
338 }
339
Arun Mirpurie008ed22019-03-21 11:21:04 -0700340 pcm_dev_rx_id = fp_platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
341 pcm_dev_tx_id = fp_platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530342 pcm_dev_asm_rx_id = hfpmod.hfp_pcm_dev_id;
343 pcm_dev_asm_tx_id = hfpmod.hfp_pcm_dev_id;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800344 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
345 pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
346 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
347 __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
348 ret = -EIO;
349 goto exit;
350 }
351
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530352 ALOGD("%s: HFP PCM devices (rx: %d tx: %d pcm dev id: %d) usecase(%d)",
353 __func__, pcm_dev_rx_id, pcm_dev_tx_id, hfpmod.hfp_pcm_dev_id, uc_info->id);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800354
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800355 hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800356 pcm_dev_rx_id,
357 PCM_OUT, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800358 if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
359 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
360 ret = -EIO;
361 goto exit;
362 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530363
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800364 hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800365 pcm_dev_tx_id,
366 PCM_IN, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800367 if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
368 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
369 ret = -EIO;
370 goto exit;
371 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530372
Satya Krishna Pindiprolice903a02014-07-28 12:40:56 +0530373 if (pcm_start(hfpmod.hfp_pcm_rx) < 0) {
374 ALOGE("%s: pcm start for hfp pcm rx failed", __func__);
375 ret = -EINVAL;
376 goto exit;
377 }
378 if (pcm_start(hfpmod.hfp_pcm_tx) < 0) {
379 ALOGE("%s: pcm start for hfp pcm tx failed", __func__);
380 ret = -EINVAL;
381 goto exit;
382 }
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800383
Derek Chenf7092792017-05-23 12:23:53 -0400384 if (fp_audio_extn_auto_hal_start_hfp_downlink(adev, uc_info))
385 ALOGE("%s: start hfp downlink failed", __func__);
386
387 hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
388 pcm_dev_asm_rx_id,
389 PCM_OUT, &pcm_config_hfp);
390 if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
391 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
392 ret = -EIO;
393 goto exit;
394 }
395
396 hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
397 pcm_dev_asm_tx_id,
398 PCM_IN, &pcm_config_hfp);
399 if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
400 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
401 ret = -EIO;
402 goto exit;
403 }
404
405 if (pcm_start(hfpmod.hfp_sco_rx) < 0) {
406 ALOGE("%s: pcm start for hfp sco rx failed", __func__);
407 ret = -EINVAL;
408 goto exit;
409 }
410 if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
411 ALOGE("%s: pcm start for hfp sco tx failed", __func__);
412 ret = -EINVAL;
413 goto exit;
414 }
415
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800416 hfpmod.is_hfp_running = true;
Amit Shekhar967cab32014-02-07 17:03:21 -0800417 hfp_set_volume(adev, hfpmod.hfp_volume);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800418
Aalique Grahame22e49102018-12-18 14:23:57 -0800419 /* Set mic volume by mute status, we don't provide set mic volume in phone app, only
420 provide mute and unmute. */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700421 hfp_set_mic_mute(adev, adev->mic_muted);
Aalique Grahame22e49102018-12-18 14:23:57 -0800422
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800423 ALOGD("%s: exit: status(%d)", __func__, ret);
424 return 0;
425
426exit:
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800427 stop_hfp(adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800428 ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
429 return ret;
430}
431
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800432static int32_t stop_hfp(struct audio_device *adev)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800433{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530434 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800435 struct audio_usecase *uc_info;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800436 struct listnode *node;
437 struct audio_device_info *item = NULL;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800438
439 ALOGD("%s: enter", __func__);
440 hfpmod.is_hfp_running = false;
ronghuiz98dbc492021-02-19 20:06:22 +0800441 route_spkr = false;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800442
443 /* 1. Close the PCM devices */
444 if (hfpmod.hfp_sco_rx) {
445 pcm_close(hfpmod.hfp_sco_rx);
446 hfpmod.hfp_sco_rx = NULL;
447 }
448 if (hfpmod.hfp_sco_tx) {
449 pcm_close(hfpmod.hfp_sco_tx);
450 hfpmod.hfp_sco_tx = NULL;
451 }
452 if (hfpmod.hfp_pcm_rx) {
453 pcm_close(hfpmod.hfp_pcm_rx);
454 hfpmod.hfp_pcm_rx = NULL;
455 }
456 if (hfpmod.hfp_pcm_tx) {
457 pcm_close(hfpmod.hfp_pcm_tx);
458 hfpmod.hfp_pcm_tx = NULL;
459 }
460
Arun Mirpurie008ed22019-03-21 11:21:04 -0700461 uc_info = fp_get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800462 if (uc_info == NULL) {
463 ALOGE("%s: Could not find the usecase (%d) in the list",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800464 __func__, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800465 return -EINVAL;
466 }
467
Derek Chend2530072014-11-24 12:39:14 -0800468 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
469 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
Arun Mirpurie008ed22019-03-21 11:21:04 -0700470 if (fp_audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
Derek Chend2530072014-11-24 12:39:14 -0800471 ALOGE("%s: failed to stop ext hw plugin", __func__);
472 }
473
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530474 /* 2. Disable echo reference while stopping hfp */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800475 fp_platform_set_echo_reference(adev, false, &uc_info->device_list);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530476
477 /* 3. Get and set stream specific mixer controls */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700478 fp_disable_audio_route(adev, uc_info);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800479
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530480 /* 4. Disable the rx and tx devices */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700481 fp_disable_snd_device(adev, uc_info->out_snd_device);
482 fp_disable_snd_device(adev, uc_info->in_snd_device);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800483
Derek Chenf7092792017-05-23 12:23:53 -0400484 if (fp_audio_extn_auto_hal_stop_hfp_downlink(adev, uc_info))
485 ALOGE("%s: stop hfp downlink failed", __func__);
486
Aalique Grahame22e49102018-12-18 14:23:57 -0800487 /* Set the unmute Tx mixer control */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700488 if (fp_voice_get_mic_mute(adev)) {
489 fp_platform_set_mic_mute(adev->platform, false);
Aalique Grahame22e49102018-12-18 14:23:57 -0800490 ALOGD("%s: unMute HFP Tx", __func__);
491 }
492 adev->enable_hfp = false;
493
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800494 list_remove(&uc_info->list);
495 free(uc_info);
496
497 ALOGD("%s: exit: status(%d)", __func__, ret);
498 return ret;
499}
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800500
Arun Mirpurie008ed22019-03-21 11:21:04 -0700501void hfp_init(hfp_init_config_t init_config)
502{
503 fp_platform_set_mic_mute = init_config.fp_platform_set_mic_mute;
504 fp_platform_get_pcm_device_id = init_config.fp_platform_get_pcm_device_id;
505 fp_platform_set_echo_reference = init_config.fp_platform_set_echo_reference;
506 fp_select_devices = init_config.fp_select_devices;
507 fp_audio_extn_ext_hw_plugin_usecase_start =
508 init_config.fp_audio_extn_ext_hw_plugin_usecase_start;
509 fp_audio_extn_ext_hw_plugin_usecase_stop =
510 init_config.fp_audio_extn_ext_hw_plugin_usecase_stop;
511 fp_get_usecase_from_list = init_config.fp_get_usecase_from_list;
512 fp_disable_audio_route = init_config.fp_disable_audio_route;
513 fp_disable_snd_device = init_config.fp_disable_snd_device;
514 fp_voice_get_mic_mute = init_config.fp_voice_get_mic_mute;
Derek Chenf7092792017-05-23 12:23:53 -0400515 fp_audio_extn_auto_hal_start_hfp_downlink =
516 init_config.fp_audio_extn_auto_hal_start_hfp_downlink;
517 fp_audio_extn_auto_hal_stop_hfp_downlink =
518 init_config.fp_audio_extn_auto_hal_stop_hfp_downlink;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700519}
520
521bool hfp_is_active(struct audio_device *adev)
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800522{
523 struct audio_usecase *hfp_usecase = NULL;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700524 hfp_usecase = fp_get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800525
526 if (hfp_usecase != NULL)
527 return true;
528 else
529 return false;
530}
531
Arun Mirpurie008ed22019-03-21 11:21:04 -0700532int hfp_set_mic_mute2(struct audio_device *adev, bool state)
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530533{
534 struct mixer_ctl *ctl;
535 const char *mixer_ctl_name = "HFP TX Mute";
Manish Dewangan338c50a2017-09-12 15:22:03 +0530536 long set_values[ ] = {0};
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530537
Arun Mirpurie008ed22019-03-21 11:21:04 -0700538 ALOGD("%s: enter, state=%d", __func__, state);
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530539
540 set_values[0] = state;
541 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
542 if (!ctl) {
543 ALOGE("%s: Could not get ctl for mixer cmd - %s",
544 __func__, mixer_ctl_name);
545 return -EINVAL;
546 }
547 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
548 ALOGV("%s: exit", __func__);
549 return 0;
550}
551
Arun Mirpurie008ed22019-03-21 11:21:04 -0700552audio_usecase_t hfp_get_usecase()
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800553{
554 return hfpmod.ucid;
555}
556
Arun Mirpurie008ed22019-03-21 11:21:04 -0700557void hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800558{
559 int ret;
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800560 int rate;
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800561 int val;
Amit Shekhar967cab32014-02-07 17:03:21 -0800562 float vol;
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800563 char value[32]={0};
ronghuiz98dbc492021-02-19 20:06:22 +0800564 struct audio_usecase *uc_info = NULL;
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800565
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700566 ALOGV("%s: enter", __func__);
Arun Mirpurie008ed22019-03-21 11:21:04 -0700567
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800568 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
569 sizeof(value));
570 if (ret >= 0) {
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530571 if (!strncmp(value, "true", sizeof(value)) && !hfpmod.is_hfp_running)
572 ret = start_hfp(adev,parms);
573 else if (!strncmp(value, "false", sizeof(value)) && hfpmod.is_hfp_running)
574 stop_hfp(adev);
575 else
576 ALOGE("hfp_enable=%s is unsupported", value);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800577 }
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800578 memset(value, 0, sizeof(value));
579 ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
580 sizeof(value));
581 if (ret >= 0) {
582 rate = atoi(value);
583 if (rate == 8000){
584 hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
585 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700586 } else if (rate == 16000){
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800587 hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
588 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700589 } else
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800590 ALOGE("Unsupported rate..");
591 }
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800592
ronghuiz98dbc492021-02-19 20:06:22 +0800593 memset(value, 0, sizeof(value));
594 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_FORCE_ROUTE_SPEAKER, value,
595 sizeof(value));
596 if(ret >= 0){
597 route_spkr = true;
598 ALOGD("%s: Set force route to speaker", __func__);
599 }
600
601 memset(value, 0, sizeof(value));
602 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800603 value, sizeof(value));
ronghuiz98dbc492021-02-19 20:06:22 +0800604 if (ret >= 0) {
605 val = atoi(value);
606 if (val > 0) {
607 if (hfpmod.is_hfp_running) {
608 if (route_spkr) {
609 if (val != AUDIO_DEVICE_OUT_SPEAKER)
610 ALOGI("%s: HFP call in progress, cannot route to device %d", __func__, val);
611 } else {
612 uc_info = fp_get_usecase_from_list(adev, hfpmod.ucid);
613
614 if (uc_info != NULL) {
615 reassign_device_list(&uc_info->device_list, val, "");
616 reassign_device_list(&uc_info->stream.out->device_list, val, "");
617 fp_select_devices(adev, hfpmod.ucid);
618 }
619 }
620
621 str_parms_del(parms, AUDIO_PARAMETER_STREAM_ROUTING);
622 }
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800623 }
624 }
Amit Shekhar967cab32014-02-07 17:03:21 -0800625
626 memset(value, 0, sizeof(value));
Trinath Thammishettyf3f53472020-09-02 12:14:57 +0530627 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_VOL_MIXER_CTL,
628 value, sizeof(value));
629 if (ret >= 0) {
630 ALOGD("%s: mixer ctl name: %s", __func__, value);
631 strlcpy(hfpmod.hfp_vol_mixer_ctl, value, sizeof(value));
632 str_parms_del(parms, AUDIO_PARAMETER_HFP_VOL_MIXER_CTL);
633 }
634
635 memset(value, 0, sizeof(value));
Amit Shekhar967cab32014-02-07 17:03:21 -0800636 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
637 value, sizeof(value));
638 if (ret >= 0) {
639 if (sscanf(value, "%f", &vol) != 1){
640 ALOGE("%s: error in retrieving hfp volume", __func__);
641 ret = -EIO;
642 goto exit;
643 }
644 ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
645 hfp_set_volume(adev, vol);
646 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530647
648 memset(value, 0, sizeof(value));
649 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID, value, sizeof(value));
650 if (ret >= 0) {
651 hfpmod.hfp_pcm_dev_id = atoi(value);
652 ALOGD("Updating HFP_PCM_DEV_ID as %d from platform XML", hfpmod.hfp_pcm_dev_id);
653 str_parms_del(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID);
654 }
655
Aalique Grahame22e49102018-12-18 14:23:57 -0800656 memset(value, 0, sizeof(value));
657 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_MIC_VOLUME,
658 value, sizeof(value));
659 if (ret >= 0) {
660 if (sscanf(value, "%f", &vol) != 1){
661 ALOGE("%s: error in retrieving hfp mic volume", __func__);
662 ret = -EIO;
663 goto exit;
664 }
665 ALOGD("%s: set_hfp_mic_volume usecase, Vol: [%f]", __func__, vol);
666 hfp_set_mic_volume(adev, vol);
667 }
668
Amit Shekhar967cab32014-02-07 17:03:21 -0800669exit:
670 ALOGV("%s Exit",__func__);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800671}