Change path of configuration and license files
[platform/adaptation/samsung_exynos/audio-hal-exynos9110.git] / tizen-audio-volume.c
1 /*
2  * audio-hal
3  *
4  * Copyright (c) 2015 - 2019 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 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h>
27 #include <vconf.h>
28 #include <iniparser.h>
29
30 #include "tizen-audio-internal.h"
31 #include "tizen-audio-impl.h"
32
33 #define VOLUME_INI_DEFAULT_PATH     SYSCONFDIR"/multimedia/mmfw_audio_volume.ini" /* SYSCONFDIR is defined at .spec */
34 #define VOLUME_INI_TEMP_PATH        "/opt/system/mmfw_audio_volume.ini"
35 #define VOLUME_VALUE_MAX            (1.0f)
36 #define GAIN_VALUE_MAX              (1.0f)
37
38 static uint32_t g_master_volume_level = 100;
39
40 static const char *g_volume_vconf[AUDIO_VOLUME_TYPE_MAX] = {
41     "file/private/sound/volume/system",         /* AUDIO_VOLUME_TYPE_SYSTEM */
42     "file/private/sound/volume/notification",   /* AUDIO_VOLUME_TYPE_NOTIFICATION */
43     "file/private/sound/volume/alarm",          /* AUDIO_VOLUME_TYPE_ALARM */
44     "file/private/sound/volume/ringtone",       /* AUDIO_VOLUME_TYPE_RINGTONE */
45     "file/private/sound/volume/media",          /* AUDIO_VOLUME_TYPE_MEDIA */
46     "file/private/sound/volume/call",           /* AUDIO_VOLUME_TYPE_CALL */
47     "file/private/sound/volume/voip",           /* AUDIO_VOLUME_TYPE_VOIP */
48     "file/private/sound/volume/voice",          /* AUDIO_VOLUME_TYPE_VOICE */
49 };
50
51 static const char *__get_volume_type_string_by_idx(uint32_t vol_type_idx)
52 {
53     switch (vol_type_idx) {
54     case AUDIO_VOLUME_TYPE_SYSTEM:          return "system";
55     case AUDIO_VOLUME_TYPE_NOTIFICATION:    return "notification";
56     case AUDIO_VOLUME_TYPE_ALARM:           return "alarm";
57     case AUDIO_VOLUME_TYPE_RINGTONE:        return "ringtone";
58     case AUDIO_VOLUME_TYPE_MEDIA:           return "media";
59     case AUDIO_VOLUME_TYPE_CALL:            return "call";
60     case AUDIO_VOLUME_TYPE_VOIP:            return "voip";
61     case AUDIO_VOLUME_TYPE_VOICE:           return "voice";
62     default:                                return "invalid";
63     }
64 }
65
66 static uint32_t __get_volume_idx_by_string_type(const char *vol_type)
67 {
68     if (!strncmp(vol_type, "system", strlen(vol_type)) || !strncmp(vol_type, "0", strlen(vol_type)))
69         return AUDIO_VOLUME_TYPE_SYSTEM;
70     else if (!strncmp(vol_type, "notification", strlen(vol_type)) || !strncmp(vol_type, "1", strlen(vol_type)))
71         return AUDIO_VOLUME_TYPE_NOTIFICATION;
72     else if (!strncmp(vol_type, "alarm", strlen(vol_type)) || !strncmp(vol_type, "2", strlen(vol_type)))
73         return AUDIO_VOLUME_TYPE_ALARM;
74     else if (!strncmp(vol_type, "ringtone", strlen(vol_type)) || !strncmp(vol_type, "3", strlen(vol_type)))
75         return AUDIO_VOLUME_TYPE_RINGTONE;
76     else if (!strncmp(vol_type, "media", strlen(vol_type)) || !strncmp(vol_type, "4", strlen(vol_type)))
77         return AUDIO_VOLUME_TYPE_MEDIA;
78     else if (!strncmp(vol_type, "call", strlen(vol_type)) || !strncmp(vol_type, "5", strlen(vol_type)))
79         return AUDIO_VOLUME_TYPE_CALL;
80     else if (!strncmp(vol_type, "voip", strlen(vol_type)) || !strncmp(vol_type, "6", strlen(vol_type)))
81         return AUDIO_VOLUME_TYPE_VOIP;
82     else if (!strncmp(vol_type, "voice", strlen(vol_type)) || !strncmp(vol_type, "7", strlen(vol_type)))
83         return AUDIO_VOLUME_TYPE_VOICE;
84     else
85         return AUDIO_VOLUME_TYPE_MEDIA;
86 }
87
88 static const char *__get_gain_type_string_by_idx(uint32_t gain_type_idx)
89 {
90     switch (gain_type_idx) {
91     case AUDIO_GAIN_TYPE_DEFAULT:           return "default";
92     case AUDIO_GAIN_TYPE_DIALER:            return "dialer";
93     case AUDIO_GAIN_TYPE_TOUCH:             return "touch";
94     case AUDIO_GAIN_TYPE_AF:                return "af";
95     case AUDIO_GAIN_TYPE_SHUTTER1:          return "shutter1";
96     case AUDIO_GAIN_TYPE_SHUTTER2:          return "shutter2";
97     case AUDIO_GAIN_TYPE_CAMCODING:         return "camcording";
98     case AUDIO_GAIN_TYPE_MIDI:              return "midi";
99     case AUDIO_GAIN_TYPE_BOOTING:           return "booting";
100     case AUDIO_GAIN_TYPE_VIDEO:             return "video";
101     case AUDIO_GAIN_TYPE_TTS:               return "tts";
102     default:                                return "invalid";
103     }
104 }
105
106 static void __dump_tb(audio_hal_s *ah)
107 {
108     audio_volume_value_table_s *volume_value_table = ah->volume.volume_value_table;
109     uint32_t vol_type_idx, vol_level_idx, gain_type_idx;
110     const char *gain_type_str[] = {
111         "def",          /* AUDIO_GAIN_TYPE_DEFAULT */
112         "dial",         /* AUDIO_GAIN_TYPE_DIALER */
113         "touch",        /* AUDIO_GAIN_TYPE_TOUCH */
114         "af",           /* AUDIO_GAIN_TYPE_AF */
115         "shut1",        /* AUDIO_GAIN_TYPE_SHUTTER1 */
116         "shut2",        /* AUDIO_GAIN_TYPE_SHUTTER2 */
117         "cam",          /* AUDIO_GAIN_TYPE_CAMCODING */
118         "midi",         /* AUDIO_GAIN_TYPE_MIDI */
119         "boot",         /* AUDIO_GAIN_TYPE_BOOTING */
120         "video",        /* AUDIO_GAIN_TYPE_VIDEO */
121         "tts",          /* AUDIO_GAIN_TYPE_TTS */
122     };
123     char dump_str[AUDIO_DUMP_STR_LEN], *dump_str_ptr;
124
125     /* Dump volume table */
126     AUDIO_LOG_INFO("<<<<< volume table >>>>>");
127
128     const char *table_str = "volumes";
129
130     AUDIO_LOG_INFO("<< %s >>", table_str);
131
132     for (vol_type_idx = 0; vol_type_idx < AUDIO_VOLUME_TYPE_MAX; vol_type_idx++) {
133         const char *vol_type_str = __get_volume_type_string_by_idx(vol_type_idx);
134
135         dump_str_ptr = &dump_str[0];
136         memset(dump_str, 0x00, sizeof(char) * sizeof(dump_str));
137         snprintf(dump_str_ptr, 8, "%6s:", vol_type_str);
138         dump_str_ptr += strlen(dump_str_ptr);
139
140         for (vol_level_idx = 0; vol_level_idx < ah->volume.volume_level_max[vol_type_idx]; vol_level_idx++) {
141             snprintf(dump_str_ptr, 6, "%01.2f ", volume_value_table->volume[vol_type_idx][vol_level_idx]);
142             dump_str_ptr += strlen(dump_str_ptr);
143         }
144         AUDIO_LOG_INFO("%s", dump_str);
145     }
146
147     volume_value_table = ah->volume.volume_value_table;
148
149     /* Dump gain table */
150     AUDIO_LOG_INFO("<<<<< gain table >>>>>");
151
152     dump_str_ptr = &dump_str[0];
153     memset(dump_str, 0x00, sizeof(char) * sizeof(dump_str));
154
155     snprintf(dump_str_ptr, 11, "%10s", " ");
156     dump_str_ptr += strlen(dump_str_ptr);
157
158     for (gain_type_idx = 0; gain_type_idx < AUDIO_GAIN_TYPE_MAX; gain_type_idx++) {
159         snprintf(dump_str_ptr, 7, "%5s ", gain_type_str[gain_type_idx]);
160         dump_str_ptr += strlen(dump_str_ptr);
161     }
162     AUDIO_LOG_INFO("%s", dump_str);
163
164     dump_str_ptr = &dump_str[0];
165     memset(dump_str, 0x00, sizeof(char) * sizeof(dump_str));
166
167     snprintf(dump_str_ptr, 11, "%9s:", table_str);
168     dump_str_ptr += strlen(dump_str_ptr);
169
170     for (gain_type_idx = 0; gain_type_idx < AUDIO_GAIN_TYPE_MAX; gain_type_idx++) {
171         snprintf(dump_str_ptr, 7, "%01.3f ", volume_value_table->gain[gain_type_idx]);
172         dump_str_ptr += strlen(dump_str_ptr);
173     }
174     AUDIO_LOG_INFO("%s", dump_str);
175
176 }
177
178 static audio_return_e __load_volume_value_table_from_ini(audio_hal_s *ah)
179 {
180     dictionary * dict = NULL;
181     uint32_t vol_type_idx, vol_level_idx, gain_type_idx;
182     audio_volume_value_table_s *volume_value_table = ah->volume.volume_value_table;
183     int size = 0;
184     const char delimiter[] = ", ";
185     const char *table_str = "volumes";
186     const char *tmp_str = NULL;
187     const char *gain_str = NULL;
188     char *list_str = NULL, *ptr = NULL;
189     char *key, *token;
190
191     if (access(VOLUME_INI_TEMP_PATH, F_OK) == 0)
192         dict = iniparser_load(VOLUME_INI_TEMP_PATH);
193     if (!dict) {
194         AUDIO_LOG_DEBUG("Use default volume&gain ini file");
195         dict = iniparser_load(VOLUME_INI_DEFAULT_PATH);
196         if (!dict) {
197             AUDIO_LOG_WARN("Loading volume&gain table from ini file failed");
198             return AUDIO_ERR_UNDEFINED;
199         }
200     }
201
202     /* Load volume table */
203     for (vol_type_idx = 0; vol_type_idx < AUDIO_VOLUME_TYPE_MAX; vol_type_idx++) {
204         const char *vol_type_str = __get_volume_type_string_by_idx(vol_type_idx);
205
206         ah->volume.volume_level_max[vol_type_idx] = 0;
207         size = strlen(table_str) + strlen(vol_type_str) + 2;
208         key = malloc(size);
209         if (key) {
210             snprintf(key, size, "%s:%s", table_str, vol_type_str);
211             if ((tmp_str = iniparser_getstring(dict, key, NULL)))
212                 list_str = strdup(tmp_str);
213
214             if (list_str) {
215                 token = strtok_r(list_str, delimiter, &ptr);
216                 while (token) {
217                     /* convert dB volume to linear volume */
218                     double vol_value = 0.0f;
219                     if (strncmp(token, "0", strlen(token)))
220                         vol_value = pow(10.0, (atof(token) - 100) / 20.0);
221                     volume_value_table->volume[vol_type_idx][ah->volume.volume_level_max[vol_type_idx]++] = vol_value;
222                     token = strtok_r(NULL, delimiter, &ptr);
223                 }
224                 free(list_str);
225                 list_str = NULL;
226             } else {
227                 ah->volume.volume_level_max[vol_type_idx] = 1;
228                 for (vol_level_idx = 0; vol_level_idx < AUDIO_VOLUME_LEVEL_MAX; vol_level_idx++) {
229                     volume_value_table->volume[vol_type_idx][vol_level_idx] = VOLUME_VALUE_MAX;
230                 }
231             }
232             free(key);
233         }
234     }
235
236     /* Load gain table */
237     volume_value_table->gain[AUDIO_GAIN_TYPE_DEFAULT] = GAIN_VALUE_MAX;
238     for (gain_type_idx = AUDIO_GAIN_TYPE_DEFAULT + 1; gain_type_idx < AUDIO_GAIN_TYPE_MAX; gain_type_idx++) {
239         const char *gain_type_str = __get_gain_type_string_by_idx(gain_type_idx);
240
241         size = strlen(table_str) + strlen("gain") + strlen(gain_type_str) + 3;
242         key = malloc(size);
243         if (key) {
244             snprintf(key, size, "%s:gain_%s", table_str, gain_type_str);
245             gain_str = iniparser_getstring(dict, key, NULL);
246             if (gain_str) {
247                 volume_value_table->gain[gain_type_idx] = atof(gain_str);
248             } else {
249                 volume_value_table->gain[gain_type_idx] = GAIN_VALUE_MAX;
250             }
251             free(key);
252         } else {
253             volume_value_table->gain[gain_type_idx] = GAIN_VALUE_MAX;
254         }
255     }
256
257     iniparser_freedict(dict);
258
259     __dump_tb(ah);
260
261     return AUDIO_RET_OK;
262 }
263
264 audio_return_e _audio_volume_init(audio_hal_s *ah)
265 {
266     int i;
267     int val = 0;
268     audio_return_e audio_ret = AUDIO_RET_OK;
269     int init_value[AUDIO_VOLUME_TYPE_MAX] = { 9, 11, 7, 11, 7, 4, 4, 7 };
270
271     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
272
273     for (i = 0; i < AUDIO_VOLUME_TYPE_MAX; i++) {
274         ah->volume.volume_level[i] = init_value[i];
275     }
276
277     for (i = 0; i < AUDIO_VOLUME_TYPE_MAX; i++) {
278         /* Get volume value string from VCONF */
279         if (vconf_get_int(g_volume_vconf[i], &val) < 0) {
280             AUDIO_LOG_ERROR("vconf_get_int(%s) failed", g_volume_vconf[i]);
281             continue;
282         }
283
284         AUDIO_LOG_INFO("read vconf. %s = %d", g_volume_vconf[i], val);
285         ah->volume.volume_level[i] = val;
286     }
287
288     if (!(ah->volume.volume_value_table = malloc(AUDIO_VOLUME_DEVICE_MAX * sizeof(audio_volume_value_table_s)))) {
289         AUDIO_LOG_ERROR("volume_value_table malloc failed");
290         return AUDIO_ERR_RESOURCE;
291     }
292
293     audio_ret = __load_volume_value_table_from_ini(ah);
294     if (audio_ret != AUDIO_RET_OK) {
295         AUDIO_LOG_ERROR("gain table load error");
296         return AUDIO_ERR_UNDEFINED;
297     }
298
299     return audio_ret;
300 }
301
302 audio_return_e _audio_volume_deinit(audio_hal_s *ah)
303 {
304     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
305
306     if (ah->volume.volume_value_table) {
307         free(ah->volume.volume_value_table);
308         ah->volume.volume_value_table = NULL;
309     }
310
311     return AUDIO_RET_OK;
312 }
313
314 audio_return_e audio_get_volume_level_max(void *audio_handle, audio_volume_info_s *info, uint32_t *level)
315 {
316     audio_hal_s *ah = (audio_hal_s *)audio_handle;
317
318     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
319     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
320     AUDIO_RETURN_VAL_IF_FAIL(level, AUDIO_ERR_PARAMETER);
321
322     /* Get max volume level by device & type */
323     *level = ah->volume.volume_level_max[__get_volume_idx_by_string_type(info->type)];
324
325     AUDIO_LOG_DEBUG("get_[%s] volume_level_max: %d", info->type, *level);
326
327     return AUDIO_RET_OK;
328 }
329
330 audio_return_e audio_get_volume_level(void *audio_handle, audio_volume_info_s *info, uint32_t *level)
331 {
332     audio_hal_s *ah = (audio_hal_s *)audio_handle;
333
334     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
335     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
336     AUDIO_RETURN_VAL_IF_FAIL(level, AUDIO_ERR_PARAMETER);
337
338     if (!strncmp(info->type, "master", strlen("master"))) {
339         *level = g_master_volume_level;
340         return AUDIO_RET_OK;
341     }
342
343     *level = ah->volume.volume_level[__get_volume_idx_by_string_type(info->type)];
344
345     AUDIO_LOG_INFO("get [%s] volume_level: %d, direction(%d)", info->type, *level, info->direction);
346
347     return AUDIO_RET_OK;
348 }
349
350 audio_return_e audio_get_volume_value(void *audio_handle, audio_volume_info_s *info, uint32_t level, double *value)
351 {
352     audio_hal_s *ah = (audio_hal_s *)audio_handle;
353     audio_volume_value_table_s *volume_value_table;
354     char dump_str[AUDIO_DUMP_STR_LEN] = {0,};
355
356     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
357     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
358     AUDIO_RETURN_VAL_IF_FAIL(value, AUDIO_ERR_PARAMETER);
359     AUDIO_RETURN_VAL_IF_FAIL(ah->volume.volume_value_table, AUDIO_ERR_PARAMETER);
360
361     /* Get basic volume by device & type & level */
362     volume_value_table = ah->volume.volume_value_table;
363     if (ah->volume.volume_level_max[__get_volume_idx_by_string_type(info->type)] < level)
364         *value = VOLUME_VALUE_MAX;
365     else
366         *value = volume_value_table->volume[__get_volume_idx_by_string_type(info->type)][level];
367     *value *= volume_value_table->gain[AUDIO_GAIN_TYPE_DEFAULT]; /* need to fix getting gain via audio_info_t */
368
369     AUDIO_LOG_DEBUG("get_volume_value:%d(%s)=>%f %s", level, info->type, *value, &dump_str[0]);
370
371     return AUDIO_RET_OK;
372 }
373
374 audio_return_e audio_set_volume_level(void *audio_handle, audio_volume_info_s *info, uint32_t level)
375 {
376     audio_return_e audio_ret = AUDIO_RET_OK;
377     audio_hal_s *ah = (audio_hal_s *)audio_handle;
378
379     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
380     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
381     if (!strncmp(info->type, "master", strlen("master"))) {
382         g_master_volume_level = level;
383         return AUDIO_RET_OK;
384     }
385     AUDIO_RETURN_VAL_IF_FAIL((ah->volume.volume_level_max[__get_volume_idx_by_string_type(info->type)] >= level), AUDIO_ERR_PARAMETER);
386
387     /* Update volume level */
388     ah->volume.volume_level[__get_volume_idx_by_string_type(info->type)] = level;
389     AUDIO_LOG_INFO("set [%s] volume_level: %d, direction(%d)", info->type, level, info->direction);
390
391     /* set mixer related to H/W volume if needed */
392
393     return audio_ret;
394 }
395
396 audio_return_e audio_get_volume_mute(void *audio_handle, audio_volume_info_s *info, uint32_t *mute)
397 {
398     audio_return_e audio_ret = AUDIO_RET_OK;
399     audio_hal_s *ah = (audio_hal_s *)audio_handle;
400
401     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
402     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
403     AUDIO_RETURN_VAL_IF_FAIL(mute, AUDIO_ERR_PARAMETER);
404
405     /* TODO. Not implemented */
406
407     return audio_ret;
408 }
409
410 audio_return_e audio_set_volume_mute(void *audio_handle, audio_volume_info_s *info, uint32_t mute)
411 {
412     audio_return_e audio_ret = AUDIO_RET_OK;
413     audio_hal_s *ah = (audio_hal_s *)audio_handle;
414
415     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
416     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
417
418     /* TODO. Not implemented */
419
420     return audio_ret;
421 }
422
423 #define COMPRESS_VOL_CTRL "ComprTx0 Volume"
424 #define MAX_VOL_VALUE (8192/4)
425 audio_return_e audio_set_volume_ratio(void *audio_handle, audio_stream_info_s *info, double ratio)
426 {
427     audio_return_e audio_ret = AUDIO_RET_OK;
428     audio_hal_s *ah = (audio_hal_s *)audio_handle;
429
430     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
431     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
432
433     AUDIO_LOG_INFO("set [%s] volume_ratio: %f, direction(%u), index(%u)", info->role, ratio, info->direction, info->idx);
434
435     /* NOTE: volume ratio can be 0.0~1.0, corresponding mixer control range is
436      0~8192. As the value matching will be part of tunning issue in the future,
437      we just set the value to '8192/4' multiplied by 'ratio' which seems fine */
438     if (!strcmp(info->role, "compressed-media"))
439         _mixer_control_set_value (ah, COMPRESS_VOL_CTRL, (int)(ratio * MAX_VOL_VALUE));
440
441     return audio_ret;
442 }
443
444 audio_return_e audio_notify_ducking_activation_changed(void *audio_handle, audio_ducking_info_s *info, uint32_t is_activated)
445 {
446     audio_return_e audio_ret = AUDIO_RET_OK;
447     audio_hal_s *ah = (audio_hal_s *)audio_handle;
448
449     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
450     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
451     AUDIO_RETURN_VAL_IF_FAIL(info->target_role, AUDIO_ERR_PARAMETER);
452
453     AUDIO_LOG_INFO("role:%s, duration:%u, ratio:%lf, is_activated:%u", info->target_role, info->duration, info->ratio, is_activated);
454
455     /* TODO. Not implemented */
456
457     return audio_ret;
458 }