blob: 57a384172ef56a2ea44a4f265bb205757a749425 [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#ifdef HFP_ENABLED
50#define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable"
Vimal Puthanveed47e64852013-12-20 13:23:39 -080051#define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate"
Amit Shekhar967cab32014-02-07 17:03:21 -080052#define AUDIO_PARAMETER_KEY_HFP_VOLUME "hfp_volume"
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +053053#define AUDIO_PARAMETER_HFP_PCM_DEV_ID "hfp_pcm_dev_id"
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080054
Aalique Grahame22e49102018-12-18 14:23:57 -080055#define AUDIO_PARAMETER_KEY_HFP_MIC_VOLUME "hfp_mic_volume"
56#define PLAYBACK_VOLUME_MAX 0x2000
57#define CAPTURE_VOLUME_DEFAULT (15.0)
58
Sudheer Papothi19e43d02014-07-16 02:34:41 +053059#ifdef PLATFORM_MSM8994
60#define HFP_RX_VOLUME "SEC AUXPCM LOOPBACK Volume"
Aalique Grahame22e49102018-12-18 14:23:57 -080061#elif defined (PLATFORM_MSM8996) || defined (EXTERNAL_BT_SUPPORTED)
Banajit Goswamida77c452015-10-14 20:45:22 -070062#define HFP_RX_VOLUME "PRI AUXPCM LOOPBACK Volume"
Derek Chen3e5b30a2018-10-24 01:04:25 -070063#elif defined PLATFORM_AUTO
64#define HFP_RX_VOLUME "Playback 36 Volume"
Meng Wangef2f6e12018-10-08 13:06:05 +080065#elif defined (PLATFORM_MSM8998) || defined (PLATFORM_MSMFALCON) || \
66 defined (PLATFORM_SDM845) || defined (PLATFORM_SDM710) || \
67 defined (PLATFORM_QCS605) || defined (PLATFORM_MSMNILE) || \
68 defined (PLATFORM_KONA) || defined (PLATFORM_MSMSTEPPE) || \
69 defined (PLATFORM_QCS405)
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
Amit Shekhar967cab32014-02-07 17:03:21 -0800117static int32_t hfp_set_volume(struct audio_device *adev, float value)
118{
119 int32_t vol, ret = 0;
120 struct mixer_ctl *ctl;
Sudheer Papothi19e43d02014-07-16 02:34:41 +0530121 const char *mixer_ctl_name = HFP_RX_VOLUME;
Amit Shekhar967cab32014-02-07 17:03:21 -0800122
123 ALOGV("%s: entry", __func__);
124 ALOGD("%s: (%f)\n", __func__, value);
125
Satya Krishna Pindiproli3ed6d792014-09-09 15:32:25 +0530126 hfpmod.hfp_volume = value;
Aalique Grahame22e49102018-12-18 14:23:57 -0800127
Amit Shekhar967cab32014-02-07 17:03:21 -0800128 if (value < 0.0) {
129 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
130 value = 0.0;
131 } else {
132 value = ((value > 15.000000) ? 1.0 : (value / 15));
133 ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
134 }
135 vol = lrint((value * 0x2000) + 0.5);
Amit Shekhar967cab32014-02-07 17:03:21 -0800136
137 if (!hfpmod.is_hfp_running) {
138 ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
139 return -EIO;
140 }
141
142 ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
143 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
144 if (!ctl) {
145 ALOGE("%s: Could not get ctl for mixer cmd - %s",
146 __func__, mixer_ctl_name);
147 return -EINVAL;
148 }
149 if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
150 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
151 return -EINVAL;
152 }
153
154 ALOGV("%s: exit", __func__);
155 return ret;
156}
157
Aalique Grahame22e49102018-12-18 14:23:57 -0800158/*Set mic volume to value.
159*
160* This interface is used for mic volume control, set mic volume as value(range 0 ~ 15).
161*/
162static int hfp_set_mic_volume(struct audio_device *adev, float value)
163{
164 int volume, ret = 0;
165 char mixer_ctl_name[128];
166 struct mixer_ctl *ctl;
167 int pcm_device_id = HFP_ASM_RX_TX;
168
169 if (!hfpmod.is_hfp_running) {
170 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
171 return -EIO;
172 }
173
174 if (value < 0.0) {
175 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
176 value = 0.0;
177 } else if (value > CAPTURE_VOLUME_DEFAULT) {
178 value = CAPTURE_VOLUME_DEFAULT;
179 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
180 }
181
182 value = value / CAPTURE_VOLUME_DEFAULT;
183 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
184 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
185 "Playback %d Volume", pcm_device_id);
186 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
187 if (!ctl) {
188 ALOGE("%s: Could not get ctl for mixer cmd - %s",
189 __func__, mixer_ctl_name);
190 return -EINVAL;
191 }
192 volume = (int)(value * PLAYBACK_VOLUME_MAX);
193
194 ALOGD("%s: Setting volume to %d (%s)\n", __func__, volume, mixer_ctl_name);
195 if (mixer_ctl_set_value(ctl, 0, volume) < 0) {
196 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
197 return -EINVAL;
198 }
199
200 return ret;
201}
202
203static float hfp_get_mic_volume(struct audio_device *adev)
204{
205 int volume;
206 char mixer_ctl_name[128];
207 struct mixer_ctl *ctl;
208 int pcm_device_id = HFP_ASM_RX_TX;
209 float value = 0.0;
210
211 if (!hfpmod.is_hfp_running) {
212 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
213 return -EIO;
214 }
215
216 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
217 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
218 "Playback %d Volume", pcm_device_id);
219 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
220 if (!ctl) {
221 ALOGE("%s: Could not get ctl for mixer cmd - %s",
222 __func__, mixer_ctl_name);
223 return -EINVAL;
224 }
225
226 volume = mixer_ctl_get_value(ctl, 0);
227 if ( volume < 0) {
228 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
229 return -EINVAL;
230 }
231 ALOGD("%s: getting mic volume %d \n", __func__, volume);
232
233 value = (volume / PLAYBACK_VOLUME_MAX) * CAPTURE_VOLUME_DEFAULT;
234 if (value < 0.0) {
235 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
236 value = 0.0;
237 } else if (value > CAPTURE_VOLUME_DEFAULT) {
238 value = CAPTURE_VOLUME_DEFAULT;
239 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
240 }
241
242 return value;
243}
244
245/*Set mic mute state.
246*
247* This interface is used for mic mute state control
248*/
249int audio_extn_hfp_set_mic_mute(struct audio_device *adev, bool state)
250{
251 int rc = 0;
252
253 if (state == hfpmod.mic_mute)
254 return rc;
255
256 if (state == true) {
257 hfpmod.mic_volume = hfp_get_mic_volume(adev);
258 }
259 rc = hfp_set_mic_volume(adev, (state == true) ? 0.0 : hfpmod.mic_volume);
260 adev->voice.mic_mute = state;
261 hfpmod.mic_mute = state;
262 ALOGD("%s: Setting mute state %d, rc %d\n", __func__, state, rc);
263 return rc;
264}
265
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800266static int32_t start_hfp(struct audio_device *adev,
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700267 struct str_parms *parms __unused)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800268{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530269 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800270 struct audio_usecase *uc_info;
271 int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
272
273 ALOGD("%s: enter", __func__);
274
Aalique Grahame22e49102018-12-18 14:23:57 -0800275 if (adev->enable_hfp == true) {
276 ALOGD("%s: HFP is already active!\n", __func__);
277 return 0;
278 }
279 adev->enable_hfp = true;
280 platform_set_mic_mute(adev->platform, false);
281
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800282 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700283
284 if (!uc_info)
285 return -ENOMEM;
286
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800287 uc_info->id = hfpmod.ucid;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800288 uc_info->type = PCM_HFP_CALL;
289 uc_info->stream.out = adev->primary_output;
290 uc_info->devices = adev->primary_output->devices;
291 uc_info->in_snd_device = SND_DEVICE_NONE;
292 uc_info->out_snd_device = SND_DEVICE_NONE;
293
294 list_add_tail(&adev->usecase_list, &uc_info->list);
295
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800296 select_devices(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800297
Derek Chend2530072014-11-24 12:39:14 -0800298 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
299 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
300 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
301 ALOGE("%s: failed to start ext hw plugin", __func__);
302 }
303
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800304 pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
305 pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530306 pcm_dev_asm_rx_id = hfpmod.hfp_pcm_dev_id;
307 pcm_dev_asm_tx_id = hfpmod.hfp_pcm_dev_id;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800308 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
309 pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
310 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
311 __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
312 ret = -EIO;
313 goto exit;
314 }
315
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530316 ALOGD("%s: HFP PCM devices (rx: %d tx: %d pcm dev id: %d) usecase(%d)",
317 __func__, pcm_dev_rx_id, pcm_dev_tx_id, hfpmod.hfp_pcm_dev_id, uc_info->id);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800318
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800319 hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800320 pcm_dev_asm_rx_id,
321 PCM_OUT, &pcm_config_hfp);
322 if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
323 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
324 ret = -EIO;
325 goto exit;
326 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530327
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800328 hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800329 pcm_dev_rx_id,
330 PCM_OUT, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800331 if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
332 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
333 ret = -EIO;
334 goto exit;
335 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530336
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800337 hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800338 pcm_dev_asm_tx_id,
339 PCM_IN, &pcm_config_hfp);
340 if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
341 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
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_sco_rx) < 0) {
356 ALOGE("%s: pcm start for hfp sco rx failed", __func__);
357 ret = -EINVAL;
358 goto exit;
359 }
360 if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
361 ALOGE("%s: pcm start for hfp sco tx failed", __func__);
362 ret = -EINVAL;
363 goto exit;
364 }
Aalique Grahame22e49102018-12-18 14:23:57 -0800365
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
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800377 hfpmod.is_hfp_running = true;
Amit Shekhar967cab32014-02-07 17:03:21 -0800378 hfp_set_volume(adev, hfpmod.hfp_volume);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800379
Aalique Grahame22e49102018-12-18 14:23:57 -0800380 /* Set mic volume by mute status, we don't provide set mic volume in phone app, only
381 provide mute and unmute. */
382 audio_extn_hfp_set_mic_mute(adev, adev->mic_muted);
383
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800384 ALOGD("%s: exit: status(%d)", __func__, ret);
385 return 0;
386
387exit:
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800388 stop_hfp(adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800389 ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
390 return ret;
391}
392
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800393static int32_t stop_hfp(struct audio_device *adev)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800394{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530395 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800396 struct audio_usecase *uc_info;
397
398 ALOGD("%s: enter", __func__);
399 hfpmod.is_hfp_running = false;
400
401 /* 1. Close the PCM devices */
402 if (hfpmod.hfp_sco_rx) {
403 pcm_close(hfpmod.hfp_sco_rx);
404 hfpmod.hfp_sco_rx = NULL;
405 }
406 if (hfpmod.hfp_sco_tx) {
407 pcm_close(hfpmod.hfp_sco_tx);
408 hfpmod.hfp_sco_tx = NULL;
409 }
410 if (hfpmod.hfp_pcm_rx) {
411 pcm_close(hfpmod.hfp_pcm_rx);
412 hfpmod.hfp_pcm_rx = NULL;
413 }
414 if (hfpmod.hfp_pcm_tx) {
415 pcm_close(hfpmod.hfp_pcm_tx);
416 hfpmod.hfp_pcm_tx = NULL;
417 }
418
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800419 uc_info = get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800420 if (uc_info == NULL) {
421 ALOGE("%s: Could not find the usecase (%d) in the list",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800422 __func__, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800423 return -EINVAL;
424 }
425
Derek Chend2530072014-11-24 12:39:14 -0800426 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
427 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
428 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
429 ALOGE("%s: failed to stop ext hw plugin", __func__);
430 }
431
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530432 /* 2. Disable echo reference while stopping hfp */
Apoorv Raghuvanshi924b3022015-07-06 15:07:14 -0700433 platform_set_echo_reference(adev, false, uc_info->devices);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530434
435 /* 3. Get and set stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -0700436 disable_audio_route(adev, uc_info);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800437
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530438 /* 4. Disable the rx and tx devices */
Haynes Mathew George1376ca62014-04-24 11:55:48 -0700439 disable_snd_device(adev, uc_info->out_snd_device);
440 disable_snd_device(adev, uc_info->in_snd_device);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800441
Aalique Grahame22e49102018-12-18 14:23:57 -0800442 /* Set the unmute Tx mixer control */
443 if (voice_get_mic_mute(adev)) {
444 platform_set_mic_mute(adev->platform, false);
445 ALOGD("%s: unMute HFP Tx", __func__);
446 }
447 adev->enable_hfp = false;
448
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800449 list_remove(&uc_info->list);
450 free(uc_info);
451
452 ALOGD("%s: exit: status(%d)", __func__, ret);
453 return ret;
454}
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800455
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800456bool audio_extn_hfp_is_active(struct audio_device *adev)
457{
458 struct audio_usecase *hfp_usecase = NULL;
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800459 hfp_usecase = get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800460
461 if (hfp_usecase != NULL)
462 return true;
463 else
464 return false;
465}
466
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530467int hfp_set_mic_mute(struct audio_device *adev, bool state)
468{
469 struct mixer_ctl *ctl;
470 const char *mixer_ctl_name = "HFP TX Mute";
Manish Dewangan338c50a2017-09-12 15:22:03 +0530471 long set_values[ ] = {0};
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530472
473 ALOGI("%s: enter, state=%d", __func__, state);
474
475 set_values[0] = state;
476 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
477 if (!ctl) {
478 ALOGE("%s: Could not get ctl for mixer cmd - %s",
479 __func__, mixer_ctl_name);
480 return -EINVAL;
481 }
482 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
483 ALOGV("%s: exit", __func__);
484 return 0;
485}
486
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800487audio_usecase_t audio_extn_hfp_get_usecase()
488{
489 return hfpmod.ucid;
490}
491
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800492void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
493{
494 int ret;
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800495 int rate;
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800496 int val;
Amit Shekhar967cab32014-02-07 17:03:21 -0800497 float vol;
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800498 char value[32]={0};
499
500 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
501 sizeof(value));
502 if (ret >= 0) {
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530503 if (!strncmp(value, "true", sizeof(value)) && !hfpmod.is_hfp_running)
504 ret = start_hfp(adev,parms);
505 else if (!strncmp(value, "false", sizeof(value)) && hfpmod.is_hfp_running)
506 stop_hfp(adev);
507 else
508 ALOGE("hfp_enable=%s is unsupported", value);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800509 }
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800510 memset(value, 0, sizeof(value));
511 ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
512 sizeof(value));
513 if (ret >= 0) {
514 rate = atoi(value);
515 if (rate == 8000){
516 hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
517 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700518 } else if (rate == 16000){
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800519 hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
520 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700521 } else
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800522 ALOGE("Unsupported rate..");
523 }
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800524
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700525 if (hfpmod.is_hfp_running) {
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800526 memset(value, 0, sizeof(value));
527 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
528 value, sizeof(value));
529 if (ret >= 0) {
530 val = atoi(value);
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700531 if (val > 0)
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800532 select_devices(adev, hfpmod.ucid);
533 }
534 }
Amit Shekhar967cab32014-02-07 17:03:21 -0800535
536 memset(value, 0, sizeof(value));
537 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
538 value, sizeof(value));
539 if (ret >= 0) {
540 if (sscanf(value, "%f", &vol) != 1){
541 ALOGE("%s: error in retrieving hfp volume", __func__);
542 ret = -EIO;
543 goto exit;
544 }
545 ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
546 hfp_set_volume(adev, vol);
547 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530548
549 memset(value, 0, sizeof(value));
550 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID, value, sizeof(value));
551 if (ret >= 0) {
552 hfpmod.hfp_pcm_dev_id = atoi(value);
553 ALOGD("Updating HFP_PCM_DEV_ID as %d from platform XML", hfpmod.hfp_pcm_dev_id);
554 str_parms_del(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID);
555 }
556
Aalique Grahame22e49102018-12-18 14:23:57 -0800557 memset(value, 0, sizeof(value));
558 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_MIC_VOLUME,
559 value, sizeof(value));
560 if (ret >= 0) {
561 if (sscanf(value, "%f", &vol) != 1){
562 ALOGE("%s: error in retrieving hfp mic volume", __func__);
563 ret = -EIO;
564 goto exit;
565 }
566 ALOGD("%s: set_hfp_mic_volume usecase, Vol: [%f]", __func__, vol);
567 hfp_set_mic_volume(adev, vol);
568 }
569
Amit Shekhar967cab32014-02-07 17:03:21 -0800570exit:
571 ALOGV("%s Exit",__func__);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800572}
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800573#endif /*HFP_ENABLED*/