• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
3  * Not a contribution.
4  *
5  * Copyright (C) 2013 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #define LOG_TAG "voice"
21 /*#define LOG_NDEBUG 0*/
22 #define LOG_NDDEBUG 0
23 
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include <cutils/log.h>
28 #include <cutils/str_parms.h>
29 
30 #include "audio_hw.h"
31 #include "voice.h"
32 #include "voice_extn/voice_extn.h"
33 #include "platform.h"
34 #include "platform_api.h"
35 #include "audio_extn.h"
36 
37 struct pcm_config pcm_config_voice_call = {
38     .channels = 1,
39     .rate = 8000,
40     .period_size = 160,
41     .period_count = 2,
42     .format = PCM_FORMAT_S16_LE,
43 };
44 
voice_get_session_from_use_case(struct audio_device * adev,audio_usecase_t usecase_id)45 static struct voice_session *voice_get_session_from_use_case(struct audio_device *adev,
46                               audio_usecase_t usecase_id)
47 {
48     struct voice_session *session = NULL;
49     int ret = 0;
50 
51     ret = voice_extn_get_session_from_use_case(adev, usecase_id, &session);
52     if (ret == -ENOSYS) {
53         session = &adev->voice.session[VOICE_SESS_IDX];
54     }
55 
56     return session;
57 }
58 
voice_stop_usecase(struct audio_device * adev,audio_usecase_t usecase_id)59 int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
60 {
61     int i, ret = 0;
62     struct audio_usecase *uc_info;
63     struct voice_session *session = NULL;
64 
65     ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
66 
67     session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
68     if (!session) {
69         ALOGE("stop_call: couldn't find voice session");
70         return -EINVAL;
71     }
72 
73     session->state.current = CALL_INACTIVE;
74     if (adev->mode == AUDIO_MODE_NORMAL)
75         adev->voice.is_in_call = false;
76 
77     ret = platform_stop_voice_call(adev->platform, session->vsid);
78 
79     /* 1. Close the PCM devices */
80     if (session->pcm_rx) {
81         pcm_close(session->pcm_rx);
82         session->pcm_rx = NULL;
83     }
84     if (session->pcm_tx) {
85         pcm_close(session->pcm_tx);
86         session->pcm_tx = NULL;
87     }
88 
89     uc_info = get_usecase_from_list(adev, usecase_id);
90     if (uc_info == NULL) {
91         ALOGE("%s: Could not find the usecase (%d) in the list",
92               __func__, usecase_id);
93         return -EINVAL;
94     }
95 
96     /* 2. Get and set stream specific mixer controls */
97     disable_audio_route(adev, uc_info);
98 
99     /* 3. Disable the rx and tx devices */
100     disable_snd_device(adev, uc_info->out_snd_device);
101     disable_snd_device(adev, uc_info->in_snd_device);
102 
103     list_remove(&uc_info->list);
104     free(uc_info);
105 
106     ALOGD("%s: exit: status(%d)", __func__, ret);
107     return ret;
108 }
109 
voice_start_usecase(struct audio_device * adev,audio_usecase_t usecase_id)110 int voice_start_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
111 {
112     int i, ret = 0;
113     struct audio_usecase *uc_info;
114     int pcm_dev_rx_id, pcm_dev_tx_id;
115     uint32_t sample_rate = 8000;
116     struct voice_session *session = NULL;
117     struct pcm_config voice_config = pcm_config_voice_call;
118 
119     ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
120 
121     session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
122     if (!session) {
123         ALOGE("start_call: couldn't find voice session");
124         return -EINVAL;
125     }
126 
127     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
128     if (!uc_info) {
129         ALOGE("start_call: couldn't allocate mem for audio_usecase");
130         return -ENOMEM;
131     }
132 
133     uc_info->id = usecase_id;
134     uc_info->type = VOICE_CALL;
135     uc_info->stream.out = adev->current_call_output ;
136     uc_info->devices = adev->current_call_output ->devices;
137     uc_info->in_snd_device = SND_DEVICE_NONE;
138     uc_info->out_snd_device = SND_DEVICE_NONE;
139 
140     list_add_tail(&adev->usecase_list, &uc_info->list);
141 
142     select_devices(adev, usecase_id);
143 
144     pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
145     pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
146 
147     if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) {
148         ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)",
149               __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
150         ret = -EIO;
151         goto error_start_voice;
152     }
153     ret = platform_get_sample_rate(adev->platform, &sample_rate);
154     if (ret < 0) {
155         ALOGE("platform_get_sample_rate error %d\n", ret);
156     } else {
157         voice_config.rate = sample_rate;
158     }
159     ALOGD("voice_config.rate %d\n", voice_config.rate);
160 
161     ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
162           __func__, adev->snd_card, pcm_dev_rx_id);
163     session->pcm_rx = pcm_open(adev->snd_card,
164                                pcm_dev_rx_id,
165                                PCM_OUT, &voice_config);
166     if (session->pcm_rx && !pcm_is_ready(session->pcm_rx)) {
167         ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_rx));
168         ret = -EIO;
169         goto error_start_voice;
170     }
171 
172     ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
173           __func__, adev->snd_card, pcm_dev_tx_id);
174     session->pcm_tx = pcm_open(adev->snd_card,
175                                pcm_dev_tx_id,
176                                PCM_IN, &voice_config);
177     if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
178         ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
179         ret = -EIO;
180         goto error_start_voice;
181     }
182     pcm_start(session->pcm_rx);
183     pcm_start(session->pcm_tx);
184 
185     voice_set_volume(adev, adev->voice.volume);
186 
187     ret = platform_start_voice_call(adev->platform, session->vsid);
188     if (ret < 0) {
189         ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret);
190         goto error_start_voice;
191     }
192 
193     session->state.current = CALL_ACTIVE;
194     goto done;
195 
196 error_start_voice:
197     voice_stop_usecase(adev, usecase_id);
198 
199 done:
200     ALOGD("%s: exit: status(%d)", __func__, ret);
201     return ret;
202 }
203 
voice_is_call_state_active(struct audio_device * adev)204 bool voice_is_call_state_active(struct audio_device *adev)
205 {
206     bool call_state = false;
207     int ret = 0;
208 
209     ret = voice_extn_is_call_state_active(adev, &call_state);
210     if (ret == -ENOSYS) {
211         call_state = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false;
212     }
213 
214     return call_state;
215 }
216 
voice_is_in_call(struct audio_device * adev)217 bool voice_is_in_call(struct audio_device *adev)
218 {
219     return adev->voice.in_call;
220 }
221 
voice_is_in_call_rec_stream(struct stream_in * in)222 bool voice_is_in_call_rec_stream(struct stream_in *in)
223 {
224     bool in_call_rec = false;
225     int ret = 0;
226 
227     ret = voice_extn_is_in_call_rec_stream(in, &in_call_rec);
228     if (ret == -ENOSYS) {
229         in_call_rec = false;
230     }
231 
232     return in_call_rec;
233 }
234 
voice_get_active_session_id(struct audio_device * adev)235 uint32_t voice_get_active_session_id(struct audio_device *adev)
236 {
237     int ret = 0;
238     uint32_t session_id;
239 
240     ret = voice_extn_get_active_session_id(adev, &session_id);
241     if (ret == -ENOSYS) {
242         session_id = VOICE_VSID;
243     }
244     return session_id;
245 }
246 
voice_check_and_set_incall_rec_usecase(struct audio_device * adev,struct stream_in * in)247 int voice_check_and_set_incall_rec_usecase(struct audio_device *adev,
248                                            struct stream_in *in)
249 {
250     int ret = 0;
251     uint32_t session_id;
252     int usecase_id;
253     int rec_mode = INCALL_REC_NONE;
254 
255     if (voice_is_call_state_active(adev)) {
256         switch (in->source) {
257         case AUDIO_SOURCE_VOICE_UPLINK:
258             if (audio_extn_compr_cap_enabled() &&
259                 audio_extn_compr_cap_format_supported(in->config.format)) {
260                 in->usecase = USECASE_INCALL_REC_UPLINK_COMPRESS;
261             } else
262                 in->usecase = USECASE_INCALL_REC_UPLINK;
263             rec_mode = INCALL_REC_UPLINK;
264             break;
265         case AUDIO_SOURCE_VOICE_DOWNLINK:
266             if (audio_extn_compr_cap_enabled() &&
267                 audio_extn_compr_cap_format_supported(in->config.format)) {
268                 in->usecase = USECASE_INCALL_REC_DOWNLINK_COMPRESS;
269             } else
270                 in->usecase = USECASE_INCALL_REC_DOWNLINK;
271             rec_mode = INCALL_REC_DOWNLINK;
272             break;
273         case AUDIO_SOURCE_VOICE_CALL:
274             if (audio_extn_compr_cap_enabled() &&
275                 audio_extn_compr_cap_format_supported(in->config.format)) {
276                 in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS;
277             } else
278                 in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK;
279             rec_mode = INCALL_REC_UPLINK_AND_DOWNLINK;
280             break;
281         default:
282             ALOGV("%s: Source type %d doesnt match incall recording criteria",
283                   __func__, in->source);
284             return ret;
285         }
286 
287         session_id = voice_get_active_session_id(adev);
288         ret = platform_set_incall_recording_session_id(adev->platform,
289                                                        session_id, rec_mode);
290         ALOGV("%s: Update usecase to %d",__func__, in->usecase);
291     } else {
292         ALOGV("%s: voice call not active", __func__);
293     }
294 
295     return ret;
296 }
297 
voice_check_and_stop_incall_rec_usecase(struct audio_device * adev,struct stream_in * in)298 int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev,
299                                             struct stream_in *in)
300 {
301     int ret = 0;
302 
303     if (in->source == AUDIO_SOURCE_VOICE_UPLINK ||
304         in->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
305         in->source == AUDIO_SOURCE_VOICE_CALL) {
306         ret = platform_stop_incall_recording_usecase(adev->platform);
307         ALOGV("%s: Stop In-call recording", __func__);
308     }
309 
310     return ret;
311 }
312 
voice_check_and_set_incall_music_usecase(struct audio_device * adev,struct stream_out * out)313 int voice_check_and_set_incall_music_usecase(struct audio_device *adev,
314                                              struct stream_out *out)
315 {
316     int ret = 0;
317 
318     ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
319     if (ret == -ENOSYS) {
320         /* Incall music delivery is used only for LCH call state */
321         ret = -EINVAL;
322     }
323 
324     return ret;
325 }
326 
voice_set_mic_mute(struct audio_device * adev,bool state)327 int voice_set_mic_mute(struct audio_device *adev, bool state)
328 {
329     int err = 0;
330 
331     adev->voice.mic_mute = state;
332     if (adev->mode == AUDIO_MODE_IN_CALL)
333         err = platform_set_mic_mute(adev->platform, state);
334     if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
335         err = voice_extn_compress_voip_set_mic_mute(adev, state);
336 
337     return err;
338 }
339 
voice_get_mic_mute(struct audio_device * adev)340 bool voice_get_mic_mute(struct audio_device *adev)
341 {
342     return adev->voice.mic_mute;
343 }
344 
voice_set_volume(struct audio_device * adev,float volume)345 int voice_set_volume(struct audio_device *adev, float volume)
346 {
347     int vol, err = 0;
348 
349     adev->voice.volume = volume;
350     if (adev->mode == AUDIO_MODE_IN_CALL) {
351         if (volume < 0.0) {
352             volume = 0.0;
353         } else if (volume > 1.0) {
354             volume = 1.0;
355         }
356 
357         vol = lrint(volume * 100.0);
358 
359         // Voice volume levels from android are mapped to driver volume levels as follows.
360         // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
361         // So adjust the volume to get the correct volume index in driver
362         vol = 100 - vol;
363 
364         err = platform_set_voice_volume(adev->platform, vol);
365     }
366     if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
367         err = voice_extn_compress_voip_set_volume(adev, volume);
368 
369 
370     return err;
371 }
372 
voice_start_call(struct audio_device * adev)373 int voice_start_call(struct audio_device *adev)
374 {
375     int ret = 0;
376 
377     ret = voice_extn_start_call(adev);
378     if (ret == -ENOSYS) {
379         ret = voice_start_usecase(adev, USECASE_VOICE_CALL);
380     }
381     adev->voice.in_call = true;
382 
383     return ret;
384 }
385 
voice_stop_call(struct audio_device * adev)386 int voice_stop_call(struct audio_device *adev)
387 {
388     int ret = 0;
389 
390     adev->voice.in_call = false;
391     ret = voice_extn_stop_call(adev);
392     if (ret == -ENOSYS) {
393         ret = voice_stop_usecase(adev, USECASE_VOICE_CALL);
394     }
395 
396     return ret;
397 }
398 
voice_get_parameters(struct audio_device * adev,struct str_parms * query,struct str_parms * reply)399 void voice_get_parameters(struct audio_device *adev,
400                           struct str_parms *query,
401                           struct str_parms *reply)
402 {
403     voice_extn_get_parameters(adev, query, reply);
404 }
405 
voice_set_parameters(struct audio_device * adev,struct str_parms * parms)406 int voice_set_parameters(struct audio_device *adev, struct str_parms *parms)
407 {
408     char *str;
409     char value[32];
410     int val;
411     int ret = 0, err;
412     char *kv_pairs = str_parms_to_str(parms);
413 
414     ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
415 
416     ret = voice_extn_set_parameters(adev, parms);
417     if (ret != 0) {
418         if (ret == -ENOSYS)
419             ret = 0;
420         else
421             goto done;
422     }
423 
424     ret = voice_extn_compress_voip_set_parameters(adev, parms);
425     if (ret != 0) {
426         if (ret == -ENOSYS)
427             ret = 0;
428         else
429             goto done;
430     }
431 
432     err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value));
433     if (err >= 0) {
434         int tty_mode;
435         str_parms_del(parms, AUDIO_PARAMETER_KEY_TTY_MODE);
436         if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0)
437             tty_mode = TTY_MODE_OFF;
438         else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_VCO) == 0)
439             tty_mode = TTY_MODE_VCO;
440         else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_HCO) == 0)
441             tty_mode = TTY_MODE_HCO;
442         else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_FULL) == 0)
443             tty_mode = TTY_MODE_FULL;
444         else {
445             ret = -EINVAL;
446             goto done;
447         }
448 
449         if (tty_mode != adev->voice.tty_mode) {
450             adev->voice.tty_mode = tty_mode;
451             adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode;
452             if (voice_is_call_state_active(adev))
453                voice_update_devices_for_all_voice_usecases(adev);
454         }
455     }
456 
457     err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC,
458                             value, sizeof(value));
459     if (err >= 0) {
460         str_parms_del(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC);
461         if (strcmp(value, AUDIO_PARAMETER_VALUE_TRUE) == 0)
462             platform_start_incall_music_usecase(adev->platform);
463         else
464             platform_stop_incall_music_usecase(adev->platform);
465     }
466 
467 done:
468     ALOGV("%s: exit with code(%d)", __func__, ret);
469     free(kv_pairs);
470     return ret;
471 }
472 
voice_init(struct audio_device * adev)473 void voice_init(struct audio_device *adev)
474 {
475     int i = 0;
476 
477     memset(&adev->voice, 0, sizeof(adev->voice));
478     adev->voice.tty_mode = TTY_MODE_OFF;
479     adev->voice.volume = 1.0f;
480     adev->voice.mic_mute = false;
481     adev->voice.in_call = false;
482     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
483         adev->voice.session[i].pcm_rx = NULL;
484         adev->voice.session[i].pcm_tx = NULL;
485         adev->voice.session[i].state.current = CALL_INACTIVE;
486         adev->voice.session[i].state.new = CALL_INACTIVE;
487         adev->voice.session[i].vsid = VOICE_VSID;
488     }
489 
490     voice_extn_init(adev);
491 }
492 
voice_update_devices_for_all_voice_usecases(struct audio_device * adev)493 void voice_update_devices_for_all_voice_usecases(struct audio_device *adev)
494 {
495     struct listnode *node;
496     struct audio_usecase *usecase;
497 
498     list_for_each(node, &adev->usecase_list) {
499         usecase = node_to_item(node, struct audio_usecase, list);
500         if (usecase->type == VOICE_CALL) {
501             ALOGV("%s: updating device for usecase:%s", __func__,
502                   use_case_table[usecase->id]);
503             usecase->stream.out = adev->current_call_output;
504             select_devices(adev, usecase->id);
505         }
506     }
507 }
508 
509 
510