Fix SVACE defects (DEREF_OF_NULL.RET.ALLOC)
[platform/adaptation/spreadtrum/audio-hal-sc7727.git] / tizen-audio-routing.c
1 /*
2  * audio-hal
3  *
4  * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdbool.h>
28
29 #include "tizen-audio-internal.h"
30 #include "tizen-audio-impl.h"
31
32 /* #define DEBUG_TIMING */
33
34 static device_type_t outDeviceTypes[] = {
35     { AUDIO_DEVICE_OUT_SPEAKER, "Speaker" },
36     { AUDIO_DEVICE_OUT_RECEIVER, "Earpiece" },
37     { AUDIO_DEVICE_OUT_JACK, "Headphones" },
38     { AUDIO_DEVICE_OUT_BT_SCO, "Bluetooth" },
39     { 0, 0 },
40 };
41
42 static device_type_t inDeviceTypes[] = {
43     { AUDIO_DEVICE_IN_MAIN_MIC, "MainMic" },
44     { AUDIO_DEVICE_IN_SUB_MIC, "SubMic" },
45     { AUDIO_DEVICE_IN_JACK, "HeadsetMic" },
46     { AUDIO_DEVICE_IN_BT_SCO, "BT Mic" },
47     { 0, 0 },
48 };
49
50 static const char* mode_to_verb_str[] = {
51     AUDIO_USE_CASE_VERB_HIFI,
52     AUDIO_USE_CASE_VERB_VOICECALL,
53     AUDIO_USE_CASE_VERB_VIDEOCALL,
54     AUDIO_USE_CASE_VERB_VOIP,
55     AUDIO_USE_CASE_VERB_FMRADIO,
56 };
57
58 static uint32_t __convert_device_string_to_enum(const char* device_str, uint32_t direction)
59 {
60     uint32_t device = 0;
61
62     if (!strncmp(device_str, "builtin-speaker", MAX_NAME_LEN)) {
63         device = AUDIO_DEVICE_OUT_SPEAKER;
64     } else if (!strncmp(device_str, "builtin-receiver", MAX_NAME_LEN)) {
65         device = AUDIO_DEVICE_OUT_RECEIVER;
66     } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
67         device = AUDIO_DEVICE_OUT_JACK;
68     } else if ((!strncmp(device_str, "bt-sco", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
69         device = AUDIO_DEVICE_OUT_BT_SCO;
70     } else if ((!strncmp(device_str, "builtin-mic", MAX_NAME_LEN))) {
71         device = AUDIO_DEVICE_IN_MAIN_MIC;
72     /* To Do : SUB_MIC */
73     } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
74         device = AUDIO_DEVICE_IN_JACK;
75     } else if ((!strncmp(device_str, "bt-sco", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
76         device = AUDIO_DEVICE_IN_BT_SCO;
77     } else {
78         device = AUDIO_DEVICE_NONE;
79     }
80     AUDIO_LOG_INFO("device type(%s), enum(0x%x)", device_str, device);
81     return device;
82 }
83
84 static void __reset_voice_devices_info(audio_hal_t *ah)
85 {
86     AUDIO_RETURN_IF_FAIL(ah);
87
88     AUDIO_LOG_INFO("reset voice device info");
89     if (ah->device.init_call_devices) {
90         free(ah->device.init_call_devices);
91         ah->device.init_call_devices = NULL;
92         ah->device.num_of_call_devices = 0;
93     }
94
95     return;
96 }
97
98 static audio_return_t __set_devices(audio_hal_t *ah, const char *verb, device_info_t *devices, uint32_t num_of_devices)
99 {
100     audio_return_t audio_ret = AUDIO_RET_OK;
101     uint32_t new_device = 0;
102     const char *active_devices[MAX_DEVICES] = {NULL,};
103     int i = 0, j = 0, dev_idx = 0;
104
105     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
106     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
107     AUDIO_RETURN_VAL_IF_FAIL(num_of_devices, AUDIO_ERR_PARAMETER);
108
109     if (num_of_devices > MAX_DEVICES) {
110         num_of_devices = MAX_DEVICES;
111         AUDIO_LOG_ERROR("error: num_of_devices");
112         return AUDIO_ERR_PARAMETER;
113     }
114
115     if (devices[0].direction == AUDIO_DIRECTION_OUT) {
116         ah->device.active_out &= 0x0;
117         if (ah->device.active_in) {
118             /* check the active in devices */
119             for (j = 0; j < inDeviceTypes[j].type; j++) {
120                 if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[j].type))
121                     active_devices[dev_idx++] = inDeviceTypes[j].name;
122             }
123         }
124     } else if (devices[0].direction == AUDIO_DIRECTION_IN) {
125         ah->device.active_in &= 0x0;
126         if (ah->device.active_out) {
127             /* check the active out devices */
128             for (j = 0; j < outDeviceTypes[j].type; j++) {
129                 if (ah->device.active_out & outDeviceTypes[j].type)
130                     active_devices[dev_idx++] = outDeviceTypes[j].name;
131             }
132         }
133     }
134
135     for (i = 0; i < num_of_devices; i++) {
136         new_device = __convert_device_string_to_enum(devices[i].type, devices[i].direction);
137         if (new_device & AUDIO_DEVICE_IN) {
138             for (j = 0; j < inDeviceTypes[j].type; j++) {
139                 if (new_device == inDeviceTypes[j].type) {
140                     active_devices[dev_idx++] = inDeviceTypes[j].name;
141                     ah->device.active_in |= new_device;
142                 }
143             }
144         } else {
145             for (j = 0; j < outDeviceTypes[j].type; j++) {
146                 if (new_device == outDeviceTypes[j].type) {
147                     active_devices[dev_idx++] = outDeviceTypes[j].name;
148                     ah->device.active_out |= new_device;
149                 }
150             }
151         }
152     }
153
154     if (active_devices[0] == NULL) {
155         AUDIO_LOG_ERROR("Failed to set device: active device is NULL");
156         return AUDIO_ERR_PARAMETER;
157     }
158
159     audio_ret = _ucm_set_devices(ah, verb, active_devices);
160     if (audio_ret)
161         AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
162
163     return audio_ret;
164 }
165
166 static audio_return_t __connect_fm_radio(audio_hal_t *ah)
167 {
168     audio_return_t audio_ret = AUDIO_RET_OK;
169
170     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
171
172     audio_ret = _mixer_control_set_value(ah,
173                     PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_VBC_ID);
174     return audio_ret;
175 }
176
177 static audio_return_t __update_route_ap_playback_capture(audio_hal_t *ah, audio_route_info_t *route_info)
178 {
179     audio_return_t audio_ret = AUDIO_RET_OK;
180     device_info_t *devices = NULL;
181     const char *verb = mode_to_verb_str[VERB_NORMAL];
182
183     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
184     AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
185
186     if (ah->modem.is_connected) {
187         AUDIO_LOG_WARN("modem is connected, skip verb[%s]", verb);
188         return audio_ret;
189     }
190
191     if (ah->device.mode != VERB_NORMAL) {
192         if (ah->device.mode == VERB_RADIO) {
193             if (ah->device.is_radio_on && !ah->modem.is_connected) {
194                 /* Skip setting NORMAL VERB and keep going with RADIO VERB */
195                 AUDIO_LOG_WARN("radio is in progress, skip verb[%s]", verb);
196                 verb = mode_to_verb_str[VERB_RADIO];
197             } else if (!ah->device.is_radio_on) {
198                 if ((audio_ret = _fmradio_pcm_close(ah)))
199                     AUDIO_LOG_ERROR("failed to _fmradio_pcm_close(), ret(0x%x)", audio_ret);
200             }
201         } else {
202             if (ah->device.mode == VERB_VOICECALL) {
203                 __reset_voice_devices_info(ah);
204                 COND_SIGNAL(ah->device.device_cond, "device_cond");
205             }
206             _reset_pcm_devices(ah);
207             ah->device.mode = VERB_NORMAL;
208         }
209     }
210
211     devices = route_info->device_infos;
212
213     AUDIO_LOG_INFO("update_route_ap_playback_capture++ ");
214
215     audio_ret = __set_devices(ah, verb, devices, route_info->num_of_devices);
216     if (audio_ret) {
217         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
218         return audio_ret;
219     }
220
221     return audio_ret;
222 }
223
224 static audio_return_t __update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
225 {
226     audio_return_t audio_ret = AUDIO_RET_OK;
227     const char *verb = mode_to_verb_str[VERB_VOICECALL];
228
229     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
230     /* if both params are 0, return error for invalid state,
231          * this error would be used to tizen-audio-modem.c */
232     AUDIO_RETURN_VAL_IF_FAIL((devices||num_of_devices), AUDIO_ERR_INVALID_STATE);
233     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
234
235     AUDIO_LOG_INFO("update_route_voicecall++");
236
237     audio_ret = __set_devices(ah, verb, devices, num_of_devices);
238     if (audio_ret) {
239         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
240         return audio_ret;
241     }
242
243     if (ah->device.mode != VERB_VOICECALL) {
244         _voice_pcm_open(ah);
245         ah->device.mode = VERB_VOICECALL;
246         /* FIXME. Get network info and configure rate in pcm device */
247     }
248
249     return audio_ret;
250 }
251
252 static audio_return_t __update_route_voip(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
253 {
254     audio_return_t audio_ret = AUDIO_RET_OK;
255     const char *verb = mode_to_verb_str[VERB_NORMAL];
256
257     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
258     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
259
260     AUDIO_LOG_INFO("update_route_voip++");
261
262     audio_ret = __set_devices(ah, verb, devices, num_of_devices);
263     if (audio_ret) {
264         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
265         return audio_ret;
266     }
267     /* FIXME. If necessary, set VERB_VOIP */
268     ah->device.mode = VERB_NORMAL;
269
270     /* TO DO: Set modifiers */
271     return audio_ret;
272 }
273
274 static audio_return_t __update_route_fmradio(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
275 {
276     audio_return_t audio_ret = AUDIO_RET_OK;
277     const char *verb = mode_to_verb_str[VERB_RADIO];
278
279     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
280     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
281
282     AUDIO_LOG_INFO("update_route_fmradio++");
283
284     if (!ah->device.fmradio_pcm_out) {
285         if ((audio_ret = _fmradio_pcm_open(ah))) {
286             AUDIO_LOG_ERROR("Failed to _fmradio_pcm_open(): error = 0x%x", audio_ret);
287             return audio_ret;
288         }
289     }
290
291     audio_ret = __set_devices(ah, verb, devices, num_of_devices);
292     if (audio_ret) {
293         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
294         return audio_ret;
295     }
296     /* FIXME. If necessary, set VERB_VOIP */
297     ah->device.mode = VERB_RADIO;
298
299     if ((audio_ret = __connect_fm_radio(ah)))
300         AUDIO_LOG_ERROR("failed to __connect_fm_radio(), ret(0x%x)", audio_ret);
301
302     /* TO DO: Set modifiers */
303     return audio_ret;
304 }
305
306 static audio_return_t __update_route_reset(audio_hal_t *ah, uint32_t direction)
307 {
308     audio_return_t audio_ret = AUDIO_RET_OK;
309     const char *active_devices[MAX_DEVICES] = {NULL,};
310     int i = 0, dev_idx = 0;
311
312     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
313
314     AUDIO_LOG_INFO("update_route_reset++, direction(0x%x)", direction);
315
316     if (direction == AUDIO_DIRECTION_OUT) {
317         ah->device.active_out &= 0x0;
318         if (ah->device.active_in) {
319             /* check the active in devices */
320             for (i = 0; i < inDeviceTypes[i].type; i++) {
321                 if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[i].type)) {
322                     active_devices[dev_idx++] = inDeviceTypes[i].name;
323                     AUDIO_LOG_INFO("added for in : %s", inDeviceTypes[i].name);
324                 }
325             }
326         }
327     } else {
328         ah->device.active_in &= 0x0;
329         if (ah->device.active_out) {
330             /* check the active out devices */
331             for (i = 0; i < outDeviceTypes[i].type; i++) {
332                 if (ah->device.active_out & outDeviceTypes[i].type) {
333                     active_devices[dev_idx++] = outDeviceTypes[i].name;
334                     AUDIO_LOG_INFO("added for out : %s", outDeviceTypes[i].name);
335                 }
336             }
337         }
338     }
339     if (ah->device.mode == VERB_VOICECALL) {
340         if ((audio_ret = _voice_pcm_close(ah, direction)))
341             AUDIO_LOG_ERROR("failed to _voice_pcm_close(), ret(0x%x)", audio_ret);
342         if (!ah->device.active_in && !ah->device.active_out)
343             ah->device.mode = VERB_NORMAL;
344         __reset_voice_devices_info(ah);
345         COND_SIGNAL(ah->device.device_cond, "device_cond");
346     } else if (ah->device.mode == VERB_RADIO) {
347         if ((audio_ret = _fmradio_pcm_close(ah)))
348             AUDIO_LOG_ERROR("failed to _fmradio_pcm_close(), ret(0x%x)", audio_ret);
349         ah->device.mode = VERB_NORMAL;
350     }
351
352     if (active_devices[0] == NULL) {
353         AUDIO_LOG_DEBUG("active device is NULL, no need to update.");
354         return AUDIO_RET_OK;
355     }
356
357     if ((audio_ret = _ucm_set_devices(ah, mode_to_verb_str[ah->device.mode], active_devices)))
358         AUDIO_LOG_ERROR("failed to _ucm_set_devices(), ret(0x%x)", audio_ret);
359
360     return audio_ret;
361 }
362
363 audio_return_t _audio_update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
364 {
365     return __update_route_voicecall(ah, devices, num_of_devices);
366 }
367
368 audio_return_t _audio_routing_init(audio_hal_t *ah)
369 {
370     audio_return_t audio_ret = AUDIO_RET_OK;
371
372     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
373
374     ah->device.active_in = 0x0;
375     ah->device.active_out = 0x0;
376     ah->device.mode = VERB_NORMAL;
377     ah->device.is_radio_on = 0;
378     ah->device.init_call_devices = NULL;
379     ah->device.num_of_call_devices = 0;
380
381     if ((audio_ret = _ucm_init(ah)))
382         AUDIO_LOG_ERROR("failed to _ucm_init(), ret(0x%x)", audio_ret);
383
384     return audio_ret;
385 }
386
387 audio_return_t _audio_routing_deinit(audio_hal_t *ah)
388 {
389     audio_return_t audio_ret = AUDIO_RET_OK;
390
391     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
392
393     if ((audio_ret = _ucm_deinit(ah)))
394         AUDIO_LOG_ERROR("failed to _ucm_deinit(), ret(0x%x)", audio_ret);
395
396     return audio_ret;
397 }
398
399 audio_return_t audio_update_route(void *audio_handle, audio_route_info_t *info)
400 {
401     audio_return_t audio_ret = AUDIO_RET_OK;
402     audio_hal_t *ah = (audio_hal_t *)audio_handle;
403     device_info_t *devices = NULL;
404     uint32_t prev_size;
405     int32_t i;
406     int32_t j;
407
408     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
409     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
410     AUDIO_RETURN_VAL_IF_FAIL(info->role, AUDIO_ERR_PARAMETER);
411
412     AUDIO_LOG_INFO("role:%s", info->role);
413
414     devices = info->device_infos;
415
416     if (!strncmp("call-voice", info->role, MAX_NAME_LEN)) {
417         if (!ah->modem.is_connected) {
418             if (info->num_of_devices) {
419                 if (!ah->device.num_of_call_devices) {
420                     if ((ah->device.init_call_devices = (device_info_t*)calloc(info->num_of_devices, sizeof(device_info_t)))) {
421                         memcpy(ah->device.init_call_devices, devices, info->num_of_devices*sizeof(device_info_t));
422                         ah->device.num_of_call_devices = info->num_of_devices;
423                     } else {
424                         AUDIO_LOG_ERROR("failed to calloc");
425                         audio_ret = AUDIO_ERR_RESOURCE;
426                         goto ERROR;
427                     }
428                 } else if (ah->device.num_of_call_devices) {
429                     prev_size = ah->device.num_of_call_devices;
430                     if (prev_size == 2) {
431                         /* There's a chance to be requested to change routing from user
432                          * though two devices(for input/output) has already been set for call-voice routing.
433                          * In this case, exchange an old device for a new device if it's direction is same as an old one's. */
434                         for (i = 0; i < prev_size; i++) {
435                             for (j = 0; j < info->num_of_devices; j++) {
436                                 if (devices[j].direction == ah->device.init_call_devices[i].direction &&
437                                     devices[j].id != ah->device.init_call_devices[i].id)
438                                     memcpy(&ah->device.init_call_devices[i], &devices[j], sizeof(device_info_t));
439                             }
440                         }
441                     } else if (prev_size < 2) {
442                         /* A device has already been added for call-voice routing,
443                          * and now it is about to add a new device(input or output device). */
444                         ah->device.num_of_call_devices += info->num_of_devices;
445                         if ((ah->device.init_call_devices = (device_info_t*)realloc(ah->device.init_call_devices, sizeof(device_info_t)*ah->device.num_of_call_devices))) {
446                             memcpy((void*)&(ah->device.init_call_devices[prev_size]), devices, info->num_of_devices*sizeof(device_info_t));
447                         } else {
448                             AUDIO_LOG_ERROR("failed to realloc");
449                             audio_ret = AUDIO_ERR_RESOURCE;
450                             goto ERROR;
451                         }
452                     } else {
453                         AUDIO_LOG_ERROR("invaild previous num. of call devices");
454                         audio_ret = AUDIO_ERR_INTERNAL;
455                         goto ERROR;
456                     }
457                 }
458             } else {
459                 AUDIO_LOG_ERROR("failed to update route for call-voice, num_of_devices is 0");
460                 audio_ret = AUDIO_ERR_PARAMETER;
461                 goto ERROR;
462             }
463             AUDIO_LOG_INFO("modem is not ready, skip...");
464         } else {
465             if ((audio_ret = __update_route_voicecall(ah, devices, info->num_of_devices)))
466                 AUDIO_LOG_WARN("update voicecall route return 0x%x", audio_ret);
467
468             COND_SIGNAL(ah->device.device_cond, "device_cond");
469         }
470     } else if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
471         if ((audio_ret = __update_route_voip(ah, devices, info->num_of_devices)))
472             AUDIO_LOG_WARN("update voip route return 0x%x", audio_ret);
473
474     } else if (!strncmp("radio", info->role, MAX_NAME_LEN)) {
475         if ((audio_ret = __update_route_fmradio(ah, devices, info->num_of_devices)))
476             AUDIO_LOG_WARN("update radio route return 0x%x", audio_ret);
477
478     } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
479         if ((audio_ret = __update_route_reset(ah, devices->direction)))
480             AUDIO_LOG_WARN("update reset return 0x%x", audio_ret);
481
482     } else {
483         /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
484         if ((audio_ret = __update_route_ap_playback_capture(ah, info)))
485             AUDIO_LOG_WARN("update playback route return 0x%x", audio_ret);
486     }
487
488 ERROR:
489     return audio_ret;
490 }
491
492 audio_return_t audio_update_route_option(void *audio_handle, audio_route_option_t *option)
493 {
494     audio_return_t audio_ret = AUDIO_RET_OK;
495     audio_hal_t *ah = (audio_hal_t *)audio_handle;
496
497     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
498     AUDIO_RETURN_VAL_IF_FAIL(option, AUDIO_ERR_PARAMETER);
499
500     AUDIO_LOG_INFO("role:%s, name:%s, value:%d", option->role, option->name, option->value);
501
502     /* Handle RADIO MUTE due to earjack disconnection */
503     if ((option->role && strcmp(option->role, "radio") == 0) &&
504         (option->name && strcmp(option->name, "mute") == 0) &&
505         option->value == 1) {
506         AUDIO_LOG_INFO("MUTE RADIO!!!!");
507         audio_ret = _mixer_control_set_value(ah, MIXER_FMRADIO_MUTE, 0);
508     }
509
510     return audio_ret;
511 }