seperate sound device from feedback internal code
[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 <vconf.h>
27 #include <haptic.h>
28 #include <fcntl.h>
29 #include <errno.h>
30
31 #include "feedback.h"
32 #include "feedback-internal.h"
33 #include "feedback-file.h"
34 #include "feedback-str.h"
35 #include "feedback-log.h"
36 #include "xmlparser.h"
37
38 #define FEEDBACK_RETRY_CNT       1
39 #define MAX_FILE_PATH          512
40
41 #define DEFAULT_FEEDBACK_HANDLE         0x0F
42
43 #define VIBRATION_XML                           "/usr/share/feedback/vibration.xml"
44
45 typedef struct {
46         haptic_device_h v_handle;
47         xmlDocPtr v_doc;
48 } FEEDBACK_HANDLE;
49
50 static int vibstatus;
51 static int vib_level;
52 static int noti_level;
53 int callstatus;
54
55 static void feedback_vibstatus_cb(keynode_t *key, void* data)
56 {
57         vibstatus = vconf_keynode_get_bool(key);
58 }
59
60 static void feedback_vib_cb(keynode_t *key, void* data)
61 {
62         vib_level = vconf_keynode_get_int(key);
63 }
64
65 static void feedback_noti_cb(keynode_t *key, void* data)
66 {
67         noti_level = vconf_keynode_get_int(key);
68 }
69
70 static void feedback_callstatus_cb(keynode_t *key, void* data)
71 {
72         callstatus = vconf_keynode_get_int(key);
73 }
74
75 feedback_pattern_e feedback_get_alert_on_call_key(feedback_pattern_e pattern)
76 {
77         switch(pattern) {
78         case FEEDBACK_PATTERN_MESSAGE:
79         case FEEDBACK_PATTERN_EMAIL:
80         case FEEDBACK_PATTERN_WAKEUP:
81         case FEEDBACK_PATTERN_SCHEDULE:
82         case FEEDBACK_PATTERN_TIMER:
83         case FEEDBACK_PATTERN_GENERAL:
84         case FEEDBACK_PATTERN_CHARGERCONN:
85         case FEEDBACK_PATTERN_FULLCHARGED:
86         case FEEDBACK_PATTERN_LOWBATT:
87                 return (feedback_pattern_e)(pattern+1);
88         default:
89                 break;
90         }
91
92         return pattern;
93 }
94
95 static haptic_priority_e feedback_get_priority(feedback_pattern_e pattern)
96 {
97         if (pattern >= FEEDBACK_PATTERN_TAP && pattern <= FEEDBACK_PATTERN_HW_HOLD)
98                 return HAPTIC_PRIORITY_MIN;
99
100         return HAPTIC_PRIORITY_MIDDLE;
101 }
102
103 static int feedback_get_haptic_level(feedback_pattern_e pattern)
104 {
105         int level = -1;
106
107         if (pattern >= FEEDBACK_PATTERN_MESSAGE && pattern <= FEEDBACK_PATTERN_GENERAL_ON_CALL)
108                 level = noti_level;
109         else
110                 level = vib_level;
111
112         FEEDBACK_LOG("Call status : %d, pattern : %s, level : %d", callstatus, str_pattern[pattern], level);
113         if (callstatus != VCONFKEY_CALL_OFF) {
114                 // if call status is ON, vibration magnitude is 20%
115                 level = (int)(level*0.2f);
116                 level = (level < 1) ? 1 : level;
117                 FEEDBACK_LOG("level changed : %d", level);
118         }
119
120         level = level * 20;
121         return level;
122 }
123
124 static bool feedback_get_always_alert_case(feedback_pattern_e pattern)
125 {
126         switch(pattern) {
127         case FEEDBACK_PATTERN_WAKEUP:
128         case FEEDBACK_PATTERN_WAKEUP_ON_CALL:
129                 return true;
130         default:
131                 break;
132         }
133         return false;
134 }
135
136 static int feedback_get_data(xmlDocPtr doc, feedback_pattern_e pattern, struct xmlData **data)
137 {
138         xmlNodePtr cur;
139         struct xmlData *retData;
140
141         cur = xml_find(doc, (const xmlChar*)str_pattern[pattern]);
142         if (cur == NULL) {
143                 FEEDBACK_ERROR("xml_find fail");
144                 return -1;
145         }
146
147         retData = xml_parse(doc, cur);
148         if (retData == NULL) {
149                 FEEDBACK_ERROR("xml_parse fail");
150                 return -1;
151         }
152
153         *data = retData;
154         return 0;
155 }
156
157 static void feedback_release_data(struct xmlData *data)
158 {
159         if (data == NULL)
160                 return;
161
162         xml_free(data);
163 }
164
165 static int feedback_change_symlink(const char *sym_path, const char *new_path)
166 {
167         struct stat buf;
168
169         if (sym_path == NULL || strlen(sym_path) == 0) {
170                 FEEDBACK_ERROR("Invalid parameter : sym_path(NULL)");
171                 return FEEDBACK_ERROR_INVALID_PARAMETER;
172         }
173
174         if (new_path == NULL || strlen(new_path) == 0) {
175                 FEEDBACK_ERROR("Invalid paramter : new_path(NULL)");
176                 return FEEDBACK_ERROR_INVALID_PARAMETER;
177         }
178
179         // check symbolic link file existence
180         if (stat(sym_path, &buf)) {
181                 FEEDBACK_ERROR("file(%s) is not presents", sym_path);
182                 return FEEDBACK_ERROR_OPERATION_FAILED;
183         }
184
185         if (unlink(sym_path) < 0) {
186                 FEEDBACK_LOG("unlink(%s) : %s", sym_path, strerror(errno));
187         }
188
189         if (symlink(new_path, sym_path) < 0) {
190                 FEEDBACK_ERROR("symlink(%s) : %s", sym_path, strerror(errno));
191                 return FEEDBACK_ERROR_OPERATION_FAILED;
192         }
193
194         return FEEDBACK_ERROR_NONE;
195 }
196
197 static int feedback_restore_default_file(feedback_type_e type, feedback_pattern_e pattern)
198 {
199         const char *cur_path = NULL;
200         char default_path[MAX_FILE_PATH] = {0,};
201         char *temp = NULL;
202         int ret = -1;
203
204         if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
205                 FEEDBACK_ERROR("Invalid parameter : type(%s)", str_type[type]);
206                 return FEEDBACK_ERROR_INVALID_PARAMETER;
207         }
208
209         if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
210                 FEEDBACK_ERROR("Invalid parameter : pattern(%s)", str_pattern[pattern]);
211                 return FEEDBACK_ERROR_INVALID_PARAMETER;
212         }
213
214         if (type == FEEDBACK_TYPE_VIBRATION) {
215                 cur_path = haptic_file[pattern];
216         }
217
218         // if there isn't cur_path, it already returns before calling this api
219         if (cur_path == NULL || strlen(cur_path) == 0) {
220                 FEEDBACK_ERROR("Invalid parameter : cur_path(NULL)");
221                 return FEEDBACK_ERROR_OPERATION_FAILED;
222         }
223
224         temp = strcat(default_path, FEEDBACK_ORIGIN_DATA_DIR);
225         strcat(temp, cur_path+strlen(FEEDBACK_DATA_DIR));
226         FEEDBACK_LOG("default_path : %s", default_path);
227
228         ret = feedback_change_symlink(cur_path, default_path);
229         if (FEEDBACK_FAILED(ret)) {
230                 FEEDBACK_ERROR("change_symlink is failed");
231                 return FEEDBACK_ERROR_OPERATION_FAILED;
232         }
233
234         return FEEDBACK_ERROR_NONE;
235 }
236
237 int feedback_init(feedback_h *handle)
238 {
239         FEEDBACK_HANDLE *phandle;
240         haptic_device_h v_handle;
241         xmlDocPtr v_doc;
242         int ret;
243
244         /* check vibration status */
245         if (vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) < 0) {
246                 FEEDBACK_ERROR("vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) ==> FAIL!!");
247                 return FEEDBACK_ERROR_OPERATION_FAILED;
248         }
249
250         /* check vib_level */
251         if (vconf_get_int(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, &vib_level) < 0) {
252                 FEEDBACK_ERROR("vconf_get_int(VCONFKEY_FEEDBACK_VIBRATION_LEVEL_INT, &vib_level) ==> FAIL!!");
253                 return FEEDBACK_ERROR_OPERATION_FAILED;
254         }
255
256         /* check noti_level */
257         if (vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, &noti_level) < 0) {
258                 FEEDBACK_ERROR("vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, &noti_level) ==> FAIL!!");
259                 return FEEDBACK_ERROR_OPERATION_FAILED;
260         }
261
262         /* check call status */
263         if (vconf_get_int(VCONFKEY_CALL_STATE, &callstatus) < 0) {
264                 FEEDBACK_ERROR("vconf_get_int(VCONFKEY_CALL_STATE, &callstatus) ==> FAIL!!");
265                 return FEEDBACK_ERROR_OPERATION_FAILED;
266         }
267
268         /* xml Init */
269         v_doc = xml_open(VIBRATION_XML);
270         if (v_doc == NULL) {
271                 FEEDBACK_ERROR("xml_open(%s) fail", VIBRATION_XML);
272                 return FEEDBACK_ERROR_OPERATION_FAILED;
273         }
274
275         /* Vibration Init */
276         ret = haptic_open(HAPTIC_DEVICE_ALL, &v_handle);
277         if (ret != HAPTIC_ERROR_NONE) {
278                 FEEDBACK_ERROR("haptic_open(HAPTIC_DEVICE_ALL, &v_handle) ==> FAIL!! : %d", ret);
279                 v_handle = (haptic_device_h)DEFAULT_FEEDBACK_HANDLE;
280         }
281
282         /* add watch for status value */
283         vconf_notify_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, feedback_vibstatus_cb, NULL);
284         vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, feedback_vib_cb, NULL);
285         vconf_notify_key_changed(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, feedback_noti_cb, NULL);
286         vconf_notify_key_changed(VCONFKEY_CALL_STATE, feedback_callstatus_cb, NULL);
287
288         FEEDBACK_LOG("vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) ==> %d", vibstatus);
289         FEEDBACK_LOG("vconf_get_int(VCONFKEY_FEEDBACK_VIBRATION_LEVEL_INT, &vib_level) ==> %d", vib_level);
290         FEEDBACK_LOG("vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, &noti_level) ==> %d", noti_level);
291         FEEDBACK_LOG("vconf_get_int(VCONFKEY_CALL_STATUS, &callstatus) ==> %d", callstatus);
292
293         phandle = (FEEDBACK_HANDLE *)malloc(sizeof(FEEDBACK_HANDLE));
294         phandle->v_handle = v_handle;
295         phandle->v_doc = v_doc;
296         *handle = (feedback_h)phandle;
297         FEEDBACK_LOG("handle value : %x", handle);
298         return FEEDBACK_ERROR_NONE;
299 }
300
301 int feedback_fini(feedback_h handle)
302 {
303         FEEDBACK_HANDLE *phandle = (FEEDBACK_HANDLE *)handle;
304         int ret = -1;
305
306         if (!handle) {
307                 FEEDBACK_ERROR("Invalid parameter : handle(NULL)");
308                 return FEEDBACK_ERROR_INVALID_PARAMETER;
309         }
310
311         if (phandle->v_handle != DEFAULT_FEEDBACK_HANDLE) {
312                 ret = haptic_close(phandle->v_handle);
313                 if (ret != HAPTIC_ERROR_NONE) {
314                         FEEDBACK_ERROR("haptic_close is failed : %d", ret);
315                 }
316         }
317
318         if (phandle->v_doc) {
319                 xml_close(phandle->v_doc);
320         }
321
322         free(phandle);
323
324         vconf_ignore_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, feedback_vibstatus_cb);
325         vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, feedback_vib_cb);
326         vconf_ignore_key_changed(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, feedback_noti_cb);
327         vconf_ignore_key_changed(VCONFKEY_CALL_STATE, feedback_callstatus_cb);
328
329         return FEEDBACK_ERROR_NONE;
330 }
331
332 int feedback_play_vibration(feedback_h handle, feedback_pattern_e pattern)
333 {
334         FEEDBACK_HANDLE *phandle = (FEEDBACK_HANDLE *)handle;
335         int ret;
336         struct stat buf;
337         struct xmlData *data;
338
339         if (!handle) {
340                 FEEDBACK_ERROR("Invalid parameter : handle(NULL)");
341                 return FEEDBACK_ERROR_INVALID_PARAMETER;
342         }
343
344         if (handle == DEFAULT_FEEDBACK_HANDLE) {
345                 FEEDBACK_ERROR("haptic is not initialized");
346                 return FEEDBACK_ERROR_OPERATION_FAILED;
347         }
348
349         if (vibstatus == 0 && !feedback_get_always_alert_case(pattern))  {
350                 FEEDBACK_LOG("Vibration condition is OFF (vibstatus : %d)", vibstatus);
351                 return FEEDBACK_ERROR_NONE;
352         }
353
354         if (callstatus != VCONFKEY_CALL_OFF) {
355                 pattern = feedback_get_alert_on_call_key(pattern);
356                 FEEDBACK_LOG("Call status is connected or connecting. pattern changed : %s", str_pattern[pattern]);
357         }
358
359         ret = feedback_get_data(phandle->v_doc, pattern, &data);
360         if (ret < 0) {
361                 FEEDBACK_ERROR("feedback_get_vibration_data fail");
362                 return FEEDBACK_ERROR_OPERATION_FAILED;
363         }
364
365         if (data->data == NULL) {
366                 FEEDBACK_LOG("This case(%s) does not play vibration", str_pattern[pattern]);
367                 feedback_release_data(data);
368                 return FEEDBACK_ERROR_NONE;
369         }
370
371         /* play haptic buffer */
372         ret = haptic_vibrate_buffer_with_detail(phandle->v_handle, data->data, HAPTIC_ITERATION_ONCE,
373                                         feedback_get_haptic_level(pattern), feedback_get_priority(pattern), NULL);
374         if (ret != HAPTIC_ERROR_NONE) {
375                 FEEDBACK_ERROR("haptic_vibrate_buffer_with_detail is failed");
376                 feedback_release_data(data);
377                 return FEEDBACK_ERROR_OPERATION_FAILED;
378         }
379
380         feedback_release_data(data);
381         return FEEDBACK_ERROR_NONE;
382 }
383
384 int feedback_set_path(feedback_type_e type, feedback_pattern_e pattern, char* path)
385 {
386         const char* cur_path = NULL;
387         int ret = -1;
388
389         if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
390                 FEEDBACK_ERROR("Invalid parameter : type(%s)", str_type[type]);
391                 return FEEDBACK_ERROR_INVALID_PARAMETER;
392         }
393
394         if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
395                 FEEDBACK_ERROR("Invalid parameter : pattern(%s)", str_pattern[pattern]);
396                 return FEEDBACK_ERROR_INVALID_PARAMETER;
397         }
398
399         if (path == NULL) {
400                 FEEDBACK_ERROR("Invalid parameter : path(NULL)");
401                 return FEEDBACK_ERROR_INVALID_PARAMETER;
402         }
403
404         if (access(path, F_OK) != 0) {
405                 FEEDBACK_ERROR("Invalid parameter : path does not exist");
406                 return FEEDBACK_ERROR_INVALID_PARAMETER;
407         }
408
409         if (type == FEEDBACK_TYPE_VIBRATION) {
410                 cur_path = haptic_file[pattern];
411         }
412
413         if (cur_path == NULL) {
414                 FEEDBACK_ERROR("This pattern(%s) in this type(%s) is not supported to play", str_pattern[pattern], str_type[type]);
415                 return FEEDBACK_ERROR_OPERATION_FAILED;
416         }
417
418         ret = feedback_change_symlink(cur_path, path);
419         if (FEEDBACK_FAILED(ret)) {
420                 FEEDBACK_ERROR("change_symlink is failed");
421                 return FEEDBACK_ERROR_OPERATION_FAILED;
422         }
423
424         return FEEDBACK_ERROR_NONE;
425 }
426
427 int feedback_get_path(feedback_type_e type, feedback_pattern_e pattern, char* buf, unsigned int buflen)
428 {
429         const char* cur_path = NULL;
430         int retry = FEEDBACK_RETRY_CNT;
431
432         if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
433                 FEEDBACK_ERROR("Invalid parameter : type(%s)", str_type[type]);
434                 return FEEDBACK_ERROR_INVALID_PARAMETER;
435         }
436
437         if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
438                 FEEDBACK_ERROR("Invalid parameter : pattern(%s)", str_pattern[pattern]);
439                 return FEEDBACK_ERROR_INVALID_PARAMETER;
440         }
441
442         if (buf == NULL || buflen <= 0) {
443                 FEEDBACK_ERROR("Invalid parameter : buf(NULL) or bufLen(%d)", buflen);
444                 return FEEDBACK_ERROR_INVALID_PARAMETER;
445         }
446
447         if (type == FEEDBACK_TYPE_VIBRATION) {
448                 cur_path = haptic_file[pattern];
449         }
450
451         if (cur_path == NULL) {
452                 FEEDBACK_ERROR("This pattern(%s) in this type(%s) is not supported to play", str_pattern[pattern], str_type[type]);
453                 snprintf(buf, buflen, "NULL");
454                 return FEEDBACK_ERROR_OPERATION_FAILED;
455         }
456
457         do {
458                 if(readlink(cur_path, buf, buflen) < 0) {
459                         FEEDBACK_ERROR("readlink is failed : %s", strerror(errno));
460                         return FEEDBACK_ERROR_OPERATION_FAILED;
461                 }
462         } while(retry--);
463
464         return FEEDBACK_ERROR_NONE;
465 }