blob: 374e9dc0c59bc6de018a8ec249071a98801e099a [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;
Guodong Huf5e614d2019-06-24 18:42:03 +080086 struct pcm *hfp_ext_ec_tx;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080087 bool is_hfp_running;
Amit Shekhar967cab32014-02-07 17:03:21 -080088 float hfp_volume;
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +053089 int32_t hfp_pcm_dev_id;
Vimal Puthanveed47e64852013-12-20 13:23:39 -080090 audio_usecase_t ucid;
Aalique Grahame22e49102018-12-18 14:23:57 -080091 float mic_volume;
92 bool mic_mute;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080093};
94
95static struct hfp_module hfpmod = {
96 .hfp_sco_rx = NULL,
97 .hfp_sco_tx = NULL,
98 .hfp_pcm_rx = NULL,
99 .hfp_pcm_tx = NULL,
Guodong Huf5e614d2019-06-24 18:42:03 +0800100 .hfp_ext_ec_tx = NULL,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800101 .is_hfp_running = 0,
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530102 .hfp_volume = 0,
103 .hfp_pcm_dev_id = HFP_ASM_RX_TX,
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800104 .ucid = USECASE_AUDIO_HFP_SCO,
Aalique Grahame22e49102018-12-18 14:23:57 -0800105 .mic_volume = CAPTURE_VOLUME_DEFAULT,
106 .mic_mute = 0,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800107};
Aalique Grahame22e49102018-12-18 14:23:57 -0800108
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800109static struct pcm_config pcm_config_hfp = {
110 .channels = 1,
111 .rate = 8000,
112 .period_size = 240,
113 .period_count = 2,
114 .format = PCM_FORMAT_S16_LE,
115 .start_threshold = 0,
116 .stop_threshold = INT_MAX,
117 .avail_min = 0,
118};
119
Arun Mirpurie008ed22019-03-21 11:21:04 -0700120//external feature dependency
121static fp_platform_set_mic_mute_t fp_platform_set_mic_mute;
122static fp_platform_get_pcm_device_id_t fp_platform_get_pcm_device_id;
123static fp_platform_set_echo_reference_t fp_platform_set_echo_reference;
124static fp_select_devices_t fp_select_devices;
125static fp_audio_extn_ext_hw_plugin_usecase_start_t fp_audio_extn_ext_hw_plugin_usecase_start;
126static fp_audio_extn_ext_hw_plugin_usecase_stop_t fp_audio_extn_ext_hw_plugin_usecase_stop;
127static fp_get_usecase_from_list_t fp_get_usecase_from_list;
128static fp_disable_audio_route_t fp_disable_audio_route;
129static fp_disable_snd_device_t fp_disable_snd_device;
130static fp_voice_get_mic_mute_t fp_voice_get_mic_mute;
Derek Chenf7092792017-05-23 12:23:53 -0400131static fp_audio_extn_auto_hal_start_hfp_downlink_t fp_audio_extn_auto_hal_start_hfp_downlink;
132static fp_audio_extn_auto_hal_stop_hfp_downlink_t fp_audio_extn_auto_hal_stop_hfp_downlink;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700133
Amit Shekhar967cab32014-02-07 17:03:21 -0800134static int32_t hfp_set_volume(struct audio_device *adev, float value)
135{
136 int32_t vol, ret = 0;
137 struct mixer_ctl *ctl;
Sudheer Papothi19e43d02014-07-16 02:34:41 +0530138 const char *mixer_ctl_name = HFP_RX_VOLUME;
Amit Shekhar967cab32014-02-07 17:03:21 -0800139
140 ALOGV("%s: entry", __func__);
141 ALOGD("%s: (%f)\n", __func__, value);
142
Satya Krishna Pindiproli3ed6d792014-09-09 15:32:25 +0530143 hfpmod.hfp_volume = value;
Aalique Grahame22e49102018-12-18 14:23:57 -0800144
Amit Shekhar967cab32014-02-07 17:03:21 -0800145 if (value < 0.0) {
146 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
147 value = 0.0;
148 } else {
149 value = ((value > 15.000000) ? 1.0 : (value / 15));
150 ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
151 }
152 vol = lrint((value * 0x2000) + 0.5);
Amit Shekhar967cab32014-02-07 17:03:21 -0800153
154 if (!hfpmod.is_hfp_running) {
155 ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
156 return -EIO;
157 }
158
159 ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
160 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
161 if (!ctl) {
162 ALOGE("%s: Could not get ctl for mixer cmd - %s",
163 __func__, mixer_ctl_name);
164 return -EINVAL;
165 }
166 if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
167 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
168 return -EINVAL;
169 }
170
171 ALOGV("%s: exit", __func__);
172 return ret;
173}
174
Aalique Grahame22e49102018-12-18 14:23:57 -0800175/*Set mic volume to value.
176*
177* This interface is used for mic volume control, set mic volume as value(range 0 ~ 15).
178*/
179static int hfp_set_mic_volume(struct audio_device *adev, float value)
180{
181 int volume, ret = 0;
182 char mixer_ctl_name[128];
183 struct mixer_ctl *ctl;
184 int pcm_device_id = HFP_ASM_RX_TX;
185
Arun Mirpurie008ed22019-03-21 11:21:04 -0700186 ALOGD("%s: enter, value=%f", __func__, value);
187
Aalique Grahame22e49102018-12-18 14:23:57 -0800188 if (!hfpmod.is_hfp_running) {
189 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
190 return -EIO;
191 }
192
193 if (value < 0.0) {
194 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
195 value = 0.0;
196 } else if (value > CAPTURE_VOLUME_DEFAULT) {
197 value = CAPTURE_VOLUME_DEFAULT;
198 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
199 }
200
201 value = value / CAPTURE_VOLUME_DEFAULT;
202 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
203 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
204 "Playback %d Volume", pcm_device_id);
205 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
206 if (!ctl) {
207 ALOGE("%s: Could not get ctl for mixer cmd - %s",
208 __func__, mixer_ctl_name);
209 return -EINVAL;
210 }
211 volume = (int)(value * PLAYBACK_VOLUME_MAX);
212
213 ALOGD("%s: Setting volume to %d (%s)\n", __func__, volume, mixer_ctl_name);
214 if (mixer_ctl_set_value(ctl, 0, volume) < 0) {
215 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
216 return -EINVAL;
217 }
218
219 return ret;
220}
221
222static float hfp_get_mic_volume(struct audio_device *adev)
223{
224 int volume;
225 char mixer_ctl_name[128];
226 struct mixer_ctl *ctl;
227 int pcm_device_id = HFP_ASM_RX_TX;
228 float value = 0.0;
229
Arun Mirpurie008ed22019-03-21 11:21:04 -0700230 ALOGD("%s: enter", __func__);
231
Aalique Grahame22e49102018-12-18 14:23:57 -0800232 if (!hfpmod.is_hfp_running) {
233 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
234 return -EIO;
235 }
236
237 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
238 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
239 "Playback %d Volume", pcm_device_id);
240 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
241 if (!ctl) {
242 ALOGE("%s: Could not get ctl for mixer cmd - %s",
243 __func__, mixer_ctl_name);
244 return -EINVAL;
245 }
246
247 volume = mixer_ctl_get_value(ctl, 0);
248 if ( volume < 0) {
249 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
250 return -EINVAL;
251 }
252 ALOGD("%s: getting mic volume %d \n", __func__, volume);
253
254 value = (volume / PLAYBACK_VOLUME_MAX) * CAPTURE_VOLUME_DEFAULT;
255 if (value < 0.0) {
256 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
257 value = 0.0;
258 } else if (value > CAPTURE_VOLUME_DEFAULT) {
259 value = CAPTURE_VOLUME_DEFAULT;
260 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
261 }
262
263 return value;
264}
265
266/*Set mic mute state.
267*
268* This interface is used for mic mute state control
269*/
Arun Mirpurie008ed22019-03-21 11:21:04 -0700270int hfp_set_mic_mute(struct audio_device *adev, bool state)
Aalique Grahame22e49102018-12-18 14:23:57 -0800271{
272 int rc = 0;
273
274 if (state == hfpmod.mic_mute)
275 return rc;
276
277 if (state == true) {
278 hfpmod.mic_volume = hfp_get_mic_volume(adev);
279 }
280 rc = hfp_set_mic_volume(adev, (state == true) ? 0.0 : hfpmod.mic_volume);
281 adev->voice.mic_mute = state;
282 hfpmod.mic_mute = state;
283 ALOGD("%s: Setting mute state %d, rc %d\n", __func__, state, rc);
284 return rc;
285}
286
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800287static int32_t start_hfp(struct audio_device *adev,
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700288 struct str_parms *parms __unused)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800289{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530290 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800291 struct audio_usecase *uc_info;
292 int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
Guodong Huf5e614d2019-06-24 18:42:03 +0800293 int32_t pcm_ext_ec_ref_id;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800294
295 ALOGD("%s: enter", __func__);
296
Aalique Grahame22e49102018-12-18 14:23:57 -0800297 if (adev->enable_hfp == true) {
298 ALOGD("%s: HFP is already active!\n", __func__);
299 return 0;
300 }
301 adev->enable_hfp = true;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700302 fp_platform_set_mic_mute(adev->platform, false);
Aalique Grahame22e49102018-12-18 14:23:57 -0800303
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800304 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700305
306 if (!uc_info)
307 return -ENOMEM;
308
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800309 uc_info->id = hfpmod.ucid;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800310 uc_info->type = PCM_HFP_CALL;
311 uc_info->stream.out = adev->primary_output;
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -0800312 list_init(&uc_info->device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800313 assign_devices(&uc_info->device_list, &adev->primary_output->device_list);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800314 uc_info->in_snd_device = SND_DEVICE_NONE;
315 uc_info->out_snd_device = SND_DEVICE_NONE;
316
317 list_add_tail(&adev->usecase_list, &uc_info->list);
318
Arun Mirpurie008ed22019-03-21 11:21:04 -0700319 fp_select_devices(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800320
Derek Chend2530072014-11-24 12:39:14 -0800321 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
322 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
Arun Mirpurie008ed22019-03-21 11:21:04 -0700323 if (fp_audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
Derek Chend2530072014-11-24 12:39:14 -0800324 ALOGE("%s: failed to start ext hw plugin", __func__);
325 }
326
Arun Mirpurie008ed22019-03-21 11:21:04 -0700327 pcm_dev_rx_id = fp_platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
328 pcm_dev_tx_id = fp_platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530329 pcm_dev_asm_rx_id = hfpmod.hfp_pcm_dev_id;
330 pcm_dev_asm_tx_id = hfpmod.hfp_pcm_dev_id;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800331 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
332 pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
333 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
334 __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
335 ret = -EIO;
336 goto exit;
337 }
338
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530339 ALOGD("%s: HFP PCM devices (rx: %d tx: %d pcm dev id: %d) usecase(%d)",
340 __func__, pcm_dev_rx_id, pcm_dev_tx_id, hfpmod.hfp_pcm_dev_id, uc_info->id);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800341
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800342 hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800343 pcm_dev_rx_id,
344 PCM_OUT, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800345 if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
346 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
347 ret = -EIO;
348 goto exit;
349 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530350
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800351 hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800352 pcm_dev_tx_id,
353 PCM_IN, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800354 if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
355 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
356 ret = -EIO;
357 goto exit;
358 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530359
Satya Krishna Pindiprolice903a02014-07-28 12:40:56 +0530360 if (pcm_start(hfpmod.hfp_pcm_rx) < 0) {
361 ALOGE("%s: pcm start for hfp pcm rx failed", __func__);
362 ret = -EINVAL;
363 goto exit;
364 }
365 if (pcm_start(hfpmod.hfp_pcm_tx) < 0) {
366 ALOGE("%s: pcm start for hfp pcm tx failed", __func__);
367 ret = -EINVAL;
368 goto exit;
369 }
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800370
Derek Chenf7092792017-05-23 12:23:53 -0400371 if (fp_audio_extn_auto_hal_start_hfp_downlink(adev, uc_info))
372 ALOGE("%s: start hfp downlink failed", __func__);
373
374 hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
375 pcm_dev_asm_rx_id,
376 PCM_OUT, &pcm_config_hfp);
377 if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
378 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
379 ret = -EIO;
380 goto exit;
381 }
382
383 hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
384 pcm_dev_asm_tx_id,
385 PCM_IN, &pcm_config_hfp);
386 if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
387 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
388 ret = -EIO;
389 goto exit;
390 }
391
392 if (pcm_start(hfpmod.hfp_sco_rx) < 0) {
393 ALOGE("%s: pcm start for hfp sco rx failed", __func__);
394 ret = -EINVAL;
395 goto exit;
396 }
397 if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
398 ALOGE("%s: pcm start for hfp sco tx failed", __func__);
399 ret = -EINVAL;
400 goto exit;
401 }
402
Guodong Huf5e614d2019-06-24 18:42:03 +0800403#ifdef PLATFORM_AUTO
404 /* echo reference path for single-mic/multi-mic surround ECNS hfp calls */
405 pcm_ext_ec_ref_id = HFP_EXT_EC_REF_TX;
406 ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
407 __func__, adev->snd_card, pcm_ext_ec_ref_id);
408 hfpmod.hfp_ext_ec_tx = pcm_open(adev->snd_card,
409 pcm_ext_ec_ref_id,
410 PCM_IN, &pcm_config_hfp);
411 if (hfpmod.hfp_ext_ec_tx && !pcm_is_ready(hfpmod.hfp_ext_ec_tx)) {
412 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_ext_ec_tx));
413 ret = -EIO;
414 goto exit;
415 }
416
417 if (pcm_start(hfpmod.hfp_ext_ec_tx) < 0) {
418 ALOGE("%s: pcm start for hfp ext ec tx failed", __func__);
419 ret = -EINVAL;
420 goto exit;
421 }
422#endif
423
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800424 hfpmod.is_hfp_running = true;
Amit Shekhar967cab32014-02-07 17:03:21 -0800425 hfp_set_volume(adev, hfpmod.hfp_volume);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800426
Aalique Grahame22e49102018-12-18 14:23:57 -0800427 /* Set mic volume by mute status, we don't provide set mic volume in phone app, only
428 provide mute and unmute. */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700429 hfp_set_mic_mute(adev, adev->mic_muted);
Aalique Grahame22e49102018-12-18 14:23:57 -0800430
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800431 ALOGD("%s: exit: status(%d)", __func__, ret);
432 return 0;
433
434exit:
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800435 stop_hfp(adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800436 ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
437 return ret;
438}
439
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800440static int32_t stop_hfp(struct audio_device *adev)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800441{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530442 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800443 struct audio_usecase *uc_info;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800444 struct listnode *node;
445 struct audio_device_info *item = NULL;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800446
447 ALOGD("%s: enter", __func__);
448 hfpmod.is_hfp_running = false;
449
450 /* 1. Close the PCM devices */
451 if (hfpmod.hfp_sco_rx) {
452 pcm_close(hfpmod.hfp_sco_rx);
453 hfpmod.hfp_sco_rx = NULL;
454 }
455 if (hfpmod.hfp_sco_tx) {
456 pcm_close(hfpmod.hfp_sco_tx);
457 hfpmod.hfp_sco_tx = NULL;
458 }
459 if (hfpmod.hfp_pcm_rx) {
460 pcm_close(hfpmod.hfp_pcm_rx);
461 hfpmod.hfp_pcm_rx = NULL;
462 }
463 if (hfpmod.hfp_pcm_tx) {
464 pcm_close(hfpmod.hfp_pcm_tx);
465 hfpmod.hfp_pcm_tx = NULL;
466 }
467
Guodong Huf5e614d2019-06-24 18:42:03 +0800468#ifdef PLATFORM_AUTO
469 /* echo reference path for single-mic/multi-mic surround ECNS hfp calls */
470 if (hfpmod.hfp_ext_ec_tx) {
471 pcm_close(hfpmod.hfp_ext_ec_tx);
472 hfpmod.hfp_ext_ec_tx = NULL;
473 }
474#endif
475
Arun Mirpurie008ed22019-03-21 11:21:04 -0700476 uc_info = fp_get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800477 if (uc_info == NULL) {
478 ALOGE("%s: Could not find the usecase (%d) in the list",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800479 __func__, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800480 return -EINVAL;
481 }
482
Derek Chend2530072014-11-24 12:39:14 -0800483 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
484 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
Arun Mirpurie008ed22019-03-21 11:21:04 -0700485 if (fp_audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
Derek Chend2530072014-11-24 12:39:14 -0800486 ALOGE("%s: failed to stop ext hw plugin", __func__);
487 }
488
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530489 /* 2. Disable echo reference while stopping hfp */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800490 fp_platform_set_echo_reference(adev, false, &uc_info->device_list);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530491
492 /* 3. Get and set stream specific mixer controls */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700493 fp_disable_audio_route(adev, uc_info);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800494
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530495 /* 4. Disable the rx and tx devices */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700496 fp_disable_snd_device(adev, uc_info->out_snd_device);
497 fp_disable_snd_device(adev, uc_info->in_snd_device);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800498
Derek Chenf7092792017-05-23 12:23:53 -0400499 if (fp_audio_extn_auto_hal_stop_hfp_downlink(adev, uc_info))
500 ALOGE("%s: stop hfp downlink failed", __func__);
501
Aalique Grahame22e49102018-12-18 14:23:57 -0800502 /* Set the unmute Tx mixer control */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700503 if (fp_voice_get_mic_mute(adev)) {
504 fp_platform_set_mic_mute(adev->platform, false);
Aalique Grahame22e49102018-12-18 14:23:57 -0800505 ALOGD("%s: unMute HFP Tx", __func__);
506 }
507 adev->enable_hfp = false;
508
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800509 list_remove(&uc_info->list);
510 free(uc_info);
511
512 ALOGD("%s: exit: status(%d)", __func__, ret);
513 return ret;
514}
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800515
Arun Mirpurie008ed22019-03-21 11:21:04 -0700516void hfp_init(hfp_init_config_t init_config)
517{
518 fp_platform_set_mic_mute = init_config.fp_platform_set_mic_mute;
519 fp_platform_get_pcm_device_id = init_config.fp_platform_get_pcm_device_id;
520 fp_platform_set_echo_reference = init_config.fp_platform_set_echo_reference;
521 fp_select_devices = init_config.fp_select_devices;
522 fp_audio_extn_ext_hw_plugin_usecase_start =
523 init_config.fp_audio_extn_ext_hw_plugin_usecase_start;
524 fp_audio_extn_ext_hw_plugin_usecase_stop =
525 init_config.fp_audio_extn_ext_hw_plugin_usecase_stop;
526 fp_get_usecase_from_list = init_config.fp_get_usecase_from_list;
527 fp_disable_audio_route = init_config.fp_disable_audio_route;
528 fp_disable_snd_device = init_config.fp_disable_snd_device;
529 fp_voice_get_mic_mute = init_config.fp_voice_get_mic_mute;
Derek Chenf7092792017-05-23 12:23:53 -0400530 fp_audio_extn_auto_hal_start_hfp_downlink =
531 init_config.fp_audio_extn_auto_hal_start_hfp_downlink;
532 fp_audio_extn_auto_hal_stop_hfp_downlink =
533 init_config.fp_audio_extn_auto_hal_stop_hfp_downlink;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700534}
535
536bool hfp_is_active(struct audio_device *adev)
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800537{
538 struct audio_usecase *hfp_usecase = NULL;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700539 hfp_usecase = fp_get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800540
541 if (hfp_usecase != NULL)
542 return true;
543 else
544 return false;
545}
546
Arun Mirpurie008ed22019-03-21 11:21:04 -0700547int hfp_set_mic_mute2(struct audio_device *adev, bool state)
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530548{
549 struct mixer_ctl *ctl;
550 const char *mixer_ctl_name = "HFP TX Mute";
Manish Dewangan338c50a2017-09-12 15:22:03 +0530551 long set_values[ ] = {0};
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530552
Arun Mirpurie008ed22019-03-21 11:21:04 -0700553 ALOGD("%s: enter, state=%d", __func__, state);
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530554
555 set_values[0] = state;
556 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
557 if (!ctl) {
558 ALOGE("%s: Could not get ctl for mixer cmd - %s",
559 __func__, mixer_ctl_name);
560 return -EINVAL;
561 }
562 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
563 ALOGV("%s: exit", __func__);
564 return 0;
565}
566
Arun Mirpurie008ed22019-03-21 11:21:04 -0700567audio_usecase_t hfp_get_usecase()
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800568{
569 return hfpmod.ucid;
570}
571
Arun Mirpurie008ed22019-03-21 11:21:04 -0700572void hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800573{
574 int ret;
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800575 int rate;
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800576 int val;
Amit Shekhar967cab32014-02-07 17:03:21 -0800577 float vol;
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800578 char value[32]={0};
579
Arun Mirpurie008ed22019-03-21 11:21:04 -0700580 ALOGD("%s: enter", __func__);
581
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800582 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
583 sizeof(value));
584 if (ret >= 0) {
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530585 if (!strncmp(value, "true", sizeof(value)) && !hfpmod.is_hfp_running)
586 ret = start_hfp(adev,parms);
587 else if (!strncmp(value, "false", sizeof(value)) && hfpmod.is_hfp_running)
588 stop_hfp(adev);
589 else
590 ALOGE("hfp_enable=%s is unsupported", value);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800591 }
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800592 memset(value, 0, sizeof(value));
593 ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
594 sizeof(value));
595 if (ret >= 0) {
596 rate = atoi(value);
597 if (rate == 8000){
598 hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
599 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700600 } else if (rate == 16000){
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800601 hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
602 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700603 } else
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800604 ALOGE("Unsupported rate..");
605 }
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800606
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700607 if (hfpmod.is_hfp_running) {
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800608 memset(value, 0, sizeof(value));
609 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
610 value, sizeof(value));
611 if (ret >= 0) {
612 val = atoi(value);
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700613 if (val > 0)
Arun Mirpurie008ed22019-03-21 11:21:04 -0700614 fp_select_devices(adev, hfpmod.ucid);
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800615 }
616 }
Amit Shekhar967cab32014-02-07 17:03:21 -0800617
618 memset(value, 0, sizeof(value));
619 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
620 value, sizeof(value));
621 if (ret >= 0) {
622 if (sscanf(value, "%f", &vol) != 1){
623 ALOGE("%s: error in retrieving hfp volume", __func__);
624 ret = -EIO;
625 goto exit;
626 }
627 ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
628 hfp_set_volume(adev, vol);
629 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530630
631 memset(value, 0, sizeof(value));
632 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID, value, sizeof(value));
633 if (ret >= 0) {
634 hfpmod.hfp_pcm_dev_id = atoi(value);
635 ALOGD("Updating HFP_PCM_DEV_ID as %d from platform XML", hfpmod.hfp_pcm_dev_id);
636 str_parms_del(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID);
637 }
638
Aalique Grahame22e49102018-12-18 14:23:57 -0800639 memset(value, 0, sizeof(value));
640 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_MIC_VOLUME,
641 value, sizeof(value));
642 if (ret >= 0) {
643 if (sscanf(value, "%f", &vol) != 1){
644 ALOGE("%s: error in retrieving hfp mic volume", __func__);
645 ret = -EIO;
646 goto exit;
647 }
648 ALOGD("%s: set_hfp_mic_volume usecase, Vol: [%f]", __func__, vol);
649 hfp_set_mic_volume(adev, vol);
650 }
651
Amit Shekhar967cab32014-02-07 17:03:21 -0800652exit:
653 ALOGV("%s Exit",__func__);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800654}