Fix for 64 bit compatibility.
[platform/core/multimedia/libmm-session.git] / mm_session.c
1 /*
2  * libmm-session
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Seungbae Shin <seungbae.shin@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <mm_session_private.h>
29 #include <mm_error.h>
30 #include <mm_debug.h>
31 #include <errno.h>
32 #include <audio-session-manager.h>
33 #include <glib.h>
34 #include <pthread.h>
35
36 #define EXPORT_API __attribute__((__visibility__("default")))
37 #define MAX_FILE_LENGTH 256
38
39 #define TRY_LOCK(x, x_ret) \
40 do {\
41     x_ret = pthread_mutex_trylock(&(x));\
42     if(x_ret != 0) {\
43         debug_warning("Mutex trylock failed, (0x%x)",x_ret);\
44     }\
45 } while(0)
46 #define LOCK(x) \
47 do {\
48     if(pthread_mutex_lock(&(x)) != 0) {\
49         debug_error("Mutex lock error");\
50     }\
51 } while(0)
52 #define UNLOCK(x) \
53 do {\
54     if(pthread_mutex_unlock(&(x)) != 0) {\
55         debug_error("Mutex unlock error");\
56     }\
57 } while(0)
58 #define DESTROY(x) \
59 do {\
60     if(pthread_mutex_destroy(&(x)) != 0) {\
61         debug_error("Mutex destroy error");\
62     }\
63 } while(0)
64
65 typedef struct {
66         session_callback_fn fn;
67         void* data;
68         session_msg_t msg;
69         session_event_t event;
70 }session_monitor_t;
71
72 int g_call_asm_handle = -1;
73 int g_monitor_asm_handle = -1;
74 session_monitor_t g_monitor_data;
75
76 pthread_mutex_t g_mutex_monitor = PTHREAD_MUTEX_INITIALIZER;
77
78 ASM_cb_result_t asm_monitor_callback(int handle, ASM_event_sources_t event_src, ASM_sound_commands_t command, unsigned int sound_status, void* cb_data);
79
80 EXPORT_API
81 int mm_session_init(int sessiontype)
82 {
83         debug_fenter();
84         return mm_session_init_ex(sessiontype, NULL, NULL);
85         debug_fleave();
86 }
87
88 EXPORT_API
89 int mm_session_init_ex(int sessiontype, session_callback_fn callback, void* user_param)
90 {
91         int error = 0;
92         int result = MM_ERROR_NONE;
93         int ltype = 0;
94         pthread_mutex_init(&g_mutex_monitor, NULL);
95         debug_fenter();
96         debug_log("type : %d", sessiontype);
97
98         if(sessiontype < MM_SESSION_TYPE_SHARE || sessiontype >= MM_SESSION_PRIVATE_TYPE_NUM) {
99                 debug_error("Invalid argument %d",sessiontype);
100                 return MM_ERROR_INVALID_ARGUMENT;
101         }
102
103         result = _mm_session_util_read_type(-1, &ltype);
104         if(MM_ERROR_INVALID_HANDLE != result) {
105                 debug_error("Session already initialized. Please finish current session first");
106                 return MM_ERROR_POLICY_DUPLICATED;
107         }
108
109         /* Monitor Callback */
110         if(NULL == callback) {
111                 debug_warning("Null callback function");
112         } else {
113                 g_monitor_data.fn = callback;
114                 g_monitor_data.data = user_param;
115                 LOCK(g_mutex_monitor);
116                 if(!ASM_register_sound(-1, &g_monitor_asm_handle, ASM_EVENT_MONITOR, ASM_STATE_NONE, asm_monitor_callback, (void*)&g_monitor_data, ASM_RESOURCE_NONE, &error)) {
117                         debug_error("Can not register monitor");
118                         UNLOCK(g_mutex_monitor);
119                         return MM_ERROR_INVALID_HANDLE;
120                 }
121                 UNLOCK(g_mutex_monitor);
122         }
123
124         /* Register here for call session types */
125         if(sessiontype == MM_SESSION_TYPE_CALL) {
126                 if(!ASM_register_sound(-1, &g_call_asm_handle, ASM_EVENT_CALL, ASM_STATE_PLAYING, NULL, NULL, ASM_RESOURCE_NONE, &error)) {
127                         debug_error("Can not register sound");
128                         return MM_ERROR_INVALID_HANDLE;
129                 }
130         } else if(sessiontype == MM_SESSION_TYPE_VIDEOCALL) {
131                 if(!ASM_register_sound(-1, &g_call_asm_handle, ASM_EVENT_VIDEOCALL, ASM_STATE_PLAYING, NULL, NULL, ASM_RESOURCE_CAMERA|ASM_RESOURCE_VIDEO_OVERLAY, &error)) {
132                         debug_error("Can not register sound");
133                         return MM_ERROR_INVALID_HANDLE;
134                 }
135         } else if(sessiontype == MM_SESSION_TYPE_RICH_CALL) {
136                 if(!ASM_register_sound(-1, &g_call_asm_handle, ASM_EVENT_RICH_CALL, ASM_STATE_PLAYING, NULL, NULL, ASM_RESOURCE_NONE, &error)) {
137                         debug_error("Can not register sound");
138                         return MM_ERROR_INVALID_HANDLE;
139                 }
140         }
141
142         result = _mm_session_util_write_type(-1, sessiontype);
143         if(MM_ERROR_NONE != result) {
144                 debug_error("Write type failed");
145                 if(sessiontype == MM_SESSION_TYPE_CALL) {
146                         ASM_unregister_sound(g_call_asm_handle, ASM_EVENT_CALL, &error);
147                 } else if(sessiontype == MM_SESSION_TYPE_VIDEOCALL) {
148                         ASM_unregister_sound(g_call_asm_handle, ASM_EVENT_VIDEOCALL, &error);
149                 } else if(sessiontype == MM_SESSION_TYPE_RICH_CALL) {
150                         ASM_unregister_sound(g_call_asm_handle, ASM_EVENT_RICH_CALL, &error);
151                 } else {
152                         LOCK(g_mutex_monitor);
153                         ASM_unregister_sound(g_monitor_asm_handle, ASM_EVENT_MONITOR, &error);
154                         UNLOCK(g_mutex_monitor);
155                 }
156                 return result;
157         }
158
159         debug_fleave();
160
161         return MM_ERROR_NONE;
162 }
163
164 EXPORT_API
165 int mm_session_get_current_type (int *sessiontype)
166 {
167         int result = MM_ERROR_NONE;
168         int ltype = 0;
169
170         if (sessiontype == NULL) {
171                 debug_error("input argument is NULL\n");
172                 return MM_ERROR_INVALID_ARGUMENT;
173         }
174
175         result = _mm_session_util_read_type(-1, &ltype);
176         if(result == MM_ERROR_NONE) {
177                 debug_log("Current process session type = [%d]\n", ltype);
178                 *sessiontype = ltype;
179         } else {
180                 debug_error("failed to get current process session type!!\n");
181         }
182
183         return result;
184 }
185
186 EXPORT_API
187 int mm_session_finish()
188 {
189         int error = 0;
190         int result = MM_ERROR_NONE;
191         int sessiontype = MM_SESSION_TYPE_SHARE;
192         ASM_sound_states_t state = ASM_STATE_NONE;
193
194         debug_fenter();
195
196         result = _mm_session_util_read_type(-1, &sessiontype);
197         if(MM_ERROR_NONE != result) {
198                 debug_error("Can not read current type");
199                 DESTROY(g_mutex_monitor);
200                 return result;
201         }
202
203         /* Unregister call session here */
204         if(sessiontype == MM_SESSION_TYPE_CALL) {
205                 if(!ASM_unregister_sound(g_call_asm_handle, ASM_EVENT_CALL, &error)) {
206                         debug_error("\"CALL\" ASM unregister failed");
207                         goto INVALID_HANDLE;
208                 }
209                 g_call_asm_handle = -1;
210         } else if(sessiontype == MM_SESSION_TYPE_VIDEOCALL) {
211                 if(!ASM_unregister_sound(g_call_asm_handle, ASM_EVENT_VIDEOCALL, &error)) {
212                         debug_error("\"VIDEOCALL\" ASM unregister failed");
213                         goto INVALID_HANDLE;
214                 }
215                 g_call_asm_handle = -1;
216         } else if(sessiontype == MM_SESSION_TYPE_RICH_CALL) {
217                 if(!ASM_unregister_sound(g_call_asm_handle, ASM_EVENT_RICH_CALL, &error)) {
218                         debug_error("\"RICH-CALL\" ASM unregister failed");
219                         goto INVALID_HANDLE;
220                 }
221                 g_call_asm_handle = -1;
222         }
223
224         /* Check monitor handle */
225         TRY_LOCK(g_mutex_monitor, error);
226         if (!error) {
227                 if(g_monitor_asm_handle != -1) {
228                         if(!ASM_get_process_session_state(g_monitor_asm_handle, &state, &error)) {
229                                 debug_error("[%s] Can not get process status", __func__);
230                                 UNLOCK(g_mutex_monitor);
231                                 DESTROY(g_mutex_monitor);
232                                 return MM_ERROR_POLICY_INTERNAL;
233                         } else {
234                                 switch(state) {
235                                 case ASM_STATE_IGNORE:
236                                 case ASM_STATE_NONE:
237                                         break;
238                                 case ASM_STATE_PLAYING:
239                                 case ASM_STATE_WAITING:
240                                 case ASM_STATE_STOP:
241                                 case ASM_STATE_PAUSE:
242                                 case ASM_STATE_PAUSE_BY_APP:
243                                         debug_error("[%s] MSL instance still alive", __func__);
244                                         UNLOCK(g_mutex_monitor);
245                                         DESTROY(g_mutex_monitor);
246                                         return MM_ERROR_POLICY_BLOCKED;
247                                 }
248                         }
249                         /* Unregister monitor */
250                         if(!ASM_unregister_sound(g_monitor_asm_handle, ASM_EVENT_MONITOR, &error)) {
251                                 debug_error("ASM unregister monitor failed");
252                                 UNLOCK(g_mutex_monitor);
253                                 goto INVALID_HANDLE;
254                         } else {
255                                 debug_log("ASM unregister monitor success");
256                                 g_monitor_asm_handle = -1;
257                         }
258                 }
259                 UNLOCK(g_mutex_monitor);
260                 DESTROY(g_mutex_monitor);
261         }
262
263         result = _mm_session_util_delete_type(-1);
264         if(result != MM_ERROR_NONE)
265                 return result;
266
267         debug_fleave();
268
269         return MM_ERROR_NONE;
270
271 INVALID_HANDLE:
272         DESTROY(g_mutex_monitor);
273         return MM_ERROR_INVALID_HANDLE;
274 }
275
276 EXPORT_API
277 int mm_session_set_subsession (mm_subsession_t subsession)
278 {
279         int error = 0;
280         int result = MM_ERROR_NONE;
281
282         debug_fenter();
283
284         if(g_call_asm_handle == -1) {
285                 debug_error ("call session is not started...\n");
286                 return MM_ERROR_INVALID_HANDLE;
287         }
288
289         /* FIXME : Error handling */
290         ASM_set_subsession (g_call_asm_handle, subsession, &error, NULL);
291
292         debug_fleave();
293
294         return MM_ERROR_NONE;
295 }
296
297 EXPORT_API
298 int mm_session_get_subsession (mm_subsession_t *subsession)
299 {
300         int error = 0;
301         int result = MM_ERROR_NONE;
302         debug_fenter();
303
304         if(g_call_asm_handle == -1) {
305                 debug_error ("call session is not started...\n");
306                 return MM_ERROR_INVALID_HANDLE;
307         }
308
309         ASM_get_subsession (g_call_asm_handle, subsession, &error, NULL);
310
311         debug_log("ASM_get_subsession returned [%d]\n", *subsession);
312         debug_fleave();
313
314         return MM_ERROR_NONE;
315 }
316
317 EXPORT_API
318 int _mm_session_util_delete_type(int app_pid)
319 {
320         pid_t mypid;
321         char filename[MAX_FILE_LENGTH];
322
323         if(app_pid == -1)
324                 mypid = getpid();
325         else
326                 mypid = (pid_t)app_pid;
327
328         ////// DELETE SESSION TYPE /////////
329         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d",mypid);
330         if(-1 ==  unlink(filename))
331                 return MM_ERROR_FILE_NOT_FOUND;
332         ////// DELETE SESSION TYPE /////////
333
334         return MM_ERROR_NONE;
335 }
336
337 EXPORT_API
338 int _mm_session_util_write_type(int app_pid, int sessiontype)
339 {
340         pid_t mypid;
341         int fd = -1;
342         char filename[MAX_FILE_LENGTH];
343
344         if(sessiontype < MM_SESSION_TYPE_SHARE || sessiontype >= MM_SESSION_PRIVATE_TYPE_NUM) {
345                 return MM_ERROR_INVALID_ARGUMENT;
346         }
347
348         if(app_pid == -1)
349                 mypid = getpid();
350         else
351                 mypid = (pid_t)app_pid;
352
353         ////// WRITE SESSION TYPE /////////
354         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d",mypid);
355         fd = open(filename, O_WRONLY | O_CREAT, 0644 );
356         if(fd < 0) {
357                 debug_error("open() failed with %d",errno);
358                 return MM_ERROR_FILE_WRITE;
359         }
360         write(fd, &sessiontype, sizeof(int));
361         if(0 > fchmod (fd, 00777)) {
362                 debug_log("fchmod failed with %d", errno);
363         }
364         close(fd);
365         ////// WRITE SESSION TYPE /////////
366
367         return MM_ERROR_NONE;
368 }
369
370 EXPORT_API
371 int _mm_session_util_read_type(int app_pid, int *sessiontype)
372 {
373         pid_t mypid;
374         int fd = -1;
375         char filename[MAX_FILE_LENGTH];
376
377         if(sessiontype == NULL)
378                 return MM_ERROR_INVALID_ARGUMENT;
379
380         if(app_pid == -1)
381                 mypid = getpid();
382         else
383                 mypid = (pid_t)app_pid;
384
385         ////// READ SESSION TYPE /////////
386         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d",mypid);
387         fd = open(filename, O_RDONLY);
388         if(fd < 0) {
389                 return MM_ERROR_INVALID_HANDLE;
390         }
391         read(fd, sessiontype, sizeof(int));
392         close(fd);
393         ////// READ SESSION TYPE /////////
394
395         return MM_ERROR_NONE;
396 }
397
398 gboolean _asm_monitor_cb(gpointer *data)
399 {
400         session_monitor_t* monitor = (session_monitor_t*)data;
401         if (monitor) {
402                 if (monitor->fn) {
403                         debug_log("calling _asm_monitor_cb()");
404                         monitor->fn(monitor->msg, monitor->event, monitor->data);
405                 }
406         }
407
408         return FALSE;
409 }
410
411 static session_event_t _translate_from_asm_to_mm_session (ASM_event_sources_t event_src)
412 {
413         switch (event_src)
414         {
415         case ASM_EVENT_SOURCE_CALL_START:
416                 return MM_SESSION_EVENT_CALL;
417
418         case ASM_EVENT_SOURCE_EARJACK_UNPLUG:
419                 return MM_SESSION_EVENT_EARJACK_UNPLUG;
420
421         case ASM_EVENT_SOURCE_RESOURCE_CONFLICT:
422                 return MM_SESSION_EVENT_RESOURCE_CONFLICT;
423
424         case ASM_EVENT_SOURCE_ALARM_START:
425         case ASM_EVENT_SOURCE_ALARM_END:
426                 return MM_SESSION_EVENT_ALARM;
427
428         case ASM_EVENT_SOURCE_EMERGENCY_START:
429         case ASM_EVENT_SOURCE_EMERGENCY_END:
430                 return MM_SESSION_EVENT_EMERGENCY;
431
432         case ASM_EVENT_SOURCE_RESUMABLE_MEDIA:
433                 return MM_SESSION_EVENT_RESUMABLE_MEDIA;
434
435         case ASM_EVENT_SOURCE_MEDIA:
436         default:
437                 return MM_SESSION_EVENT_MEDIA;
438         }
439 }
440
441 ASM_cb_result_t
442 asm_monitor_callback(int handle, ASM_event_sources_t event_src, ASM_sound_commands_t command, unsigned int sound_status, void* cb_data)
443 {
444         ASM_cb_result_t cb_res = ASM_CB_RES_NONE;
445         session_monitor_t *monitor = (session_monitor_t*)cb_data;
446
447         debug_log("monitor callback called for handle %d, event_src %d", handle, event_src);
448         if(!monitor) {
449                 debug_log("monitor instance is null\n");
450                 return ASM_CB_RES_IGNORE;
451         }
452
453         switch(command)
454         {
455         case ASM_COMMAND_STOP:
456         case ASM_COMMAND_PAUSE:
457                 //call session_callback_fn for stop here
458                 if(monitor->fn) {
459                         monitor->msg = MM_SESSION_MSG_STOP;
460                         monitor->event = _translate_from_asm_to_mm_session (event_src);
461                         g_idle_add((GSourceFunc)_asm_monitor_cb, (gpointer)monitor);
462                 }
463                 cb_res = (command == ASM_COMMAND_STOP)? ASM_CB_RES_STOP : ASM_CB_RES_PAUSE;
464                 break;
465
466         case ASM_COMMAND_RESUME:
467         case ASM_COMMAND_PLAY:
468                 //call session_callback_fn for resume here
469                 if(monitor->fn) {
470                         monitor->msg = MM_SESSION_MSG_RESUME;
471                         monitor->event = _translate_from_asm_to_mm_session (event_src);
472                         g_idle_add((GSourceFunc)_asm_monitor_cb, (gpointer)monitor);
473                 }
474                 cb_res = ASM_CB_RES_IGNORE;
475                 break;
476
477         default:
478                 break;
479         }
480         return cb_res;
481 }
482
483 __attribute__ ((destructor))
484 void __mmsession_finalize(void)
485 {
486         int error=0;
487
488         debug_fenter();
489
490         TRY_LOCK(g_mutex_monitor, error);
491         if (!error) {
492                 if(g_monitor_asm_handle != -1) {
493                         /* Unregister monitor */
494                         if(!ASM_unregister_sound(g_monitor_asm_handle, ASM_EVENT_MONITOR, &error)) {
495                                 debug_error("ASM unregister monitor failed");
496                         } else {
497                                 debug_log("ASM unregister monitor success");
498                                 g_monitor_asm_handle = -1;
499                         }
500                 }
501                 UNLOCK(g_mutex_monitor);
502                 DESTROY(g_mutex_monitor);
503         }
504         _mm_session_util_delete_type(-1);
505
506         debug_fleave();
507 }
508
509 __attribute__ ((constructor))
510 void __mmsession_initialize(void)
511 {
512
513 }
514