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