blob: 3eb96d66771a82cf917ad851bdd3265df40b9be7 [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"
Naresh Tannirucb5b5782018-10-12 20:42:07 +053065#elif defined (PLATFORM_MSM8998) || defined (PLATFORM_MSMFALCON) || defined (PLATFORM_SDM845) || defined (PLATFORM_SDM710) || defined (PLATFORM_QCS605) || defined (PLATFORM_MSMNILE) || defined (PLATFORM_MSMSTEPPE) || defined (PLATFORM_QCS405)
Banajit Goswami4c0dff22016-03-04 18:31:22 -080066#define HFP_RX_VOLUME "SLIMBUS_7 LOOPBACK Volume"
Sudheer Papothi19e43d02014-07-16 02:34:41 +053067#else
68#define HFP_RX_VOLUME "Internal HFP RX Volume"
69#endif
70
Vimal Puthanveed584048b2013-12-11 17:00:50 -080071static int32_t start_hfp(struct audio_device *adev,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080072 struct str_parms *parms);
73
Vimal Puthanveed584048b2013-12-11 17:00:50 -080074static int32_t stop_hfp(struct audio_device *adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080075
76struct hfp_module {
77 struct pcm *hfp_sco_rx;
78 struct pcm *hfp_sco_tx;
79 struct pcm *hfp_pcm_rx;
80 struct pcm *hfp_pcm_tx;
81 bool is_hfp_running;
Amit Shekhar967cab32014-02-07 17:03:21 -080082 float hfp_volume;
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +053083 int32_t hfp_pcm_dev_id;
Vimal Puthanveed47e64852013-12-20 13:23:39 -080084 audio_usecase_t ucid;
Aalique Grahame22e49102018-12-18 14:23:57 -080085 float mic_volume;
86 bool mic_mute;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080087};
88
89static struct hfp_module hfpmod = {
90 .hfp_sco_rx = NULL,
91 .hfp_sco_tx = NULL,
92 .hfp_pcm_rx = NULL,
93 .hfp_pcm_tx = NULL,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080094 .is_hfp_running = 0,
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +053095 .hfp_volume = 0,
96 .hfp_pcm_dev_id = HFP_ASM_RX_TX,
Vimal Puthanveed47e64852013-12-20 13:23:39 -080097 .ucid = USECASE_AUDIO_HFP_SCO,
Aalique Grahame22e49102018-12-18 14:23:57 -080098 .mic_volume = CAPTURE_VOLUME_DEFAULT,
99 .mic_mute = 0,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800100};
Aalique Grahame22e49102018-12-18 14:23:57 -0800101
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800102static struct pcm_config pcm_config_hfp = {
103 .channels = 1,
104 .rate = 8000,
105 .period_size = 240,
106 .period_count = 2,
107 .format = PCM_FORMAT_S16_LE,
108 .start_threshold = 0,
109 .stop_threshold = INT_MAX,
110 .avail_min = 0,
111};
112
Amit Shekhar967cab32014-02-07 17:03:21 -0800113static int32_t hfp_set_volume(struct audio_device *adev, float value)
114{
115 int32_t vol, ret = 0;
116 struct mixer_ctl *ctl;
Sudheer Papothi19e43d02014-07-16 02:34:41 +0530117 const char *mixer_ctl_name = HFP_RX_VOLUME;
Amit Shekhar967cab32014-02-07 17:03:21 -0800118
119 ALOGV("%s: entry", __func__);
120 ALOGD("%s: (%f)\n", __func__, value);
121
Satya Krishna Pindiproli3ed6d792014-09-09 15:32:25 +0530122 hfpmod.hfp_volume = value;
Aalique Grahame22e49102018-12-18 14:23:57 -0800123
Amit Shekhar967cab32014-02-07 17:03:21 -0800124 if (value < 0.0) {
125 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
126 value = 0.0;
127 } else {
128 value = ((value > 15.000000) ? 1.0 : (value / 15));
129 ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
130 }
131 vol = lrint((value * 0x2000) + 0.5);
Amit Shekhar967cab32014-02-07 17:03:21 -0800132
133 if (!hfpmod.is_hfp_running) {
134 ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
135 return -EIO;
136 }
137
138 ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
139 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
140 if (!ctl) {
141 ALOGE("%s: Could not get ctl for mixer cmd - %s",
142 __func__, mixer_ctl_name);
143 return -EINVAL;
144 }
145 if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
146 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
147 return -EINVAL;
148 }
149
150 ALOGV("%s: exit", __func__);
151 return ret;
152}
153
Aalique Grahame22e49102018-12-18 14:23:57 -0800154/*Set mic volume to value.
155*
156* This interface is used for mic volume control, set mic volume as value(range 0 ~ 15).
157*/
158static int hfp_set_mic_volume(struct audio_device *adev, float value)
159{
160 int volume, ret = 0;
161 char mixer_ctl_name[128];
162 struct mixer_ctl *ctl;
163 int pcm_device_id = HFP_ASM_RX_TX;
164
165 if (!hfpmod.is_hfp_running) {
166 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
167 return -EIO;
168 }
169
170 if (value < 0.0) {
171 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
172 value = 0.0;
173 } else if (value > CAPTURE_VOLUME_DEFAULT) {
174 value = CAPTURE_VOLUME_DEFAULT;
175 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
176 }
177
178 value = value / CAPTURE_VOLUME_DEFAULT;
179 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
180 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
181 "Playback %d Volume", pcm_device_id);
182 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
183 if (!ctl) {
184 ALOGE("%s: Could not get ctl for mixer cmd - %s",
185 __func__, mixer_ctl_name);
186 return -EINVAL;
187 }
188 volume = (int)(value * PLAYBACK_VOLUME_MAX);
189
190 ALOGD("%s: Setting volume to %d (%s)\n", __func__, volume, mixer_ctl_name);
191 if (mixer_ctl_set_value(ctl, 0, volume) < 0) {
192 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
193 return -EINVAL;
194 }
195
196 return ret;
197}
198
199static float hfp_get_mic_volume(struct audio_device *adev)
200{
201 int volume;
202 char mixer_ctl_name[128];
203 struct mixer_ctl *ctl;
204 int pcm_device_id = HFP_ASM_RX_TX;
205 float value = 0.0;
206
207 if (!hfpmod.is_hfp_running) {
208 ALOGE("%s: HFP not active, ignoring set_hfp_mic_volume call", __func__);
209 return -EIO;
210 }
211
212 memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name));
213 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
214 "Playback %d Volume", pcm_device_id);
215 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
216 if (!ctl) {
217 ALOGE("%s: Could not get ctl for mixer cmd - %s",
218 __func__, mixer_ctl_name);
219 return -EINVAL;
220 }
221
222 volume = mixer_ctl_get_value(ctl, 0);
223 if ( volume < 0) {
224 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, volume);
225 return -EINVAL;
226 }
227 ALOGD("%s: getting mic volume %d \n", __func__, volume);
228
229 value = (volume / PLAYBACK_VOLUME_MAX) * CAPTURE_VOLUME_DEFAULT;
230 if (value < 0.0) {
231 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
232 value = 0.0;
233 } else if (value > CAPTURE_VOLUME_DEFAULT) {
234 value = CAPTURE_VOLUME_DEFAULT;
235 ALOGW("%s: Volume brought within range (%f)\n", __func__, value);
236 }
237
238 return value;
239}
240
241/*Set mic mute state.
242*
243* This interface is used for mic mute state control
244*/
245int audio_extn_hfp_set_mic_mute(struct audio_device *adev, bool state)
246{
247 int rc = 0;
248
249 if (state == hfpmod.mic_mute)
250 return rc;
251
252 if (state == true) {
253 hfpmod.mic_volume = hfp_get_mic_volume(adev);
254 }
255 rc = hfp_set_mic_volume(adev, (state == true) ? 0.0 : hfpmod.mic_volume);
256 adev->voice.mic_mute = state;
257 hfpmod.mic_mute = state;
258 ALOGD("%s: Setting mute state %d, rc %d\n", __func__, state, rc);
259 return rc;
260}
261
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800262static int32_t start_hfp(struct audio_device *adev,
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700263 struct str_parms *parms __unused)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800264{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530265 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800266 struct audio_usecase *uc_info;
267 int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
268
269 ALOGD("%s: enter", __func__);
270
Aalique Grahame22e49102018-12-18 14:23:57 -0800271 if (adev->enable_hfp == true) {
272 ALOGD("%s: HFP is already active!\n", __func__);
273 return 0;
274 }
275 adev->enable_hfp = true;
276 platform_set_mic_mute(adev->platform, false);
277
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800278 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700279
280 if (!uc_info)
281 return -ENOMEM;
282
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800283 uc_info->id = hfpmod.ucid;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800284 uc_info->type = PCM_HFP_CALL;
285 uc_info->stream.out = adev->primary_output;
286 uc_info->devices = adev->primary_output->devices;
287 uc_info->in_snd_device = SND_DEVICE_NONE;
288 uc_info->out_snd_device = SND_DEVICE_NONE;
289
290 list_add_tail(&adev->usecase_list, &uc_info->list);
291
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800292 select_devices(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800293
Derek Chend2530072014-11-24 12:39:14 -0800294 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
295 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
296 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
297 ALOGE("%s: failed to start ext hw plugin", __func__);
298 }
299
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800300 pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
301 pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530302 pcm_dev_asm_rx_id = hfpmod.hfp_pcm_dev_id;
303 pcm_dev_asm_tx_id = hfpmod.hfp_pcm_dev_id;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800304 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
305 pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
306 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
307 __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
308 ret = -EIO;
309 goto exit;
310 }
311
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530312 ALOGD("%s: HFP PCM devices (rx: %d tx: %d pcm dev id: %d) usecase(%d)",
313 __func__, pcm_dev_rx_id, pcm_dev_tx_id, hfpmod.hfp_pcm_dev_id, uc_info->id);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800314
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800315 hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800316 pcm_dev_asm_rx_id,
317 PCM_OUT, &pcm_config_hfp);
318 if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
319 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
320 ret = -EIO;
321 goto exit;
322 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530323
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800324 hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800325 pcm_dev_rx_id,
326 PCM_OUT, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800327 if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
328 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
329 ret = -EIO;
330 goto exit;
331 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530332
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800333 hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800334 pcm_dev_asm_tx_id,
335 PCM_IN, &pcm_config_hfp);
336 if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
337 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
338 ret = -EIO;
339 goto exit;
340 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530341
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800342 hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
Aalique Grahame22e49102018-12-18 14:23:57 -0800343 pcm_dev_tx_id,
344 PCM_IN, &pcm_config_hfp);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800345 if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
346 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
347 ret = -EIO;
348 goto exit;
349 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530350
Satya Krishna Pindiprolice903a02014-07-28 12:40:56 +0530351 if (pcm_start(hfpmod.hfp_sco_rx) < 0) {
352 ALOGE("%s: pcm start for hfp sco rx failed", __func__);
353 ret = -EINVAL;
354 goto exit;
355 }
356 if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
357 ALOGE("%s: pcm start for hfp sco tx failed", __func__);
358 ret = -EINVAL;
359 goto exit;
360 }
Aalique Grahame22e49102018-12-18 14:23:57 -0800361
Satya Krishna Pindiprolice903a02014-07-28 12:40:56 +0530362 if (pcm_start(hfpmod.hfp_pcm_rx) < 0) {
363 ALOGE("%s: pcm start for hfp pcm rx failed", __func__);
364 ret = -EINVAL;
365 goto exit;
366 }
367 if (pcm_start(hfpmod.hfp_pcm_tx) < 0) {
368 ALOGE("%s: pcm start for hfp pcm tx failed", __func__);
369 ret = -EINVAL;
370 goto exit;
371 }
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800372
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800373 hfpmod.is_hfp_running = true;
Amit Shekhar967cab32014-02-07 17:03:21 -0800374 hfp_set_volume(adev, hfpmod.hfp_volume);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800375
Aalique Grahame22e49102018-12-18 14:23:57 -0800376 /* Set mic volume by mute status, we don't provide set mic volume in phone app, only
377 provide mute and unmute. */
378 audio_extn_hfp_set_mic_mute(adev, adev->mic_muted);
379
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800380 ALOGD("%s: exit: status(%d)", __func__, ret);
381 return 0;
382
383exit:
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800384 stop_hfp(adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800385 ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
386 return ret;
387}
388
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800389static int32_t stop_hfp(struct audio_device *adev)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800390{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530391 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800392 struct audio_usecase *uc_info;
393
394 ALOGD("%s: enter", __func__);
395 hfpmod.is_hfp_running = false;
396
397 /* 1. Close the PCM devices */
398 if (hfpmod.hfp_sco_rx) {
399 pcm_close(hfpmod.hfp_sco_rx);
400 hfpmod.hfp_sco_rx = NULL;
401 }
402 if (hfpmod.hfp_sco_tx) {
403 pcm_close(hfpmod.hfp_sco_tx);
404 hfpmod.hfp_sco_tx = NULL;
405 }
406 if (hfpmod.hfp_pcm_rx) {
407 pcm_close(hfpmod.hfp_pcm_rx);
408 hfpmod.hfp_pcm_rx = NULL;
409 }
410 if (hfpmod.hfp_pcm_tx) {
411 pcm_close(hfpmod.hfp_pcm_tx);
412 hfpmod.hfp_pcm_tx = NULL;
413 }
414
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800415 uc_info = get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800416 if (uc_info == NULL) {
417 ALOGE("%s: Could not find the usecase (%d) in the list",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800418 __func__, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800419 return -EINVAL;
420 }
421
Derek Chend2530072014-11-24 12:39:14 -0800422 if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
423 (uc_info->in_snd_device != SND_DEVICE_NONE)) {
424 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
425 ALOGE("%s: failed to stop ext hw plugin", __func__);
426 }
427
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530428 /* 2. Disable echo reference while stopping hfp */
Apoorv Raghuvanshi924b3022015-07-06 15:07:14 -0700429 platform_set_echo_reference(adev, false, uc_info->devices);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530430
431 /* 3. Get and set stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -0700432 disable_audio_route(adev, uc_info);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800433
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530434 /* 4. Disable the rx and tx devices */
Haynes Mathew George1376ca62014-04-24 11:55:48 -0700435 disable_snd_device(adev, uc_info->out_snd_device);
436 disable_snd_device(adev, uc_info->in_snd_device);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800437
Aalique Grahame22e49102018-12-18 14:23:57 -0800438 /* Set the unmute Tx mixer control */
439 if (voice_get_mic_mute(adev)) {
440 platform_set_mic_mute(adev->platform, false);
441 ALOGD("%s: unMute HFP Tx", __func__);
442 }
443 adev->enable_hfp = false;
444
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800445 list_remove(&uc_info->list);
446 free(uc_info);
447
448 ALOGD("%s: exit: status(%d)", __func__, ret);
449 return ret;
450}
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800451
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800452bool audio_extn_hfp_is_active(struct audio_device *adev)
453{
454 struct audio_usecase *hfp_usecase = NULL;
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800455 hfp_usecase = get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800456
457 if (hfp_usecase != NULL)
458 return true;
459 else
460 return false;
461}
462
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530463int hfp_set_mic_mute(struct audio_device *adev, bool state)
464{
465 struct mixer_ctl *ctl;
466 const char *mixer_ctl_name = "HFP TX Mute";
Manish Dewangan338c50a2017-09-12 15:22:03 +0530467 long set_values[ ] = {0};
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530468
469 ALOGI("%s: enter, state=%d", __func__, state);
470
471 set_values[0] = state;
472 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
473 if (!ctl) {
474 ALOGE("%s: Could not get ctl for mixer cmd - %s",
475 __func__, mixer_ctl_name);
476 return -EINVAL;
477 }
478 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
479 ALOGV("%s: exit", __func__);
480 return 0;
481}
482
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800483audio_usecase_t audio_extn_hfp_get_usecase()
484{
485 return hfpmod.ucid;
486}
487
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800488void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
489{
490 int ret;
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800491 int rate;
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800492 int val;
Amit Shekhar967cab32014-02-07 17:03:21 -0800493 float vol;
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800494 char value[32]={0};
495
496 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
497 sizeof(value));
498 if (ret >= 0) {
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530499 if (!strncmp(value, "true", sizeof(value)) && !hfpmod.is_hfp_running)
500 ret = start_hfp(adev,parms);
501 else if (!strncmp(value, "false", sizeof(value)) && hfpmod.is_hfp_running)
502 stop_hfp(adev);
503 else
504 ALOGE("hfp_enable=%s is unsupported", value);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800505 }
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800506 memset(value, 0, sizeof(value));
507 ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
508 sizeof(value));
509 if (ret >= 0) {
510 rate = atoi(value);
511 if (rate == 8000){
512 hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
513 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700514 } else if (rate == 16000){
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800515 hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
516 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700517 } else
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800518 ALOGE("Unsupported rate..");
519 }
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800520
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700521 if (hfpmod.is_hfp_running) {
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800522 memset(value, 0, sizeof(value));
523 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
524 value, sizeof(value));
525 if (ret >= 0) {
526 val = atoi(value);
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700527 if (val > 0)
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800528 select_devices(adev, hfpmod.ucid);
529 }
530 }
Amit Shekhar967cab32014-02-07 17:03:21 -0800531
532 memset(value, 0, sizeof(value));
533 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
534 value, sizeof(value));
535 if (ret >= 0) {
536 if (sscanf(value, "%f", &vol) != 1){
537 ALOGE("%s: error in retrieving hfp volume", __func__);
538 ret = -EIO;
539 goto exit;
540 }
541 ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
542 hfp_set_volume(adev, vol);
543 }
Satya Krishna Pindiprolic6b0a742017-02-03 14:37:18 +0530544
545 memset(value, 0, sizeof(value));
546 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID, value, sizeof(value));
547 if (ret >= 0) {
548 hfpmod.hfp_pcm_dev_id = atoi(value);
549 ALOGD("Updating HFP_PCM_DEV_ID as %d from platform XML", hfpmod.hfp_pcm_dev_id);
550 str_parms_del(parms, AUDIO_PARAMETER_HFP_PCM_DEV_ID);
551 }
552
Aalique Grahame22e49102018-12-18 14:23:57 -0800553 memset(value, 0, sizeof(value));
554 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_MIC_VOLUME,
555 value, sizeof(value));
556 if (ret >= 0) {
557 if (sscanf(value, "%f", &vol) != 1){
558 ALOGE("%s: error in retrieving hfp mic volume", __func__);
559 ret = -EIO;
560 goto exit;
561 }
562 ALOGD("%s: set_hfp_mic_volume usecase, Vol: [%f]", __func__, vol);
563 hfp_set_mic_volume(adev, vol);
564 }
565
Amit Shekhar967cab32014-02-07 17:03:21 -0800566exit:
567 ALOGV("%s Exit",__func__);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800568}
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800569#endif /*HFP_ENABLED*/