blob: 9b6008364224f92598a6b135326e18311d45a987 [file] [log] [blame]
Aalique Grahame22e49102018-12-18 14:23:57 -08001/* Copyright (c) 2012-2019, 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) || \
Faiz Nabi Kuchay0b79d7d2019-08-05 20:36:31 +053069 defined (PLATFORM_LITO) || defined(PLATFORM_ATOLL)
Banajit Goswami4c0dff22016-03-04 18:31:22 -080070#define HFP_RX_VOLUME "SLIMBUS_7 LOOPBACK Volume"
Sudheer Papothi19e43d02014-07-16 02:34:41 +053071#else
72#define HFP_RX_VOLUME "Internal HFP RX Volume"
73#endif
74
Vimal Puthanveed584048b2013-12-11 17:00:50 -080075static int32_t start_hfp(struct audio_device *adev,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080076 struct str_parms *parms);
77
Vimal Puthanveed584048b2013-12-11 17:00:50 -080078static int32_t stop_hfp(struct audio_device *adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080079
80struct hfp_module {
81 struct pcm *hfp_sco_rx;
82 struct pcm *hfp_sco_tx;
83 struct pcm *hfp_pcm_rx;
84 struct pcm *hfp_pcm_tx;
85 bool is_hfp_running;
Amit Shekhar967cab32014-02-07 17:03:21 -080086 float hfp_volume;
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +053087 int32_t hfp_pcm_dev_id;
Vimal Puthanveed47e64852013-12-20 13:23:39 -080088 audio_usecase_t ucid;
Aalique Grahame22e49102018-12-18 14:23:57 -080089 float mic_volume;
90 bool mic_mute;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080091};
92
93static struct hfp_module hfpmod = {
94 .hfp_sco_rx = NULL,
95 .hfp_sco_tx = NULL,
96 .hfp_pcm_rx = NULL,
97 .hfp_pcm_tx = NULL,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080098 .is_hfp_running = 0,
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +053099 .hfp_volume = 0,
100 .hfp_pcm_dev_id = HFP_ASM_RX_TX,
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800101 .ucid = USECASE_AUDIO_HFP_SCO,
Aalique Grahame22e49102018-12-18 14:23:57 -0800102 .mic_volume = CAPTURE_VOLUME_DEFAULT,
103 .mic_mute = 0,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800104};
Aalique Grahame22e49102018-12-18 14:23:57 -0800105
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800106static struct pcm_config pcm_config_hfp = {
107 .channels = 1,
108 .rate = 8000,
109 .period_size = 240,
110 .period_count = 2,
111 .format = PCM_FORMAT_S16_LE,
112 .start_threshold = 0,
113 .stop_threshold = INT_MAX,
114 .avail_min = 0,
115};
116
Arun Mirpurie008ed22019-03-21 11:21:04 -0700117//external feature dependency
118static fp_platform_set_mic_mute_t fp_platform_set_mic_mute;
119static fp_platform_get_pcm_device_id_t fp_platform_get_pcm_device_id;
120static fp_platform_set_echo_reference_t fp_platform_set_echo_reference;
121static fp_select_devices_t fp_select_devices;
122static fp_audio_extn_ext_hw_plugin_usecase_start_t fp_audio_extn_ext_hw_plugin_usecase_start;
123static fp_audio_extn_ext_hw_plugin_usecase_stop_t fp_audio_extn_ext_hw_plugin_usecase_stop;
124static fp_get_usecase_from_list_t fp_get_usecase_from_list;
125static fp_disable_audio_route_t fp_disable_audio_route;
126static fp_disable_snd_device_t fp_disable_snd_device;
127static fp_voice_get_mic_mute_t fp_voice_get_mic_mute;
Derek Chenf7092792017-05-23 12:23:53 -0400128static fp_audio_extn_auto_hal_start_hfp_downlink_t fp_audio_extn_auto_hal_start_hfp_downlink;
129static fp_audio_extn_auto_hal_stop_hfp_downlink_t fp_audio_extn_auto_hal_stop_hfp_downlink;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700130
Amit Shekhar967cab32014-02-07 17:03:21 -0800131static int32_t hfp_set_volume(struct audio_device *adev, float value)
132{
133 int32_t vol, ret = 0;
134 struct mixer_ctl *ctl;
Sudheer Papothi19e43d02014-07-16 02:34:41 +0530135 const char *mixer_ctl_name = HFP_RX_VOLUME;
Amit Shekhar967cab32014-02-07 17:03:21 -0800136
137 ALOGV("%s: entry", __func__);
138 ALOGD("%s: (%f)\n", __func__, value);
139
Satya Krishna Pindiproli3ed6d792014-09-09 15:32:25 +0530140 hfpmod.hfp_volume = value;
Aalique Grahame22e49102018-12-18 14:23:57 -0800141
Amit Shekhar967cab32014-02-07 17:03:21 -0800142 if (value < 0.0) {
143 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
144 value = 0.0;
145 } else {
146 value = ((value > 15.000000) ? 1.0 : (value / 15));
147 ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
148 }
149 vol = lrint((value * 0x2000) + 0.5);
Amit Shekhar967cab32014-02-07 17:03:21 -0800150
151 if (!hfpmod.is_hfp_running) {
152 ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
153 return -EIO;
154 }
155
156 ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
157 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
158 if (!ctl) {
159 ALOGE("%s: Could not get ctl for mixer cmd - %s",
160 __func__, mixer_ctl_name);
161 return -EINVAL;
162 }
163 if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
164 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
165 return -EINVAL;
166 }
167
168 ALOGV("%s: exit", __func__);
169 return ret;
170}
171
Aalique Grahame22e49102018-12-18 14:23:57 -0800172/*Set mic volume to value.
173*
174* This interface is used for mic volume control, set mic volume as value(range 0 ~ 15).
175*/
176static int hfp_set_mic_volume(struct audio_device *adev, float value)
177{
178 int volume, ret = 0;
179 char mixer_ctl_name[128];
180 struct mixer_ctl *ctl;
181 int pcm_device_id = HFP_ASM_RX_TX;
182
Arun Mirpurie008ed22019-03-21 11:21:04 -0700183 ALOGD("%s: enter, value=%f", __func__, value);
184
Aalique Grahame22e49102018-12-18 14:23:57 -0800185 if (!hfpmod.is_hfp_running) {
186 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
187 return -EIO;
188 }
189
190 if (value < 0.0) {
191 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
192 value = 0.0;
193 } else if (value > CAPTURE_VOLUME_DEFAULT) {
194 value = CAPTURE_VOLUME_DEFAULT;
195 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
196 }
197
198 value = value / CAPTURE_VOLUME_DEFAULT;
199 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
200 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
201 "Playback %d Volume", pcm_device_id);
202 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
203 if (!ctl) {
204 ALOGE("%s: Could not get ctl for mixer cmd - %s",
205 __func__, mixer_ctl_name);
206 return -EINVAL;
207 }
208 volume = (int)(value * PLAYBACK_VOLUME_MAX);
209
210 ALOGD("%s: Setting volume to %d (%s)\n", __func__, volume, mixer_ctl_name);
211 if (mixer_ctl_set_value(ctl, 0, volume) < 0) {
212 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
213 return -EINVAL;
214 }
215
216 return ret;
217}
218
219static float hfp_get_mic_volume(struct audio_device *adev)
220{
221 int volume;
222 char mixer_ctl_name[128];
223 struct mixer_ctl *ctl;
224 int pcm_device_id = HFP_ASM_RX_TX;
225 float value = 0.0;
226
Arun Mirpurie008ed22019-03-21 11:21:04 -0700227 ALOGD("%s: enter", __func__);
228
Aalique Grahame22e49102018-12-18 14:23:57 -0800229 if (!hfpmod.is_hfp_running) {
230 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
231 return -EIO;
232 }
233
234 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
235 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
236 "Playback %d Volume", pcm_device_id);
237 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
238 if (!ctl) {
239 ALOGE("%s: Could not get ctl for mixer cmd - %s",
240 __func__, mixer_ctl_name);
241 return -EINVAL;
242 }
243
244 volume = mixer_ctl_get_value(ctl, 0);
245 if ( volume < 0) {
246 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
247 return -EINVAL;
248 }
249 ALOGD("%s: getting mic volume %d \n", __func__, volume);
250
251 value = (volume / PLAYBACK_VOLUME_MAX) * CAPTURE_VOLUME_DEFAULT;
252 if (value < 0.0) {
253 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
254 value = 0.0;
255 } else if (value > CAPTURE_VOLUME_DEFAULT) {
256 value = CAPTURE_VOLUME_DEFAULT;
257 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
258 }
259
260 return value;
261}
262
263/*Set mic mute state.
264*
265* This interface is used for mic mute state control
266*/
Arun Mirpurie008ed22019-03-21 11:21:04 -0700267int hfp_set_mic_mute(struct audio_device *adev, bool state)
Aalique Grahame22e49102018-12-18 14:23:57 -0800268{
269 int rc = 0;
270
271 if (state == hfpmod.mic_mute)
272 return rc;
273
274 if (state == true) {
275 hfpmod.mic_volume = hfp_get_mic_volume(adev);
276 }
277 rc = hfp_set_mic_volume(adev, (state == true) ? 0.0 : hfpmod.mic_volume);
278 adev->voice.mic_mute = state;
279 hfpmod.mic_mute = state;
280 ALOGD("%s: Setting mute state %d, rc %d\n", __func__, state, rc);
281 return rc;
282}
283
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800284static int32_t start_hfp(struct audio_device *adev,
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700285 struct str_parms *parms __unused)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800286{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530287 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800288 struct audio_usecase *uc_info;
289 int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
290
291 ALOGD("%s: enter", __func__);
292
Aalique Grahame22e49102018-12-18 14:23:57 -0800293 if (adev->enable_hfp == true) {
294 ALOGD("%s: HFP is already active!\n", __func__);
295 return 0;
296 }
297 adev->enable_hfp = true;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700298 fp_platform_set_mic_mute(adev->platform, false);
Aalique Grahame22e49102018-12-18 14:23:57 -0800299
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800300 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700301
302 if (!uc_info)
303 return -ENOMEM;
304
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800305 uc_info->id = hfpmod.ucid;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800306 uc_info->type = PCM_HFP_CALL;
307 uc_info->stream.out = adev->primary_output;
308 uc_info->devices = adev->primary_output->devices;
309 uc_info->in_snd_device = SND_DEVICE_NONE;
310 uc_info->out_snd_device = SND_DEVICE_NONE;
311
312 list_add_tail(&adev->usecase_list, &uc_info->list);
313
Arun Mirpurie008ed22019-03-21 11:21:04 -0700314 fp_select_devices(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800315
Derek Chend2530072014-11-24 12:39:14 -0800316 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
317 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
Arun Mirpurie008ed22019-03-21 11:21:04 -0700318 if (fp_audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
Derek Chend2530072014-11-24 12:39:14 -0800319 ALOGE("%s: failed to start ext hw plugin", __func__);
320 }
321
Arun Mirpurie008ed22019-03-21 11:21:04 -0700322 pcm_dev_rx_id = fp_platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
323 pcm_dev_tx_id = fp_platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530324 pcm_dev_asm_rx_id = hfpmod.hfp_pcm_dev_id;
325 pcm_dev_asm_tx_id = hfpmod.hfp_pcm_dev_id;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800326 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
327 pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
328 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
329 __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
330 ret = -EIO;
331 goto exit;
332 }
333
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530334 ALOGD("%s: HFP PCM devices (rx: %d tx: %d pcm dev id: %d) usecase(%d)",
335 __func__, pcm_dev_rx_id, pcm_dev_tx_id, hfpmod.hfp_pcm_dev_id, uc_info->id);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800336
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800337 hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800338 pcm_dev_rx_id,
339 PCM_OUT, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800340 if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
341 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
342 ret = -EIO;
343 goto exit;
344 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530345
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800346 hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800347 pcm_dev_tx_id,
348 PCM_IN, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800349 if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
350 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
351 ret = -EIO;
352 goto exit;
353 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530354
Satya Krishna Pindiprolice903a02014-07-28 12:40:56 +0530355 if (pcm_start(hfpmod.hfp_pcm_rx) < 0) {
356 ALOGE("%s: pcm start for hfp pcm rx failed", __func__);
357 ret = -EINVAL;
358 goto exit;
359 }
360 if (pcm_start(hfpmod.hfp_pcm_tx) < 0) {
361 ALOGE("%s: pcm start for hfp pcm tx failed", __func__);
362 ret = -EINVAL;
363 goto exit;
364 }
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800365
Derek Chenf7092792017-05-23 12:23:53 -0400366 if (fp_audio_extn_auto_hal_start_hfp_downlink(adev, uc_info))
367 ALOGE("%s: start hfp downlink failed", __func__);
368
369 hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
370 pcm_dev_asm_rx_id,
371 PCM_OUT, &pcm_config_hfp);
372 if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
373 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
374 ret = -EIO;
375 goto exit;
376 }
377
378 hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
379 pcm_dev_asm_tx_id,
380 PCM_IN, &pcm_config_hfp);
381 if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
382 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
383 ret = -EIO;
384 goto exit;
385 }
386
387 if (pcm_start(hfpmod.hfp_sco_rx) < 0) {
388 ALOGE("%s: pcm start for hfp sco rx failed", __func__);
389 ret = -EINVAL;
390 goto exit;
391 }
392 if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
393 ALOGE("%s: pcm start for hfp sco tx failed", __func__);
394 ret = -EINVAL;
395 goto exit;
396 }
397
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800398 hfpmod.is_hfp_running = true;
Amit Shekhar967cab32014-02-07 17:03:21 -0800399 hfp_set_volume(adev, hfpmod.hfp_volume);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800400
Aalique Grahame22e49102018-12-18 14:23:57 -0800401 /* Set mic volume by mute status, we don't provide set mic volume in phone app, only
402 provide mute and unmute. */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700403 hfp_set_mic_mute(adev, adev->mic_muted);
Aalique Grahame22e49102018-12-18 14:23:57 -0800404
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800405 ALOGD("%s: exit: status(%d)", __func__, ret);
406 return 0;
407
408exit:
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800409 stop_hfp(adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800410 ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
411 return ret;
412}
413
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800414static int32_t stop_hfp(struct audio_device *adev)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800415{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530416 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800417 struct audio_usecase *uc_info;
418
419 ALOGD("%s: enter", __func__);
420 hfpmod.is_hfp_running = false;
421
422 /* 1. Close the PCM devices */
423 if (hfpmod.hfp_sco_rx) {
424 pcm_close(hfpmod.hfp_sco_rx);
425 hfpmod.hfp_sco_rx = NULL;
426 }
427 if (hfpmod.hfp_sco_tx) {
428 pcm_close(hfpmod.hfp_sco_tx);
429 hfpmod.hfp_sco_tx = NULL;
430 }
431 if (hfpmod.hfp_pcm_rx) {
432 pcm_close(hfpmod.hfp_pcm_rx);
433 hfpmod.hfp_pcm_rx = NULL;
434 }
435 if (hfpmod.hfp_pcm_tx) {
436 pcm_close(hfpmod.hfp_pcm_tx);
437 hfpmod.hfp_pcm_tx = NULL;
438 }
439
Arun Mirpurie008ed22019-03-21 11:21:04 -0700440 uc_info = fp_get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800441 if (uc_info == NULL) {
442 ALOGE("%s: Could not find the usecase (%d) in the list",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800443 __func__, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800444 return -EINVAL;
445 }
446
Derek Chend2530072014-11-24 12:39:14 -0800447 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
448 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
Arun Mirpurie008ed22019-03-21 11:21:04 -0700449 if (fp_audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
Derek Chend2530072014-11-24 12:39:14 -0800450 ALOGE("%s: failed to stop ext hw plugin", __func__);
451 }
452
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530453 /* 2. Disable echo reference while stopping hfp */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700454 fp_platform_set_echo_reference(adev, false, uc_info->devices);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530455
456 /* 3. Get and set stream specific mixer controls */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700457 fp_disable_audio_route(adev, uc_info);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800458
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530459 /* 4. Disable the rx and tx devices */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700460 fp_disable_snd_device(adev, uc_info->out_snd_device);
461 fp_disable_snd_device(adev, uc_info->in_snd_device);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800462
Derek Chenf7092792017-05-23 12:23:53 -0400463 if (fp_audio_extn_auto_hal_stop_hfp_downlink(adev, uc_info))
464 ALOGE("%s: stop hfp downlink failed", __func__);
465
Aalique Grahame22e49102018-12-18 14:23:57 -0800466 /* Set the unmute Tx mixer control */
Arun Mirpurie008ed22019-03-21 11:21:04 -0700467 if (fp_voice_get_mic_mute(adev)) {
468 fp_platform_set_mic_mute(adev->platform, false);
Aalique Grahame22e49102018-12-18 14:23:57 -0800469 ALOGD("%s: unMute HFP Tx", __func__);
470 }
471 adev->enable_hfp = false;
472
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800473 list_remove(&uc_info->list);
474 free(uc_info);
475
476 ALOGD("%s: exit: status(%d)", __func__, ret);
477 return ret;
478}
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800479
Arun Mirpurie008ed22019-03-21 11:21:04 -0700480void hfp_init(hfp_init_config_t init_config)
481{
482 fp_platform_set_mic_mute = init_config.fp_platform_set_mic_mute;
483 fp_platform_get_pcm_device_id = init_config.fp_platform_get_pcm_device_id;
484 fp_platform_set_echo_reference = init_config.fp_platform_set_echo_reference;
485 fp_select_devices = init_config.fp_select_devices;
486 fp_audio_extn_ext_hw_plugin_usecase_start =
487 init_config.fp_audio_extn_ext_hw_plugin_usecase_start;
488 fp_audio_extn_ext_hw_plugin_usecase_stop =
489 init_config.fp_audio_extn_ext_hw_plugin_usecase_stop;
490 fp_get_usecase_from_list = init_config.fp_get_usecase_from_list;
491 fp_disable_audio_route = init_config.fp_disable_audio_route;
492 fp_disable_snd_device = init_config.fp_disable_snd_device;
493 fp_voice_get_mic_mute = init_config.fp_voice_get_mic_mute;
Derek Chenf7092792017-05-23 12:23:53 -0400494 fp_audio_extn_auto_hal_start_hfp_downlink =
495 init_config.fp_audio_extn_auto_hal_start_hfp_downlink;
496 fp_audio_extn_auto_hal_stop_hfp_downlink =
497 init_config.fp_audio_extn_auto_hal_stop_hfp_downlink;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700498}
499
500bool hfp_is_active(struct audio_device *adev)
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800501{
502 struct audio_usecase *hfp_usecase = NULL;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700503 hfp_usecase = fp_get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800504
505 if (hfp_usecase != NULL)
506 return true;
507 else
508 return false;
509}
510
Arun Mirpurie008ed22019-03-21 11:21:04 -0700511int hfp_set_mic_mute2(struct audio_device *adev, bool state)
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530512{
513 struct mixer_ctl *ctl;
514 const char *mixer_ctl_name = "HFP TX Mute";
Manish Dewangan338c50a2017-09-12 15:22:03 +0530515 long set_values[ ] = {0};
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530516
Arun Mirpurie008ed22019-03-21 11:21:04 -0700517 ALOGD("%s: enter, state=%d", __func__, state);
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530518
519 set_values[0] = state;
520 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
521 if (!ctl) {
522 ALOGE("%s: Could not get ctl for mixer cmd - %s",
523 __func__, mixer_ctl_name);
524 return -EINVAL;
525 }
526 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
527 ALOGV("%s: exit", __func__);
528 return 0;
529}
530
Arun Mirpurie008ed22019-03-21 11:21:04 -0700531audio_usecase_t hfp_get_usecase()
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800532{
533 return hfpmod.ucid;
534}
535
Arun Mirpurie008ed22019-03-21 11:21:04 -0700536void hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800537{
538 int ret;
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800539 int rate;
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800540 int val;
Amit Shekhar967cab32014-02-07 17:03:21 -0800541 float vol;
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800542 char value[32]={0};
543
Arun Mirpurie008ed22019-03-21 11:21:04 -0700544 ALOGD("%s: enter", __func__);
545
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800546 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
547 sizeof(value));
548 if (ret >= 0) {
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530549 if (!strncmp(value, "true", sizeof(value)) && !hfpmod.is_hfp_running)
550 ret = start_hfp(adev,parms);
551 else if (!strncmp(value, "false", sizeof(value)) && hfpmod.is_hfp_running)
552 stop_hfp(adev);
553 else
554 ALOGE("hfp_enable=%s is unsupported", value);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800555 }
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800556 memset(value, 0, sizeof(value));
557 ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
558 sizeof(value));
559 if (ret >= 0) {
560 rate = atoi(value);
561 if (rate == 8000){
562 hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
563 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700564 } else if (rate == 16000){
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800565 hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
566 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700567 } else
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800568 ALOGE("Unsupported rate..");
569 }
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800570
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700571 if (hfpmod.is_hfp_running) {
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800572 memset(value, 0, sizeof(value));
573 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
574 value, sizeof(value));
575 if (ret >= 0) {
576 val = atoi(value);
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700577 if (val > 0)
Arun Mirpurie008ed22019-03-21 11:21:04 -0700578 fp_select_devices(adev, hfpmod.ucid);
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800579 }
580 }
Amit Shekhar967cab32014-02-07 17:03:21 -0800581
582 memset(value, 0, sizeof(value));
583 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
584 value, sizeof(value));
585 if (ret >= 0) {
586 if (sscanf(value, "%f", &vol) != 1){
587 ALOGE("%s: error in retrieving hfp volume", __func__);
588 ret = -EIO;
589 goto exit;
590 }
591 ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
592 hfp_set_volume(adev, vol);
593 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530594
595 memset(value, 0, sizeof(value));
596 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID, value, sizeof(value));
597 if (ret >= 0) {
598 hfpmod.hfp_pcm_dev_id = atoi(value);
599 ALOGD("Updating HFP_PCM_DEV_ID as %d from platform XML", hfpmod.hfp_pcm_dev_id);
600 str_parms_del(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID);
601 }
602
Aalique Grahame22e49102018-12-18 14:23:57 -0800603 memset(value, 0, sizeof(value));
604 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_MIC_VOLUME,
605 value, sizeof(value));
606 if (ret >= 0) {
607 if (sscanf(value, "%f", &vol) != 1){
608 ALOGE("%s: error in retrieving hfp mic volume", __func__);
609 ret = -EIO;
610 goto exit;
611 }
612 ALOGD("%s: set_hfp_mic_volume usecase, Vol: [%f]", __func__, vol);
613 hfp_set_mic_volume(adev, vol);
614 }
615
Amit Shekhar967cab32014-02-07 17:03:21 -0800616exit:
617 ALOGV("%s Exit",__func__);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800618}