blob: 18bb59c842b8256953a61f46380a3ee1bdca79a9 [file] [log] [blame]
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07001/*
2 * Copyright (c) 2013, 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
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -070020#define LOG_TAG "voice_extn"
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -080021#define LOG_NDEBUG 0
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -070022#define LOG_NDDEBUG 0
23
24#include <errno.h>
25#include <math.h>
26#include <cutils/log.h>
27#include <cutils/str_parms.h>
28#include <sys/ioctl.h>
29#include <sound/voice_params.h>
30
31#include "audio_hw.h"
32#include "voice.h"
33#include "platform.h"
34#include "platform_api.h"
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080035#include "voice_extn.h"
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -070036
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -080037#define AUDIO_PARAMETER_KEY_VSID "vsid"
38#define AUDIO_PARAMETER_KEY_CALL_STATE "call_state"
39#define AUDIO_PARAMETER_KEY_AUDIO_MODE "audio_mode"
40#define AUDIO_PARAMETER_KEY_ALL_CALL_STATES "all_call_states"
41
42#define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -070043
44#define VOICE2_VSID 0x10DC1000
45#define VOLTE_VSID 0x10C02000
46#define QCHAT_VSID 0x10803000
47#define ALL_VSID 0xFFFFFFFF
48
49/* Voice Session Indices */
50#define VOICE2_SESS_IDX (VOICE_SESS_IDX + 1)
51#define VOLTE_SESS_IDX (VOICE_SESS_IDX + 2)
52#define QCHAT_SESS_IDX (VOICE_SESS_IDX + 3)
53
54/* Call States */
55#define CALL_HOLD (BASE_CALL_STATE + 2)
56#define CALL_LOCAL_HOLD (BASE_CALL_STATE + 3)
57
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -070058struct pcm_config pcm_config_incall_music = {
59 .channels = 1,
60 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
61 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
62 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
63 .format = PCM_FORMAT_S16_LE,
64 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
65 .stop_threshold = INT_MAX,
66 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
67};
68
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -070069extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id);
70extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -080071int voice_extn_is_in_call(struct audio_device *adev, bool *in_call);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -070072
73static bool is_valid_call_state(int call_state)
74{
75 if (call_state < CALL_INACTIVE || call_state > CALL_LOCAL_HOLD)
76 return false;
77 else
78 return true;
79}
80
81static bool is_valid_vsid(uint32_t vsid)
82{
83 if (vsid == VOICE_VSID ||
84 vsid == VOICE2_VSID ||
85 vsid == VOLTE_VSID ||
86 vsid == QCHAT_VSID)
87 return true;
88 else
89 return false;
90}
91
92static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index)
93{
94 audio_usecase_t usecase_id = -1;
95
96 switch(index) {
97 case VOICE_SESS_IDX:
98 usecase_id = USECASE_VOICE_CALL;
99 break;
100
101 case VOICE2_SESS_IDX:
102 usecase_id = USECASE_VOICE2_CALL;
103 break;
104
105 case VOLTE_SESS_IDX:
106 usecase_id = USECASE_VOLTE_CALL;
107 break;
108
109 case QCHAT_SESS_IDX:
110 usecase_id = USECASE_QCHAT_CALL;
111 break;
112
113 default:
114 ALOGE("%s: Invalid voice session index\n", __func__);
115 }
116
117 return usecase_id;
118}
119
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700120static uint32_t get_session_id_with_state(struct audio_device *adev,
121 int call_state)
Shiv Maliyappanahallida107642013-10-17 11:16:13 -0700122{
123 struct voice_session *session = NULL;
124 int i = 0;
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700125 uint32_t session_id = 0;
Shiv Maliyappanahallida107642013-10-17 11:16:13 -0700126
127 for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
128 session = &adev->voice.session[i];
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700129 if(session->state.current == call_state){
130 session_id = session->vsid;
Shiv Maliyappanahallida107642013-10-17 11:16:13 -0700131 break;
132 }
133 }
134
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700135 return session_id;
136}
137
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -0800138static int update_calls(struct audio_device *adev)
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700139{
140 int i = 0;
141 audio_usecase_t usecase_id = 0;
142 enum voice_lch_mode lch_mode;
143 struct voice_session *session = NULL;
144 int fd = 0;
145 int ret = 0;
146
147 ALOGD("%s: enter:", __func__);
148
149 for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
150 usecase_id = voice_extn_get_usecase_for_session_idx(i);
151 session = &adev->voice.session[i];
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700152 ALOGD("%s: cur_state=%d new_state=%d vsid=%x",
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700153 __func__, session->state.current, session->state.new, session->vsid);
154
155 switch(session->state.new)
156 {
157 case CALL_ACTIVE:
158 switch(session->state.current)
159 {
160 case CALL_INACTIVE:
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700161 ALOGD("%s: INACTIVE -> ACTIVE vsid:%x", __func__, session->vsid);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700162 ret = start_call(adev, usecase_id);
163 if(ret < 0) {
164 ALOGE("%s: voice_start_call() failed for usecase: %d\n",
165 __func__, usecase_id);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -0800166 } else {
167 session->state.current = session->state.new;
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700168 }
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700169 break;
170
171 case CALL_HOLD:
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700172 ALOGD("%s: HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700173 session->state.current = session->state.new;
174 break;
175
176 case CALL_LOCAL_HOLD:
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700177 ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700178 lch_mode = VOICE_LCH_STOP;
179 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700180 ALOGE("LOCAL_HOLD -> ACTIVE failed");
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700181 } else {
182 session->state.current = session->state.new;
183 }
184 break;
185
186 default:
187 ALOGV("%s: CALL_ACTIVE cannot be handled in state=%d vsid:%x",
188 __func__, session->state.current, session->vsid);
189 break;
190 }
191 break;
192
193 case CALL_INACTIVE:
194 switch(session->state.current)
195 {
196 case CALL_ACTIVE:
197 case CALL_HOLD:
198 case CALL_LOCAL_HOLD:
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700199 ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD -> INACTIVE vsid:%x", __func__, session->vsid);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700200 ret = stop_call(adev, usecase_id);
201 if(ret < 0) {
202 ALOGE("%s: voice_end_call() failed for usecase: %d\n",
203 __func__, usecase_id);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -0800204 } else {
205 session->state.current = session->state.new;
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700206 }
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700207 break;
208
209 default:
210 ALOGV("%s: CALL_INACTIVE cannot be handled in state=%d vsid:%x",
211 __func__, session->state.current, session->vsid);
212 break;
213 }
214 break;
215
216 case CALL_HOLD:
217 switch(session->state.current)
218 {
219 case CALL_ACTIVE:
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700220 ALOGD("%s: CALL_ACTIVE -> HOLD vsid:%x", __func__, session->vsid);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700221 session->state.current = session->state.new;
222 break;
223
224 case CALL_LOCAL_HOLD:
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700225 ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700226 lch_mode = VOICE_LCH_STOP;
227 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700228 ALOGE("LOCAL_HOLD -> HOLD failed");
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700229 } else {
230 session->state.current = session->state.new;
231 }
232 break;
233
234 default:
235 ALOGV("%s: CALL_HOLD cannot be handled in state=%d vsid:%x",
236 __func__, session->state.current, session->vsid);
237 break;
238 }
239 break;
240
241 case CALL_LOCAL_HOLD:
242 switch(session->state.current)
243 {
244 case CALL_ACTIVE:
245 case CALL_HOLD:
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700246 ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__,
247 session->vsid);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700248 lch_mode = VOICE_LCH_START;
249 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700250 ALOGE("LOCAL_HOLD -> HOLD failed");
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700251 } else {
252 session->state.current = session->state.new;
253 }
254 break;
255
256 default:
257 ALOGV("%s: CALL_LOCAL_HOLD cannot be handled in state=%d vsid:%x",
258 __func__, session->state.current, session->vsid);
259 break;
260 }
261 break;
262
263 default:
264 break;
265 } //end out switch loop
266 } //end for loop
267
268 return ret;
269}
270
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -0800271static int update_call_states(struct audio_device *adev,
272 const uint32_t vsid, const int call_state)
273{
274 struct voice_session *session = NULL;
275 int i = 0;
276 bool is_in_call;
277
278 for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
279 if (vsid == adev->voice.session[i].vsid) {
280 session = &adev->voice.session[i];
281 break;
282 }
283 }
284
285 if (session) {
286 session->state.new = call_state;
287 voice_extn_is_in_call(adev, &is_in_call);
288 ALOGD("%s is_in_call:%d mode:%d\n", __func__, is_in_call, adev->mode);
Shiv Maliyappanahalli7a2545c2013-11-08 18:26:33 -0800289 /* Dont start voice call before device routing for voice usescases has
290 * occured, otherwise voice calls will be started unintendedly on
291 * speaker.
292 */
293 if (is_in_call ||
294 (adev->mode == AUDIO_MODE_IN_CALL &&
295 adev->primary_output->devices != AUDIO_DEVICE_OUT_SPEAKER)) {
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -0800296 /* Device routing is not triggered for voice calls on the subsequent
297 * subs, Hence update the call states if voice call is already
298 * active on other sub.
299 */
300 update_calls(adev);
301 }
302 } else {
303 return -EINVAL;
304 }
305
306 return 0;
307
308}
309
310int voice_extn_get_active_session_id(struct audio_device *adev,
311 uint32_t *session_id)
312{
313 *session_id = get_session_id_with_state(adev, CALL_ACTIVE);
314 return 0;
315}
316
317int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
318{
319 struct voice_session *session = NULL;
320 int i = 0;
321 *in_call = false;
322
323 for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
324 session = &adev->voice.session[i];
325 if(session->state.current != CALL_INACTIVE){
326 *in_call = true;
327 break;
328 }
329 }
330
331 return 0;
332}
333
334void voice_extn_init(struct audio_device *adev)
335{
336 adev->voice.session[VOICE_SESS_IDX].vsid = VOICE_VSID;
337 adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID;
338 adev->voice.session[VOLTE_SESS_IDX].vsid = VOLTE_VSID;
339 adev->voice.session[QCHAT_SESS_IDX].vsid = QCHAT_VSID;
340}
341
342int voice_extn_get_session_from_use_case(struct audio_device *adev,
343 const audio_usecase_t usecase_id,
344 struct voice_session **session)
345{
346
347 switch(usecase_id)
348 {
349 case USECASE_VOICE_CALL:
350 *session = &adev->voice.session[VOICE_SESS_IDX];
351 break;
352
353 case USECASE_VOICE2_CALL:
354 *session = &adev->voice.session[VOICE2_SESS_IDX];
355 break;
356
357 case USECASE_VOLTE_CALL:
358 *session = &adev->voice.session[VOLTE_SESS_IDX];
359 break;
360
361 case USECASE_QCHAT_CALL:
362 *session = &adev->voice.session[QCHAT_SESS_IDX];
363 break;
364
365 default:
366 ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id);
367 *session = NULL;
368 return -EINVAL;
369 }
370
371 return 0;
372}
373
374int voice_extn_start_call(struct audio_device *adev)
375{
376 /* Start voice calls on sessions whose call state has been
377 * udpated.
378 */
379 ALOGV("%s: enter:", __func__);
380 return update_calls(adev);
381}
382
383int voice_extn_stop_call(struct audio_device *adev)
384{
385 int i;
386 int ret = 0;
387
388 ALOGV("%s: enter:", __func__);
389
390 /* If BT device is enabled and voice calls are ended, telephony will call
391 * set_mode(AUDIO_MODE_NORMAL) which will trigger audio policy manager to
392 * set routing with device BT A2DP profile. Hence end all voice calls when
393 * set_mode(AUDIO_MODE_NORMAL) before BT A2DP profile is selected.
394 */
395 if (adev->mode == AUDIO_MODE_NORMAL) {
396 ALOGD("%s: end all calls", __func__);
397 for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
398 adev->voice.session[i].state.new = CALL_INACTIVE;
399 }
400
401 ret = update_calls(adev);
402 }
403
404 return ret;
405}
406
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700407int voice_extn_set_parameters(struct audio_device *adev,
408 struct str_parms *parms)
409{
410 char *str;
411 int value;
412 int ret = 0;
413
414 ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms));
415
416 ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value);
417 if (ret >= 0) {
418 str_parms_del(parms, AUDIO_PARAMETER_KEY_VSID);
419 int vsid = value;
420 int call_state = -1;
421 ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value);
422 if (ret >= 0) {
423 call_state = value;
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700424 } else {
425 ALOGE("%s: call_state key not found", __func__);
426 ret = -EINVAL;
427 goto done;
428 }
429
430 if (is_valid_vsid(vsid) && is_valid_call_state(call_state)) {
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -0800431 ret = update_call_states(adev, vsid, call_state);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700432 } else {
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -0800433 ALOGE("%s: invalid vsid:%x or call_state:%d",
434 __func__, vsid, call_state);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700435 ret = -EINVAL;
436 goto done;
437 }
438 } else {
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -0800439 ALOGV("%s: Not handled here", __func__);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700440 }
441
442done:
443 ALOGV("%s: exit with code(%d)", __func__, ret);
444 return ret;
445}
446
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -0800447int get_all_call_states_str(const struct audio_device *adev,
448 char *value)
449{
450 int ret = 0;
451 char *cur_ptr = value;
452 int i, len=0;
453
454 for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
455 snprintf(cur_ptr, VOICE_EXTN_PARAMETER_VALUE_MAX_LEN - len,
456 "%d:%d,",adev->voice.session[i].vsid,
457 adev->voice.session[i].state.current);
458 len = strlen(cur_ptr);
459 cur_ptr = cur_ptr + len;
460 }
461 ALOGV("%s:value=%s", __func__, value);
462 return ret;
463}
464
Narsinga Rao Chella1eceff82013-12-02 19:25:28 -0800465void voice_extn_get_parameters(const struct audio_device *adev,
466 struct str_parms *query,
467 struct str_parms *reply)
468{
469 int ret;
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -0800470 char value[VOICE_EXTN_PARAMETER_VALUE_MAX_LEN] = {0};
Narsinga Rao Chella1eceff82013-12-02 19:25:28 -0800471 char *str = NULL;
472
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -0800473 ALOGV("%s: enter %s", __func__, str_parms_to_str(query));
474
475 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUDIO_MODE, value,
Narsinga Rao Chella1eceff82013-12-02 19:25:28 -0800476 sizeof(value));
477 if (ret >= 0) {
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -0800478 str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUDIO_MODE, adev->mode);
Narsinga Rao Chella1eceff82013-12-02 19:25:28 -0800479 }
480
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -0800481 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ALL_CALL_STATES,
482 value, sizeof(value));
483 if (ret >= 0) {
484 ret = get_all_call_states_str(adev, value);
485 if (ret) {
486 ALOGE("%s: Error fetching call states, err:%d", __func__, ret);
487 return;
488 }
489 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_ALL_CALL_STATES, value);
490 }
491 ALOGV("%s: exit: returns \"%s\"", __func__, str_parms_to_str(reply));
Narsinga Rao Chella1eceff82013-12-02 19:25:28 -0800492}
493
Narsinga Rao Chella05573b72013-11-15 15:21:40 -0800494void voice_extn_out_get_parameters(struct stream_out *out,
495 struct str_parms *query,
496 struct str_parms *reply)
497{
498 voice_extn_compress_voip_out_get_parameters(out, query, reply);
499}
500
501void voice_extn_in_get_parameters(struct stream_in *in,
502 struct str_parms *query,
503 struct str_parms *reply)
504{
505 voice_extn_compress_voip_in_get_parameters(in, query, reply);
506}
507
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700508int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
509 struct stream_out *out)
510{
511 uint32_t session_id = 0;
512
513 session_id = get_session_id_with_state(adev, CALL_LOCAL_HOLD);
514 if (session_id == VOICE_VSID) {
515 out->usecase = USECASE_INCALL_MUSIC_UPLINK;
516 } else if (session_id == VOICE2_VSID) {
517 out->usecase = USECASE_INCALL_MUSIC_UPLINK2;
518 } else {
519 ALOGE("%s: Invalid session id %x", __func__, session_id);
520 return -EINVAL;
521 }
522
523 out->config = pcm_config_incall_music;
524 out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO;
525 out->channel_mask = AUDIO_CHANNEL_OUT_MONO;
526
527 return 0;
528}
529