fbf0f8ad647526773158670bcb4c8b85e8876cbd
[platform/adaptation/ap_broadcom/audio-hal-bcm2837.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 #include <vconf.h>
33
34 /* #define DEBUG_TIMING */
35
36 static device_type_s outDeviceTypes[] = {
37     { AUDIO_DEVICE_OUT_SPEAKER, "Speaker" },
38     { AUDIO_DEVICE_OUT_BT_SCO, "Bluetooth" },
39     { AUDIO_DEVICE_OUT_AUX, "Line" },
40     { AUDIO_DEVICE_OUT_HDMI, "HDMI" },
41     { 0, 0 },
42 };
43
44 static device_type_s inDeviceTypes[] = {
45     { AUDIO_DEVICE_IN_BT_SCO, "BT Mic" },
46     { 0, 0 },
47 };
48
49 static const char* mode_to_verb_str[] = {
50     AUDIO_USE_CASE_VERB_HIFI,
51 };
52
53 static uint32_t __convert_device_string_to_enum(const char* device_str, uint32_t direction)
54 {
55     uint32_t device = 0;
56
57     if (!strncmp(device_str, "builtin-speaker", MAX_NAME_LEN)) {
58         device = AUDIO_DEVICE_OUT_SPEAKER;
59     } else if (!strncmp(device_str, "builtin-receiver", MAX_NAME_LEN)) {
60         device = AUDIO_DEVICE_OUT_RECEIVER;
61     } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
62         device = AUDIO_DEVICE_OUT_JACK;
63     } else if ((!strncmp(device_str, "bt-sco", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
64         device = AUDIO_DEVICE_OUT_BT_SCO;
65     } else if (!strncmp(device_str, "aux", MAX_NAME_LEN)) {
66         device = AUDIO_DEVICE_OUT_AUX;
67     } else if (!strncmp(device_str, "hdmi", MAX_NAME_LEN)) {
68         device = AUDIO_DEVICE_OUT_HDMI;
69     } else if ((!strncmp(device_str, "builtin-mic", MAX_NAME_LEN))) {
70         device = AUDIO_DEVICE_IN_MAIN_MIC;
71     } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
72         device = AUDIO_DEVICE_IN_JACK;
73     } else if ((!strncmp(device_str, "bt-sco", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
74         device = AUDIO_DEVICE_IN_BT_SCO;
75     } else {
76         device = AUDIO_DEVICE_NONE;
77     }
78     AUDIO_LOG_INFO("device type(%s), enum(0x%x)", device_str, device);
79     return device;
80 }
81
82 static audio_return_e __set_devices(audio_hal_s *ah, const char *verb, device_info_s *devices, uint32_t num_of_devices)
83 {
84     audio_return_e audio_ret = AUDIO_RET_OK;
85     uint32_t new_device = 0;
86     const char *active_devices[MAX_DEVICES] = {NULL,};
87     int i = 0, j = 0, dev_idx = 0;
88
89     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
90     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
91     AUDIO_RETURN_VAL_IF_FAIL(num_of_devices, AUDIO_ERR_PARAMETER);
92
93     if (num_of_devices > MAX_DEVICES) {
94         num_of_devices = MAX_DEVICES;
95         AUDIO_LOG_ERROR("error: num_of_devices");
96         return AUDIO_ERR_PARAMETER;
97     }
98
99     if (devices[0].direction == AUDIO_DIRECTION_OUT) {
100         ah->device.active_out &= 0x0;
101         if (ah->device.active_in) {
102             /* check the active in devices */
103             for (j = 0; j < inDeviceTypes[j].type; j++) {
104                 if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[j].type))
105                     active_devices[dev_idx++] = inDeviceTypes[j].name;
106             }
107         }
108     } else if (devices[0].direction == AUDIO_DIRECTION_IN) {
109         ah->device.active_in &= 0x0;
110         if (ah->device.active_out) {
111             /* check the active out devices */
112             for (j = 0; j < outDeviceTypes[j].type; j++) {
113                 if (ah->device.active_out & outDeviceTypes[j].type)
114                     active_devices[dev_idx++] = outDeviceTypes[j].name;
115             }
116         }
117     }
118
119     for (i = 0; i < num_of_devices; i++) {
120         new_device = __convert_device_string_to_enum(devices[i].type, devices[i].direction);
121         if (new_device & AUDIO_DEVICE_IN) {
122             for (j = 0; j < inDeviceTypes[j].type; j++) {
123                 if (new_device == inDeviceTypes[j].type) {
124                     active_devices[dev_idx++] = inDeviceTypes[j].name;
125                     ah->device.active_in |= new_device;
126                 }
127             }
128         } else {
129             for (j = 0; j < outDeviceTypes[j].type; j++) {
130                 if (new_device == outDeviceTypes[j].type) {
131                     active_devices[dev_idx++] = outDeviceTypes[j].name;
132                     ah->device.active_out |= new_device;
133                 }
134             }
135         }
136     }
137
138     if (active_devices[0] == NULL) {
139         AUDIO_LOG_ERROR("Failed to set device: active device is NULL");
140         return AUDIO_ERR_PARAMETER;
141     }
142
143     /* Routing path is set only via __audio_routing_playback_rpi3() function, do nothing here.  */
144
145     return audio_ret;
146 }
147
148 static audio_return_e __update_route_ap_playback_capture(audio_hal_s *ah, audio_route_info_s *route_info)
149 {
150     audio_return_e audio_ret = AUDIO_RET_OK;
151     device_info_s *devices = NULL;
152     const char *verb = mode_to_verb_str[VERB_NORMAL];
153
154     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
155     AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
156
157     devices = route_info->device_infos;
158
159     /* To Do: Set modifiers */
160     /* int mod_idx = 0; */
161     /* const char *modifiers[MAX_MODIFIERS] = {NULL,}; */
162
163     AUDIO_LOG_INFO("update_route_ap_playback_capture++ ");
164
165     audio_ret = __set_devices(ah, verb, devices, route_info->num_of_devices);
166     if (audio_ret) {
167         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
168         return audio_ret;
169     }
170     ah->device.mode = VERB_NORMAL;
171
172     /* Routing path is set only via __audio_routing_playback_rpi3() function, do nothing here.  */
173
174     return audio_ret;
175 }
176
177 static audio_return_e __update_route_voip(audio_hal_s *ah, device_info_s *devices, int32_t num_of_devices)
178 {
179     audio_return_e audio_ret = AUDIO_RET_OK;
180     const char *verb = mode_to_verb_str[VERB_NORMAL];
181
182     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
183     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
184
185     AUDIO_LOG_INFO("update_route_voip++");
186
187     audio_ret = __set_devices(ah, verb, devices, num_of_devices);
188     if (audio_ret) {
189         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
190         return audio_ret;
191     }
192     /* FIXME. If necessary, set VERB_VOIP */
193     ah->device.mode = VERB_NORMAL;
194
195     /* TO DO: Set modifiers */
196     return audio_ret;
197 }
198
199 static audio_return_e __update_route_reset(audio_hal_s *ah, uint32_t direction)
200 {
201     audio_return_e audio_ret = AUDIO_RET_OK;
202     const char *active_devices[MAX_DEVICES] = {NULL,};
203     int i = 0, dev_idx = 0;
204
205     /* FIXME: If you need to reset, set verb inactive */
206     /* const char *verb = NULL; */
207     /* verb = AUDIO_USE_CASE_VERB_INACTIVE; */
208
209     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
210
211     AUDIO_LOG_INFO("update_route_reset++, direction(0x%x)", direction);
212
213     if (direction == AUDIO_DIRECTION_OUT) {
214         ah->device.active_out &= 0x0;
215         if (ah->device.active_in) {
216             /* check the active in devices */
217             for (i = 0; i < inDeviceTypes[i].type; i++) {
218                 if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[i].type)) {
219                     active_devices[dev_idx++] = inDeviceTypes[i].name;
220                     AUDIO_LOG_INFO("added for in : %s", inDeviceTypes[i].name);
221                 }
222             }
223         }
224     } else {
225         ah->device.active_in &= 0x0;
226         if (ah->device.active_out) {
227             /* check the active out devices */
228             for (i = 0; i < outDeviceTypes[i].type; i++) {
229                 if (ah->device.active_out & outDeviceTypes[i].type) {
230                     active_devices[dev_idx++] = outDeviceTypes[i].name;
231                     AUDIO_LOG_INFO("added for out : %s", outDeviceTypes[i].name);
232                 }
233             }
234         }
235     }
236
237     if (active_devices[0] == NULL) {
238         AUDIO_LOG_DEBUG("active device is NULL, no need to update.");
239         return AUDIO_RET_OK;
240     }
241
242     /* Routing path is set only via __audio_routing_playback_rpi3() function, do nothing here.  */
243
244     return audio_ret;
245 }
246
247 static void __audio_routing_playback_rpi3(audio_hal_s *ah)
248 {
249     int type;
250     int ret;
251
252     ret = vconf_get_int(VCONFKEY_SOUND_RPI_PLAYBACK_ROUTE, &type);
253     if (ret != 0) {
254         AUDIO_LOG_ERROR("Failed to get vconf [%s], err [%d]", VCONFKEY_SOUND_RPI_PLAYBACK_ROUTE, ret);
255         return;
256     }
257
258     _mixer_control_set_value(ah, "PCM Playback Route", type);
259 }
260
261 audio_return_e _audio_routing_init(audio_hal_s *ah)
262 {
263     audio_return_e audio_ret = AUDIO_RET_OK;
264
265     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
266
267     ah->device.active_in = 0x0;
268     ah->device.active_out = 0x0;
269     ah->device.mode = VERB_NORMAL;
270
271     /* additional setting for rpi3 playback route mixer control */
272     __audio_routing_playback_rpi3(ah);
273
274     return audio_ret;
275 }
276
277 audio_return_e _audio_routing_deinit(audio_hal_s *ah)
278 {
279     audio_return_e audio_ret = AUDIO_RET_OK;
280
281     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
282
283     return audio_ret;
284 }
285
286 audio_return_e audio_update_route(void *audio_handle, audio_route_info_s *info)
287 {
288     audio_return_e audio_ret = AUDIO_RET_OK;
289     audio_hal_s *ah = (audio_hal_s *)audio_handle;
290     device_info_s *devices = NULL;
291
292     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
293     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
294     AUDIO_RETURN_VAL_IF_FAIL(info->role, AUDIO_ERR_PARAMETER);
295
296     AUDIO_LOG_INFO("role:%s", info->role);
297
298     devices = info->device_infos;
299
300     if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
301         if ((audio_ret = __update_route_voip(ah, devices, info->num_of_devices)))
302             AUDIO_LOG_WARN("update voip route return 0x%x", audio_ret);
303
304     } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
305         if ((audio_ret = __update_route_reset(ah, devices->direction)))
306             AUDIO_LOG_WARN("update reset return 0x%x", audio_ret);
307
308     } else {
309         /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
310         if ((audio_ret = __update_route_ap_playback_capture(ah, info)))
311             AUDIO_LOG_WARN("update playback route return 0x%x", audio_ret);
312     }
313     return audio_ret;
314 }
315
316 audio_return_e audio_update_route_option(void *audio_handle, audio_route_option_s *option)
317 {
318     audio_return_e audio_ret = AUDIO_RET_OK;
319     audio_hal_s *ah = (audio_hal_s *)audio_handle;
320     int ret;
321
322     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
323     AUDIO_RETURN_VAL_IF_FAIL(option, AUDIO_ERR_PARAMETER);
324
325     AUDIO_LOG_INFO("role:%s, name:%s, value:%d", option->role, option->name, option->value);
326
327     if (!strcmp("rpi playback route", option->name)) {
328         audio_ret = _mixer_control_set_value(ah, "PCM Playback Route", option->value);
329         if (audio_ret == AUDIO_RET_OK) {
330             ret = vconf_set_int(VCONFKEY_SOUND_RPI_PLAYBACK_ROUTE, option->value);
331             if (ret != 0) {
332                 AUDIO_LOG_ERROR("Failed to set vconf [%s], err [%d]", VCONFKEY_SOUND_RPI_PLAYBACK_ROUTE, ret);
333                 return AUDIO_ERR_INTERNAL;
334             }
335         }
336     }
337
338     return audio_ret;
339 }