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