blob: c48049068e3ebb80e07f3b2d8743acabd44d82ff [file] [log] [blame]
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -08001/* hfp.c
2Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
3
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"
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080046
Vimal Puthanveed584048b2013-12-11 17:00:50 -080047static int32_t start_hfp(struct audio_device *adev,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080048 struct str_parms *parms);
49
Vimal Puthanveed584048b2013-12-11 17:00:50 -080050static int32_t stop_hfp(struct audio_device *adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080051
52struct hfp_module {
53 struct pcm *hfp_sco_rx;
54 struct pcm *hfp_sco_tx;
55 struct pcm *hfp_pcm_rx;
56 struct pcm *hfp_pcm_tx;
57 bool is_hfp_running;
58 int hfp_volume;
Vimal Puthanveed47e64852013-12-20 13:23:39 -080059 audio_usecase_t ucid;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080060};
61
62static struct hfp_module hfpmod = {
63 .hfp_sco_rx = NULL,
64 .hfp_sco_tx = NULL,
65 .hfp_pcm_rx = NULL,
66 .hfp_pcm_tx = NULL,
67 .hfp_volume = 0,
68 .is_hfp_running = 0,
Vimal Puthanveed47e64852013-12-20 13:23:39 -080069 .ucid = USECASE_AUDIO_HFP_SCO,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080070};
71static struct pcm_config pcm_config_hfp = {
72 .channels = 1,
73 .rate = 8000,
74 .period_size = 240,
75 .period_count = 2,
76 .format = PCM_FORMAT_S16_LE,
77 .start_threshold = 0,
78 .stop_threshold = INT_MAX,
79 .avail_min = 0,
80};
81
Vimal Puthanveed584048b2013-12-11 17:00:50 -080082static int32_t start_hfp(struct audio_device *adev,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080083 struct str_parms *parms)
84{
85 int32_t i, ret = 0;
86 struct audio_usecase *uc_info;
87 int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
88
89 ALOGD("%s: enter", __func__);
90
91 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Vimal Puthanveed47e64852013-12-20 13:23:39 -080092 uc_info->id = hfpmod.ucid;
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080093 uc_info->type = PCM_HFP_CALL;
94 uc_info->stream.out = adev->primary_output;
95 uc_info->devices = adev->primary_output->devices;
96 uc_info->in_snd_device = SND_DEVICE_NONE;
97 uc_info->out_snd_device = SND_DEVICE_NONE;
98
99 list_add_tail(&adev->usecase_list, &uc_info->list);
100
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800101 select_devices(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800102
103 pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
104 pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
105 pcm_dev_asm_rx_id = HFP_ASM_RX_TX;
106 pcm_dev_asm_tx_id = HFP_ASM_RX_TX;
107 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
108 pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
109 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
110 __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
111 ret = -EIO;
112 goto exit;
113 }
114
115 ALOGV("%s: HFP PCM devices (hfp rx tx: %d pcm rx tx: %d) for the usecase(%d)",
116 __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
117
118 ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800119 __func__, adev->snd_card, pcm_dev_rx_id);
120 hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800121 pcm_dev_asm_rx_id,
122 PCM_OUT, &pcm_config_hfp);
123 if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
124 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
125 ret = -EIO;
126 goto exit;
127 }
128 ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800129 __func__, adev->snd_card, pcm_dev_tx_id);
130 hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800131 pcm_dev_rx_id,
132 PCM_OUT, &pcm_config_hfp);
133 if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
134 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
135 ret = -EIO;
136 goto exit;
137 }
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800138 hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800139 pcm_dev_asm_tx_id,
140 PCM_IN, &pcm_config_hfp);
141 if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
142 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
143 ret = -EIO;
144 goto exit;
145 }
146 ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800147 __func__, adev->snd_card, pcm_dev_tx_id);
148 hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800149 pcm_dev_tx_id,
150 PCM_IN, &pcm_config_hfp);
151 if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
152 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
153 ret = -EIO;
154 goto exit;
155 }
156 pcm_start(hfpmod.hfp_sco_rx);
157 pcm_start(hfpmod.hfp_sco_tx);
158 pcm_start(hfpmod.hfp_pcm_rx);
159 pcm_start(hfpmod.hfp_pcm_tx);
160
161
162 hfpmod.is_hfp_running = true;
163
164 ALOGD("%s: exit: status(%d)", __func__, ret);
165 return 0;
166
167exit:
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800168 stop_hfp(adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800169 ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
170 return ret;
171}
172
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800173static int32_t stop_hfp(struct audio_device *adev)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800174{
175 int32_t i, ret = 0;
176 struct audio_usecase *uc_info;
177
178 ALOGD("%s: enter", __func__);
179 hfpmod.is_hfp_running = false;
180
181 /* 1. Close the PCM devices */
182 if (hfpmod.hfp_sco_rx) {
183 pcm_close(hfpmod.hfp_sco_rx);
184 hfpmod.hfp_sco_rx = NULL;
185 }
186 if (hfpmod.hfp_sco_tx) {
187 pcm_close(hfpmod.hfp_sco_tx);
188 hfpmod.hfp_sco_tx = NULL;
189 }
190 if (hfpmod.hfp_pcm_rx) {
191 pcm_close(hfpmod.hfp_pcm_rx);
192 hfpmod.hfp_pcm_rx = NULL;
193 }
194 if (hfpmod.hfp_pcm_tx) {
195 pcm_close(hfpmod.hfp_pcm_tx);
196 hfpmod.hfp_pcm_tx = NULL;
197 }
198
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800199 uc_info = get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800200 if (uc_info == NULL) {
201 ALOGE("%s: Could not find the usecase (%d) in the list",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800202 __func__, hfpmod.ucid);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800203 return -EINVAL;
204 }
205
206 /* 2. Get and set stream specific mixer controls */
207 disable_audio_route(adev, uc_info, true);
208
209 /* 3. Disable the rx and tx devices */
210 disable_snd_device(adev, uc_info->out_snd_device, false);
211 disable_snd_device(adev, uc_info->in_snd_device, true);
212
213 list_remove(&uc_info->list);
214 free(uc_info);
215
216 ALOGD("%s: exit: status(%d)", __func__, ret);
217 return ret;
218}
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800219
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800220bool audio_extn_hfp_is_active(struct audio_device *adev)
221{
222 struct audio_usecase *hfp_usecase = NULL;
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800223 hfp_usecase = get_usecase_from_list(adev, hfpmod.ucid);
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -0800224
225 if (hfp_usecase != NULL)
226 return true;
227 else
228 return false;
229}
230
Vimal Puthanveed41fcff22014-01-23 15:56:53 -0800231audio_usecase_t audio_extn_hfp_get_usecase()
232{
233 return hfpmod.ucid;
234}
235
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800236void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
237{
238 int ret;
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800239 int rate;
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800240 int val;
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800241 char value[32]={0};
242
243 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
244 sizeof(value));
245 if (ret >= 0) {
246 if(!strncmp(value,"true",sizeof(value)))
247 ret = start_hfp(adev,parms);
248 else
249 stop_hfp(adev);
250 }
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800251 memset(value, 0, sizeof(value));
252 ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
253 sizeof(value));
254 if (ret >= 0) {
255 rate = atoi(value);
256 if (rate == 8000){
257 hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
258 pcm_config_hfp.rate = rate;
259 }
260 else if (rate == 16000){
261 hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
262 pcm_config_hfp.rate = rate;
263 }
264 else
265 ALOGE("Unsupported rate..");
266 }
Vimal Puthanveed21e5c762014-01-08 14:10:09 -0800267
268 if(hfpmod.is_hfp_running) {
269 memset(value, 0, sizeof(value));
270 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
271 value, sizeof(value));
272 if (ret >= 0) {
273 val = atoi(value);
274 if(val > 0)
275 select_devices(adev, hfpmod.ucid);
276 }
277 }
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800278}
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800279#endif /*HFP_ENABLED*/