Remove unused variable for play sound
[platform/core/multimedia/libmm-sound.git] / mm_sound.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Seungbae Shin <seungbae.shin@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdlib.h>
23 #include <memory.h>
24 #include <unistd.h>
25 #include <pthread.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29
30 #include <sys/stat.h>
31 #include <errno.h>
32
33 #include <vconf.h>
34 #include <mm_types.h>
35 #include <mm_error.h>
36 #include <mm_message.h>
37 #include <mm_debug.h>
38 #include "include/mm_sound_private.h"
39 #include "include/mm_sound.h"
40 #include "include/mm_sound_utils.h"
41 #include "include/mm_sound_client.h"
42 #include "include/mm_sound_pa_client.h"
43 #include "include/mm_ipc.h"
44 #include "include/mm_sound_common.h"
45
46
47 #define VOLUME_MAX_MULTIMEDIA   16
48 #define VOLUME_MAX_BASIC                8
49 #define VOLUME_MAX_SINGLE               1
50
51
52 #define MASTER_VOLUME_MAX 100
53 #define MASTER_VOLUME_MIN 0
54
55
56 typedef struct {
57         volume_callback_fn      func;
58         void*                           data;
59         volume_type_t           type;
60 } volume_cb_param;
61
62 volume_cb_param g_volume_param[VOLUME_TYPE_MAX];
63
64 static pthread_mutex_t g_volume_mutex = PTHREAD_MUTEX_INITIALIZER;
65
66 #include <gio/gio.h>
67
68 static GList *g_subscribe_cb_list = NULL;
69 static pthread_mutex_t g_subscribe_cb_list_mutex = PTHREAD_MUTEX_INITIALIZER;
70
71 #define MM_SOUND_DBUS_BUS_NAME_PREPIX  "org.tizen.MMSound"
72 #define MM_SOUND_DBUS_OBJECT_PATH  "/org/tizen/MMSound"
73 #define MM_SOUND_DBUS_INTERFACE    "org.tizen.mmsound"
74
75 GDBusConnection *g_dbus_conn_mmsound;
76
77 int g_dbus_signal_values[MM_SOUND_SIGNAL_MAX] = {0,};
78
79 const char* dbus_signal_name_str[] = {
80         "ReleaseInternalFocus",
81 };
82
83 typedef struct _subscribe_cb {
84         mm_sound_signal_name_t signal_type;
85         mm_sound_signal_callback callback;
86         void *user_data;
87         unsigned int id;
88 } subscribe_cb_t;
89
90 static char* _get_volume_str (volume_type_t type)
91 {
92         static const char *volume_type_str[VOLUME_TYPE_MAX] =
93                 { "SYSTEM", "NOTIFICATION", "ALARM", "RINGTONE", "MEDIA", "CALL", "VOIP", "VOICE", "FIXED"};
94
95         return (type >= VOLUME_TYPE_SYSTEM && type < VOLUME_TYPE_MAX)? volume_type_str[type] : "Unknown";
96 }
97
98 static int _validate_volume(volume_type_t type, int value)
99 {
100         if (value < 0)
101                 return -1;
102
103         switch (type)
104         {
105         case VOLUME_TYPE_CALL:
106         case VOLUME_TYPE_VOIP:
107                 if (value >= VOLUME_MAX_BASIC) {
108                         return -1;
109                 }
110                 break;
111         case VOLUME_TYPE_SYSTEM:
112         case VOLUME_TYPE_MEDIA:
113         case VOLUME_TYPE_ALARM:
114         case VOLUME_TYPE_NOTIFICATION:
115         case VOLUME_TYPE_RINGTONE:
116         case VOLUME_TYPE_VOICE:
117                 if (value >= VOLUME_MAX_MULTIMEDIA) {
118                         return -1;
119                 }
120                 break;
121         default:
122                 return -1;
123                 break;
124         }
125         return 0;
126 }
127
128 static void _volume_changed_cb(keynode_t* node, void* data)
129 {
130         volume_cb_param* param = (volume_cb_param*) data;
131
132         debug_msg("%s changed callback called\n",vconf_keynode_get_name(node));
133
134         MMSOUND_ENTER_CRITICAL_SECTION( &g_volume_mutex )
135
136         if(param && (param->func != NULL)) {
137                 debug_log("function 0x%x\n", param->func);
138                 ((volume_callback_fn)param->func)(param->data);
139         }
140
141         MMSOUND_LEAVE_CRITICAL_SECTION( &g_volume_mutex )
142 }
143
144 EXPORT_API
145 int mm_sound_volume_add_callback(volume_type_t type, volume_callback_fn func, void* user_data)
146 {
147         debug_msg("type = (%d)%15s, func = %p, user_data = %p", type, _get_volume_str(type), func, user_data);
148
149         /* Check input param */
150         if (type < 0 || type >= VOLUME_TYPE_MAX) {
151                 debug_error("invalid argument\n");
152                 return MM_ERROR_INVALID_ARGUMENT;
153         }
154         if (!func) {
155                 debug_warning("callback function is null\n");
156                 return MM_ERROR_INVALID_ARGUMENT;
157         }
158
159         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN( &g_volume_mutex, MM_ERROR_SOUND_INTERNAL );
160
161         g_volume_param[type].func = func;
162         g_volume_param[type].data = user_data;
163         g_volume_param[type].type = type;
164
165         MMSOUND_LEAVE_CRITICAL_SECTION( &g_volume_mutex );
166
167         return mm_sound_util_volume_add_callback(type, _volume_changed_cb, (void*)&g_volume_param[type]);
168 }
169
170 EXPORT_API
171 int mm_sound_volume_remove_callback(volume_type_t type)
172 {
173         debug_msg("type = (%d)%s", type, _get_volume_str(type));
174
175         if(type < 0 || type >=VOLUME_TYPE_MAX) {
176                 debug_error("invalid argument\n");
177                 return MM_ERROR_INVALID_ARGUMENT;
178         }
179
180         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN( &g_volume_mutex, MM_ERROR_SOUND_INTERNAL );
181
182         g_volume_param[type].func = NULL;
183         g_volume_param[type].data = NULL;
184         g_volume_param[type].type = type;
185
186         MMSOUND_LEAVE_CRITICAL_SECTION( &g_volume_mutex );
187
188         return mm_sound_util_volume_remove_callback(type, _volume_changed_cb);
189 }
190
191 EXPORT_API
192 int mm_sound_add_volume_changed_callback(mm_sound_volume_changed_cb func, void* user_data)
193 {
194         int ret = MM_ERROR_NONE;
195
196         if (func == NULL) {
197                 debug_error("argument is not valid\n");
198                 return MM_ERROR_INVALID_ARGUMENT;
199         }
200
201         ret = mm_sound_client_add_volume_changed_callback(func, user_data);
202         if (ret < 0) {
203                 debug_error("Can not add volume changed callback, ret = %x\n", ret);
204         }
205
206         return ret;
207 }
208
209 EXPORT_API
210 int mm_sound_remove_volume_changed_callback(void)
211 {
212         int ret = MM_ERROR_NONE;
213
214         ret = mm_sound_client_remove_volume_changed_callback();
215         if (ret < 0) {
216                 debug_error("Can not remove volume changed callback, ret = %x\n", ret);
217         }
218
219         return ret;
220 }
221
222 EXPORT_API
223 int mm_sound_volume_get_step(volume_type_t type, int *step)
224 {
225         return MM_ERROR_SOUND_NOT_SUPPORTED_OPERATION;
226 }
227
228 EXPORT_API
229 int mm_sound_volume_set_value(volume_type_t volume_type, const unsigned int volume_level)
230 {
231         int ret = MM_ERROR_NONE;
232
233         debug_msg("type = (%d)%s, value = %d", volume_type, _get_volume_str(volume_type), volume_level);
234
235         /* Check input param */
236         if (0 > _validate_volume(volume_type, (int)volume_level)) {
237                 debug_error("invalid volume type %d, value %u\n", volume_type, volume_level);
238                 return MM_ERROR_INVALID_ARGUMENT;
239         }
240
241         ret = mm_sound_util_volume_set_value_by_type(volume_type, volume_level);
242         if (ret == MM_ERROR_NONE) {
243                 /* update shared memory value */
244                 if(MM_ERROR_NONE != mm_sound_client_set_volume_by_type(volume_type, volume_level)) {
245                         debug_error("Can not set volume to shared memory 0x%x\n", ret);
246                 }
247         }
248
249         return ret;
250 }
251
252 EXPORT_API
253 int mm_sound_volume_get_value(volume_type_t type, unsigned int *value)
254 {
255         int ret = MM_ERROR_NONE;
256
257         /* Check input param */
258         if (value == NULL) {
259                 debug_error("invalid argument\n");
260                 return MM_ERROR_INVALID_ARGUMENT;
261         }
262         if (type < 0 || type >= VOLUME_TYPE_MAX) {
263                 debug_error("invalid volume type value %d\n", type);
264                 return MM_ERROR_INVALID_ARGUMENT;
265         }
266
267         ret = mm_sound_util_volume_get_value_by_type(type, value);
268
269         debug_msg("returned %s = %d", _get_volume_str(type), *value);
270         return ret;
271 }
272
273 EXPORT_API
274 int mm_sound_volume_primary_type_set(volume_type_t type)
275 {
276         pid_t mypid;
277         int ret = MM_ERROR_NONE;
278
279         /* Check input param */
280         if(type < VOLUME_TYPE_UNKNOWN || type >= VOLUME_TYPE_MAX) {
281                 debug_error("invalid argument\n");
282                 return MM_ERROR_INVALID_ARGUMENT;
283         }
284
285         if (vconf_set_int(VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE, type)) {
286                 debug_error("could not set vconf for RIMARY_VOLUME_TYPE\n");
287                 ret = MM_ERROR_SOUND_INTERNAL;
288         } else {
289                 debug_msg("set primary volume type forcibly %d(%s)", type, _get_volume_str(type));
290         }
291
292         return ret;
293 }
294
295 EXPORT_API
296 int mm_sound_volume_primary_type_get(volume_type_t *type)
297 {
298         int ret = MM_ERROR_NONE;
299         int voltype = VOLUME_TYPE_RINGTONE;
300
301         /* Check input param */
302         if(type == NULL) {
303                 debug_error("invalid argument\n");
304                 return MM_ERROR_INVALID_ARGUMENT;
305         }
306
307         /* check force set */
308         if (vconf_get_int(VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE, &voltype)) {
309                 debug_error("could not get vconf for PRIMARY_VOLUME_TYPE\n");
310                 ret = MM_ERROR_SOUND_INTERNAL;
311         } else {
312                 debug_msg("get primary volume type %d(%s)", voltype, _get_volume_str(voltype));
313                 *type = voltype;
314         }
315
316         return ret;
317 }
318
319 /* it will be removed */
320 EXPORT_API
321 int mm_sound_volume_primary_type_clear(void)
322 {
323         pid_t mypid;
324         int ret = MM_ERROR_NONE;
325
326         if (vconf_set_int(VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE, -1)) {
327                 debug_error("could not reset vconf for PRIMARY_VOLUME_TYPE\n");
328                 ret = MM_ERROR_SOUND_INTERNAL;
329         } else {
330                 debug_msg("clear primary volume type forcibly %d(%s)", -1, "none");
331         }
332
333         return ret;
334 }
335
336 ///////////////////////////////////
337 ////     MMSOUND PLAY APIs
338 ///////////////////////////////////
339 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)
340 {
341         param->filename = filename;
342         param->volume = 0; //volume value dose not effect anymore
343         param->callback = callback;
344         param->data = data;
345         param->loop = 1;
346         param->volume_config = volume_config;
347         param->priority = priority;
348         param->handle_route = handle_route;
349 }
350
351 EXPORT_API
352 int mm_sound_play_loud_solo_sound_no_restore(const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int *handle)
353 {
354         MMSoundPlayParam param = { 0, };
355
356         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_SOLO, MM_SOUND_HANDLE_ROUTE_SPEAKER_NO_RESTORE);
357         return mm_sound_play_sound_ex(&param, handle);
358 }
359
360 EXPORT_API
361 int mm_sound_play_loud_solo_sound(const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int *handle)
362 {
363         MMSoundPlayParam param = { 0, };
364
365         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_SOLO, MM_SOUND_HANDLE_ROUTE_SPEAKER);
366         return mm_sound_play_sound_ex(&param, handle);
367 }
368
369 EXPORT_API
370 int mm_sound_play_solo_sound(const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int *handle)
371 {
372         MMSoundPlayParam param = { 0, };
373
374         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_SOLO, MM_SOUND_HANDLE_ROUTE_USING_CURRENT);
375         return mm_sound_play_sound_ex(&param, handle);
376 }
377
378 EXPORT_API
379 int mm_sound_play_sound_without_session(const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int *handle)
380 {
381         MMSoundPlayParam param = { 0, };
382
383         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_SOLO, MM_SOUND_HANDLE_ROUTE_USING_CURRENT);
384         param.skip_session = true;
385         return mm_sound_play_sound_ex(&param, handle);
386 }
387
388 EXPORT_API
389 int mm_sound_play_sound(const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int *handle)
390 {
391         MMSoundPlayParam param = { 0, };
392
393         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_NORMAL, MM_SOUND_HANDLE_ROUTE_USING_CURRENT);
394         return mm_sound_play_sound_ex(&param, handle);
395 }
396
397 EXPORT_API
398 int mm_sound_play_sound_ex(MMSoundPlayParam *param, int *handle)
399 {
400         int err;
401         int lhandle = -1;
402         int volume_type = 0;
403         /* Check input param */
404         if (param == NULL) {
405                 debug_error("param is null\n");
406                 return MM_ERROR_INVALID_ARGUMENT;
407         }
408
409         volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(param->volume_config);
410
411         if (param->filename == NULL) {
412                 debug_error("filename is NULL\n");
413                 return MM_ERROR_SOUND_FILE_NOT_FOUND;
414         }
415         if (volume_type < 0 || volume_type >= VOLUME_TYPE_MAX) {
416                 debug_error("Volume type is invalid %d\n", volume_type);
417                 return MM_ERROR_INVALID_ARGUMENT;
418         }
419
420         debug_warning ("play sound : priority=[%d], handle_route=[%d]\n", param->priority, param->handle_route);
421
422         /* Play sound */
423         err = mm_sound_client_play_sound(param, 0, &lhandle);
424         if (err < 0) {
425                 debug_error("Failed to play sound\n");
426                 return err;
427         }
428
429         /* Set handle to return */
430         if (handle) {
431                 *handle = lhandle;
432         } else {
433                 debug_critical("The sound hadle cannot be get [%d]\n", lhandle);
434         }
435
436         debug_warning ("success : handle=[%p]\n", handle);
437
438         return MM_ERROR_NONE;
439 }
440
441 EXPORT_API
442 int mm_sound_play_sound_with_stream_info(const char *filename, char *stream_type, int stream_id, mm_sound_stop_callback_func callback, void *data, int *handle)
443 {
444         MMSoundPlayParam param = { 0, };
445         int err;
446
447         param.filename = filename;
448         param.volume = 0; //volume value dose not effect anymore
449         param.callback = callback;
450         param.data = data;
451         param.loop = 1;
452         param.priority = HANDLE_PRIORITY_NORMAL;
453         param.handle_route = MM_SOUND_HANDLE_ROUTE_USING_CURRENT;
454
455         err = mm_sound_client_play_sound_with_stream_info(&param, handle, stream_type, stream_id);
456         if (err < 0) {
457                 debug_error("Failed to play sound\n");
458                 return err;
459         }
460
461         debug_warning ("success : handle=[%p]\n", handle);
462
463         return MM_ERROR_NONE;
464
465 }
466
467
468 EXPORT_API
469 int mm_sound_stop_sound(int handle)
470 {
471         int err;
472
473         debug_warning ("enter : handle=[%p]\n", handle);
474         /* Stop sound */
475         err = mm_sound_client_stop_sound(handle);
476         if (err < 0) {
477                 debug_error("Fail to stop sound\n");
478                 return err;
479         }
480         debug_warning ("success : handle=[%p]\n", handle);
481
482         return MM_ERROR_NONE;
483 }
484
485 ///////////////////////////////////
486 ////     MMSOUND TONE APIs
487 ///////////////////////////////////
488 EXPORT_API
489 int mm_sound_play_tone_ex (MMSoundTone_t num, int volume_config, const double volume, const int duration, int *handle, bool enable_session)
490 {
491         int lhandle = -1;
492         int err = MM_ERROR_NONE;
493         int volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(volume_config);
494
495         debug_fenter();
496
497         /* Check input param */
498         if (duration < -1) {
499                 debug_error("number is invalid %d\n", duration);
500                 return MM_ERROR_INVALID_ARGUMENT;
501         }
502         if (num < MM_SOUND_TONE_DTMF_0 || num >= MM_SOUND_TONE_NUM) {
503                 debug_error("TONE Value is invalid %d\n", num);
504                 return MM_ERROR_INVALID_ARGUMENT;
505         }
506         if (volume_type < 0 || volume_type >= VOLUME_TYPE_MAX) {
507                 debug_error("Volume type is invalid %d\n", volume_type);
508                 return MM_ERROR_INVALID_ARGUMENT;
509         }
510         if (volume < 0.0 || volume > 1.0) {
511                 debug_error("Volume Value is invalid %d\n", volume);
512                 return MM_ERROR_INVALID_ARGUMENT;
513         }
514
515         /* Play tone */
516         debug_msg("Call MMSoundClientPlayTone\n");
517         err = mm_sound_client_play_tone(num, volume_config, volume, duration, &lhandle, enable_session);
518         if (err < 0) {
519                 debug_error("Failed to play sound\n");
520                 return err;
521         }
522
523         /* Set handle to return */
524         if (handle)
525                 *handle = lhandle;
526         else
527                 debug_critical("The sound handle cannot be get [%d]\n", lhandle);
528
529         debug_fleave();
530         return MM_ERROR_NONE;
531 }
532
533 EXPORT_API
534 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)
535 {
536
537         int err = MM_ERROR_NONE;
538
539         err = mm_sound_client_play_tone_with_stream_info(tone, stream_type, stream_id, volume, duration, handle);
540         if (err <0) {
541                 debug_error("Failed to play sound\n");
542                 return err;
543         }
544
545         return err;
546
547 }
548
549
550 EXPORT_API
551 int mm_sound_play_tone (MMSoundTone_t num, int volume_config, const double volume, const int duration, int *handle)
552 {
553         return mm_sound_play_tone_ex (num, volume_config, volume, duration, handle, true);
554 }
555
556 ///////////////////////////////////
557 ////     MMSOUND ROUTING APIs
558 ///////////////////////////////////
559
560 EXPORT_API
561 int mm_sound_route_get_a2dp_status (bool *connected, char **bt_name)
562 {
563         int ret = MM_ERROR_NONE;
564
565         if (connected == NULL || bt_name == NULL) {
566                 debug_error ("argument is not valid\n");
567                 return MM_ERROR_INVALID_ARGUMENT;
568         }
569
570         ret = mm_sound_client_is_bt_a2dp_on (connected, bt_name);
571         debug_msg ("connected=[%d] bt_name[%s]\n", *connected, *bt_name);
572         if (ret < 0) {
573                 debug_error("MMSoundClientIsBtA2dpOn() Failed\n");
574                 return ret;
575         }
576
577         return ret;
578 }
579
580 EXPORT_API
581 int mm_sound_is_route_available(mm_sound_route route, bool *is_available)
582 {
583         int ret = MM_ERROR_NONE;
584
585         debug_warning ("enter : route=[%x], is_available=[%p]\n", route, is_available);
586
587         if (!mm_sound_util_is_route_valid(route)) {
588                 debug_error("route is invalid %d\n", route);
589                 return MM_ERROR_INVALID_ARGUMENT;
590         }
591         if (!is_available) {
592                 debug_error("is_available is invalid\n");
593                 return MM_ERROR_INVALID_ARGUMENT;
594         }
595
596         ret = mm_sound_client_is_route_available(route, is_available);
597         if (ret < 0) {
598                 debug_error("Can not check given route is available, ret = %x\n", ret);
599         } else {
600                 debug_warning ("success : route=[%x], available=[%d]\n", route, *is_available);
601         }
602
603         return ret;
604 }
605
606 EXPORT_API
607 int mm_sound_foreach_available_route_cb(mm_sound_available_route_cb available_route_cb, void *user_data)
608 {
609         int ret = MM_ERROR_NONE;
610
611         if (!available_route_cb) {
612                 debug_error("available_route_cb is invalid\n");
613                 return MM_ERROR_INVALID_ARGUMENT;
614         }
615
616         ret = mm_sound_client_foreach_available_route_cb(available_route_cb, user_data);
617         if (ret < 0) {
618                 debug_error("Can not set foreach available route callback, ret = %x\n", ret);
619         }
620
621         return ret;
622 }
623
624 EXPORT_API
625 int mm_sound_set_active_route(mm_sound_route route)
626 {
627         int ret = MM_ERROR_NONE;
628
629         debug_warning ("enter : route=[%x]\n", route);
630         if (!mm_sound_util_is_route_valid(route)) {
631                 debug_error("route is invalid %d\n", route);
632                 return MM_ERROR_INVALID_ARGUMENT;
633         }
634
635         ret = mm_sound_client_set_active_route(route, true);
636         if (ret < 0) {
637                 debug_error("Can not set active route, ret = %x\n", ret);
638         } else {
639                 debug_warning ("success : route=[%x]\n", route);
640         }
641
642         return ret;
643 }
644
645 EXPORT_API
646 int mm_sound_set_active_route_auto(void)
647 {
648         int ret = MM_ERROR_NONE;
649
650         ret = mm_sound_client_set_active_route_auto();
651         if (ret < 0) {
652                 debug_error("fail to set active route auto, ret = %x\n", ret);
653         } else {
654                 debug_msg ("success !!\n");
655         }
656
657         return ret;
658 }
659
660 EXPORT_API
661 int mm_sound_set_active_route_without_broadcast(mm_sound_route route)
662 {
663         int ret = MM_ERROR_NONE;
664
665         debug_warning ("enter : route=[%x]\n", route);
666         if (!mm_sound_util_is_route_valid(route)) {
667                 debug_error("route is invalid %d\n", route);
668                 return MM_ERROR_INVALID_ARGUMENT;
669         }
670
671         ret = mm_sound_client_set_active_route(route, false);
672         if (ret < 0) {
673                 debug_error("Can not set active route, ret = %x\n", ret);
674         } else {
675                 debug_warning ("success : route=[%x]\n", route);
676         }
677
678         return ret;
679 }
680
681 EXPORT_API
682 int mm_sound_get_active_device(mm_sound_device_in *device_in, mm_sound_device_out *device_out)
683 {
684         int ret = MM_ERROR_NONE;
685
686         if (device_in == NULL || device_out == NULL) {
687                 debug_error("argument is not valid\n");
688                 return MM_ERROR_INVALID_ARGUMENT;
689         }
690
691         ret = mm_sound_client_get_active_device(device_in, device_out);
692         if (ret < 0) {
693                 debug_error("Can not add active device callback, ret = %x\n", ret);
694         } else {
695                 debug_msg ("success : in=[%x], out=[%x]\n", *device_in, *device_out);
696         }
697
698         return ret;
699 }
700
701 EXPORT_API
702 int mm_sound_get_audio_path(mm_sound_device_in *device_in, mm_sound_device_out *device_out)
703 {
704         int ret = MM_ERROR_NONE;
705
706         if (device_in == NULL || device_out == NULL) {
707                 debug_error("argument is not valid\n");
708                 return MM_ERROR_INVALID_ARGUMENT;
709         }
710
711         ret = mm_sound_client_get_audio_path(device_in, device_out);
712         if (ret < 0) {
713                 debug_error("Can not add active device callback, ret = %x\n", ret);
714         } else {
715                 debug_msg ("success : in=[%x], out=[%x]\n", *device_in, *device_out);
716         }
717
718         return ret;
719 }
720
721 EXPORT_API
722 int mm_sound_add_active_device_changed_callback(const char *name, mm_sound_active_device_changed_cb func, void *user_data)
723 {
724         int ret = MM_ERROR_NONE;
725
726         debug_warning ("enter %s\n", name);
727         if (func == NULL) {
728                 debug_error("argument is not valid\n");
729                 return MM_ERROR_INVALID_ARGUMENT;
730         }
731
732         ret = mm_sound_client_add_active_device_changed_callback(name, func, user_data);
733         if (ret < 0) {
734                 debug_error("Can not add active device changed callback, ret = %x\n", ret);
735         }
736
737         return ret;
738 }
739
740 EXPORT_API
741 int mm_sound_remove_active_device_changed_callback(const char *name)
742 {
743         int ret = MM_ERROR_NONE;
744
745         debug_warning ("enter name %s \n", name);
746         ret = mm_sound_client_remove_active_device_changed_callback(name);
747         if (ret < 0) {
748                 debug_error("Can not remove active device changed callback, ret = %x\n", ret);
749         }
750
751         return ret;
752 }
753
754 EXPORT_API
755 int mm_sound_add_available_route_changed_callback(mm_sound_available_route_changed_cb func, void *user_data)
756 {
757         int ret = MM_ERROR_NONE;
758
759         if (func == NULL) {
760                 debug_error("argument is not valid\n");
761                 return MM_ERROR_INVALID_ARGUMENT;
762         }
763
764         ret = mm_sound_client_add_available_route_changed_callback(func, user_data);
765         if (ret < 0) {
766                 debug_error("Can not add available route changed callback, ret = %x\n", ret);
767         }
768
769         return ret;
770 }
771
772 EXPORT_API
773 int mm_sound_remove_available_route_changed_callback(void)
774 {
775         int ret = MM_ERROR_NONE;
776
777         ret = mm_sound_client_remove_available_route_changed_callback();
778         if (ret < 0) {
779                 debug_error("Can not remove available route changed callback, ret = %x\n", ret);
780         }
781
782         return ret;
783 }
784
785 EXPORT_API
786 int mm_sound_set_sound_path_for_active_device(mm_sound_device_out device_out, mm_sound_device_in device_in)
787 {
788         int ret = MM_ERROR_NONE;
789
790         ret = mm_sound_client_set_sound_path_for_active_device(device_out, device_in);
791         if (ret < 0) {
792                 debug_error("Can not mm sound set sound path for active device, ret = %x\n", ret);
793         }
794
795         return ret;
796 }
797
798
799 EXPORT_API
800 int mm_sound_test(int a, int b, int* getv)
801 {
802         int ret = MM_ERROR_NONE;
803
804         debug_log("mm_sound_test enter");
805         if (!getv) {
806                 debug_error("argu null");
807                 return MM_ERROR_INVALID_ARGUMENT;
808         }
809         ret = mm_sound_client_test(a, b, getv);
810         if (ret < 0) {
811                 debug_error("Can not mm sound test, ret = %x\n", ret);
812         }
813         debug_log("mm_sound_test leave");
814
815         return ret;
816 }
817
818 EXPORT_API
819 int mm_sound_add_test_callback(mm_sound_test_cb func, void *user_data)
820 {
821         int ret = MM_ERROR_NONE;
822
823         debug_log("mm_sound_add_test_callback enter");
824         if (!func) {
825                 debug_error("argument is not valid\n");
826                 return MM_ERROR_INVALID_ARGUMENT;
827         }
828
829         ret = mm_sound_client_add_test_callback(func, user_data);
830         if (ret < 0) {
831                 debug_error("Can not add test callback, ret = %x\n", ret);
832         }
833         debug_log("mm_sound_add_test_callback leave");
834
835         return ret;
836 }
837
838 EXPORT_API
839 int mm_sound_remove_test_callback(void)
840 {
841         int ret = MM_ERROR_NONE;
842
843         debug_log("mm_sound_remove_test_callback enter");
844         ret = mm_sound_client_remove_test_callback();
845         if (ret < 0) {
846                 debug_error("Can not remove test callback, ret = %x\n", ret);
847         }
848         debug_log("mm_sound_remove_test_callback leave");
849
850         return ret;
851 }
852
853 static void signal_callback(GDBusConnection *conn,
854                                                            const gchar *sender_name,
855                                                            const gchar *object_path,
856                                                            const gchar *interface_name,
857                                                            const gchar *signal_name,
858                                                            GVariant *parameters,
859                                                            gpointer user_data)
860 {
861         int value=0;
862         const GVariantType* value_type;
863
864         debug_msg ("sender : %s, object : %s, interface : %s, signal : %s",
865                         sender_name, object_path, interface_name, signal_name);
866         if(g_variant_is_of_type(parameters, G_VARIANT_TYPE("(i)"))) {
867                 g_variant_get(parameters, "(i)",&value);
868                 debug_msg(" - value : %d\n", value);
869                 _dbus_signal_callback (signal_name, value, user_data);
870         } else  {
871                 value_type = g_variant_get_type(parameters);
872                 debug_warning("signal type is %s", value_type);
873         }
874 }
875
876 int _convert_signal_name_str_to_enum (const char *name_str, mm_sound_signal_name_t *name_enum) {
877         int ret = MM_ERROR_NONE;
878
879         if (!name_str || !name_enum)
880                 return MM_ERROR_INVALID_ARGUMENT;
881
882         if (!strncmp(name_str, "ReleaseInternalFocus", strlen("ReleaseInternalFocus"))) {
883                 *name_enum = MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS;
884         } else {
885                 ret = MM_ERROR_INVALID_ARGUMENT;
886                 LOGE("not supported signal name(%s), err(0x%08x)", name_str, ret);
887         }
888         return ret;
889 }
890
891 void _dbus_signal_callback (const char *signal_name, int value, void *user_data)
892 {
893         int ret = MM_ERROR_NONE;
894         mm_sound_signal_name_t signal;
895         subscribe_cb_t *subscribe_cb = (subscribe_cb_t*)user_data;
896
897         debug_fenter();
898
899         if (!subscribe_cb)
900                 return;
901
902         ret = _convert_signal_name_str_to_enum(signal_name, &signal);
903         if (ret)
904                 return;
905
906         debug_msg ("signal_name[%s], value[%d], user_data[0x%x]\n", signal_name, value, user_data);
907
908         if (subscribe_cb->signal_type == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
909                 /* trigger the signal callback when it comes from the same process */
910                 if (getpid() == ((value & 0xFFFF0000) >> 16)) {
911                         subscribe_cb->callback(signal, (value & 0x0000FFFF), subscribe_cb->user_data);
912                 }
913         } else {
914                 subscribe_cb->callback(signal, value, subscribe_cb->user_data);
915         }
916
917         debug_fleave();
918
919         return;
920 }
921
922 EXPORT_API
923 int mm_sound_subscribe_signal(mm_sound_signal_name_t signal, unsigned int *subscribe_id, mm_sound_signal_callback callback, void *user_data)
924 {
925         int ret = MM_ERROR_NONE;
926         GError *err = NULL;
927
928         subscribe_cb_t *subscribe_cb = NULL;
929
930         debug_fenter();
931
932         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
933
934         if (signal < 0 || signal >= MM_SOUND_SIGNAL_MAX || !subscribe_id) {
935                 debug_error ("invalid argument, signal(%d), subscribe_id(0x%p)", signal, subscribe_id);
936                 ret = MM_ERROR_INVALID_ARGUMENT;
937                 goto error;
938         }
939
940         subscribe_cb = malloc(sizeof(subscribe_cb_t));
941         if (!subscribe_cb) {
942                 ret = MM_ERROR_SOUND_INTERNAL;
943                 goto error;
944         }
945         memset(subscribe_cb, 0, sizeof(subscribe_cb_t));
946
947         g_type_init();
948
949         g_dbus_conn_mmsound = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
950         if (!g_dbus_conn_mmsound && err) {
951                 debug_error ("g_bus_get_sync() error (%s) ", err->message);
952                 g_error_free (err);
953                 ret = MM_ERROR_SOUND_INTERNAL;
954                 goto error;
955         }
956
957         subscribe_cb->signal_type = signal;
958         subscribe_cb->callback = callback;
959         subscribe_cb->user_data = user_data;
960
961         *subscribe_id = g_dbus_connection_signal_subscribe(g_dbus_conn_mmsound,
962                         NULL, MM_SOUND_DBUS_INTERFACE, dbus_signal_name_str[signal], MM_SOUND_DBUS_OBJECT_PATH, NULL, 0,
963                         signal_callback, subscribe_cb, NULL);
964         if (*subscribe_id == 0) {
965                 debug_error ("g_dbus_connection_signal_subscribe() error (%d)", *subscribe_id);
966                 ret = MM_ERROR_SOUND_INTERNAL;
967                 goto sig_error;
968         }
969
970         subscribe_cb->id = *subscribe_id;
971
972         g_subscribe_cb_list = g_list_append(g_subscribe_cb_list, subscribe_cb);
973         if (g_subscribe_cb_list) {
974                 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);
975         } else {
976                 debug_error("g_list_append failed\n");
977                 ret = MM_ERROR_SOUND_INTERNAL;
978                 goto error;
979         }
980
981         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
982
983         debug_fleave();
984
985         return ret;
986
987 sig_error:
988         g_dbus_connection_signal_unsubscribe(g_dbus_conn_mmsound, *subscribe_id);
989         g_object_unref(g_dbus_conn_mmsound);
990
991 error:
992         if (subscribe_cb)
993                 free (subscribe_cb);
994
995         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
996
997         return ret;
998 }
999
1000 EXPORT_API
1001 void mm_sound_unsubscribe_signal(unsigned int subscribe_id)
1002 {
1003         GList *list = NULL;
1004         subscribe_cb_t *subscribe_cb = NULL;
1005
1006         debug_fenter();
1007
1008         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
1009
1010         if (g_dbus_conn_mmsound && subscribe_id) {
1011                 g_dbus_connection_signal_unsubscribe(g_dbus_conn_mmsound, subscribe_id);
1012                 g_object_unref(g_dbus_conn_mmsound);
1013                 for (list = g_subscribe_cb_list; list != NULL; list = list->next) {
1014                         subscribe_cb = (subscribe_cb_t *)list->data;
1015                         if (subscribe_cb && (subscribe_cb->id == subscribe_id)) {
1016                                 g_subscribe_cb_list = g_list_remove(g_subscribe_cb_list, subscribe_cb);
1017                                 debug_log("subscribe_cb(0x%x) is removed\n", subscribe_cb);
1018                                 free (subscribe_cb);
1019                         }
1020                 }
1021         }
1022
1023         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1024
1025         debug_fleave();
1026 }
1027
1028 EXPORT_API
1029 int mm_sound_send_signal(mm_sound_signal_name_t signal, int value)
1030 {
1031         int ret = MM_ERROR_NONE;
1032         GError *err = NULL;
1033         GDBusConnection *conn = NULL;
1034         gboolean dbus_ret = TRUE;
1035
1036         debug_fenter();
1037
1038         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
1039
1040         if (signal < 0 || signal >= MM_SOUND_SIGNAL_MAX) {
1041                 debug_error ("invalid argument, signal(%d)", signal);
1042                 ret = MM_ERROR_INVALID_ARGUMENT;
1043                 goto error;
1044         }
1045
1046         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1047         if (!conn && err) {
1048                 debug_error ("g_bus_get_sync() error (%s)", err->message);
1049                 ret = MM_ERROR_SOUND_INTERNAL;
1050                 goto error;
1051         }
1052
1053         g_dbus_signal_values[signal] = value;
1054         if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
1055                 /* trigger the signal callback when it comes from the same process */
1056                 value |= ((int)getpid() << 16);
1057         }
1058         dbus_ret = g_dbus_connection_emit_signal (conn,
1059                                 NULL, MM_SOUND_DBUS_OBJECT_PATH, MM_SOUND_DBUS_INTERFACE, dbus_signal_name_str[signal],
1060                                 g_variant_new ("(i)", value),
1061                                 &err);
1062         if (!dbus_ret && err) {
1063                 debug_error ("g_dbus_connection_emit_signal() error (%s)", err->message);
1064                 ret = MM_ERROR_SOUND_INTERNAL;
1065                 goto error;
1066         }
1067
1068         dbus_ret = g_dbus_connection_flush_sync(conn, NULL, &err);
1069         if (!dbus_ret && err) {
1070                 debug_error ("g_dbus_connection_flush_sync() error (%s)", err->message);
1071                 ret = MM_ERROR_SOUND_INTERNAL;
1072                 goto error;
1073         }
1074
1075         g_object_unref(conn);
1076         debug_msg ("sending signal[%s], value[%d] success", dbus_signal_name_str[signal], value);
1077
1078         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1079
1080         debug_fleave();
1081
1082         return ret;
1083
1084 error:
1085         if (err)
1086                 g_error_free (err);
1087         if (conn)
1088                 g_object_unref(conn);
1089
1090         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1091
1092         return ret;
1093 }
1094
1095 EXPORT_API
1096 int mm_sound_get_signal_value(mm_sound_signal_name_t signal, int *value)
1097 {
1098         int ret = MM_ERROR_NONE;
1099
1100         debug_fenter();
1101
1102         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
1103
1104         *value = g_dbus_signal_values[signal];
1105
1106         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1107
1108         debug_fleave();
1109
1110         return ret;
1111 }
1112
1113 __attribute__ ((constructor))
1114 static void _mm_sound_initialize(void)
1115 {
1116         mm_sound_client_initialize();
1117         /* Will be Fixed */
1118 }
1119
1120 __attribute__ ((destructor))
1121 static void _mm_sound_finalize(void)
1122 {
1123         mm_sound_client_finalize();
1124 }
1125
1126