Add mm_sound_subscribe_signal_for_daemon() for use case of daemon and remove mm_sound...
[platform/core/multimedia/libmm-sound.git] / mm_sound.c
1 /*
2  * libmm-sound
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 #include <stdlib.h>
23 #include <memory.h>
24 #include <unistd.h>
25 #include <pthread.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29
30 #include <sys/stat.h>
31 #include <errno.h>
32
33 #include <vconf.h>
34 #include <mm_types.h>
35 #include <mm_error.h>
36 #include <mm_message.h>
37 #include <mm_debug.h>
38 #include "include/mm_sound_private.h"
39 #include "include/mm_sound.h"
40 #include "include/mm_sound_utils.h"
41 #include "include/mm_sound_client.h"
42 #include "include/mm_sound_pa_client.h"
43 #include "include/mm_ipc.h"
44 #include "include/mm_sound_common.h"
45
46
47 #define VOLUME_MAX_MULTIMEDIA   16
48 #define VOLUME_MAX_BASIC                8
49 #define VOLUME_MAX_SINGLE               1
50
51
52 #define MASTER_VOLUME_MAX 100
53 #define MASTER_VOLUME_MIN 0
54
55 static pthread_mutex_t g_volume_mutex = PTHREAD_MUTEX_INITIALIZER;
56
57 #include <gio/gio.h>
58
59 static GList *g_subscribe_cb_list = NULL;
60 static pthread_mutex_t g_subscribe_cb_list_mutex = PTHREAD_MUTEX_INITIALIZER;
61
62 #define MM_SOUND_DBUS_BUS_NAME_PREPIX  "org.tizen.MMSound"
63 #define MM_SOUND_DBUS_OBJECT_PATH  "/org/tizen/MMSound"
64 #define MM_SOUND_DBUS_INTERFACE    "org.tizen.mmsound"
65
66 GDBusConnection *g_dbus_conn_mmsound;
67
68 int g_dbus_signal_values[MM_SOUND_SIGNAL_MAX] = {0,};
69
70 const char* dbus_signal_name_str[] = {
71         "ReleaseInternalFocus",
72 };
73
74 typedef struct _subscribe_cb {
75         mm_sound_signal_name_t signal_type;
76         mm_sound_signal_callback callback;
77         void *user_data;
78         unsigned int id;
79         int client_pid;
80 } subscribe_cb_t;
81
82 static const char* _get_volume_str (volume_type_t type)
83 {
84         static const char *volume_type_str[VOLUME_TYPE_MAX] =
85                 { "SYSTEM", "NOTIFICATION", "ALARM", "RINGTONE", "MEDIA", "CALL", "VOIP", "VOICE", "FIXED"};
86
87         return (type >= VOLUME_TYPE_SYSTEM && type < VOLUME_TYPE_MAX)? volume_type_str[type] : "Unknown";
88 }
89
90 static int _validate_volume(volume_type_t type, int value)
91 {
92         if (value < 0)
93                 return -1;
94
95         switch (type)
96         {
97         case VOLUME_TYPE_CALL:
98         case VOLUME_TYPE_VOIP:
99                 if (value >= VOLUME_MAX_BASIC) {
100                         return -1;
101                 }
102                 break;
103         case VOLUME_TYPE_SYSTEM:
104         case VOLUME_TYPE_MEDIA:
105         case VOLUME_TYPE_ALARM:
106         case VOLUME_TYPE_NOTIFICATION:
107         case VOLUME_TYPE_RINGTONE:
108         case VOLUME_TYPE_VOICE:
109                 if (value >= VOLUME_MAX_MULTIMEDIA) {
110                         return -1;
111                 }
112                 break;
113         default:
114                 return -1;
115                 break;
116         }
117         return 0;
118 }
119
120 EXPORT_API
121 int mm_sound_volume_remove_callback(volume_type_t type)
122 {
123         /* FIXME : Will be removed */
124         return MM_ERROR_NOT_SUPPORT_API;
125 }
126
127 EXPORT_API
128 int mm_sound_add_volume_changed_callback(mm_sound_volume_changed_cb func, void* user_data, unsigned int *subs_id)
129 {
130         int ret = MM_ERROR_NONE;
131
132         if (func == NULL || subs_id == NULL) {
133                 debug_error("argument is not valid\n");
134                 return MM_ERROR_INVALID_ARGUMENT;
135         }
136
137         ret = mm_sound_client_add_volume_changed_callback(func, user_data, subs_id);
138         if (ret < 0) {
139                 debug_error("Can not add volume changed callback, ret = %x\n", ret);
140         }
141
142         return ret;
143 }
144
145 EXPORT_API
146 int mm_sound_remove_volume_changed_callback(unsigned int subs_id)
147 {
148         int ret = MM_ERROR_NONE;
149
150         ret = mm_sound_client_remove_volume_changed_callback(subs_id);
151         if (ret < 0) {
152                 debug_error("Can not remove volume changed callback, ret = %x\n", ret);
153         }
154
155         return ret;
156 }
157
158 EXPORT_API
159 int mm_sound_volume_set_value(volume_type_t volume_type, const unsigned int volume_level)
160 {
161         int ret = MM_ERROR_NONE;
162
163         debug_msg("type = (%d)%s, value = %d", volume_type, _get_volume_str(volume_type), volume_level);
164
165         /* Check input param */
166         if (0 > _validate_volume(volume_type, (int)volume_level)) {
167                 debug_error("invalid volume type %d, value %u\n", volume_type, volume_level);
168                 return MM_ERROR_INVALID_ARGUMENT;
169         }
170
171         ret = mm_sound_util_volume_set_value_by_type(volume_type, volume_level);
172         if (ret == MM_ERROR_NONE) {
173                 /* update shared memory value */
174                 if(MM_ERROR_NONE != mm_sound_client_set_volume_by_type(volume_type, volume_level)) {
175                         debug_error("Can not set volume to shared memory 0x%x\n", ret);
176                 }
177         }
178
179         return ret;
180 }
181
182 EXPORT_API
183 int mm_sound_volume_get_value(volume_type_t type, unsigned int *value)
184 {
185         int ret = MM_ERROR_NONE;
186
187         /* Check input param */
188         if (value == NULL) {
189                 debug_error("invalid argument\n");
190                 return MM_ERROR_INVALID_ARGUMENT;
191         }
192         if (type < 0 || type >= VOLUME_TYPE_MAX) {
193                 debug_error("invalid volume type value %d\n", type);
194                 return MM_ERROR_INVALID_ARGUMENT;
195         }
196
197         ret = mm_sound_util_volume_get_value_by_type(type, value);
198
199         debug_msg("returned %s = %d", _get_volume_str(type), *value);
200         return ret;
201 }
202
203 EXPORT_API
204 int mm_sound_volume_primary_type_set(volume_type_t type)
205 {
206         int ret = MM_ERROR_NONE;
207
208         /* Check input param */
209         if(type < VOLUME_TYPE_UNKNOWN || type >= VOLUME_TYPE_MAX) {
210                 debug_error("invalid argument\n");
211                 return MM_ERROR_INVALID_ARGUMENT;
212         }
213
214         if (vconf_set_int(VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE, type)) {
215                 debug_error("could not set vconf for RIMARY_VOLUME_TYPE\n");
216                 ret = MM_ERROR_SOUND_INTERNAL;
217         } else {
218                 debug_msg("set primary volume type forcibly %d(%s)", type, _get_volume_str(type));
219         }
220
221         return ret;
222 }
223
224 EXPORT_API
225 int mm_sound_volume_primary_type_get(volume_type_t *type)
226 {
227         int ret = MM_ERROR_NONE;
228         int voltype = VOLUME_TYPE_RINGTONE;
229
230         /* Check input param */
231         if(type == NULL) {
232                 debug_error("invalid argument\n");
233                 return MM_ERROR_INVALID_ARGUMENT;
234         }
235
236         /* check force set */
237         if (vconf_get_int(VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE, &voltype)) {
238                 debug_error("could not get vconf for PRIMARY_VOLUME_TYPE\n");
239                 ret = MM_ERROR_SOUND_INTERNAL;
240         } else {
241                 debug_msg("get primary volume type %d(%s)", voltype, _get_volume_str(voltype));
242                 *type = voltype;
243         }
244
245         return ret;
246 }
247
248 ///////////////////////////////////
249 ////     MMSOUND PLAY APIs
250 ///////////////////////////////////
251 static inline void _mm_sound_fill_play_param(MMSoundPlayParam *param, const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int priority, int handle_route)
252 {
253         param->filename = filename;
254         param->volume = 0; //volume value dose not effect anymore
255         param->callback = callback;
256         param->data = data;
257         param->loop = 1;
258         param->volume_config = volume_config;
259         param->priority = priority;
260         param->handle_route = handle_route;
261 }
262
263 EXPORT_API
264 int mm_sound_play_loud_solo_sound(const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int *handle)
265 {
266         MMSoundPlayParam param = { 0, };
267
268     /* FIXME : this function will be deleted */
269         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_NORMAL, MM_SOUND_HANDLE_ROUTE_USING_CURRENT);
270         return mm_sound_play_sound_ex(&param, handle);
271 }
272
273 EXPORT_API
274 int mm_sound_play_sound(const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int *handle)
275 {
276         MMSoundPlayParam param = { 0, };
277
278         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_NORMAL, MM_SOUND_HANDLE_ROUTE_USING_CURRENT);
279         return mm_sound_play_sound_ex(&param, handle);
280 }
281
282 EXPORT_API
283 int mm_sound_play_sound_ex(MMSoundPlayParam *param, int *handle)
284 {
285         int err;
286         int lhandle = -1;
287         int volume_type = 0;
288         /* Check input param */
289         if (param == NULL) {
290                 debug_error("param is null\n");
291                 return MM_ERROR_INVALID_ARGUMENT;
292         }
293
294         volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(param->volume_config);
295
296         if (param->filename == NULL) {
297                 debug_error("filename is NULL\n");
298                 return MM_ERROR_SOUND_FILE_NOT_FOUND;
299         }
300         if (volume_type < 0 || volume_type >= VOLUME_TYPE_MAX) {
301                 debug_error("Volume type is invalid %d\n", volume_type);
302                 return MM_ERROR_INVALID_ARGUMENT;
303         }
304
305         debug_warning ("play sound : priority=[%d], handle_route=[%d]\n", param->priority, param->handle_route);
306
307         /* Play sound */
308         err = mm_sound_client_play_sound(param, 0, &lhandle);
309         if (err < 0) {
310                 debug_error("Failed to play sound\n");
311                 return err;
312         }
313
314         /* Set handle to return */
315         if (handle) {
316                 *handle = lhandle;
317         } else {
318                 debug_critical("The sound hadle cannot be get [%d]\n", lhandle);
319         }
320
321         debug_warning ("success : handle=[%p]\n", handle);
322
323         return MM_ERROR_NONE;
324 }
325
326 EXPORT_API
327 int mm_sound_play_sound_with_stream_info(const char *filename, char *stream_type, int stream_id, mm_sound_stop_callback_func callback, void *data, int *handle)
328 {
329         MMSoundPlayParam param = { 0, };
330         int err;
331
332         param.filename = filename;
333         param.volume = 0; //volume value dose not effect anymore
334         param.callback = callback;
335         param.data = data;
336         param.loop = 1;
337         param.priority = HANDLE_PRIORITY_NORMAL;
338         param.handle_route = MM_SOUND_HANDLE_ROUTE_USING_CURRENT;
339
340         err = mm_sound_client_play_sound_with_stream_info(&param, handle, stream_type, stream_id);
341         if (err < 0) {
342                 debug_error("Failed to play sound\n");
343                 return err;
344         }
345
346         debug_warning ("success : handle=[%p]\n", handle);
347
348         return MM_ERROR_NONE;
349
350 }
351
352
353 EXPORT_API
354 int mm_sound_stop_sound(int handle)
355 {
356         int err;
357
358         debug_warning ("enter : handle=[%p]\n", handle);
359         /* Stop sound */
360         err = mm_sound_client_stop_sound(handle);
361         if (err < 0) {
362                 debug_error("Fail to stop sound\n");
363                 return err;
364         }
365         debug_warning ("success : handle=[%p]\n", handle);
366
367         return MM_ERROR_NONE;
368 }
369
370 ///////////////////////////////////
371 ////     MMSOUND TONE APIs
372 ///////////////////////////////////
373 EXPORT_API
374 int mm_sound_play_tone_ex (MMSoundTone_t num, int volume_config, const double volume, const int duration, int *handle, bool enable_session)
375 {
376         int lhandle = -1;
377         int err = MM_ERROR_NONE;
378         int volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(volume_config);
379
380         debug_fenter();
381
382         /* Check input param */
383         if (duration < -1) {
384                 debug_error("number is invalid %d\n", duration);
385                 return MM_ERROR_INVALID_ARGUMENT;
386         }
387         if (num < MM_SOUND_TONE_DTMF_0 || num >= MM_SOUND_TONE_NUM) {
388                 debug_error("TONE Value is invalid %d\n", num);
389                 return MM_ERROR_INVALID_ARGUMENT;
390         }
391         if (volume_type < 0 || volume_type >= VOLUME_TYPE_MAX) {
392                 debug_error("Volume type is invalid %d\n", volume_type);
393                 return MM_ERROR_INVALID_ARGUMENT;
394         }
395         if (volume < 0.0 || volume > 1.0) {
396                 debug_error("Volume Value is invalid %d\n", volume);
397                 return MM_ERROR_INVALID_ARGUMENT;
398         }
399
400         /* Play tone */
401         debug_msg("Call MMSoundClientPlayTone\n");
402         err = mm_sound_client_play_tone(num, volume_config, volume, duration, &lhandle, enable_session);
403         if (err < 0) {
404                 debug_error("Failed to play sound\n");
405                 return err;
406         }
407
408         /* Set handle to return */
409         if (handle)
410                 *handle = lhandle;
411         else
412                 debug_critical("The sound handle cannot be get [%d]\n", lhandle);
413
414         debug_fleave();
415         return MM_ERROR_NONE;
416 }
417
418 EXPORT_API
419 int mm_sound_play_tone_with_stream_info(MMSoundTone_t tone, char *stream_type, int stream_id, const double volume, const int duration, int *handle)
420 {
421
422         int err = MM_ERROR_NONE;
423
424         err = mm_sound_client_play_tone_with_stream_info(tone, stream_type, stream_id, volume, duration, handle);
425         if (err <0) {
426                 debug_error("Failed to play sound\n");
427                 return err;
428         }
429
430         return err;
431
432 }
433
434
435 EXPORT_API
436 int mm_sound_play_tone (MMSoundTone_t num, int volume_config, const double volume, const int duration, int *handle)
437 {
438         return mm_sound_play_tone_ex (num, volume_config, volume, duration, handle, true);
439 }
440
441 ///////////////////////////////////
442 ////     MMSOUND ROUTING APIs
443 ///////////////////////////////////
444
445 EXPORT_API
446 int mm_sound_test(int a, int b, int* getv)
447 {
448         int ret = MM_ERROR_NONE;
449
450         debug_log("mm_sound_test enter");
451         if (!getv) {
452                 debug_error("argu null");
453                 return MM_ERROR_INVALID_ARGUMENT;
454         }
455         ret = mm_sound_client_test(a, b, getv);
456         if (ret < 0) {
457                 debug_error("Can not mm sound test, ret = %x\n", ret);
458         }
459         debug_log("mm_sound_test leave");
460
461         return ret;
462 }
463
464 EXPORT_API
465 int mm_sound_add_test_callback(mm_sound_test_cb func, void *user_data, unsigned int *subs_id)
466 {
467         int ret = MM_ERROR_NONE;
468
469         debug_log("mm_sound_add_test_callback enter");
470         if (!func || !subs_id) {
471                 debug_error("argument is not valid\n");
472                 return MM_ERROR_INVALID_ARGUMENT;
473         }
474
475         ret = mm_sound_client_add_test_callback(func, user_data, subs_id);
476         if (ret < 0) {
477                 debug_error("Can not add test callback, ret = %x\n", ret);
478         }
479         debug_log("mm_sound_add_test_callback leave");
480
481         return ret;
482 }
483
484 EXPORT_API
485 int mm_sound_remove_test_callback(unsigned int subs_id)
486 {
487         int ret = MM_ERROR_NONE;
488
489         debug_log("mm_sound_remove_test_callback enter");
490         ret = mm_sound_client_remove_test_callback(subs_id);
491         if (ret < 0) {
492                 debug_error("Can not remove test callback, ret = %x\n", ret);
493         }
494         debug_log("mm_sound_remove_test_callback leave");
495
496         return ret;
497 }
498
499 static int _convert_signal_name_str_to_enum (const char *name_str, mm_sound_signal_name_t *name_enum) {
500         int ret = MM_ERROR_NONE;
501
502         if (!name_str || !name_enum)
503                 return MM_ERROR_INVALID_ARGUMENT;
504
505         if (!strncmp(name_str, "ReleaseInternalFocus", strlen("ReleaseInternalFocus"))) {
506                 *name_enum = MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS;
507         } else {
508                 ret = MM_ERROR_INVALID_ARGUMENT;
509                 LOGE("not supported signal name(%s), err(0x%08x)", name_str, ret);
510         }
511         return ret;
512 }
513
514 #define MASK_FOR_PID    0x00FFFFFF
515 #define MASK_FOR_VALUE  0x000000FF
516 static void _dbus_signal_callback (const char *signal_name, int value, void *user_data)
517 {
518         int ret = MM_ERROR_NONE;
519         mm_sound_signal_name_t signal;
520         subscribe_cb_t *subscribe_cb = (subscribe_cb_t*)user_data;
521
522         debug_fenter();
523
524         if (!subscribe_cb)
525                 return;
526
527         ret = _convert_signal_name_str_to_enum(signal_name, &signal);
528         if (ret)
529                 return;
530
531         debug_msg ("signal_name[%s], value[%d], user_data[0x%x]\n", signal_name, value, user_data);
532
533         if (subscribe_cb->signal_type == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
534                 /* trigger the signal callback when it comes from the same process,
535                 * in case of daemon usage, it uses the client_pid of subscribe_cb */
536                 if ((subscribe_cb->client_pid ? (subscribe_cb->client_pid & MASK_FOR_PID) : (getpid() & MASK_FOR_PID)) == ((value & (MASK_FOR_PID << 8)) >> 8)) {
537                         subscribe_cb->callback(signal, (value & MASK_FOR_VALUE), subscribe_cb->user_data);
538                 }
539         } else {
540                 subscribe_cb->callback(signal, value, subscribe_cb->user_data);
541         }
542
543         debug_fleave();
544
545         return;
546 }
547
548 static void signal_callback(GDBusConnection *conn,
549                                                            const gchar *sender_name,
550                                                            const gchar *object_path,
551                                                            const gchar *interface_name,
552                                                            const gchar *signal_name,
553                                                            GVariant *parameters,
554                                                            gpointer user_data)
555 {
556         int value=0;
557         const GVariantType* value_type;
558
559         debug_msg ("sender : %s, object : %s, interface : %s, signal : %s",
560                         sender_name, object_path, interface_name, signal_name);
561         if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(i)"))) {
562                 g_variant_get(parameters, "(i)",&value);
563                 debug_msg(" - value : %d\n", value);
564                 _dbus_signal_callback(signal_name, value, user_data);
565         } else  {
566                 value_type = g_variant_get_type(parameters);
567                 debug_warning("signal type is %s", value_type);
568         }
569 }
570
571 EXPORT_API
572 int mm_sound_subscribe_signal(mm_sound_signal_name_t signal, unsigned int *subscribe_id, mm_sound_signal_callback callback, void *user_data)
573 {
574         int ret = MM_ERROR_NONE;
575         GError *err = NULL;
576
577         subscribe_cb_t *subscribe_cb = NULL;
578
579         debug_fenter();
580
581         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
582
583         if (signal < 0 || signal >= MM_SOUND_SIGNAL_MAX || !subscribe_id) {
584                 debug_error ("invalid argument, signal(%d), subscribe_id(0x%p)", signal, subscribe_id);
585                 ret = MM_ERROR_INVALID_ARGUMENT;
586                 goto error;
587         }
588
589         subscribe_cb = malloc(sizeof(subscribe_cb_t));
590         if (!subscribe_cb) {
591                 ret = MM_ERROR_SOUND_INTERNAL;
592                 goto error;
593         }
594         memset(subscribe_cb, 0, sizeof(subscribe_cb_t));
595
596         g_dbus_conn_mmsound = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
597         if (!g_dbus_conn_mmsound && err) {
598                 debug_error ("g_bus_get_sync() error (%s) ", err->message);
599                 g_error_free (err);
600                 ret = MM_ERROR_SOUND_INTERNAL;
601                 goto error;
602         }
603
604         subscribe_cb->signal_type = signal;
605         subscribe_cb->callback = callback;
606         subscribe_cb->user_data = user_data;
607
608         *subscribe_id = g_dbus_connection_signal_subscribe(g_dbus_conn_mmsound,
609                         NULL, MM_SOUND_DBUS_INTERFACE, dbus_signal_name_str[signal], MM_SOUND_DBUS_OBJECT_PATH, NULL, 0,
610                         signal_callback, subscribe_cb, NULL);
611         if (*subscribe_id == 0) {
612                 debug_error ("g_dbus_connection_signal_subscribe() error (%d)", *subscribe_id);
613                 ret = MM_ERROR_SOUND_INTERNAL;
614                 goto sig_error;
615         }
616
617         subscribe_cb->id = *subscribe_id;
618
619         g_subscribe_cb_list = g_list_append(g_subscribe_cb_list, subscribe_cb);
620         if (g_subscribe_cb_list) {
621                 debug_log("new subscribe_cb(0x%x)[user_callback(0x%x), subscribe_id(%u)] is added\n", subscribe_cb, subscribe_cb->callback, subscribe_cb->id);
622         } else {
623                 debug_error("g_list_append failed\n");
624                 ret = MM_ERROR_SOUND_INTERNAL;
625                 goto error;
626         }
627
628         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
629
630         debug_fleave();
631
632         return ret;
633
634 sig_error:
635         g_dbus_connection_signal_unsubscribe(g_dbus_conn_mmsound, *subscribe_id);
636         g_object_unref(g_dbus_conn_mmsound);
637
638 error:
639         if (subscribe_cb)
640                 free (subscribe_cb);
641
642         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
643
644         return ret;
645 }
646
647 EXPORT_API
648 int mm_sound_subscribe_signal_for_daemon(mm_sound_signal_name_t signal, int client_pid, unsigned int *subscribe_id, mm_sound_signal_callback callback, void *user_data)
649 {
650         int ret = MM_ERROR_NONE;
651         GError *err = NULL;
652
653         subscribe_cb_t *subscribe_cb = NULL;
654
655         debug_fenter();
656
657         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
658
659         if (signal < 0 || signal >= MM_SOUND_SIGNAL_MAX || !client_pid || !subscribe_id) {
660                 debug_error ("invalid argument, signal(%d), client_pid(%d), subscribe_id(0x%p)", signal, client_pid, subscribe_id);
661                 ret = MM_ERROR_INVALID_ARGUMENT;
662                 goto error;
663         }
664
665         subscribe_cb = malloc(sizeof(subscribe_cb_t));
666         if (!subscribe_cb) {
667                 ret = MM_ERROR_SOUND_INTERNAL;
668                 goto error;
669         }
670         memset(subscribe_cb, 0, sizeof(subscribe_cb_t));
671
672         g_dbus_conn_mmsound = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
673         if (!g_dbus_conn_mmsound && err) {
674                 debug_error ("g_bus_get_sync() error (%s) ", err->message);
675                 g_error_free (err);
676                 ret = MM_ERROR_SOUND_INTERNAL;
677                 goto error;
678         }
679
680         subscribe_cb->signal_type = signal;
681         subscribe_cb->callback = callback;
682         subscribe_cb->user_data = user_data;
683         subscribe_cb->client_pid = client_pid;
684
685         *subscribe_id = g_dbus_connection_signal_subscribe(g_dbus_conn_mmsound,
686                         NULL, MM_SOUND_DBUS_INTERFACE, dbus_signal_name_str[signal], MM_SOUND_DBUS_OBJECT_PATH, NULL, 0,
687                         signal_callback, subscribe_cb, NULL);
688         if (*subscribe_id == 0) {
689                 debug_error ("g_dbus_connection_signal_subscribe() error (%d)", *subscribe_id);
690                 ret = MM_ERROR_SOUND_INTERNAL;
691                 goto sig_error;
692         }
693
694         subscribe_cb->id = *subscribe_id;
695
696         g_subscribe_cb_list = g_list_append(g_subscribe_cb_list, subscribe_cb);
697         if (g_subscribe_cb_list) {
698                 debug_log("new subscribe_cb(0x%x)[user_callback(0x%x), subscribe_id(%u)] is added\n", subscribe_cb, subscribe_cb->callback, subscribe_cb->id);
699         } else {
700                 debug_error("g_list_append failed\n");
701                 ret = MM_ERROR_SOUND_INTERNAL;
702                 goto error;
703         }
704
705         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
706
707         debug_fleave();
708
709         return ret;
710
711 sig_error:
712         g_dbus_connection_signal_unsubscribe(g_dbus_conn_mmsound, *subscribe_id);
713         g_object_unref(g_dbus_conn_mmsound);
714
715 error:
716         if (subscribe_cb)
717                 free (subscribe_cb);
718
719         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
720
721         return ret;
722 }
723
724 EXPORT_API
725 void mm_sound_unsubscribe_signal(unsigned int subscribe_id)
726 {
727         GList *list = NULL;
728         subscribe_cb_t *subscribe_cb = NULL;
729
730         debug_fenter();
731
732         MMSOUND_ENTER_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
733
734         if (g_dbus_conn_mmsound && subscribe_id) {
735                 g_dbus_connection_signal_unsubscribe(g_dbus_conn_mmsound, subscribe_id);
736                 g_object_unref(g_dbus_conn_mmsound);
737                 for (list = g_subscribe_cb_list; list != NULL; list = list->next) {
738                         subscribe_cb = (subscribe_cb_t *)list->data;
739                         if (subscribe_cb && (subscribe_cb->id == subscribe_id)) {
740                                 g_subscribe_cb_list = g_list_remove(g_subscribe_cb_list, subscribe_cb);
741                                 debug_log("subscribe_cb(0x%x) is removed\n", subscribe_cb);
742                                 free (subscribe_cb);
743                         }
744                 }
745         }
746
747         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
748
749         debug_fleave();
750 }
751
752 EXPORT_API
753 int mm_sound_send_signal(mm_sound_signal_name_t signal, int value)
754 {
755         int ret = MM_ERROR_NONE;
756         GError *err = NULL;
757         GDBusConnection *conn = NULL;
758         gboolean dbus_ret = TRUE;
759
760         debug_fenter();
761
762         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
763
764         if (signal < 0 || signal >= MM_SOUND_SIGNAL_MAX) {
765                 debug_error ("invalid argument, signal(%d)", signal);
766                 ret = MM_ERROR_INVALID_ARGUMENT;
767                 goto error;
768         }
769
770         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
771         if (!conn && err) {
772                 debug_error ("g_bus_get_sync() error (%s)", err->message);
773                 ret = MM_ERROR_SOUND_INTERNAL;
774                 goto error;
775         }
776
777         g_dbus_signal_values[signal] = value;
778         if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
779                 /* trigger the signal callback when it comes from the same process */
780                 value |= ((int)getpid() << 8);
781         }
782         dbus_ret = g_dbus_connection_emit_signal (conn,
783                                 NULL, MM_SOUND_DBUS_OBJECT_PATH, MM_SOUND_DBUS_INTERFACE, dbus_signal_name_str[signal],
784                                 g_variant_new ("(i)", value),
785                                 &err);
786         if (!dbus_ret && err) {
787                 debug_error ("g_dbus_connection_emit_signal() error (%s)", err->message);
788                 ret = MM_ERROR_SOUND_INTERNAL;
789                 goto error;
790         }
791
792         dbus_ret = g_dbus_connection_flush_sync(conn, NULL, &err);
793         if (!dbus_ret && err) {
794                 debug_error ("g_dbus_connection_flush_sync() error (%s)", err->message);
795                 ret = MM_ERROR_SOUND_INTERNAL;
796                 goto error;
797         }
798
799         g_object_unref(conn);
800         debug_msg ("sending signal[%s], value[%d] success", dbus_signal_name_str[signal], value);
801
802         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
803
804         debug_fleave();
805
806         return ret;
807
808 error:
809         if (err)
810                 g_error_free (err);
811         if (conn)
812                 g_object_unref(conn);
813
814         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
815
816         return ret;
817 }
818
819 EXPORT_API
820 int mm_sound_get_signal_value(mm_sound_signal_name_t signal, int *value)
821 {
822         int ret = MM_ERROR_NONE;
823
824         debug_fenter();
825
826         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
827
828         *value = g_dbus_signal_values[signal];
829
830         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
831
832         debug_fleave();
833
834         return ret;
835 }
836
837 __attribute__ ((constructor))
838 static void _mm_sound_initialize(void)
839 {
840         mm_sound_client_initialize();
841         /* Will be Fixed */
842 }
843
844 __attribute__ ((destructor))
845 static void _mm_sound_finalize(void)
846 {
847         mm_sound_client_finalize();
848 }
849
850