blob: 4eb9d37284b8dc9df266083a61867304ec5fc451 [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
220void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
221{
222 int ret;
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800223 int rate;
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800224 char value[32]={0};
225
226 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
227 sizeof(value));
228 if (ret >= 0) {
229 if(!strncmp(value,"true",sizeof(value)))
230 ret = start_hfp(adev,parms);
231 else
232 stop_hfp(adev);
233 }
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800234 memset(value, 0, sizeof(value));
235 ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
236 sizeof(value));
237 if (ret >= 0) {
238 rate = atoi(value);
239 if (rate == 8000){
240 hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
241 pcm_config_hfp.rate = rate;
242 }
243 else if (rate == 16000){
244 hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
245 pcm_config_hfp.rate = rate;
246 }
247 else
248 ALOGE("Unsupported rate..");
249 }
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800250}
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800251#endif /*HFP_ENABLED*/