f1dbd1bd8f5d0bc0dbedb5eb0bbbb978dac15662
[platform/core/system/libsvi.git] / src / feedback-internal.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 <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <mm_sound_private.h>
27 #include <vconf.h>
28 #include <haptic.h>
29 #include <fcntl.h>
30 #include <errno.h>
31
32 #include "feedback.h"
33 #include "feedback-internal.h"
34 #include "feedback-file.h"
35 #include "feedback-str.h"
36 #include "feedback-log.h"
37 #include "xmlparser.h"
38
39 #define FEEDBACK_RETRY_CNT       1
40 #define MAX_FILE_PATH          512
41
42 #define DEFAULT_FEEDBACK_HANDLE         0x0F
43
44 #define VIBRATION_XML                           "/usr/share/feedback/vibration.xml"
45
46 typedef struct {
47         haptic_device_h v_handle;
48         xmlDocPtr v_doc;
49 } FEEDBACK_HANDLE;
50
51 static int sndstatus;
52 static int touch_sndstatus;
53 static int soundon;
54 static int vibstatus;
55 static int vib_level;
56 static int noti_level;
57 static int callstatus;
58
59 static void feedback_sndstatus_cb(keynode_t *key, void* data)
60 {
61         sndstatus = vconf_keynode_get_bool(key);
62 }
63
64 static void feedback_touch_sndstatus_cb(keynode_t *key, void* data)
65 {
66         touch_sndstatus = vconf_keynode_get_bool(key);
67 }
68
69 static void feedback_soundon_cb(keynode_t *key, void* data)
70 {
71         soundon = vconf_keynode_get_int(key);
72 }
73
74 static void feedback_vibstatus_cb(keynode_t *key, void* data)
75 {
76         vibstatus = vconf_keynode_get_bool(key);
77 }
78
79 static void feedback_vib_cb(keynode_t *key, void* data)
80 {
81         vib_level = vconf_keynode_get_int(key);
82 }
83
84 static void feedback_noti_cb(keynode_t *key, void* data)
85 {
86         noti_level = vconf_keynode_get_int(key);
87 }
88
89
90 static void feedback_callstatus_cb(keynode_t *key, void* data)
91 {
92         callstatus = vconf_keynode_get_int(key);
93 }
94
95 static feedback_pattern_e feedback_get_alert_on_call_key(feedback_pattern_e pattern)
96 {
97         switch(pattern) {
98         case FEEDBACK_PATTERN_MESSAGE:
99         case FEEDBACK_PATTERN_EMAIL:
100         case FEEDBACK_PATTERN_WAKEUP:
101         case FEEDBACK_PATTERN_SCHEDULE:
102         case FEEDBACK_PATTERN_TIMER:
103         case FEEDBACK_PATTERN_GENERAL:
104         case FEEDBACK_PATTERN_CHARGERCONN:
105         case FEEDBACK_PATTERN_FULLCHARGED:
106         case FEEDBACK_PATTERN_LOWBATT:
107                 return (feedback_pattern_e)(pattern+1);
108         default:
109                 break;
110         }
111
112         return pattern;
113 }
114
115 static haptic_priority_e feedback_get_priority(feedback_pattern_e pattern)
116 {
117         if (pattern >= FEEDBACK_PATTERN_TAP && pattern <= FEEDBACK_PATTERN_HW_HOLD)
118                 return HAPTIC_PRIORITY_MIN;
119
120         return HAPTIC_PRIORITY_MIDDLE;
121 }
122
123 static volume_type_t feedback_get_volume_type(feedback_pattern_e pattern)
124 {
125         if (pattern == FEEDBACK_PATTERN_TAP)
126                 return VOLUME_TYPE_SYSTEM|VOLUME_GAIN_TOUCH;
127         else if (pattern >= FEEDBACK_PATTERN_KEY0 && pattern <= FEEDBACK_PATTERN_KEY_SHARP)
128                 return VOLUME_TYPE_SYSTEM|VOLUME_GAIN_DIALER;
129         else if (pattern == FEEDBACK_PATTERN_VOLUME_KEY)
130                 return VOLUME_TYPE_RINGTONE;
131
132         return VOLUME_TYPE_SYSTEM;
133 }
134
135 static int feedback_get_haptic_level(feedback_pattern_e pattern)
136 {
137         int level = -1;
138
139         if (pattern >= FEEDBACK_PATTERN_MESSAGE && pattern <= FEEDBACK_PATTERN_GENERAL_ON_CALL)
140                 level = noti_level;
141         else
142                 level = vib_level;
143
144         FEEDBACK_LOG("Call status : %d, pattern : %s, level : %d", callstatus, str_pattern[pattern], level);
145         if (callstatus != VCONFKEY_CALL_OFF) {
146                 // if call status is ON, vibration magnitude is 20%
147                 level = (int)(level*0.2f);
148                 level = (level < 1) ? 1 : level;
149                 FEEDBACK_LOG("level changed : %d", level);
150         }
151
152         level = level * 20;
153         return level;
154 }
155
156 static bool feedback_get_always_alert_case(feedback_pattern_e pattern)
157 {
158         switch(pattern) {
159         case FEEDBACK_PATTERN_WAKEUP:
160         case FEEDBACK_PATTERN_WAKEUP_ON_CALL:
161                 return true;
162         default:
163                 break;
164         }
165         return false;
166 }
167
168 static int feedback_get_data(xmlDocPtr doc, feedback_pattern_e pattern, struct xmlData **data)
169 {
170         xmlNodePtr cur;
171         struct xmlData *retData;
172
173         cur = xml_find(doc, (const xmlChar*)str_pattern[pattern]);
174         if (cur == NULL) {
175                 FEEDBACK_ERROR("xml_find fail");
176                 return -1;
177         }
178
179         retData = xml_parse(doc, cur);
180         if (retData == NULL) {
181                 FEEDBACK_ERROR("xml_parse fail");
182                 return -1;
183         }
184
185         *data = retData;
186         return 0;
187 }
188
189 static void feedback_release_data(struct xmlData *data)
190 {
191         if (data == NULL)
192                 return;
193
194         xml_free(data);
195 }
196
197 static int feedback_change_symlink(const char *sym_path, const char *new_path)
198 {
199         struct stat buf;
200
201         if (sym_path == NULL || strlen(sym_path) == 0) {
202                 FEEDBACK_ERROR("Invalid parameter : sym_path(NULL)");
203                 return FEEDBACK_ERROR_INVALID_PARAMETER;
204         }
205
206         if (new_path == NULL || strlen(new_path) == 0) {
207                 FEEDBACK_ERROR("Invalid paramter : new_path(NULL)");
208                 return FEEDBACK_ERROR_INVALID_PARAMETER;
209         }
210
211         // check symbolic link file existence
212         if (stat(sym_path, &buf)) {
213                 FEEDBACK_ERROR("file(%s) is not presents", sym_path);
214                 return FEEDBACK_ERROR_OPERATION_FAILED;
215         }
216
217         if (unlink(sym_path) < 0) {
218                 FEEDBACK_LOG("unlink(%s) : %s", sym_path, strerror(errno));
219         }
220
221         if (symlink(new_path, sym_path) < 0) {
222                 FEEDBACK_ERROR("symlink(%s) : %s", sym_path, strerror(errno));
223                 return FEEDBACK_ERROR_OPERATION_FAILED;
224         }
225
226         return FEEDBACK_ERROR_NONE;
227 }
228
229 static int feedback_restore_default_file(feedback_type_e type, feedback_pattern_e pattern)
230 {
231         const char *cur_path = NULL;
232         char default_path[MAX_FILE_PATH] = {0,};
233         char *temp = NULL;
234         int ret = -1;
235
236         if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
237                 FEEDBACK_ERROR("Invalid parameter : type(%s)", str_type[type]);
238                 return FEEDBACK_ERROR_INVALID_PARAMETER;
239         }
240
241         if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
242                 FEEDBACK_ERROR("Invalid parameter : pattern(%s)", str_pattern[pattern]);
243                 return FEEDBACK_ERROR_INVALID_PARAMETER;
244         }
245
246         if (type == FEEDBACK_TYPE_SOUND) {
247                 cur_path = snd_file[pattern];
248         } else {
249                 cur_path = haptic_file[pattern];
250         }
251
252         // if there isn't cur_path, it already returns before calling this api
253         if (cur_path == NULL || strlen(cur_path) == 0) {
254                 FEEDBACK_ERROR("Invalid parameter : cur_path(NULL)");
255                 return FEEDBACK_ERROR_OPERATION_FAILED;
256         }
257
258         temp = strcat(default_path, FEEDBACK_ORIGIN_DATA_DIR);
259         strcat(temp, cur_path+strlen(FEEDBACK_DATA_DIR));
260         FEEDBACK_LOG("default_path : %s", default_path);
261
262         ret = feedback_change_symlink(cur_path, default_path);
263         if (FEEDBACK_FAILED(ret)) {
264                 FEEDBACK_ERROR("change_symlink is failed");
265                 return FEEDBACK_ERROR_OPERATION_FAILED;
266         }
267
268         return FEEDBACK_ERROR_NONE;
269 }
270
271 int feedback_init(feedback_h *handle)
272 {
273         FEEDBACK_HANDLE *phandle;
274         haptic_device_h v_handle;
275         xmlDocPtr v_doc;
276         int ret;
277
278         /* Sound Init */
279         if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sndstatus) < 0) {
280                 FEEDBACK_ERROR("vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sndstatus) ==> FAIL!!");
281                 return FEEDBACK_ERROR_OPERATION_FAILED;
282         }
283
284         if (vconf_get_bool(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, &touch_sndstatus) < 0) {
285                 FEEDBACK_ERROR("vconf_get_bool(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, &touch_sndstatus) ==> FAIL!!");
286                 return FEEDBACK_ERROR_OPERATION_FAILED;
287         }
288
289         if (vconf_get_int(VCONFKEY_SOUND_STATUS, &soundon) < 0) {
290                 FEEDBACK_ERROR("vconf_get_int(VCONFKEY_SOUND_STATUS, &soundon) ==> FAIL!!");
291                 return FEEDBACK_ERROR_OPERATION_FAILED;
292         }
293
294         /* check vibration status */
295         if (vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) < 0) {
296                 FEEDBACK_ERROR("vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) ==> FAIL!!");
297                 return FEEDBACK_ERROR_OPERATION_FAILED;
298         }
299
300         /* check vib_level */
301         if (vconf_get_int(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, &vib_level) < 0) {
302                 FEEDBACK_ERROR("vconf_get_int(VCONFKEY_FEEDBACK_VIBRATION_LEVEL_INT, &vib_level) ==> FAIL!!");
303                 return FEEDBACK_ERROR_OPERATION_FAILED;
304         }
305
306         /* check noti_level */
307         if (vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, &noti_level) < 0) {
308                 FEEDBACK_ERROR("vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, &noti_level) ==> FAIL!!");
309                 return FEEDBACK_ERROR_OPERATION_FAILED;
310         }
311
312         /* check call status */
313         if (vconf_get_int(VCONFKEY_CALL_STATE, &callstatus) < 0) {
314                 FEEDBACK_ERROR("vconf_get_int(VCONFKEY_CALL_STATE, &callstatus) ==> FAIL!!");
315                 return FEEDBACK_ERROR_OPERATION_FAILED;
316         }
317
318         /* xml Init */
319         v_doc = xml_open(VIBRATION_XML);
320         if (v_doc == NULL) {
321                 FEEDBACK_ERROR("xml_open(%s) fail", VIBRATION_XML);
322                 return FEEDBACK_ERROR_OPERATION_FAILED;
323         }
324
325         /* Vibration Init */
326         ret = haptic_open(HAPTIC_DEVICE_ALL, &v_handle);
327         if (ret != HAPTIC_ERROR_NONE) {
328                 FEEDBACK_ERROR("haptic_open(HAPTIC_DEVICE_ALL, &v_handle) ==> FAIL!! : %d", ret);
329                 v_handle = (haptic_device_h)DEFAULT_FEEDBACK_HANDLE;
330         }
331
332         /* add watch for status value */
333         vconf_notify_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, feedback_sndstatus_cb, NULL);
334         vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, feedback_touch_sndstatus_cb, NULL);
335         vconf_notify_key_changed(VCONFKEY_SOUND_STATUS, feedback_soundon_cb, NULL);
336         vconf_notify_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, feedback_vibstatus_cb, NULL);
337         vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, feedback_vib_cb, NULL);
338         vconf_notify_key_changed(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, feedback_noti_cb, NULL);
339         vconf_notify_key_changed(VCONFKEY_CALL_STATE, feedback_callstatus_cb, NULL);
340
341         FEEDBACK_LOG("vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sndstatus) ==> %d", sndstatus);
342         FEEDBACK_LOG("vconf_get_bool(VCONFKEY_SETAPPL_....UNDS_BOOL, &touch_sndstatus) ==> %d", touch_sndstatus);
343         FEEDBACK_LOG("vconf_get_int(VCONFKEY_SOUND_STATUS, &soundon) ==> %d", soundon);
344         FEEDBACK_LOG("vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) ==> %d", vibstatus);
345         FEEDBACK_LOG("vconf_get_int(VCONFKEY_FEEDBACK_VIBRATION_LEVEL_INT, &vib_level) ==> %d", vib_level);
346         FEEDBACK_LOG("vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, &noti_level) ==> %d", noti_level);
347         FEEDBACK_LOG("vconf_get_int(VCONFKEY_CALL_STATUS, &callstatus) ==> %d", callstatus);
348
349         phandle = (FEEDBACK_HANDLE *)malloc(sizeof(FEEDBACK_HANDLE));
350         phandle->v_handle = v_handle;
351         phandle->v_doc = v_doc;
352         *handle = (feedback_h)phandle;
353         FEEDBACK_LOG("handle value : %x", handle);
354         return FEEDBACK_ERROR_NONE;
355 }
356
357 int feedback_fini(feedback_h handle)
358 {
359         FEEDBACK_HANDLE *phandle = (FEEDBACK_HANDLE *)handle;
360         int ret = -1;
361
362         if (!handle) {
363                 FEEDBACK_ERROR("Invalid parameter : handle(NULL)");
364                 return FEEDBACK_ERROR_INVALID_PARAMETER;
365         }
366
367         if (phandle->v_handle != DEFAULT_FEEDBACK_HANDLE) {
368                 ret = haptic_close(phandle->v_handle);
369                 if (ret != HAPTIC_ERROR_NONE) {
370                         FEEDBACK_ERROR("haptic_close is failed : %d", ret);
371                 }
372         }
373
374         if (phandle->v_doc) {
375                 xml_close(phandle->v_doc);
376         }
377
378         free(phandle);
379
380         vconf_ignore_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, feedback_sndstatus_cb);
381         vconf_ignore_key_changed(VCONFKEY_SOUND_STATUS, feedback_soundon_cb);
382         vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, feedback_touch_sndstatus_cb);
383         vconf_ignore_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, feedback_vibstatus_cb);
384         vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, feedback_vib_cb);
385         vconf_ignore_key_changed(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, feedback_noti_cb);
386         vconf_ignore_key_changed(VCONFKEY_CALL_STATE, feedback_callstatus_cb);
387
388         return FEEDBACK_ERROR_NONE;
389 }
390
391 int feedback_play_sound(feedback_h handle, feedback_pattern_e pattern)
392 {
393         int ret = -1;
394         int retry = FEEDBACK_RETRY_CNT;
395         struct stat buf;
396
397         if (!handle) {
398                 FEEDBACK_ERROR("Invalid parameter : handle(NULL)");
399                 return FEEDBACK_ERROR_INVALID_PARAMETER;
400         }
401
402         if (sndstatus == 0 && !feedback_get_always_alert_case(pattern)) {
403                 FEEDBACK_LOG("Sound condition is OFF (sndstatus : %d)", sndstatus);
404                 return FEEDBACK_ERROR_NONE;
405         }
406
407         if (soundon == 1 && pattern >= FEEDBACK_PATTERN_TAP && pattern <= FEEDBACK_PATTERN_HW_HOLD) {
408                 FEEDBACK_LOG("Touch feedback sound doesn't work during playing sound");
409                 return FEEDBACK_ERROR_NONE;
410         }
411
412         if (touch_sndstatus == 0 && pattern >= FEEDBACK_PATTERN_TAP && pattern <= FEEDBACK_PATTERN_HW_HOLD) {
413                 FEEDBACK_LOG("Touch Sound condition is OFF and pattern is touch type (touch_sndstatus : %d, pattern : %s)", touch_sndstatus, str_pattern[pattern]);
414                 return FEEDBACK_ERROR_NONE;
415         }
416
417         if (callstatus != VCONFKEY_CALL_OFF) {
418                 pattern = feedback_get_alert_on_call_key(pattern);
419                 FEEDBACK_LOG("Call status is connected or connecting. pattern changed : %s", str_pattern[pattern]);
420         }
421
422         if (snd_file[pattern] == NULL) {
423                 FEEDBACK_LOG("This case(%s) does not play sound", str_pattern[pattern]);
424                 return FEEDBACK_ERROR_NONE;
425         }
426
427         if (stat(snd_file[pattern], &buf)) {
428                 FEEDBACK_ERROR("%s is not presents", snd_file[pattern]);
429                 ret = feedback_restore_default_file(FEEDBACK_TYPE_SOUND, pattern);
430                 if (FEEDBACK_FAILED(ret)) {
431                         FEEDBACK_ERROR("feedback_restore_default_file(%s) error", str_pattern[pattern]);
432                         return FEEDBACK_ERROR_OPERATION_FAILED;
433                 }
434                 FEEDBACK_LOG("%s is restored", snd_file[pattern]);
435         }
436
437         do {
438                 ret = mm_sound_play_keysound(snd_file[pattern], feedback_get_volume_type(pattern));
439                 if (ret == MM_ERROR_NONE) {
440                         FEEDBACK_LOG("Play success! SND filename is %s", snd_file[pattern]);
441                         return FEEDBACK_ERROR_NONE;
442                 }
443                 FEEDBACK_ERROR("mm_sound_play_keysound() returned error(%d)", ret);
444         } while(retry--);
445
446         return FEEDBACK_ERROR_OPERATION_FAILED;
447 }
448
449 int feedback_play_vibration(feedback_h handle, feedback_pattern_e pattern)
450 {
451         FEEDBACK_HANDLE *phandle = (FEEDBACK_HANDLE *)handle;
452         int ret;
453         struct stat buf;
454         struct xmlData *data;
455
456         if (!handle) {
457                 FEEDBACK_ERROR("Invalid parameter : handle(NULL)");
458                 return FEEDBACK_ERROR_INVALID_PARAMETER;
459         }
460
461         if (handle == DEFAULT_FEEDBACK_HANDLE) {
462                 FEEDBACK_ERROR("haptic is not initialized");
463                 return FEEDBACK_ERROR_OPERATION_FAILED;
464         }
465
466         if (vibstatus == 0 && !feedback_get_always_alert_case(pattern))  {
467                 FEEDBACK_LOG("Vibration condition is OFF (vibstatus : %d)", vibstatus);
468                 return FEEDBACK_ERROR_NONE;
469         }
470
471         if (callstatus != VCONFKEY_CALL_OFF) {
472                 pattern = feedback_get_alert_on_call_key(pattern);
473                 FEEDBACK_LOG("Call status is connected or connecting. pattern changed : %s", str_pattern[pattern]);
474         }
475
476         ret = feedback_get_data(phandle->v_doc, pattern, &data);
477         if (ret < 0) {
478                 FEEDBACK_ERROR("feedback_get_vibration_data fail");
479                 return FEEDBACK_ERROR_OPERATION_FAILED;
480         }
481
482         if (data->data == NULL) {
483                 FEEDBACK_LOG("This case(%s) does not play vibration", str_pattern[pattern]);
484                 feedback_release_data(data);
485                 return FEEDBACK_ERROR_NONE;
486         }
487
488         /* play haptic buffer */
489         ret = haptic_vibrate_buffer_with_detail(phandle->v_handle, data->data, HAPTIC_ITERATION_ONCE,
490                                         feedback_get_haptic_level(pattern), feedback_get_priority(pattern), NULL);
491         if (ret != HAPTIC_ERROR_NONE) {
492                 FEEDBACK_ERROR("haptic_vibrate_buffer_with_detail is failed");
493                 feedback_release_data(data);
494                 return FEEDBACK_ERROR_OPERATION_FAILED;
495         }
496
497         feedback_release_data(data);
498         return FEEDBACK_ERROR_NONE;
499 }
500
501 int feedback_set_path(feedback_type_e type, feedback_pattern_e pattern, char* path)
502 {
503         const char* cur_path = NULL;
504         int ret = -1;
505
506         if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
507                 FEEDBACK_ERROR("Invalid parameter : type(%s)", str_type[type]);
508                 return FEEDBACK_ERROR_INVALID_PARAMETER;
509         }
510
511         if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
512                 FEEDBACK_ERROR("Invalid parameter : pattern(%s)", str_pattern[pattern]);
513                 return FEEDBACK_ERROR_INVALID_PARAMETER;
514         }
515
516         if (path == NULL) {
517                 FEEDBACK_ERROR("Invalid parameter : path(NULL)");
518                 return FEEDBACK_ERROR_INVALID_PARAMETER;
519         }
520
521         if (access(path, F_OK) != 0) {
522                 FEEDBACK_ERROR("Invalid parameter : path does not exist");
523                 return FEEDBACK_ERROR_INVALID_PARAMETER;
524         }
525
526         if (type == FEEDBACK_TYPE_SOUND) {
527                 cur_path = snd_file[pattern];
528         } else {
529                 cur_path = haptic_file[pattern];
530         }
531
532         if (cur_path == NULL) {
533                 FEEDBACK_ERROR("This pattern(%s) in this type(%s) is not supported to play", str_pattern[pattern], str_type[type]);
534                 return FEEDBACK_ERROR_OPERATION_FAILED;
535         }
536
537         ret = feedback_change_symlink(cur_path, path);
538         if (FEEDBACK_FAILED(ret)) {
539                 FEEDBACK_ERROR("change_symlink is failed");
540                 return FEEDBACK_ERROR_OPERATION_FAILED;
541         }
542
543         return FEEDBACK_ERROR_NONE;
544 }
545
546 int feedback_get_path(feedback_type_e type, feedback_pattern_e pattern, char* buf, unsigned int buflen)
547 {
548         const char* cur_path = NULL;
549         int retry = FEEDBACK_RETRY_CNT;
550
551         if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
552                 FEEDBACK_ERROR("Invalid parameter : type(%s)", str_type[type]);
553                 return FEEDBACK_ERROR_INVALID_PARAMETER;
554         }
555
556         if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
557                 FEEDBACK_ERROR("Invalid parameter : pattern(%s)", str_pattern[pattern]);
558                 return FEEDBACK_ERROR_INVALID_PARAMETER;
559         }
560
561         if (buf == NULL || buflen <= 0) {
562                 FEEDBACK_ERROR("Invalid parameter : buf(NULL) or bufLen(%d)", buflen);
563                 return FEEDBACK_ERROR_INVALID_PARAMETER;
564         }
565
566         if (type == FEEDBACK_TYPE_SOUND) {
567                 cur_path = snd_file[pattern];
568         } else {
569                 cur_path = haptic_file[pattern];
570         }
571
572         if (cur_path == NULL) {
573                 FEEDBACK_ERROR("This pattern(%s) in this type(%s) is not supported to play", str_pattern[pattern], str_type[type]);
574                 snprintf(buf, buflen, "NULL");
575                 return FEEDBACK_ERROR_OPERATION_FAILED;
576         }
577
578         do {
579                 if(readlink(cur_path, buf, buflen) < 0) {
580                         FEEDBACK_ERROR("readlink is failed : %s", strerror(errno));
581                         return FEEDBACK_ERROR_OPERATION_FAILED;
582                 }
583         } while(retry--);
584
585         return FEEDBACK_ERROR_NONE;
586 }