feedback: Change feedback pattern data from list to GHashTable
[platform/core/system/libsvi.git] / src / sound.c
1 /*
2  * libfeedback
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18
19 #include <stdio.h>
20 #include <stdbool.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <assert.h>
27 #include <limits.h>
28 #include <vconf.h>
29 #include <mm_sound_private.h>
30 #include <sound_manager.h>
31 #include <wav_player.h>
32 #include <libsyscommon/ini-parser.h>
33 #include <libsyscommon/list.h>
34
35 #include "feedback-ids.h"
36 #include "profiles.h"
37 #include "devices.h"
38 #include "log.h"
39 #include "feedback-config.h"
40 #include "sound-parser.h"
41 #include "sound-theme-manager.h"
42
43 /* Temporary keys */
44 #ifndef VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL
45 #define VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL "db/setting/sound/button_sounds"
46 #endif
47
48 static int sndstatus;
49 static int touch_sndstatus;
50 static int keytone_sndstatus;
51 static unsigned int current_theme_id = 0;
52
53 static char *get_data(feedback_pattern_e pattern)
54 {
55         char *data;
56
57         if (pattern <= FEEDBACK_PATTERN_NONE ||
58             pattern >= profile->max_pattern)
59                 return NULL;
60
61         data = profile->get_path(pattern);
62         if (data)
63                 return data;
64
65         data = sound_thememan_get_pattern_sound_path(current_theme_id, pattern);
66         if (!data)
67                 _E("Not supported pattern : %d", pattern);
68
69         return data;
70 }
71
72 inline int is_sound_mode(void)
73 {
74         return sndstatus;
75 }
76
77 inline int is_touch_sndstatus(void)
78 {
79         return touch_sndstatus;
80 }
81
82 inline int is_keytone_sndstatus(void)
83 {
84         return keytone_sndstatus;
85 }
86
87 //LCOV_EXCL_START Not called Callback
88 static void feedback_sndstatus_cb(keynode_t *key, void* data)
89 {
90         sndstatus = vconf_keynode_get_bool(key);
91 }
92
93 static void feedback_touch_sndstatus_cb(keynode_t *key, void* data)
94 {
95         touch_sndstatus = vconf_keynode_get_bool(key);
96 }
97
98 static void feedback_keytone_sndstatus_cb(keynode_t *key, void* data)
99 {
100         keytone_sndstatus = vconf_keynode_get_bool(key);
101 }
102 //LCOV_EXCL_STOP
103
104 //LCOV_EXCL_START
105 static void feedback_sound_theme_changed_cb(keynode_t *key, void* data)
106 {
107         int vconf_sound_theme_id = vconf_keynode_get_int(key);
108
109         if (vconf_sound_theme_id <= 0) {
110                 current_theme_id = 0;
111                 return;
112         }
113
114         current_theme_id = vconf_keynode_get_int(key);
115 }
116 //LCOV_EXCL_STOP
117
118 static void sound_init(void)
119 {
120         int ret = 0;
121
122         current_theme_id = 0;
123
124         ret = sound_thememan_init();
125         if (ret < 0) {
126                 _E("Failed to initialize sound theme manager(%d)", ret);
127                 sound_thememan_exit();
128         }
129
130         ret = sound_parser_init();
131         if (ret < 0) {
132                 _E("Failed to parsing sound config file(%d)", ret);
133                 sound_thememan_exit();
134                 sound_parser_exit();
135         }
136
137         sound_thememan_get_default_sound_theme_id(&current_theme_id);
138         ret = vconf_set_int(VCONFKEY_SETAPPL_ACCESSIBILITY_SOUND_FEEDBACK_THEME, current_theme_id);
139
140         /* check sound status */
141         if (vconf_get_bool(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, &touch_sndstatus) < 0)
142                 _W("VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL ==> FAIL!!"); //LCOV_EXCL_LINE
143
144         if (vconf_get_bool(VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL, &keytone_sndstatus) < 0)
145                 _W("VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL ==> FAIL!!"); //LCOV_EXCL_LINE
146
147         if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sndstatus) < 0) {
148                 _D("fail to get sound status, will work as turning off"); //LCOV_EXCL_LINE
149                 sndstatus = 0; //LCOV_EXCL_LINE
150         }
151
152         /* add watch for status value */
153         ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, feedback_sndstatus_cb, NULL);
154         if (ret != 0)
155                 _W("Add watch for VCONFKEY_SETAPPL_SOUND_STATUS_BOOL failed"); //LCOV_EXCL_LINE
156         ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, feedback_touch_sndstatus_cb, NULL);
157         if (ret != 0)
158                 _W("Add watch for VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL failed"); //LCOV_EXCL_LINE
159         ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL, feedback_keytone_sndstatus_cb, NULL);
160         if (ret != 0)
161                 _W("Add watch for VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL failed"); //LCOV_EXCL_LINE
162         ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_SOUND_FEEDBACK_THEME, feedback_sound_theme_changed_cb, NULL);
163         if (ret != 0)
164                 _W("Add watch for VCONFKEY_SETAPPL_ACCESSIBILITY_SOUND_FEEDBACK_THEME failed"); //LCOV_EXCL_LINE
165 }
166
167 static void sound_exit(void)
168 {
169         int ret;
170
171         sound_parser_exit();
172         sound_thememan_exit();
173
174         /* remove watch */
175         ret = vconf_ignore_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, feedback_sndstatus_cb);
176         if (ret != 0)
177                 _W("Remove watch for VCONFKEY_SETAPPL_SOUND_STATUS_BOOL failed"); //LCOV_EXCL_LINE
178
179         ret = vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, feedback_touch_sndstatus_cb);
180         if (ret != 0)
181                 _W("Remove watch for VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL failed"); //LCOV_EXCL_LINE
182         ret = vconf_ignore_key_changed(VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL, feedback_keytone_sndstatus_cb);
183         if (ret != 0)
184                 _W("Remove watch for VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL failed"); //LCOV_EXCL_LINE
185         ret = vconf_ignore_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_SOUND_FEEDBACK_THEME, feedback_sound_theme_changed_cb);
186         if (ret != 0)
187                 _W("Remove watch for VCONFKEY_SETAPPL_ACCESSIBILITY_SOUND_FEEDBACK_THEME failed"); //LCOV_EXCL_LINE
188
189 }
190
191 //LCOV_EXCL_START
192 static void play_completed(int id, void *data)
193 {
194         int ret;
195         sound_stream_info_h stream_info = (sound_stream_info_h)data;
196
197         ret = sound_manager_destroy_stream_information(stream_info);
198         if (ret != SOUND_MANAGER_ERROR_NONE)
199                 _E("Failed to set session to play sound(%d)", ret); //LCOV_EXCL_LINE
200 }
201 //LCOV_EXCL_STOP
202
203 static int sound_play(feedback_pattern_e pattern, bool always)
204 {
205         struct stat buf;
206         int retry = FEEDBACK_RETRY_CNT, ret;
207         sound_stream_info_h stream_info;
208         char *path;
209         int level;
210
211         if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sndstatus) < 0) {
212                 _D("fail to get sound status, will work as turning off"); //LCOV_EXCL_LINE
213                 sndstatus = 0; //LCOV_EXCL_LINE
214         }
215
216         if (always) {
217                 _W("Always on condition(pattern %s)", profile->str_pattern(pattern)); //LCOV_EXCL_LINE
218                 goto check_pattern;
219         }
220
221         if (sndstatus == 0 && profile->get_always_alert_case &&
222             !profile->get_always_alert_case(FEEDBACK_TYPE_SOUND, pattern)) {
223                 _D("Sound condition is OFF (sndstatus : %d)", sndstatus); //LCOV_EXCL_LINE
224                 return 0;
225         }
226
227         if (sndstatus && profile->get_always_off_case &&
228             profile->get_always_off_case(FEEDBACK_TYPE_SOUND, pattern)) {
229                 _D("Sound always off condition(pattern %s)", profile->str_pattern(pattern)); //LCOV_EXCL_LINE
230                 return 0;
231         }
232
233 check_pattern:
234         /* get sound file path */
235         path = get_data(pattern);
236         if (!path || stat(path, &buf)) {
237                 //LCOV_EXCL_START
238                 _E("Not supported sound pattern(pattern %d)", pattern); //LCOV_EXCL_LINE
239                 return -ENOTSUP;
240                 //LCOV_EXCL_STOP
241         }
242
243         /* play sound file */
244         if (profile->is_notification_type && profile->is_notification_type(pattern)) {
245                 ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_NOTIFICATION,
246                 NULL, NULL, &stream_info);
247                 if (ret != SOUND_MANAGER_ERROR_NONE) {
248                         //LCOV_EXCL_START
249                         _E("Failed to set session to play sound(%d)", ret);
250                         return -ENOENT;
251                         //LCOV_EXCL_STOP
252                 }
253                 do {
254                         ret = wav_player_start_new(path, stream_info, play_completed, stream_info, NULL);
255                         if (ret == WAV_PLAYER_ERROR_NONE) {
256                                 _D("Wav Play success! SND filename is %s", path); //LCOV_EXCL_LINE
257                                 return 0;
258                         }
259                         _E("Failed to play sound file (%d, %s)", ret, path); //LCOV_EXCL_LINE
260                 } while (retry--); //LCOV_EXCL_LINE
261         } else {
262                 do {
263                         if (profile->get_strength_type)
264                                 level = profile->get_strength_type(FEEDBACK_TYPE_SOUND, pattern);
265                         else
266                                 level = VOLUME_TYPE_SYSTEM;
267
268                         ret = mm_sound_play_keysound(path, level);
269                         if (ret == MM_ERROR_NONE) {
270                                 _D("Play success! %s(%s)", profile->str_pattern(pattern), path);
271                                 return 0;
272                         }
273                         _E("mm_sound_play_keysound() returned error(%d)", ret); //LCOV_EXCL_LINE
274                 } while (retry--); //LCOV_EXCL_LINE
275         }
276         return -EPERM;
277 }
278
279 //LCOV_EXCL_START
280 static int sound_play_path(feedback_pattern_e pattern, const char *soundpath, bool always)
281 {
282         struct stat buf;
283         int retry = FEEDBACK_RETRY_CNT, ret;
284         sound_stream_info_h stream_info;
285         int level;
286
287         if (!soundpath || stat(soundpath, &buf)) {
288                 if (!soundpath) //LCOV_EXCL_LINE
289                         _E("Not supported sound pattern(pattern %d)", pattern); //LCOV_EXCL_LINE
290                 else
291                         _E("Not supported sound pattern(soundpath %s of pattern %s)", soundpath, profile->str_pattern(pattern)); //LCOV_EXCL_LINE
292                 return -ENOTSUP; //LCOV_EXCL_LINE
293         }
294
295         if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sndstatus) < 0) {
296                 _D("fail to get sound status, will work as turning off"); //LCOV_EXCL_LINE
297                 sndstatus = 0; //LCOV_EXCL_LINE
298         }
299
300         if (always) {
301                 _W("Always on condition(pattern %s)", profile->str_pattern(pattern)); //LCOV_EXCL_LINE
302                 goto check_pattern;
303         }
304
305         if (sndstatus == 0 && profile->get_always_alert_case &&
306             !profile->get_always_alert_case(FEEDBACK_TYPE_SOUND, pattern)) {
307                 _D("Sound condition is OFF (sndstatus : %d)", sndstatus); //LCOV_EXCL_LINE
308                 return 0;
309         }
310
311         if (sndstatus && profile->get_always_off_case &&
312             profile->get_always_off_case(FEEDBACK_TYPE_SOUND, pattern)) {
313                 _D("Sound always off condition(pattern %s)", profile->str_pattern(pattern)); //LCOV_EXCL_LINE
314                 return 0;
315         }
316
317 check_pattern:
318         /* play sound file */
319         if (profile->is_notification_type && profile->is_notification_type(pattern)) {
320                 ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_NOTIFICATION,
321                 NULL, NULL, &stream_info);
322                 if (ret != SOUND_MANAGER_ERROR_NONE) {
323                         _E("Failed to set session to play sound(%d)", ret); //LCOV_EXCL_LINE
324                         return -ENOENT;
325                 }
326                 do {
327             ret = wav_player_start_new(soundpath, stream_info, play_completed, stream_info, NULL);
328                         if (ret == WAV_PLAYER_ERROR_NONE) {
329                 _D("Wav Play success! SND filename is %s", soundpath); //LCOV_EXCL_LINE
330                                 return 0; //LCOV_EXCL_LINE
331                         }
332             _E("Failed to play sound file (%d, %s)", ret, soundpath); //LCOV_EXCL_LINE
333                 } while (retry--); //LCOV_EXCL_LINE
334         } else {
335                 do {
336                         if (profile->get_strength_type)
337                                 level = profile->get_strength_type(FEEDBACK_TYPE_SOUND, pattern);
338                         else
339                                 level = VOLUME_TYPE_SYSTEM;
340
341                         ret = mm_sound_play_keysound(soundpath, level);
342                         if (ret == MM_ERROR_NONE) {
343                                 _D("Play success! %s(%s)", profile->str_pattern(pattern), soundpath);
344                                 return 0;
345                         }
346                         _E("mm_sound_play_keysound(\'%s\') returned error(%d)", soundpath, ret); //LCOV_EXCL_LINE
347                 } while (retry--); //LCOV_EXCL_LINE
348         }
349         return -EPERM;
350 }
351 //LCOV_EXCL_STOP
352
353 static int sound_is_supported(feedback_pattern_e pattern, bool *supported)
354 {
355         struct stat buf;
356         char *path;
357         bool ret = true;
358
359         if (!supported) {
360                 _E("Invalid parameter : supported(NULL)"); //LCOV_EXCL_LINE
361                 return -EINVAL; //LCOV_EXCL_LINE
362         }
363
364         /* get sound file path */
365         path = get_data(pattern);
366         if (!path || stat(path, &buf)) {
367                 _D("%d is not presents", pattern);
368                 ret = false;
369         }
370
371         *supported = ret;
372         return 0;
373 }
374
375 static int sound_stop(void)
376 {
377         int ret;
378
379         /**
380         * @param        filename        [in] keytone filename to stop (can be null if whole exist keytones needs stops)
381         * int mm_sound_stop_keysound(const char *filename);
382         */
383         ret = mm_sound_stop_keysound(NULL);
384         if (ret == MM_ERROR_NONE)       {
385                 _D("stop success!");
386                 return 0;
387         }
388         _E("mm_sound_stop_keysound() returned error(%d)", ret); //LCOV_EXCL_LINE
389         return ret; //LCOV_EXCL_LINE
390 }
391
392 //LCOV_EXCL_START Not used function
393 static int sound_get_path(feedback_pattern_e pattern, char *buf, unsigned int buflen)
394 {
395         char *cur_path;
396         int ret = 0;
397
398         if (!buf || buflen == 0)
399                 return -EINVAL;
400
401         /* get sound file path */
402         cur_path = get_data(pattern);
403         if (!cur_path) {
404                 _E("This pattern(%s) in sound type is not supported to play",
405                                 profile->str_pattern(pattern));
406                 cur_path = "NULL";
407                 ret = -ENOENT;
408         }
409
410         snprintf(buf, buflen, "%s", cur_path);
411         return ret;
412 }
413 //LCOV_EXCL_STOP
414
415 //LCOV_EXCL_START
416 static int sound_get_count_of_theme(unsigned int *count_of_theme)
417 {
418         int ret = 0;
419         if (!count_of_theme)
420                 return -EINVAL;
421
422         ret = sound_thememan_get_number_of_theme(count_of_theme);
423         if (ret < 0)
424                 return -EPERM;
425
426         return 0;
427 }
428 //LCOV_EXCL_STOP
429
430 static int sound_get_theme_id(unsigned int *id_of_theme)
431 {
432         if (!id_of_theme)
433                 return -EINVAL;
434
435         *id_of_theme = current_theme_id;
436
437         return 0;
438 }
439 //LCOV_EXCL_STOP
440
441 static int sound_set_theme_id(unsigned int id_of_theme)
442 {
443         int ret = 0;
444
445         if (!sound_thememan_is_sound_theme_id_exist(id_of_theme))
446                 return -EINVAL;
447
448         ret = vconf_set_int(VCONFKEY_SETAPPL_ACCESSIBILITY_SOUND_FEEDBACK_THEME, id_of_theme);
449         if (ret < 0) {
450                 _E("Failed to set vconf value for VCONFKEY_SETAPPL_ACCESSIBILITY_SOUND_FEEDBACK_THEME");
451                 return -EPERM;
452         }
453
454         current_theme_id = id_of_theme;
455
456         return 0;
457 }
458 //LCOV_EXCL_STOP
459
460 static int sound_get_theme_ids(unsigned int *count_of_theme, unsigned int **theme_ids)
461 {
462         int ret = 0;
463
464         if (!count_of_theme || !theme_ids)
465                 return -EINVAL;
466
467         ret = sound_thememan_get_sound_theme_ids(count_of_theme, theme_ids);
468         if (ret < 0)
469                 return -EPERM;
470
471         return 0;
472 }
473
474 static const struct device_ops sound_device_ops = {
475         .type = FEEDBACK_TYPE_SOUND,
476         .name = "Sound",
477         .init = sound_init,
478         .exit = sound_exit,
479         .play = sound_play,
480         .play_path = sound_play_path,
481         .stop = sound_stop,
482         .is_supported = sound_is_supported,
483         .get_path = sound_get_path,
484         .set_path = NULL,
485         .get_count_of_theme = sound_get_count_of_theme,
486         .get_theme_id = sound_get_theme_id,
487         .set_theme_id = sound_set_theme_id,
488         .get_theme_ids = sound_get_theme_ids,
489 };
490
491 DEVICE_OPS_REGISTER(&sound_device_ops);