• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "audio_hw_hfp"
18 /*#define LOG_NDEBUG 0*/
19 #define LOG_NDDEBUG 0
20 
21 #include <errno.h>
22 #include <math.h>
23 #include <cutils/log.h>
24 
25 #include "audio_hw.h"
26 #include "platform.h"
27 #include "platform_api.h"
28 #include <stdlib.h>
29 #include <cutils/str_parms.h>
30 
31 #define AUDIO_PARAMETER_HFP_ENABLE            "hfp_enable"
32 #define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate"
33 #define AUDIO_PARAMETER_KEY_HFP_VOLUME        "hfp_volume"
34 #define AUDIO_PARAMETER_HFP_VOL_MIXER_CTL     "hfp_vol_mixer_ctl"
35 #define AUDIO_PARAMATER_HFP_VALUE_MAX         128
36 
37 static int32_t start_hfp(struct audio_device *adev,
38                                struct str_parms *parms);
39 
40 static int32_t stop_hfp(struct audio_device *adev);
41 
42 struct hfp_module {
43     struct pcm *hfp_sco_rx;
44     struct pcm *hfp_sco_tx;
45     struct pcm *hfp_pcm_rx;
46     struct pcm *hfp_pcm_tx;
47     float  hfp_volume;
48     char   hfp_vol_mixer_ctl[AUDIO_PARAMATER_HFP_VALUE_MAX];
49     bool   is_hfp_running;
50     audio_usecase_t ucid;
51 };
52 
53 static struct hfp_module hfpmod = {
54     .hfp_sco_rx = NULL,
55     .hfp_sco_tx = NULL,
56     .hfp_pcm_rx = NULL,
57     .hfp_pcm_tx = NULL,
58     .hfp_volume = 0,
59     .hfp_vol_mixer_ctl = {0, },
60     .is_hfp_running = 0,
61     .ucid = USECASE_AUDIO_HFP_SCO,
62 };
63 static struct pcm_config pcm_config_hfp = {
64     .channels = 1,
65     .rate = 8000,
66     .period_size = 240,
67     .period_count = 2,
68     .format = PCM_FORMAT_S16_LE,
69     .start_threshold = 0,
70     .stop_threshold = INT_MAX,
71     .avail_min = 0,
72 };
73 
hfp_set_volume(struct audio_device * adev,float value)74 static int32_t hfp_set_volume(struct audio_device *adev, float value)
75 {
76     int32_t vol, ret = 0;
77     struct mixer_ctl *ctl;
78 
79     ALOGV("%s: entry", __func__);
80     ALOGD("%s: (%f)\n", __func__, value);
81 
82     if (value < 0.0) {
83         ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
84         value = 0.0;
85     } else {
86         value = ((value > 15.000000) ? 1.0 : (value / 15));
87         ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
88     }
89     vol  = lrint((value * 0x2000) + 0.5);
90     hfpmod.hfp_volume = value;
91 
92     if (!hfpmod.is_hfp_running) {
93         ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
94         return -EIO;
95     }
96 
97     ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
98     if (0 == hfpmod.hfp_vol_mixer_ctl[0]) {
99 #ifdef EXTERNAL_BT_SUPPORTED
100         strcpy(hfpmod.hfp_vol_mixer_ctl, "PRI AUXPCM LOOPBACK Volume");
101 #else
102         strcpy(hfpmod.hfp_vol_mixer_ctl, "Internal HFP RX Volume");
103 #endif
104         ALOGW("%s: Defaulting hfp mixer control to: %s",
105                  __func__, hfpmod.hfp_vol_mixer_ctl);
106     }
107     ctl = mixer_get_ctl_by_name(adev->mixer, hfpmod.hfp_vol_mixer_ctl);
108     if (!ctl) {
109         ALOGE("%s: Could not get ctl for mixer cmd - %s",
110               __func__, hfpmod.hfp_vol_mixer_ctl);
111         return -EINVAL;
112     }
113     if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
114         ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
115         return -EINVAL;
116     }
117 
118     ALOGV("%s: exit", __func__);
119     return ret;
120 }
121 
start_hfp(struct audio_device * adev,struct str_parms * parms __unused)122 static int32_t start_hfp(struct audio_device *adev,
123                          struct str_parms *parms __unused)
124 {
125     int32_t i, ret = 0;
126     struct audio_usecase *uc_info;
127     int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
128 
129     ALOGD("%s: enter", __func__);
130     adev->enable_hfp = true;
131     platform_set_mic_mute(adev->platform, false);
132 
133     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
134     uc_info->id = hfpmod.ucid;
135     uc_info->type = PCM_HFP_CALL;
136     uc_info->stream.out = adev->primary_output;
137     uc_info->devices = adev->primary_output->devices;
138     uc_info->in_snd_device = SND_DEVICE_NONE;
139     uc_info->out_snd_device = SND_DEVICE_NONE;
140 
141     list_add_tail(&adev->usecase_list, &uc_info->list);
142 
143     select_devices(adev, hfpmod.ucid);
144 
145     pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
146     pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
147     pcm_dev_asm_rx_id = HFP_ASM_RX_TX;
148     pcm_dev_asm_tx_id = HFP_ASM_RX_TX;
149     if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
150         pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
151         ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
152               __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
153         ret = -EIO;
154         goto exit;
155     }
156 
157     ALOGV("%s: HFP PCM devices (hfp rx tx: %d pcm rx tx: %d) for the usecase(%d)",
158               __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
159 
160     ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
161           __func__, adev->snd_card, pcm_dev_rx_id);
162     hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
163                                   pcm_dev_asm_rx_id,
164                                   PCM_OUT, &pcm_config_hfp);
165     if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
166         ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
167         ret = -EIO;
168         goto exit;
169     }
170     ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
171           __func__, adev->snd_card, pcm_dev_tx_id);
172     hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
173                                    pcm_dev_rx_id,
174                                    PCM_OUT, &pcm_config_hfp);
175     if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
176         ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
177         ret = -EIO;
178         goto exit;
179     }
180     hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
181                                   pcm_dev_asm_tx_id,
182                                   PCM_IN, &pcm_config_hfp);
183     if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
184         ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
185         ret = -EIO;
186         goto exit;
187     }
188     ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
189           __func__, adev->snd_card, pcm_dev_tx_id);
190     hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
191                                    pcm_dev_tx_id,
192                                    PCM_IN, &pcm_config_hfp);
193     if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
194         ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
195         ret = -EIO;
196         goto exit;
197     }
198     pcm_start(hfpmod.hfp_sco_rx);
199     pcm_start(hfpmod.hfp_sco_tx);
200     pcm_start(hfpmod.hfp_pcm_rx);
201     pcm_start(hfpmod.hfp_pcm_tx);
202 
203     hfpmod.is_hfp_running = true;
204     hfp_set_volume(adev, hfpmod.hfp_volume);
205 
206     ALOGD("%s: exit: status(%d)", __func__, ret);
207     return 0;
208 
209 exit:
210     stop_hfp(adev);
211     ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
212     return ret;
213 }
214 
stop_hfp(struct audio_device * adev)215 static int32_t stop_hfp(struct audio_device *adev)
216 {
217     int32_t i, ret = 0;
218     struct audio_usecase *uc_info;
219 
220     ALOGD("%s: enter", __func__);
221     hfpmod.is_hfp_running = false;
222 
223     /* 1. Close the PCM devices */
224     if (hfpmod.hfp_sco_rx) {
225         pcm_close(hfpmod.hfp_sco_rx);
226         hfpmod.hfp_sco_rx = NULL;
227     }
228     if (hfpmod.hfp_sco_tx) {
229         pcm_close(hfpmod.hfp_sco_tx);
230         hfpmod.hfp_sco_tx = NULL;
231     }
232     if (hfpmod.hfp_pcm_rx) {
233         pcm_close(hfpmod.hfp_pcm_rx);
234         hfpmod.hfp_pcm_rx = NULL;
235     }
236     if (hfpmod.hfp_pcm_tx) {
237         pcm_close(hfpmod.hfp_pcm_tx);
238         hfpmod.hfp_pcm_tx = NULL;
239     }
240 
241     uc_info = get_usecase_from_list(adev, hfpmod.ucid);
242     if (uc_info == NULL) {
243         ALOGE("%s: Could not find the usecase (%d) in the list",
244               __func__, hfpmod.ucid);
245         return -EINVAL;
246     }
247 
248     /* 2. Get and set stream specific mixer controls */
249     disable_audio_route(adev, uc_info);
250 
251     /* 3. Disable the rx and tx devices */
252     disable_snd_device(adev, uc_info->out_snd_device);
253     disable_snd_device(adev, uc_info->in_snd_device);
254 
255     /* Disable the echo reference for HFP Tx */
256     platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
257 
258     /* Set the unmute Tx mixer control */
259     if (voice_get_mic_mute(adev)) {
260         platform_set_mic_mute(adev->platform, false);
261         ALOGD("%s: unMute HFP Tx", __func__);
262     }
263     adev->enable_hfp = false;
264 
265     list_remove(&uc_info->list);
266     free(uc_info);
267 
268     ALOGD("%s: exit: status(%d)", __func__, ret);
269     return ret;
270 }
271 
audio_extn_hfp_is_active(struct audio_device * adev)272 bool audio_extn_hfp_is_active(struct audio_device *adev)
273 {
274     struct audio_usecase *hfp_usecase = NULL;
275     hfp_usecase = get_usecase_from_list(adev, hfpmod.ucid);
276 
277     if (hfp_usecase != NULL)
278         return true;
279     else
280         return false;
281 }
282 
audio_extn_hfp_get_usecase()283 audio_usecase_t audio_extn_hfp_get_usecase()
284 {
285     return hfpmod.ucid;
286 }
287 
audio_extn_hfp_set_parameters(struct audio_device * adev,struct str_parms * parms)288 void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
289 {
290     int ret;
291     int rate;
292     int val;
293     float vol;
294     char value[AUDIO_PARAMATER_HFP_VALUE_MAX] = {0, };
295 
296     ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
297                             sizeof(value));
298     if (ret >= 0) {
299            if (!strncmp(value,"true",sizeof(value)))
300                ret = start_hfp(adev,parms);
301            else
302                stop_hfp(adev);
303     }
304     memset(value, 0, sizeof(value));
305     ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
306                             sizeof(value));
307     if (ret >= 0) {
308            rate = atoi(value);
309            if (rate == 8000){
310                hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
311                pcm_config_hfp.rate = rate;
312            } else if (rate == 16000){
313                hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
314                pcm_config_hfp.rate = rate;
315            } else
316                ALOGE("Unsupported rate..");
317     }
318 
319     if (hfpmod.is_hfp_running) {
320         memset(value, 0, sizeof(value));
321         ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
322                                 value, sizeof(value));
323         if (ret >= 0) {
324             val = atoi(value);
325             if (val > 0)
326                 select_devices(adev, hfpmod.ucid);
327         }
328     }
329 
330     memset(value, 0, sizeof(value));
331     ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_VOL_MIXER_CTL,
332                           value, sizeof(value));
333     if (ret >= 0) {
334         ALOGD("%s: mixer ctl name: %s", __func__, value);
335         strcpy(hfpmod.hfp_vol_mixer_ctl, value);
336         str_parms_del(parms, AUDIO_PARAMETER_HFP_VOL_MIXER_CTL);
337     }
338 
339     memset(value, 0, sizeof(value));
340     ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
341                             value, sizeof(value));
342     if (ret >= 0) {
343         if (sscanf(value, "%f", &vol) != 1){
344             ALOGE("%s: error in retrieving hfp volume", __func__);
345             ret = -EIO;
346             goto exit;
347         }
348         ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
349         hfp_set_volume(adev, vol);
350     }
351 exit:
352     ALOGV("%s Exit",__func__);
353 }
354