Add doxygen description
[platform/adaptation/samsung_exynos/audio-hal-max98090.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_JACK, "Headphones" },
37     { AUDIO_DEVICE_OUT_BT_SCO, "Bluetooth" },
38     { AUDIO_DEVICE_OUT_AUX, "Line" },
39     { AUDIO_DEVICE_OUT_HDMI, "HDMI" },
40     { 0, 0 },
41 };
42
43 static device_type_t inDeviceTypes[] = {
44     { AUDIO_DEVICE_IN_MAIN_MIC, "MainMic" },
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 };
53
54 static uint32_t __convert_device_string_to_enum(const char* device_str, uint32_t direction)
55 {
56     uint32_t device = 0;
57
58     if (!strncmp(device_str, "builtin-speaker", MAX_NAME_LEN)) {
59         device = AUDIO_DEVICE_OUT_SPEAKER;
60     } else if (!strncmp(device_str, "builtin-receiver", MAX_NAME_LEN)) {
61         device = AUDIO_DEVICE_OUT_RECEIVER;
62     } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
63         device = AUDIO_DEVICE_OUT_JACK;
64     } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
65         device = AUDIO_DEVICE_OUT_BT_SCO;
66     } else if (!strncmp(device_str, "aux", MAX_NAME_LEN)) {
67         device = AUDIO_DEVICE_OUT_AUX;
68     } else if (!strncmp(device_str, "hdmi", MAX_NAME_LEN)) {
69         device = AUDIO_DEVICE_OUT_HDMI;
70     } else if ((!strncmp(device_str, "builtin-mic", MAX_NAME_LEN))) {
71         device = AUDIO_DEVICE_IN_MAIN_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 audio_return_t __set_devices(audio_hal_t *ah, const char *verb, device_info_t *devices, uint32_t num_of_devices)
84 {
85     audio_return_t audio_ret = AUDIO_RET_OK;
86     uint32_t new_device = 0;
87     const char *active_devices[MAX_DEVICES] = {NULL,};
88     int i = 0, j = 0, dev_idx = 0;
89
90     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
91     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
92     AUDIO_RETURN_VAL_IF_FAIL(num_of_devices, AUDIO_ERR_PARAMETER);
93
94     if (num_of_devices > MAX_DEVICES) {
95         num_of_devices = MAX_DEVICES;
96         AUDIO_LOG_ERROR("error: num_of_devices");
97         return AUDIO_ERR_PARAMETER;
98     }
99
100     if (devices[0].direction == AUDIO_DIRECTION_OUT) {
101         ah->device.active_out &= 0x0;
102         if (ah->device.active_in) {
103             /* check the active in devices */
104             for (j = 0; j < inDeviceTypes[j].type; j++) {
105                 if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[j].type))
106                     active_devices[dev_idx++] = inDeviceTypes[j].name;
107             }
108         }
109     } else if (devices[0].direction == AUDIO_DIRECTION_IN) {
110         ah->device.active_in &= 0x0;
111         if (ah->device.active_out) {
112             /* check the active out devices */
113             for (j = 0; j < outDeviceTypes[j].type; j++) {
114                 if (ah->device.active_out & outDeviceTypes[j].type)
115                     active_devices[dev_idx++] = outDeviceTypes[j].name;
116             }
117         }
118     }
119
120     for (i = 0; i < num_of_devices; i++) {
121         new_device = __convert_device_string_to_enum(devices[i].type, devices[i].direction);
122         if (new_device & AUDIO_DEVICE_IN) {
123             for (j = 0; j < inDeviceTypes[j].type; j++) {
124                 if (new_device == inDeviceTypes[j].type) {
125                     active_devices[dev_idx++] = inDeviceTypes[j].name;
126                     ah->device.active_in |= new_device;
127                 }
128             }
129         } else {
130             for (j = 0; j < outDeviceTypes[j].type; j++) {
131                 if (new_device == outDeviceTypes[j].type) {
132                     active_devices[dev_idx++] = outDeviceTypes[j].name;
133                     ah->device.active_out |= new_device;
134                 }
135             }
136         }
137     }
138
139     if (active_devices[0] == NULL) {
140         AUDIO_LOG_ERROR("Failed to set device: active device is NULL");
141         return AUDIO_ERR_PARAMETER;
142     }
143
144     audio_ret = _ucm_set_devices(ah, verb, active_devices);
145     if (audio_ret)
146         AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
147
148     return audio_ret;
149 }
150
151 static audio_return_t __update_route_ap_playback_capture(audio_hal_t *ah, audio_route_info_t *route_info)
152 {
153     audio_return_t audio_ret = AUDIO_RET_OK;
154     device_info_t *devices = NULL;
155     const char *verb = mode_to_verb_str[VERB_NORMAL];
156
157     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
158     AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
159
160     devices = route_info->device_infos;
161
162     /* To Do: Set modifiers */
163     /* int mod_idx = 0; */
164     /* const char *modifiers[MAX_MODIFIERS] = {NULL,}; */
165
166     AUDIO_LOG_INFO("update_route_ap_playback_capture++ ");
167
168     audio_ret = __set_devices(ah, verb, devices, route_info->num_of_devices);
169     if (audio_ret) {
170         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
171         return audio_ret;
172     }
173     ah->device.mode = VERB_NORMAL;
174
175     /* To Do: Set modifiers */
176     /*
177     if (!strncmp("voice_recognition", route_info->role, MAX_NAME_LEN)) {
178         modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_VOICESEARCH;
179     } else if ((!strncmp("alarm", route_info->role, MAX_NAME_LEN))||(!strncmp("notifiication", route_info->role, MAX_NAME_LEN))) {
180         if (ah->device.active_out &= AUDIO_DEVICE_OUT_JACK)
181             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_DUAL_MEDIA;
182         else
183             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
184     } else {
185         if (ah->device.active_in)
186             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_CAMCORDING;
187         else
188             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
189     }
190     audio_ret = _audio_ucm_set_modifiers (ah, verb, modifiers);
191     */
192
193     return audio_ret;
194 }
195
196 static audio_return_t __update_route_voip(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
197 {
198     audio_return_t audio_ret = AUDIO_RET_OK;
199     const char *verb = mode_to_verb_str[VERB_NORMAL];
200
201     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
202     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
203
204     AUDIO_LOG_INFO("update_route_voip++");
205
206     audio_ret = __set_devices(ah, verb, devices, num_of_devices);
207     if (audio_ret) {
208         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
209         return audio_ret;
210     }
211     /* FIXME. If necessary, set VERB_VOIP */
212     ah->device.mode = VERB_NORMAL;
213
214     /* TO DO: Set modifiers */
215     return audio_ret;
216 }
217
218 static audio_return_t __update_route_reset(audio_hal_t *ah, uint32_t direction)
219 {
220     audio_return_t audio_ret = AUDIO_RET_OK;
221     const char *active_devices[MAX_DEVICES] = {NULL,};
222     int i = 0, dev_idx = 0;
223
224     /* FIXME: If you need to reset, set verb inactive */
225     /* const char *verb = NULL; */
226     /* verb = AUDIO_USE_CASE_VERB_INACTIVE; */
227
228     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
229
230     AUDIO_LOG_INFO("update_route_reset++, direction(0x%x)", direction);
231
232     if (direction == AUDIO_DIRECTION_OUT) {
233         ah->device.active_out &= 0x0;
234         if (ah->device.active_in) {
235             /* check the active in devices */
236             for (i = 0; i < inDeviceTypes[i].type; i++) {
237                 if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[i].type)) {
238                     active_devices[dev_idx++] = inDeviceTypes[i].name;
239                     AUDIO_LOG_INFO("added for in : %s", inDeviceTypes[i].name);
240                 }
241             }
242         }
243     } else {
244         ah->device.active_in &= 0x0;
245         if (ah->device.active_out) {
246             /* check the active out devices */
247             for (i = 0; i < outDeviceTypes[i].type; i++) {
248                 if (ah->device.active_out & outDeviceTypes[i].type) {
249                     active_devices[dev_idx++] = outDeviceTypes[i].name;
250                     AUDIO_LOG_INFO("added for out : %s", outDeviceTypes[i].name);
251                 }
252             }
253         }
254     }
255
256     if (active_devices[0] == NULL) {
257         AUDIO_LOG_DEBUG("active device is NULL, no need to update.");
258         return AUDIO_RET_OK;
259     }
260
261     if ((audio_ret = _ucm_set_devices(ah, mode_to_verb_str[ah->device.mode], active_devices)))
262         AUDIO_LOG_ERROR("failed to _ucm_set_devices(), ret(0x%x)", audio_ret);
263
264     return audio_ret;
265 }
266
267 audio_return_t _audio_routing_init(audio_hal_t *ah)
268 {
269     audio_return_t audio_ret = AUDIO_RET_OK;
270
271     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
272
273     ah->device.active_in = 0x0;
274     ah->device.active_out = 0x0;
275     ah->device.mode = VERB_NORMAL;
276
277     if ((audio_ret = _ucm_init(ah)))
278         AUDIO_LOG_ERROR("failed to _ucm_init(), ret(0x%x)", audio_ret);
279
280     return audio_ret;
281 }
282
283 audio_return_t _audio_routing_deinit(audio_hal_t *ah)
284 {
285     audio_return_t audio_ret = AUDIO_RET_OK;
286
287     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
288
289     if ((audio_ret = _ucm_deinit(ah)))
290         AUDIO_LOG_ERROR("failed to _ucm_deinit(), ret(0x%x)", audio_ret);
291
292     return audio_ret;
293 }
294
295 #define LOOPBACK_ARG_LATENCY_MSEC      40
296 #define LOOPBACK_ARG_ADJUST_TIME_SEC   3
297 audio_return_t audio_update_route(void *audio_handle, audio_route_info_t *info)
298 {
299     audio_return_t audio_ret = AUDIO_RET_OK;
300     audio_hal_t *ah = (audio_hal_t *)audio_handle;
301     device_info_t *devices = NULL;
302
303     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
304     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
305
306     AUDIO_LOG_INFO("role:%s", info->role);
307
308     devices = info->device_infos;
309
310     if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
311         if ((audio_ret = __update_route_voip(ah, devices, info->num_of_devices)))
312             AUDIO_LOG_WARN("update voip route return 0x%x", audio_ret);
313
314     } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
315         if ((audio_ret = __update_route_reset(ah, devices->direction)))
316             AUDIO_LOG_WARN("update reset return 0x%x", audio_ret);
317
318     } else {
319         /* send latency and adjust time for loopback */
320         if (!strncmp("loopback", info->role, MAX_NAME_LEN)) {
321             _audio_comm_send_message(ah, "loopback::latency", LOOPBACK_ARG_LATENCY_MSEC);
322             _audio_comm_send_message(ah, "loopback::adjust_time", LOOPBACK_ARG_ADJUST_TIME_SEC);
323         }
324         /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
325         if ((audio_ret = __update_route_ap_playback_capture(ah, info)))
326             AUDIO_LOG_WARN("update playback route return 0x%x", audio_ret);
327     }
328     return audio_ret;
329 }
330
331 audio_return_t audio_update_route_option(void *audio_handle, audio_route_option_t *option)
332 {
333     audio_return_t audio_ret = AUDIO_RET_OK;
334     audio_hal_t *ah = (audio_hal_t *)audio_handle;
335
336     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
337     AUDIO_RETURN_VAL_IF_FAIL(option, AUDIO_ERR_PARAMETER);
338
339     AUDIO_LOG_INFO("role:%s, name:%s, value:%d", option->role, option->name, option->value);
340
341     return audio_ret;
342 }