blob: 6b0546a3bd5b84eb57e6c2c3265127bcc4cd595a [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"
45
Vimal Puthanveed584048b2013-12-11 17:00:50 -080046static int32_t start_hfp(struct audio_device *adev,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080047 struct str_parms *parms);
48
Vimal Puthanveed584048b2013-12-11 17:00:50 -080049static int32_t stop_hfp(struct audio_device *adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080050
51struct hfp_module {
52 struct pcm *hfp_sco_rx;
53 struct pcm *hfp_sco_tx;
54 struct pcm *hfp_pcm_rx;
55 struct pcm *hfp_pcm_tx;
56 bool is_hfp_running;
57 int hfp_volume;
58};
59
60static struct hfp_module hfpmod = {
61 .hfp_sco_rx = NULL,
62 .hfp_sco_tx = NULL,
63 .hfp_pcm_rx = NULL,
64 .hfp_pcm_tx = NULL,
65 .hfp_volume = 0,
66 .is_hfp_running = 0,
67};
68static struct pcm_config pcm_config_hfp = {
69 .channels = 1,
70 .rate = 8000,
71 .period_size = 240,
72 .period_count = 2,
73 .format = PCM_FORMAT_S16_LE,
74 .start_threshold = 0,
75 .stop_threshold = INT_MAX,
76 .avail_min = 0,
77};
78
Vimal Puthanveed584048b2013-12-11 17:00:50 -080079static int32_t start_hfp(struct audio_device *adev,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -080080 struct str_parms *parms)
81{
82 int32_t i, ret = 0;
83 struct audio_usecase *uc_info;
84 int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
85
86 ALOGD("%s: enter", __func__);
87
88 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
89 uc_info->id = USECASE_AUDIO_HFP_SCO;
90 uc_info->type = PCM_HFP_CALL;
91 uc_info->stream.out = adev->primary_output;
92 uc_info->devices = adev->primary_output->devices;
93 uc_info->in_snd_device = SND_DEVICE_NONE;
94 uc_info->out_snd_device = SND_DEVICE_NONE;
95
96 list_add_tail(&adev->usecase_list, &uc_info->list);
97
98 select_devices(adev, USECASE_AUDIO_HFP_SCO);
99
100 pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
101 pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
102 pcm_dev_asm_rx_id = HFP_ASM_RX_TX;
103 pcm_dev_asm_tx_id = HFP_ASM_RX_TX;
104 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
105 pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
106 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
107 __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
108 ret = -EIO;
109 goto exit;
110 }
111
112 ALOGV("%s: HFP PCM devices (hfp rx tx: %d pcm rx tx: %d) for the usecase(%d)",
113 __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
114
115 ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800116 __func__, adev->snd_card, pcm_dev_rx_id);
117 hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800118 pcm_dev_asm_rx_id,
119 PCM_OUT, &pcm_config_hfp);
120 if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
121 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
122 ret = -EIO;
123 goto exit;
124 }
125 ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800126 __func__, adev->snd_card, pcm_dev_tx_id);
127 hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800128 pcm_dev_rx_id,
129 PCM_OUT, &pcm_config_hfp);
130 if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
131 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
132 ret = -EIO;
133 goto exit;
134 }
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800135 hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800136 pcm_dev_asm_tx_id,
137 PCM_IN, &pcm_config_hfp);
138 if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
139 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
140 ret = -EIO;
141 goto exit;
142 }
143 ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -0800144 __func__, adev->snd_card, pcm_dev_tx_id);
145 hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800146 pcm_dev_tx_id,
147 PCM_IN, &pcm_config_hfp);
148 if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
149 ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
150 ret = -EIO;
151 goto exit;
152 }
153 pcm_start(hfpmod.hfp_sco_rx);
154 pcm_start(hfpmod.hfp_sco_tx);
155 pcm_start(hfpmod.hfp_pcm_rx);
156 pcm_start(hfpmod.hfp_pcm_tx);
157
158
159 hfpmod.is_hfp_running = true;
160
161 ALOGD("%s: exit: status(%d)", __func__, ret);
162 return 0;
163
164exit:
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800165 stop_hfp(adev);
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800166 ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
167 return ret;
168}
169
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800170static int32_t stop_hfp(struct audio_device *adev)
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800171{
172 int32_t i, ret = 0;
173 struct audio_usecase *uc_info;
174
175 ALOGD("%s: enter", __func__);
176 hfpmod.is_hfp_running = false;
177
178 /* 1. Close the PCM devices */
179 if (hfpmod.hfp_sco_rx) {
180 pcm_close(hfpmod.hfp_sco_rx);
181 hfpmod.hfp_sco_rx = NULL;
182 }
183 if (hfpmod.hfp_sco_tx) {
184 pcm_close(hfpmod.hfp_sco_tx);
185 hfpmod.hfp_sco_tx = NULL;
186 }
187 if (hfpmod.hfp_pcm_rx) {
188 pcm_close(hfpmod.hfp_pcm_rx);
189 hfpmod.hfp_pcm_rx = NULL;
190 }
191 if (hfpmod.hfp_pcm_tx) {
192 pcm_close(hfpmod.hfp_pcm_tx);
193 hfpmod.hfp_pcm_tx = NULL;
194 }
195
196 uc_info = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO);
197 if (uc_info == NULL) {
198 ALOGE("%s: Could not find the usecase (%d) in the list",
199 __func__, USECASE_AUDIO_HFP_SCO);
200 return -EINVAL;
201 }
202
203 /* 2. Get and set stream specific mixer controls */
204 disable_audio_route(adev, uc_info, true);
205
206 /* 3. Disable the rx and tx devices */
207 disable_snd_device(adev, uc_info->out_snd_device, false);
208 disable_snd_device(adev, uc_info->in_snd_device, true);
209
210 list_remove(&uc_info->list);
211 free(uc_info);
212
213 ALOGD("%s: exit: status(%d)", __func__, ret);
214 return ret;
215}
Vimal Puthanveed584048b2013-12-11 17:00:50 -0800216
217void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
218{
219 int ret;
220 char value[32]={0};
221
222 ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
223 sizeof(value));
224 if (ret >= 0) {
225 if(!strncmp(value,"true",sizeof(value)))
226 ret = start_hfp(adev,parms);
227 else
228 stop_hfp(adev);
229 }
230}
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800231#endif /*HFP_ENABLED*/