tizen 2.3.1 release
[framework/system/libfeedback.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 <assert.h>
26 #include <limits.h>
27 #include <vconf.h>
28 #include <mm_sound_private.h>
29
30 #include "feedback-ids.h"
31 #include "common.h"
32 #include "log.h"
33 #include "devices.h"
34 #include "xmlparser.h"
35
36 #define SOUND_XML                                       "/usr/share/feedback/sound.xml"
37
38 static int sndstatus;
39 static int touch_sndstatus;
40 static int lock_sndstatus;
41 static int keytone_sndstatus;
42 static int camerastatus;
43 static int shutter_sndstatus;
44
45 static xmlDocPtr v_doc;
46
47 static char sound_file[FEEDBACK_PATTERN_END][NAME_MAX];
48
49 inline int is_sound_mode(void)
50 {
51         return sndstatus;
52 }
53
54 static void feedback_touch_sndstatus_cb(keynode_t *key, void* data)
55 {
56         touch_sndstatus = vconf_keynode_get_bool(key);
57 }
58
59 static void feedback_lock_sndstatus_cb(keynode_t *key, void* data)
60 {
61         lock_sndstatus = vconf_keynode_get_bool(key);
62 }
63
64 static void feedback_keytone_sndstatus_cb(keynode_t *key, void* data)
65 {
66         keytone_sndstatus = vconf_keynode_get_bool(key);
67 }
68
69 static void feedback_camerastatus_cb(keynode_t *key, void* data)
70 {
71         camerastatus = vconf_keynode_get_int(key);
72 }
73
74 static volume_type_t get_volume_type(feedback_pattern_e pattern)
75 {
76         if (pattern == FEEDBACK_PATTERN_TAP)
77                 return VOLUME_TYPE_SYSTEM|VOLUME_GAIN_TOUCH;
78         else if (pattern >= FEEDBACK_PATTERN_KEY0 && pattern <= FEEDBACK_PATTERN_KEY_BACK)
79                 return VOLUME_TYPE_SYSTEM|VOLUME_GAIN_DIALER;
80         else if (pattern == FEEDBACK_PATTERN_VOLUME_KEY)
81                 return VOLUME_TYPE_RINGTONE;
82         else if (camerastatus && shutter_sndstatus && pattern == FEEDBACK_PATTERN_SCREEN_CAPTURE)
83                 return VOLUME_TYPE_FIXED;
84
85         return VOLUME_TYPE_SYSTEM;
86 }
87
88 static bool get_always_alert_case(feedback_pattern_e pattern)
89 {
90         switch (pattern) {
91         case FEEDBACK_PATTERN_WAKEUP:
92         case FEEDBACK_PATTERN_WAKEUP_ON_CALL:
93                 return true;
94         case FEEDBACK_PATTERN_MESSAGE_ON_CALL:
95         case FEEDBACK_PATTERN_EMAIL_ON_CALL:
96         case FEEDBACK_PATTERN_GENERAL_ON_CALL:
97                 if (alert_callstatus)
98                         return true;
99                 break;
100         case FEEDBACK_PATTERN_SMART_ALERT:
101         case FEEDBACK_PATTERN_SEND_SOS_MESSAGE:
102         case FEEDBACK_PATTERN_END_SOS_MESSAGE:
103         case FEEDBACK_PATTERN_CMAS:
104                 return true;
105         case FEEDBACK_PATTERN_SCREEN_CAPTURE:
106                 if (camerastatus && shutter_sndstatus)
107                         return true;
108                 break;
109         case FEEDBACK_PATTERN_OUTGOING_CALL:
110                 return true;
111         default:
112                 break;
113         }
114         return false;
115 }
116
117 static bool get_always_off_case(feedback_pattern_e pattern)
118 {
119         switch (pattern) {
120         case FEEDBACK_PATTERN_TAP ... FEEDBACK_PATTERN_MAX_CHARACTER:
121         case FEEDBACK_PATTERN_HOLD ... FEEDBACK_PATTERN_HW_HOLD:
122                 if (!touch_sndstatus)
123                         return true;
124                 break;
125         case FEEDBACK_PATTERN_KEY0 ... FEEDBACK_PATTERN_KEY_BACK:
126                 if (!keytone_sndstatus)
127                         return true;
128                 break;
129         case FEEDBACK_PATTERN_LOCK:
130         case FEEDBACK_PATTERN_UNLOCK:
131         case FEEDBACK_PATTERN_LOCK_SWIPE:
132         case FEEDBACK_PATTERN_UNLOCK_SWIPE:
133                 if (!lock_sndstatus)
134                         return true;
135                 break;
136         default:
137                 break;
138         }
139         return false;
140 }
141
142 static int get_xml_data(xmlDocPtr doc, feedback_pattern_e pattern, struct xmlData **data)
143 {
144         xmlNodePtr cur;
145         struct xmlData *retData;
146
147         cur = xml_find(doc, SOUND_STR, (const xmlChar*)str_pattern[pattern]);
148         /* This pattern does not have sound file to play */
149         if (cur == NULL)
150                 return -ENOENT;
151
152         retData = xml_parse(doc, cur);
153         if (retData == NULL) {
154                 _E("xml_parse fail");
155                 return -EPERM;
156         }
157
158         *data = retData;
159         return 0;
160 }
161
162 static void release_xml_data(struct xmlData *data)
163 {
164         if (data == NULL)
165                 return;
166
167         xml_free(data);
168 }
169
170 static void sound_init(void)
171 {
172         /* xml Init */
173         v_doc = xml_open(SOUND_XML);
174         if (v_doc == NULL) {
175                 _E("xml_open(%s) fail", SOUND_XML);
176                 return;
177         }
178
179         /* check sound status */
180         if (vconf_get_bool(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, &touch_sndstatus) < 0)
181                 _W("VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL ==> FAIL!!");
182
183         if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_LOCK_BOOL, &lock_sndstatus) < 0)
184                 _W("VCONFKEY_SETAPPL_SOUND_LOCK_BOOL ==> FAIL!!");
185
186         if (vconf_get_bool(VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL, &keytone_sndstatus) < 0)
187                 _W("VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL ==> FAIL!!");
188
189         /* check camera status */
190         if (vconf_get_int(VCONFKEY_CAMERA_STATE, &camerastatus) < 0)
191                 _W("VCONFKEY_CAMERA_STATE ==> FAIL!!");
192
193         /* shutter sound policy */
194         // This vconf is read just once, because this value is not changed in running time.
195         if (vconf_get_int(VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY, &shutter_sndstatus) < 0)
196                 _W("VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY ==> FAIL!!");
197
198         /* add watch for status value */
199         vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, feedback_touch_sndstatus_cb, NULL);
200         vconf_notify_key_changed(VCONFKEY_SETAPPL_SOUND_LOCK_BOOL, feedback_lock_sndstatus_cb, NULL);
201         vconf_notify_key_changed(VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL, feedback_keytone_sndstatus_cb, NULL);
202         vconf_notify_key_changed(VCONFKEY_CAMERA_STATE, feedback_camerastatus_cb, NULL);
203 }
204
205 static void sound_exit(void)
206 {
207         /* remove watch */
208         vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, feedback_touch_sndstatus_cb);
209         vconf_ignore_key_changed(VCONFKEY_SETAPPL_SOUND_LOCK_BOOL, feedback_lock_sndstatus_cb);
210         vconf_ignore_key_changed(VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL, feedback_keytone_sndstatus_cb);
211         vconf_ignore_key_changed(VCONFKEY_CAMERA_STATE, feedback_camerastatus_cb);
212
213         if (v_doc) {
214                 xml_close(v_doc);
215                 v_doc = NULL;
216         }
217 }
218
219 static int sound_play(feedback_pattern_e pattern)
220 {
221         struct stat buf;
222         int retry = FEEDBACK_RETRY_CNT, ret;
223         char *path;
224         struct xmlData *data = NULL;
225
226         if (!v_doc) {
227                 _E("Not initialize");
228                 return -EPERM;
229         }
230
231         if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sndstatus) < 0) {
232                 _D("fail to get sound status, will work as turning off");
233                 sndstatus = 0;
234         }
235
236         if (sndstatus == 0 && !get_always_alert_case(pattern)) {
237                 _D("Sound condition is OFF (sndstatus : %d)", sndstatus);
238                 return 0;
239         }
240
241         if (sndstatus && get_always_off_case(pattern)) {
242                 _D("Sound always off condition");
243                 return 0;
244         }
245
246         /* check if the state of voice recorder is recording */
247         if (vconf_get_int(VCONFKEY_SOUND_STATUS, &ret) < 0) {
248                 _D("fail to get media sound status, status will be zero");
249                 ret = 0;
250         }
251
252         if (ret & VCONFKEY_SOUND_STATUS_AVRECORDING) {
253                 _D("voice recording status is RECORDING");
254                 return 0;
255         }
256
257         /* check whether there is a user defined file */
258         path = sound_file[pattern];
259
260         /* if not */
261         if (!(*path)) {
262                 ret = get_xml_data(v_doc, pattern, &data);
263                 if (ret == -ENOENT) {
264                         _D("No sound case(%s)", str_pattern[pattern]);
265                         return 0;
266                 }
267
268                 if (ret < 0) {
269                         _E("get_xml_data fail");
270                         return -EPERM;
271                 }
272
273                 if (!data->data) {
274                         _D("No sound case(%s)", str_pattern[pattern]);
275                         release_xml_data(data);
276                         return 0;
277                 }
278
279                 path = data->data;
280         }
281
282         if (stat(path, &buf)) {
283                 _E("%s is not presents", path);
284                 release_xml_data(data);
285                 return -ENOENT;
286         }
287
288         /* play sound file */
289         do {
290                 ret = mm_sound_play_keysound(path, get_volume_type(pattern));
291                 if (ret == MM_ERROR_NONE) {
292                         _D("Play success! SND filename is %s", path);
293                         release_xml_data(data);
294                         return 0;
295                 }
296                 _E("mm_sound_play_keysound() returned error(%d)", ret);
297         } while(retry--);
298
299         release_xml_data(data);
300         return -EPERM;
301 }
302
303 static int sound_get_path(feedback_pattern_e pattern, char *buf, unsigned int buflen)
304 {
305         char *cur_path;
306         int ret = 0;
307         struct xmlData *data = NULL;
308
309         if (!buf || buflen <= 0)
310                 return -EINVAL;
311
312         cur_path = sound_file[pattern];
313         if (!strncmp(cur_path, "", 1)) {
314                 ret = get_xml_data(v_doc, pattern, &data);
315                 if (ret >= 0 && data && data->data)
316                         cur_path = (char*)data->data;
317         }
318
319         if (!cur_path) {
320                 _E("This pattern(%s) in sound type is not supported to play", str_pattern[pattern]);
321                 cur_path = "NULL";
322                 ret = -ENOENT;
323         }
324
325         snprintf(buf, buflen, "%s", cur_path);
326         release_xml_data(data);
327         return 0;
328 }
329
330 static int sound_set_path(feedback_pattern_e pattern, char *path)
331 {
332         struct stat buf;
333         char *ppath;
334
335         /*
336          * check the path is valid
337          * if path is null, below operation is ignored
338          */
339         if (path && stat(path, &buf)) {
340                 _E("%s is not presents", path);
341                 return -errno;
342         }
343
344         ppath = sound_file[pattern];
345
346         /* if path is NULL, this pattern set to default file */
347         if (path)
348                 snprintf(ppath, NAME_MAX, "%s", path);
349         else
350                 memset(ppath, 0, NAME_MAX);
351
352         _D("The file of pattern(%s) is changed to [%s]", str_pattern[pattern], path);
353         return 0;
354 }
355
356 static const struct device_ops sound_device_ops = {
357         .type = FEEDBACK_TYPE_SOUND,
358         .init = sound_init,
359         .exit = sound_exit,
360         .play = sound_play,
361         .get_path = sound_get_path,
362         .set_path = sound_set_path,
363 };
364
365 DEVICE_OPS_REGISTER(&sound_device_ops);