blob: 243d48d79242a35f292fe5bbcbe6e3c897f98589 [file] [log] [blame]
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -08001/* hfp.c
Banajit Goswami4c0dff22016-03-04 18:31:22 -08002Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -08003
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are
6met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of The Linux Foundation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
28
29#define LOG_TAG "audio_hw_hfp"
30/*#define LOG_NDEBUG 0*/
31#define LOG_NDDEBUG 0
32
33#include <errno.h>
34#include <math.h>
35#include <cutils/log.h>
36
37#include "audio_hw.h"
38#include "platform.h"
39#include "platform_api.h"
40#include <stdlib.h>
41#include <cutils/str_parms.h>
42
43#ifdef HFP_ENABLED
44#define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable"
Vimal Puthanveed47e64852013-12-20 13:23:39 -080045#define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate"
Amit Shekhar967cab32014-02-07 17:03:21 -080046#define AUDIO_PARAMETER_KEY_HFP_VOLUME "hfp_volume"
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080047
Sudheer Papothi19e43d02014-07-16 02:34:41 +053048#ifdef PLATFORM_MSM8994
49#define HFP_RX_VOLUME "SEC AUXPCM LOOPBACK Volume"
Banajit Goswamida77c452015-10-14 20:45:22 -070050#elif defined PLATFORM_MSM8996
51#define HFP_RX_VOLUME "PRI AUXPCM LOOPBACK Volume"
Dhananjay Kumard3ab9f42016-07-20 17:05:47 +053052#elif defined (PLATFORM_MSMCOBALT) || defined (PLATFORM_MSMFALCON)
Banajit Goswami4c0dff22016-03-04 18:31:22 -080053#define HFP_RX_VOLUME "SLIMBUS_7 LOOPBACK Volume"
Sudheer Papothi19e43d02014-07-16 02:34:41 +053054#else
55#define HFP_RX_VOLUME "Internal HFP RX Volume"
56#endif
57
Vimal Puthanveed584048b2013-12-11 17:00:50 -080058static int32_t start_hfp(struct audio_device *adev,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080059 struct str_parms *parms);
60
Vimal Puthanveed584048b2013-12-11 17:00:50 -080061static int32_t stop_hfp(struct audio_device *adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080062
63struct hfp_module {
64 struct pcm *hfp_sco_rx;
65 struct pcm *hfp_sco_tx;
66 struct pcm *hfp_pcm_rx;
67 struct pcm *hfp_pcm_tx;
68 bool is_hfp_running;
Amit Shekhar967cab32014-02-07 17:03:21 -080069 float hfp_volume;
Vimal Puthanveed47e64852013-12-20 13:23:39 -080070 audio_usecase_t ucid;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080071};
72
73static struct hfp_module hfpmod = {
74 .hfp_sco_rx = NULL,
75 .hfp_sco_tx = NULL,
76 .hfp_pcm_rx = NULL,
77 .hfp_pcm_tx = NULL,
78 .hfp_volume = 0,
79 .is_hfp_running = 0,
Vimal Puthanveed47e64852013-12-20 13:23:39 -080080 .ucid = USECASE_AUDIO_HFP_SCO,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080081};
82static struct pcm_config pcm_config_hfp = {
83 .channels = 1,
84 .rate = 8000,
85 .period_size = 240,
86 .period_count = 2,
87 .format = PCM_FORMAT_S16_LE,
88 .start_threshold = 0,
89 .stop_threshold = INT_MAX,
90 .avail_min = 0,
91};
92
Amit Shekhar967cab32014-02-07 17:03:21 -080093static int32_t hfp_set_volume(struct audio_device *adev, float value)
94{
95 int32_t vol, ret = 0;
96 struct mixer_ctl *ctl;
Sudheer Papothi19e43d02014-07-16 02:34:41 +053097 const char *mixer_ctl_name = HFP_RX_VOLUME;
Amit Shekhar967cab32014-02-07 17:03:21 -080098
99 ALOGV("%s: entry", __func__);
100 ALOGD("%s: (%f)\n", __func__, value);
101
Satya Krishna Pindiproli3ed6d792014-09-09 15:32:25 +0530102 hfpmod.hfp_volume = value;
Amit Shekhar967cab32014-02-07 17:03:21 -0800103 if (value < 0.0) {
104 ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
105 value = 0.0;
106 } else {
107 value = ((value > 15.000000) ? 1.0 : (value / 15));
108 ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
109 }
110 vol = lrint((value * 0x2000) + 0.5);
Amit Shekhar967cab32014-02-07 17:03:21 -0800111
112 if (!hfpmod.is_hfp_running) {
113 ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
114 return -EIO;
115 }
116
117 ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
118 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
119 if (!ctl) {
120 ALOGE("%s: Could not get ctl for mixer cmd - %s",
121 __func__, mixer_ctl_name);
122 return -EINVAL;
123 }
124 if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
125 ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
126 return -EINVAL;
127 }
128
129 ALOGV("%s: exit", __func__);
130 return ret;
131}
132
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800133static int32_t start_hfp(struct audio_device *adev,
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700134 struct str_parms *parms __unused)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800135{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530136 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800137 struct audio_usecase *uc_info;
138 int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
139
140 ALOGD("%s: enter", __func__);
141
142 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700143
144 if (!uc_info)
145 return -ENOMEM;
146
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800147 uc_info->id = hfpmod.ucid;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800148 uc_info->type = PCM_HFP_CALL;
149 uc_info->stream.out = adev->primary_output;
150 uc_info->devices = adev->primary_output->devices;
151 uc_info->in_snd_device = SND_DEVICE_NONE;
152 uc_info->out_snd_device = SND_DEVICE_NONE;
153
154 list_add_tail(&adev->usecase_list, &uc_info->list);
155
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800156 select_devices(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800157
158 pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
159 pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
160 pcm_dev_asm_rx_id = HFP_ASM_RX_TX;
161 pcm_dev_asm_tx_id = HFP_ASM_RX_TX;
162 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
163 pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
164 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
165 __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
166 ret = -EIO;
167 goto exit;
168 }
169
170 ALOGV("%s: HFP PCM devices (hfp rx tx: %d pcm rx tx: %d) for the usecase(%d)",
171 __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
172
173 ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800174 __func__, adev->snd_card, pcm_dev_rx_id);
175 hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800176 pcm_dev_asm_rx_id,
177 PCM_OUT, &pcm_config_hfp);
178 if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
179 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
180 ret = -EIO;
181 goto exit;
182 }
183 ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800184 __func__, adev->snd_card, pcm_dev_tx_id);
185 hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800186 pcm_dev_rx_id,
187 PCM_OUT, &pcm_config_hfp);
188 if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
189 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
190 ret = -EIO;
191 goto exit;
192 }
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800193 hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800194 pcm_dev_asm_tx_id,
195 PCM_IN, &pcm_config_hfp);
196 if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
197 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
198 ret = -EIO;
199 goto exit;
200 }
201 ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800202 __func__, adev->snd_card, pcm_dev_tx_id);
203 hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800204 pcm_dev_tx_id,
205 PCM_IN, &pcm_config_hfp);
206 if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
207 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
208 ret = -EIO;
209 goto exit;
210 }
Satya Krishna Pindiprolice903a02014-07-28 12:40:56 +0530211 if (pcm_start(hfpmod.hfp_sco_rx) < 0) {
212 ALOGE("%s: pcm start for hfp sco rx failed", __func__);
213 ret = -EINVAL;
214 goto exit;
215 }
216 if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
217 ALOGE("%s: pcm start for hfp sco tx failed", __func__);
218 ret = -EINVAL;
219 goto exit;
220 }
221 if (pcm_start(hfpmod.hfp_pcm_rx) < 0) {
222 ALOGE("%s: pcm start for hfp pcm rx failed", __func__);
223 ret = -EINVAL;
224 goto exit;
225 }
226 if (pcm_start(hfpmod.hfp_pcm_tx) < 0) {
227 ALOGE("%s: pcm start for hfp pcm tx failed", __func__);
228 ret = -EINVAL;
229 goto exit;
230 }
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800231
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800232 hfpmod.is_hfp_running = true;
Amit Shekhar967cab32014-02-07 17:03:21 -0800233 hfp_set_volume(adev, hfpmod.hfp_volume);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800234
235 ALOGD("%s: exit: status(%d)", __func__, ret);
236 return 0;
237
238exit:
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800239 stop_hfp(adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800240 ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
241 return ret;
242}
243
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800244static int32_t stop_hfp(struct audio_device *adev)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800245{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +0530246 int32_t ret = 0;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800247 struct audio_usecase *uc_info;
248
249 ALOGD("%s: enter", __func__);
250 hfpmod.is_hfp_running = false;
251
252 /* 1. Close the PCM devices */
253 if (hfpmod.hfp_sco_rx) {
254 pcm_close(hfpmod.hfp_sco_rx);
255 hfpmod.hfp_sco_rx = NULL;
256 }
257 if (hfpmod.hfp_sco_tx) {
258 pcm_close(hfpmod.hfp_sco_tx);
259 hfpmod.hfp_sco_tx = NULL;
260 }
261 if (hfpmod.hfp_pcm_rx) {
262 pcm_close(hfpmod.hfp_pcm_rx);
263 hfpmod.hfp_pcm_rx = NULL;
264 }
265 if (hfpmod.hfp_pcm_tx) {
266 pcm_close(hfpmod.hfp_pcm_tx);
267 hfpmod.hfp_pcm_tx = NULL;
268 }
269
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800270 uc_info = get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800271 if (uc_info == NULL) {
272 ALOGE("%s: Could not find the usecase (%d) in the list",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800273 __func__, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800274 return -EINVAL;
275 }
276
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530277 /* 2. Disable echo reference while stopping hfp */
Apoorv Raghuvanshi924b3022015-07-06 15:07:14 -0700278 platform_set_echo_reference(adev, false, uc_info->devices);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530279
280 /* 3. Get and set stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -0700281 disable_audio_route(adev, uc_info);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800282
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +0530283 /* 4. Disable the rx and tx devices */
Haynes Mathew George1376ca62014-04-24 11:55:48 -0700284 disable_snd_device(adev, uc_info->out_snd_device);
285 disable_snd_device(adev, uc_info->in_snd_device);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800286
287 list_remove(&uc_info->list);
288 free(uc_info);
289
290 ALOGD("%s: exit: status(%d)", __func__, ret);
291 return ret;
292}
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800293
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800294bool audio_extn_hfp_is_active(struct audio_device *adev)
295{
296 struct audio_usecase *hfp_usecase = NULL;
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800297 hfp_usecase = get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800298
299 if (hfp_usecase != NULL)
300 return true;
301 else
302 return false;
303}
304
Dhanalakshmi Siddani823dc5a2016-09-28 14:47:26 +0530305int hfp_set_mic_mute(struct audio_device *adev, bool state)
306{
307 struct mixer_ctl *ctl;
308 const char *mixer_ctl_name = "HFP TX Mute";
309 uint32_t set_values[ ] = {0};
310
311 ALOGI("%s: enter, state=%d", __func__, state);
312
313 set_values[0] = state;
314 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
315 if (!ctl) {
316 ALOGE("%s: Could not get ctl for mixer cmd - %s",
317 __func__, mixer_ctl_name);
318 return -EINVAL;
319 }
320 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
321 ALOGV("%s: exit", __func__);
322 return 0;
323}
324
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800325audio_usecase_t audio_extn_hfp_get_usecase()
326{
327 return hfpmod.ucid;
328}
329
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800330void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
331{
332 int ret;
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800333 int rate;
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800334 int val;
Amit Shekhar967cab32014-02-07 17:03:21 -0800335 float vol;
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800336 char value[32]={0};
337
338 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
339 sizeof(value));
340 if (ret >= 0) {
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700341 if (!strncmp(value,"true",sizeof(value)))
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800342 ret = start_hfp(adev,parms);
343 else
344 stop_hfp(adev);
345 }
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800346 memset(value, 0, sizeof(value));
347 ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
348 sizeof(value));
349 if (ret >= 0) {
350 rate = atoi(value);
351 if (rate == 8000){
352 hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
353 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700354 } else if (rate == 16000){
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800355 hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
356 pcm_config_hfp.rate = rate;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700357 } else
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800358 ALOGE("Unsupported rate..");
359 }
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800360
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700361 if (hfpmod.is_hfp_running) {
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800362 memset(value, 0, sizeof(value));
363 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
364 value, sizeof(value));
365 if (ret >= 0) {
366 val = atoi(value);
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -0700367 if (val > 0)
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800368 select_devices(adev, hfpmod.ucid);
369 }
370 }
Amit Shekhar967cab32014-02-07 17:03:21 -0800371
372 memset(value, 0, sizeof(value));
373 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
374 value, sizeof(value));
375 if (ret >= 0) {
376 if (sscanf(value, "%f", &vol) != 1){
377 ALOGE("%s: error in retrieving hfp volume", __func__);
378 ret = -EIO;
379 goto exit;
380 }
381 ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
382 hfp_set_volume(adev, vol);
383 }
384exit:
385 ALOGV("%s Exit",__func__);
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800386}
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800387#endif /*HFP_ENABLED*/