Restructure files
[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 };
56
57 static uint32_t __convert_device_string_to_enum(const char* device_str, uint32_t direction)
58 {
59     uint32_t device = 0;
60
61     if (!strncmp(device_str, "builtin-speaker", MAX_NAME_LEN)) {
62         device = AUDIO_DEVICE_OUT_SPEAKER;
63     } else if (!strncmp(device_str, "builtin-receiver", MAX_NAME_LEN)) {
64         device = AUDIO_DEVICE_OUT_RECEIVER;
65     } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
66         device = AUDIO_DEVICE_OUT_JACK;
67     } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
68         device = AUDIO_DEVICE_OUT_BT_SCO;
69     } else if ((!strncmp(device_str, "builtin-mic", MAX_NAME_LEN))) {
70         device = AUDIO_DEVICE_IN_MAIN_MIC;
71     /* To Do : SUB_MIC */
72     } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
73         device = AUDIO_DEVICE_IN_JACK;
74     } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
75         device = AUDIO_DEVICE_IN_BT_SCO;
76     } else {
77         device = AUDIO_DEVICE_NONE;
78     }
79     AUDIO_LOG_INFO("device type(%s), enum(0x%x)", device_str, device);
80     return device;
81 }
82
83 static void __reset_voice_devices_info(audio_hal_t *ah)
84 {
85     AUDIO_RETURN_IF_FAIL(ah);
86
87     AUDIO_LOG_INFO("reset voice device info");
88     if (ah->device.init_call_devices) {
89         free(ah->device.init_call_devices);
90         ah->device.init_call_devices = NULL;
91         ah->device.num_of_call_devices = 0;
92     }
93
94     return;
95 }
96
97 static audio_return_t __set_devices(audio_hal_t *ah, const char *verb, device_info_t *devices, uint32_t num_of_devices)
98 {
99     audio_return_t audio_ret = AUDIO_RET_OK;
100     uint32_t new_device = 0;
101     const char *active_devices[MAX_DEVICES] = {NULL,};
102     int i = 0, j = 0, dev_idx = 0;
103
104     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
105     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
106     AUDIO_RETURN_VAL_IF_FAIL(num_of_devices, AUDIO_ERR_PARAMETER);
107
108     if (num_of_devices > MAX_DEVICES) {
109         num_of_devices = MAX_DEVICES;
110         AUDIO_LOG_ERROR("error: num_of_devices");
111         return AUDIO_ERR_PARAMETER;
112     }
113
114     if (devices[0].direction == AUDIO_DIRECTION_OUT) {
115         ah->device.active_out &= 0x0;
116         if (ah->device.active_in) {
117             /* check the active in devices */
118             for (j = 0; j < inDeviceTypes[j].type; j++) {
119                 if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[j].type))
120                     active_devices[dev_idx++] = inDeviceTypes[j].name;
121             }
122         }
123     } else if (devices[0].direction == AUDIO_DIRECTION_IN) {
124         ah->device.active_in &= 0x0;
125         if (ah->device.active_out) {
126             /* check the active out devices */
127             for (j = 0; j < outDeviceTypes[j].type; j++) {
128                 if (ah->device.active_out & outDeviceTypes[j].type)
129                     active_devices[dev_idx++] = outDeviceTypes[j].name;
130             }
131         }
132     }
133
134     for (i = 0; i < num_of_devices; i++) {
135         new_device = __convert_device_string_to_enum(devices[i].type, devices[i].direction);
136         if (new_device & AUDIO_DEVICE_IN) {
137             for (j = 0; j < inDeviceTypes[j].type; j++) {
138                 if (new_device == inDeviceTypes[j].type) {
139                     active_devices[dev_idx++] = inDeviceTypes[j].name;
140                     ah->device.active_in |= new_device;
141                 }
142             }
143         } else {
144             for (j = 0; j < outDeviceTypes[j].type; j++) {
145                 if (new_device == outDeviceTypes[j].type) {
146                     active_devices[dev_idx++] = outDeviceTypes[j].name;
147                     ah->device.active_out |= new_device;
148                 }
149             }
150         }
151     }
152
153     if (active_devices[0] == NULL) {
154         AUDIO_LOG_ERROR("Failed to set device: active device is NULL");
155         return AUDIO_ERR_PARAMETER;
156     }
157
158     audio_ret = _ucm_set_devices(ah, verb, active_devices);
159     if (audio_ret)
160         AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
161
162     return audio_ret;
163 }
164
165 static audio_return_t __update_route_ap_playback_capture(audio_hal_t *ah, audio_route_info_t *route_info)
166 {
167     audio_return_t audio_ret = AUDIO_RET_OK;
168     device_info_t *devices = NULL;
169     const char *verb = mode_to_verb_str[VERB_NORMAL];
170 #if 0  /* Disable setting modifiers, because driver does not support it yet */
171     int mod_idx = 0;
172     const char *modifiers[MAX_MODIFIERS] = {NULL,};
173 #endif
174
175     if (ah->modem.is_connected) {
176         AUDIO_LOG_INFO("modem is connected, skip verb[%s]", verb);
177         return audio_ret;
178     }
179
180     if (ah->device.mode != VERB_NORMAL) {
181         if (ah->device.mode == VERB_VOICECALL) {
182             __reset_voice_devices_info(ah);
183             COND_SIGNAL(ah->device.device_cond, "device_cond");
184         }
185         _reset_pcm_devices(ah);
186         ah->device.mode = VERB_NORMAL;
187     }
188
189     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
190     AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
191
192     devices = route_info->device_infos;
193
194     AUDIO_LOG_INFO("update_route_ap_playback_capture++ ");
195
196     audio_ret = __set_devices(ah, verb, devices, route_info->num_of_devices);
197     if (audio_ret) {
198         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
199         return audio_ret;
200     }
201     ah->device.mode = VERB_NORMAL;
202
203 #if 0 /* Disable setting modifiers, because driver does not support it yet */
204     /* Set modifiers */
205     if (!strncmp("voice_recognition", route_info->role, MAX_NAME_LEN)) {
206         modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_VOICESEARCH;
207     } else if ((!strncmp("alarm", route_info->role, MAX_NAME_LEN))||(!strncmp("notifiication", route_info->role, MAX_NAME_LEN))) {
208         if (ah->device.active_out &= AUDIO_DEVICE_OUT_JACK)
209             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_DUAL_MEDIA;
210         else
211             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
212     } else if (!strncmp("ringtone", route_info->role, MAX_NAME_LEN)) {
213         if (ah->device.active_out)
214             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_RINGTONE;
215     } else {
216         if (ah->device.active_in)
217             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_CAMCORDING;
218         else
219             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
220     }
221     audio_ret = _audio_ucm_set_modifiers (ah, verb, modifiers);
222 #endif
223     return audio_ret;
224 }
225
226 static audio_return_t __update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
227 {
228     audio_return_t audio_ret = AUDIO_RET_OK;
229     const char *verb = mode_to_verb_str[VERB_VOICECALL];
230
231     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
232     /* if both params are 0, return error for invalid state,
233          * this error would be used to tizen-audio-modem.c */
234     AUDIO_RETURN_VAL_IF_FAIL((devices||num_of_devices), AUDIO_ERR_INVALID_STATE);
235     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
236
237     AUDIO_LOG_INFO("update_route_voicecall++");
238
239     audio_ret = __set_devices(ah, verb, devices, num_of_devices);
240     if (audio_ret) {
241         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
242         return audio_ret;
243     }
244
245     if (ah->device.mode != VERB_VOICECALL) {
246         _voice_pcm_open(ah);
247         ah->device.mode = VERB_VOICECALL;
248         /* FIXME. Get network info and configure rate in pcm device */
249     }
250
251     return audio_ret;
252 }
253
254 static audio_return_t __update_route_voip(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
255 {
256     audio_return_t audio_ret = AUDIO_RET_OK;
257     const char *verb = mode_to_verb_str[VERB_NORMAL];
258
259     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
260     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
261
262     AUDIO_LOG_INFO("update_route_voip++");
263
264     audio_ret = __set_devices(ah, verb, devices, num_of_devices);
265     if (audio_ret) {
266         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
267         return audio_ret;
268     }
269     /* FIXME. If necessary, set VERB_VOIP */
270     ah->device.mode = VERB_NORMAL;
271
272     /* TO DO: Set modifiers */
273     return audio_ret;
274 }
275
276 static audio_return_t __update_route_reset(audio_hal_t *ah, uint32_t direction)
277 {
278     audio_return_t audio_ret = AUDIO_RET_OK;
279     const char *active_devices[MAX_DEVICES] = {NULL,};
280     int i = 0, dev_idx = 0;
281
282     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
283
284     AUDIO_LOG_INFO("update_route_reset++, direction(0x%x)", direction);
285
286     if (direction == AUDIO_DIRECTION_OUT) {
287         ah->device.active_out &= 0x0;
288         if (ah->device.active_in) {
289             /* check the active in devices */
290             for (i = 0; i < inDeviceTypes[i].type; i++) {
291                 if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[i].type)) {
292                     active_devices[dev_idx++] = inDeviceTypes[i].name;
293                     AUDIO_LOG_INFO("added for in : %s", inDeviceTypes[i].name);
294                 }
295             }
296         }
297     } else {
298         ah->device.active_in &= 0x0;
299         if (ah->device.active_out) {
300             /* check the active out devices */
301             for (i = 0; i < outDeviceTypes[i].type; i++) {
302                 if (ah->device.active_out & outDeviceTypes[i].type) {
303                     active_devices[dev_idx++] = outDeviceTypes[i].name;
304                     AUDIO_LOG_INFO("added for out : %s", outDeviceTypes[i].name);
305                 }
306             }
307         }
308     }
309     if (ah->device.mode == VERB_VOICECALL) {
310         _voice_pcm_close(ah, direction);
311         if (!ah->device.active_in && !ah->device.active_out)
312             ah->device.mode = VERB_NORMAL;
313         __reset_voice_devices_info(ah);
314         COND_SIGNAL(ah->device.device_cond, "device_cond");
315     }
316
317     if (active_devices[0] == NULL) {
318         AUDIO_LOG_DEBUG("active device is NULL, no need to update.");
319         return AUDIO_RET_OK;
320     }
321
322     if ((audio_ret = _ucm_set_devices(ah, mode_to_verb_str[ah->device.mode], active_devices)))
323         AUDIO_LOG_ERROR("failed to _ucm_set_devices(), ret(0x%x)", audio_ret);
324
325     return audio_ret;
326 }
327
328 audio_return_t _audio_update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
329 {
330     return __update_route_voicecall(ah, devices, num_of_devices);
331 }
332
333 audio_return_t _audio_routing_init(audio_hal_t *ah)
334 {
335     audio_return_t audio_ret = AUDIO_RET_OK;
336
337     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
338
339     ah->device.active_in = 0x0;
340     ah->device.active_out = 0x0;
341     ah->device.mode = VERB_NORMAL;
342
343     if ((audio_ret = _ucm_init(ah)))
344         AUDIO_LOG_ERROR("failed to _ucm_init(), ret(0x%x)", audio_ret);
345
346     return audio_ret;
347 }
348
349 audio_return_t _audio_routing_deinit(audio_hal_t *ah)
350 {
351     audio_return_t audio_ret = AUDIO_RET_OK;
352
353     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
354
355     if ((audio_ret = _ucm_deinit(ah)))
356         AUDIO_LOG_ERROR("failed to _ucm_deinit(), ret(0x%x)", audio_ret);
357
358     return audio_ret;
359 }
360
361 audio_return_t audio_update_route(void *audio_handle, audio_route_info_t *info)
362 {
363     audio_return_t audio_ret = AUDIO_RET_OK;
364     audio_hal_t *ah = (audio_hal_t *)audio_handle;
365     device_info_t *devices = NULL;
366     uint32_t prev_size;
367     int32_t i;
368     int32_t j;
369
370     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
371     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
372
373     AUDIO_LOG_INFO("role:%s", info->role);
374
375     devices = info->device_infos;
376
377     if (!strncmp("call-voice", info->role, MAX_NAME_LEN)) {
378         if (!ah->modem.is_connected) {
379             if (info->num_of_devices) {
380                 if (!ah->device.num_of_call_devices) {
381                     if ((ah->device.init_call_devices = (device_info_t*)calloc(info->num_of_devices, sizeof(device_info_t)))) {
382                         memcpy(ah->device.init_call_devices, devices, info->num_of_devices*sizeof(device_info_t));
383                         ah->device.num_of_call_devices = info->num_of_devices;
384                     } else {
385                         AUDIO_LOG_ERROR("failed to calloc");
386                         audio_ret = AUDIO_ERR_RESOURCE;
387                         goto ERROR;
388                     }
389                 } else if (ah->device.num_of_call_devices) {
390                     prev_size = ah->device.num_of_call_devices;
391                     if (prev_size == 2) {
392                         /* There's a chance to be requested to change routing from user
393                          * though two devices(for input/output) has already been set for call-voice routing.
394                          * In this case, exchange an old device for a new device if it's direction is same as an old one's. */
395                         for (i = 0; i < prev_size; i++) {
396                             for (j = 0; j < info->num_of_devices; j++) {
397                                 if (devices[j].direction == ah->device.init_call_devices[i].direction &&
398                                     devices[j].id != ah->device.init_call_devices[i].id)
399                                     memcpy(&ah->device.init_call_devices[i], &devices[j], sizeof(device_info_t));
400                             }
401                         }
402                     } else if (prev_size < 2) {
403                         /* A device has already been added for call-voice routing,
404                          * and now it is about to add a new device(input or output device). */
405                         ah->device.num_of_call_devices += info->num_of_devices;
406                         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))) {
407                             memcpy((void*)&(ah->device.init_call_devices[prev_size]), devices, info->num_of_devices*sizeof(device_info_t));
408                         } else {
409                             AUDIO_LOG_ERROR("failed to realloc");
410                             audio_ret = AUDIO_ERR_RESOURCE;
411                             goto ERROR;
412                         }
413                     } else {
414                         AUDIO_LOG_ERROR("invaild previous num. of call devices");
415                         audio_ret = AUDIO_ERR_INTERNAL;
416                         goto ERROR;
417                     }
418                 }
419             } else {
420                 AUDIO_LOG_ERROR("failed to update route for call-voice, num_of_devices is 0");
421                 audio_ret = AUDIO_ERR_PARAMETER;
422                 goto ERROR;
423             }
424             AUDIO_LOG_INFO("modem is not ready, skip...");
425         } else {
426             if ((audio_ret = __update_route_voicecall(ah, devices, info->num_of_devices)))
427                 AUDIO_LOG_WARN("update voicecall route return 0x%x", audio_ret);
428
429             COND_SIGNAL(ah->device.device_cond, "device_cond");
430         }
431     } else if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
432         if ((audio_ret = __update_route_voip(ah, devices, info->num_of_devices)))
433             AUDIO_LOG_WARN("update voip route return 0x%x", audio_ret);
434
435     } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
436         if ((audio_ret = __update_route_reset(ah, devices->direction)))
437             AUDIO_LOG_WARN("update reset return 0x%x", audio_ret);
438
439     } else {
440         /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
441         if ((audio_ret = __update_route_ap_playback_capture(ah, info)))
442             AUDIO_LOG_WARN("update playback route return 0x%x", audio_ret);
443     }
444
445 ERROR:
446     return audio_ret;
447 }
448
449 audio_return_t audio_update_route_option(void *audio_handle, audio_route_option_t *option)
450 {
451     audio_return_t audio_ret = AUDIO_RET_OK;
452     audio_hal_t *ah = (audio_hal_t *)audio_handle;
453
454     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
455     AUDIO_RETURN_VAL_IF_FAIL(option, AUDIO_ERR_PARAMETER);
456
457     AUDIO_LOG_INFO("role:%s, name:%s, value:%d", option->role, option->name, option->value);
458
459     return audio_ret;
460 }