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