Fix SVACE defects / remove unused a2dp functions
[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 const 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, unsigned int *subs_id)
193 {
194         int ret = MM_ERROR_NONE;
195
196         if (func == NULL || subs_id == 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, subs_id);
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(unsigned int subs_id)
211 {
212         int ret = MM_ERROR_NONE;
213
214         ret = mm_sound_client_remove_volume_changed_callback(subs_id);
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_NOT_SUPPORT_API;
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         int ret = MM_ERROR_NONE;
277
278         /* Check input param */
279         if(type < VOLUME_TYPE_UNKNOWN || type >= VOLUME_TYPE_MAX) {
280                 debug_error("invalid argument\n");
281                 return MM_ERROR_INVALID_ARGUMENT;
282         }
283
284         if (vconf_set_int(VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE, type)) {
285                 debug_error("could not set vconf for RIMARY_VOLUME_TYPE\n");
286                 ret = MM_ERROR_SOUND_INTERNAL;
287         } else {
288                 debug_msg("set primary volume type forcibly %d(%s)", type, _get_volume_str(type));
289         }
290
291         return ret;
292 }
293
294 EXPORT_API
295 int mm_sound_volume_primary_type_get(volume_type_t *type)
296 {
297         int ret = MM_ERROR_NONE;
298         int voltype = VOLUME_TYPE_RINGTONE;
299
300         /* Check input param */
301         if(type == NULL) {
302                 debug_error("invalid argument\n");
303                 return MM_ERROR_INVALID_ARGUMENT;
304         }
305
306         /* check force set */
307         if (vconf_get_int(VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE, &voltype)) {
308                 debug_error("could not get vconf for PRIMARY_VOLUME_TYPE\n");
309                 ret = MM_ERROR_SOUND_INTERNAL;
310         } else {
311                 debug_msg("get primary volume type %d(%s)", voltype, _get_volume_str(voltype));
312                 *type = voltype;
313         }
314
315         return ret;
316 }
317
318 /* it will be removed */
319 EXPORT_API
320 int mm_sound_volume_primary_type_clear(void)
321 {
322         int ret = MM_ERROR_NONE;
323
324         if (vconf_set_int(VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE, -1)) {
325                 debug_error("could not reset vconf for PRIMARY_VOLUME_TYPE\n");
326                 ret = MM_ERROR_SOUND_INTERNAL;
327         } else {
328                 debug_msg("clear primary volume type forcibly %d(%s)", -1, "none");
329         }
330
331         return ret;
332 }
333
334 ///////////////////////////////////
335 ////     MMSOUND PLAY APIs
336 ///////////////////////////////////
337 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)
338 {
339         param->filename = filename;
340         param->volume = 0; //volume value dose not effect anymore
341         param->callback = callback;
342         param->data = data;
343         param->loop = 1;
344         param->volume_config = volume_config;
345         param->priority = priority;
346         param->handle_route = handle_route;
347 }
348
349 EXPORT_API
350 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)
351 {
352         MMSoundPlayParam param = { 0, };
353
354         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_SOLO, MM_SOUND_HANDLE_ROUTE_SPEAKER_NO_RESTORE);
355         return mm_sound_play_sound_ex(&param, handle);
356 }
357
358 EXPORT_API
359 int mm_sound_play_loud_solo_sound(const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int *handle)
360 {
361         MMSoundPlayParam param = { 0, };
362
363         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_SOLO, MM_SOUND_HANDLE_ROUTE_SPEAKER);
364         return mm_sound_play_sound_ex(&param, handle);
365 }
366
367 EXPORT_API
368 int mm_sound_play_solo_sound(const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int *handle)
369 {
370         MMSoundPlayParam param = { 0, };
371
372         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_SOLO, MM_SOUND_HANDLE_ROUTE_USING_CURRENT);
373         return mm_sound_play_sound_ex(&param, handle);
374 }
375
376 EXPORT_API
377 int mm_sound_play_sound_without_session(const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int *handle)
378 {
379         MMSoundPlayParam param = { 0, };
380
381         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_SOLO, MM_SOUND_HANDLE_ROUTE_USING_CURRENT);
382         param.skip_session = true;
383         return mm_sound_play_sound_ex(&param, handle);
384 }
385
386 EXPORT_API
387 int mm_sound_play_sound(const char *filename, int volume_config, mm_sound_stop_callback_func callback, void *data, int *handle)
388 {
389         MMSoundPlayParam param = { 0, };
390
391         _mm_sound_fill_play_param(&param, filename, volume_config, callback, data, HANDLE_PRIORITY_NORMAL, MM_SOUND_HANDLE_ROUTE_USING_CURRENT);
392         return mm_sound_play_sound_ex(&param, handle);
393 }
394
395 EXPORT_API
396 int mm_sound_play_sound_ex(MMSoundPlayParam *param, int *handle)
397 {
398         int err;
399         int lhandle = -1;
400         int volume_type = 0;
401         /* Check input param */
402         if (param == NULL) {
403                 debug_error("param is null\n");
404                 return MM_ERROR_INVALID_ARGUMENT;
405         }
406
407         volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(param->volume_config);
408
409         if (param->filename == NULL) {
410                 debug_error("filename is NULL\n");
411                 return MM_ERROR_SOUND_FILE_NOT_FOUND;
412         }
413         if (volume_type < 0 || volume_type >= VOLUME_TYPE_MAX) {
414                 debug_error("Volume type is invalid %d\n", volume_type);
415                 return MM_ERROR_INVALID_ARGUMENT;
416         }
417
418         debug_warning ("play sound : priority=[%d], handle_route=[%d]\n", param->priority, param->handle_route);
419
420         /* Play sound */
421         err = mm_sound_client_play_sound(param, 0, &lhandle);
422         if (err < 0) {
423                 debug_error("Failed to play sound\n");
424                 return err;
425         }
426
427         /* Set handle to return */
428         if (handle) {
429                 *handle = lhandle;
430         } else {
431                 debug_critical("The sound hadle cannot be get [%d]\n", lhandle);
432         }
433
434         debug_warning ("success : handle=[%p]\n", handle);
435
436         return MM_ERROR_NONE;
437 }
438
439 EXPORT_API
440 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)
441 {
442         MMSoundPlayParam param = { 0, };
443         int err;
444
445         param.filename = filename;
446         param.volume = 0; //volume value dose not effect anymore
447         param.callback = callback;
448         param.data = data;
449         param.loop = 1;
450         param.priority = HANDLE_PRIORITY_NORMAL;
451         param.handle_route = MM_SOUND_HANDLE_ROUTE_USING_CURRENT;
452
453         err = mm_sound_client_play_sound_with_stream_info(&param, handle, stream_type, stream_id);
454         if (err < 0) {
455                 debug_error("Failed to play sound\n");
456                 return err;
457         }
458
459         debug_warning ("success : handle=[%p]\n", handle);
460
461         return MM_ERROR_NONE;
462
463 }
464
465
466 EXPORT_API
467 int mm_sound_stop_sound(int handle)
468 {
469         int err;
470
471         debug_warning ("enter : handle=[%p]\n", handle);
472         /* Stop sound */
473         err = mm_sound_client_stop_sound(handle);
474         if (err < 0) {
475                 debug_error("Fail to stop sound\n");
476                 return err;
477         }
478         debug_warning ("success : handle=[%p]\n", handle);
479
480         return MM_ERROR_NONE;
481 }
482
483 ///////////////////////////////////
484 ////     MMSOUND TONE APIs
485 ///////////////////////////////////
486 EXPORT_API
487 int mm_sound_play_tone_ex (MMSoundTone_t num, int volume_config, const double volume, const int duration, int *handle, bool enable_session)
488 {
489         int lhandle = -1;
490         int err = MM_ERROR_NONE;
491         int volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(volume_config);
492
493         debug_fenter();
494
495         /* Check input param */
496         if (duration < -1) {
497                 debug_error("number is invalid %d\n", duration);
498                 return MM_ERROR_INVALID_ARGUMENT;
499         }
500         if (num < MM_SOUND_TONE_DTMF_0 || num >= MM_SOUND_TONE_NUM) {
501                 debug_error("TONE Value is invalid %d\n", num);
502                 return MM_ERROR_INVALID_ARGUMENT;
503         }
504         if (volume_type < 0 || volume_type >= VOLUME_TYPE_MAX) {
505                 debug_error("Volume type is invalid %d\n", volume_type);
506                 return MM_ERROR_INVALID_ARGUMENT;
507         }
508         if (volume < 0.0 || volume > 1.0) {
509                 debug_error("Volume Value is invalid %d\n", volume);
510                 return MM_ERROR_INVALID_ARGUMENT;
511         }
512
513         /* Play tone */
514         debug_msg("Call MMSoundClientPlayTone\n");
515         err = mm_sound_client_play_tone(num, volume_config, volume, duration, &lhandle, enable_session);
516         if (err < 0) {
517                 debug_error("Failed to play sound\n");
518                 return err;
519         }
520
521         /* Set handle to return */
522         if (handle)
523                 *handle = lhandle;
524         else
525                 debug_critical("The sound handle cannot be get [%d]\n", lhandle);
526
527         debug_fleave();
528         return MM_ERROR_NONE;
529 }
530
531 EXPORT_API
532 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)
533 {
534
535         int err = MM_ERROR_NONE;
536
537         err = mm_sound_client_play_tone_with_stream_info(tone, stream_type, stream_id, volume, duration, handle);
538         if (err <0) {
539                 debug_error("Failed to play sound\n");
540                 return err;
541         }
542
543         return err;
544
545 }
546
547
548 EXPORT_API
549 int mm_sound_play_tone (MMSoundTone_t num, int volume_config, const double volume, const int duration, int *handle)
550 {
551         return mm_sound_play_tone_ex (num, volume_config, volume, duration, handle, true);
552 }
553
554 ///////////////////////////////////
555 ////     MMSOUND ROUTING APIs
556 ///////////////////////////////////
557
558 EXPORT_API
559 int mm_sound_is_route_available(mm_sound_route route, bool *is_available)
560 {
561         int ret = MM_ERROR_NONE;
562
563         debug_warning ("enter : route=[%x], is_available=[%p]\n", route, is_available);
564
565         if (!mm_sound_util_is_route_valid(route)) {
566                 debug_error("route is invalid %d\n", route);
567                 return MM_ERROR_INVALID_ARGUMENT;
568         }
569         if (!is_available) {
570                 debug_error("is_available is invalid\n");
571                 return MM_ERROR_INVALID_ARGUMENT;
572         }
573
574         ret = mm_sound_client_is_route_available(route, is_available);
575         if (ret < 0) {
576                 debug_error("Can not check given route is available, ret = %x\n", ret);
577         } else {
578                 debug_warning ("success : route=[%x], available=[%d]\n", route, *is_available);
579         }
580
581         return ret;
582 }
583
584 EXPORT_API
585 int mm_sound_foreach_available_route_cb(mm_sound_available_route_cb available_route_cb, void *user_data)
586 {
587         int ret = MM_ERROR_NONE;
588
589         if (!available_route_cb) {
590                 debug_error("available_route_cb is invalid\n");
591                 return MM_ERROR_INVALID_ARGUMENT;
592         }
593
594         ret = mm_sound_client_foreach_available_route_cb(available_route_cb, user_data);
595         if (ret < 0) {
596                 debug_error("Can not set foreach available route callback, ret = %x\n", ret);
597         }
598
599         return ret;
600 }
601
602 EXPORT_API
603 int mm_sound_set_active_route(mm_sound_route route)
604 {
605         int ret = MM_ERROR_NONE;
606
607         debug_warning ("enter : route=[%x]\n", route);
608         if (!mm_sound_util_is_route_valid(route)) {
609                 debug_error("route is invalid %d\n", route);
610                 return MM_ERROR_INVALID_ARGUMENT;
611         }
612
613         ret = mm_sound_client_set_active_route(route, true);
614         if (ret < 0) {
615                 debug_error("Can not set active route, ret = %x\n", ret);
616         } else {
617                 debug_warning ("success : route=[%x]\n", route);
618         }
619
620         return ret;
621 }
622
623 EXPORT_API
624 int mm_sound_set_active_route_auto(void)
625 {
626         int ret = MM_ERROR_NONE;
627
628         ret = mm_sound_client_set_active_route_auto();
629         if (ret < 0) {
630                 debug_error("fail to set active route auto, ret = %x\n", ret);
631         } else {
632                 debug_msg ("success !!\n");
633         }
634
635         return ret;
636 }
637
638 EXPORT_API
639 int mm_sound_set_active_route_without_broadcast(mm_sound_route route)
640 {
641         int ret = MM_ERROR_NONE;
642
643         debug_warning ("enter : route=[%x]\n", route);
644         if (!mm_sound_util_is_route_valid(route)) {
645                 debug_error("route is invalid %d\n", route);
646                 return MM_ERROR_INVALID_ARGUMENT;
647         }
648
649         ret = mm_sound_client_set_active_route(route, false);
650         if (ret < 0) {
651                 debug_error("Can not set active route, ret = %x\n", ret);
652         } else {
653                 debug_warning ("success : route=[%x]\n", route);
654         }
655
656         return ret;
657 }
658
659 EXPORT_API
660 int mm_sound_get_active_device(mm_sound_device_in *device_in, mm_sound_device_out *device_out)
661 {
662         int ret = MM_ERROR_NONE;
663
664         if (device_in == NULL || device_out == NULL) {
665                 debug_error("argument is not valid\n");
666                 return MM_ERROR_INVALID_ARGUMENT;
667         }
668
669         ret = mm_sound_client_get_active_device(device_in, device_out);
670         if (ret < 0) {
671                 debug_error("Can not add active device callback, ret = %x\n", ret);
672         } else {
673                 debug_msg ("success : in=[%x], out=[%x]\n", *device_in, *device_out);
674         }
675
676         return ret;
677 }
678
679 EXPORT_API
680 int mm_sound_get_audio_path(mm_sound_device_in *device_in, mm_sound_device_out *device_out)
681 {
682         int ret = MM_ERROR_NONE;
683
684         if (device_in == NULL || device_out == NULL) {
685                 debug_error("argument is not valid\n");
686                 return MM_ERROR_INVALID_ARGUMENT;
687         }
688
689         ret = mm_sound_client_get_audio_path(device_in, device_out);
690         if (ret < 0) {
691                 debug_error("Can not add active device callback, ret = %x\n", ret);
692         } else {
693                 debug_msg ("success : in=[%x], out=[%x]\n", *device_in, *device_out);
694         }
695
696         return ret;
697 }
698
699 EXPORT_API
700 int mm_sound_add_active_device_changed_callback(const char *name, mm_sound_active_device_changed_cb func, void *user_data)
701 {
702         int ret = MM_ERROR_NONE;
703
704         debug_warning ("enter %s\n", name);
705         if (func == NULL) {
706                 debug_error("argument is not valid\n");
707                 return MM_ERROR_INVALID_ARGUMENT;
708         }
709
710         ret = mm_sound_client_add_active_device_changed_callback(name, func, user_data);
711         if (ret < 0) {
712                 debug_error("Can not add active device changed callback, ret = %x\n", ret);
713         }
714
715         return ret;
716 }
717
718 EXPORT_API
719 int mm_sound_remove_active_device_changed_callback(const char *name)
720 {
721         int ret = MM_ERROR_NONE;
722
723         debug_warning ("enter name %s \n", name);
724         ret = mm_sound_client_remove_active_device_changed_callback(name);
725         if (ret < 0) {
726                 debug_error("Can not remove active device changed callback, ret = %x\n", ret);
727         }
728
729         return ret;
730 }
731
732 EXPORT_API
733 int mm_sound_add_available_route_changed_callback(mm_sound_available_route_changed_cb func, void *user_data)
734 {
735         int ret = MM_ERROR_NONE;
736
737         if (func == NULL) {
738                 debug_error("argument is not valid\n");
739                 return MM_ERROR_INVALID_ARGUMENT;
740         }
741
742         ret = mm_sound_client_add_available_route_changed_callback(func, user_data);
743         if (ret < 0) {
744                 debug_error("Can not add available route changed callback, ret = %x\n", ret);
745         }
746
747         return ret;
748 }
749
750 EXPORT_API
751 int mm_sound_remove_available_route_changed_callback(void)
752 {
753         int ret = MM_ERROR_NONE;
754
755         ret = mm_sound_client_remove_available_route_changed_callback();
756         if (ret < 0) {
757                 debug_error("Can not remove available route changed callback, ret = %x\n", ret);
758         }
759
760         return ret;
761 }
762
763 EXPORT_API
764 int mm_sound_set_sound_path_for_active_device(mm_sound_device_out device_out, mm_sound_device_in device_in)
765 {
766         int ret = MM_ERROR_NONE;
767
768         ret = mm_sound_client_set_sound_path_for_active_device(device_out, device_in);
769         if (ret < 0) {
770                 debug_error("Can not mm sound set sound path for active device, ret = %x\n", ret);
771         }
772
773         return ret;
774 }
775
776
777 EXPORT_API
778 int mm_sound_test(int a, int b, int* getv)
779 {
780         int ret = MM_ERROR_NONE;
781
782         debug_log("mm_sound_test enter");
783         if (!getv) {
784                 debug_error("argu null");
785                 return MM_ERROR_INVALID_ARGUMENT;
786         }
787         ret = mm_sound_client_test(a, b, getv);
788         if (ret < 0) {
789                 debug_error("Can not mm sound test, ret = %x\n", ret);
790         }
791         debug_log("mm_sound_test leave");
792
793         return ret;
794 }
795
796 EXPORT_API
797 int mm_sound_add_test_callback(mm_sound_test_cb func, void *user_data, unsigned int *subs_id)
798 {
799         int ret = MM_ERROR_NONE;
800
801         debug_log("mm_sound_add_test_callback enter");
802         if (!func || !subs_id) {
803                 debug_error("argument is not valid\n");
804                 return MM_ERROR_INVALID_ARGUMENT;
805         }
806
807         ret = mm_sound_client_add_test_callback(func, user_data, subs_id);
808         if (ret < 0) {
809                 debug_error("Can not add test callback, ret = %x\n", ret);
810         }
811         debug_log("mm_sound_add_test_callback leave");
812
813         return ret;
814 }
815
816 EXPORT_API
817 int mm_sound_remove_test_callback(unsigned int subs_id)
818 {
819         int ret = MM_ERROR_NONE;
820
821         debug_log("mm_sound_remove_test_callback enter");
822         ret = mm_sound_client_remove_test_callback(subs_id);
823         if (ret < 0) {
824                 debug_error("Can not remove test callback, ret = %x\n", ret);
825         }
826         debug_log("mm_sound_remove_test_callback leave");
827
828         return ret;
829 }
830
831 static int _convert_signal_name_str_to_enum (const char *name_str, mm_sound_signal_name_t *name_enum) {
832         int ret = MM_ERROR_NONE;
833
834         if (!name_str || !name_enum)
835                 return MM_ERROR_INVALID_ARGUMENT;
836
837         if (!strncmp(name_str, "ReleaseInternalFocus", strlen("ReleaseInternalFocus"))) {
838                 *name_enum = MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS;
839         } else {
840                 ret = MM_ERROR_INVALID_ARGUMENT;
841                 LOGE("not supported signal name(%s), err(0x%08x)", name_str, ret);
842         }
843         return ret;
844 }
845
846 static void _dbus_signal_callback (const char *signal_name, int value, void *user_data)
847 {
848         int ret = MM_ERROR_NONE;
849         mm_sound_signal_name_t signal;
850         subscribe_cb_t *subscribe_cb = (subscribe_cb_t*)user_data;
851
852         debug_fenter();
853
854         if (!subscribe_cb)
855                 return;
856
857         ret = _convert_signal_name_str_to_enum(signal_name, &signal);
858         if (ret)
859                 return;
860
861         debug_msg ("signal_name[%s], value[%d], user_data[0x%x]\n", signal_name, value, user_data);
862
863         if (subscribe_cb->signal_type == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
864                 /* trigger the signal callback when it comes from the same process */
865                 if (getpid() == ((value & 0xFFFF0000) >> 16)) {
866                         subscribe_cb->callback(signal, (value & 0x0000FFFF), subscribe_cb->user_data);
867                 }
868         } else {
869                 subscribe_cb->callback(signal, value, subscribe_cb->user_data);
870         }
871
872         debug_fleave();
873
874         return;
875 }
876
877 static void signal_callback(GDBusConnection *conn,
878                                                            const gchar *sender_name,
879                                                            const gchar *object_path,
880                                                            const gchar *interface_name,
881                                                            const gchar *signal_name,
882                                                            GVariant *parameters,
883                                                            gpointer user_data)
884 {
885         int value=0;
886         const GVariantType* value_type;
887
888         debug_msg ("sender : %s, object : %s, interface : %s, signal : %s",
889                         sender_name, object_path, interface_name, signal_name);
890         if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(i)"))) {
891                 g_variant_get(parameters, "(i)",&value);
892                 debug_msg(" - value : %d\n", value);
893                 _dbus_signal_callback(signal_name, value, user_data);
894         } else  {
895                 value_type = g_variant_get_type(parameters);
896                 debug_warning("signal type is %s", value_type);
897         }
898 }
899
900 EXPORT_API
901 int mm_sound_subscribe_signal(mm_sound_signal_name_t signal, unsigned int *subscribe_id, mm_sound_signal_callback callback, void *user_data)
902 {
903         int ret = MM_ERROR_NONE;
904         GError *err = NULL;
905
906         subscribe_cb_t *subscribe_cb = NULL;
907
908         debug_fenter();
909
910         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
911
912         if (signal < 0 || signal >= MM_SOUND_SIGNAL_MAX || !subscribe_id) {
913                 debug_error ("invalid argument, signal(%d), subscribe_id(0x%p)", signal, subscribe_id);
914                 ret = MM_ERROR_INVALID_ARGUMENT;
915                 goto error;
916         }
917
918         subscribe_cb = malloc(sizeof(subscribe_cb_t));
919         if (!subscribe_cb) {
920                 ret = MM_ERROR_SOUND_INTERNAL;
921                 goto error;
922         }
923         memset(subscribe_cb, 0, sizeof(subscribe_cb_t));
924
925         g_dbus_conn_mmsound = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
926         if (!g_dbus_conn_mmsound && err) {
927                 debug_error ("g_bus_get_sync() error (%s) ", err->message);
928                 g_error_free (err);
929                 ret = MM_ERROR_SOUND_INTERNAL;
930                 goto error;
931         }
932
933         subscribe_cb->signal_type = signal;
934         subscribe_cb->callback = callback;
935         subscribe_cb->user_data = user_data;
936
937         *subscribe_id = g_dbus_connection_signal_subscribe(g_dbus_conn_mmsound,
938                         NULL, MM_SOUND_DBUS_INTERFACE, dbus_signal_name_str[signal], MM_SOUND_DBUS_OBJECT_PATH, NULL, 0,
939                         signal_callback, subscribe_cb, NULL);
940         if (*subscribe_id == 0) {
941                 debug_error ("g_dbus_connection_signal_subscribe() error (%d)", *subscribe_id);
942                 ret = MM_ERROR_SOUND_INTERNAL;
943                 goto sig_error;
944         }
945
946         subscribe_cb->id = *subscribe_id;
947
948         g_subscribe_cb_list = g_list_append(g_subscribe_cb_list, subscribe_cb);
949         if (g_subscribe_cb_list) {
950                 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);
951         } else {
952                 debug_error("g_list_append failed\n");
953                 ret = MM_ERROR_SOUND_INTERNAL;
954                 goto error;
955         }
956
957         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
958
959         debug_fleave();
960
961         return ret;
962
963 sig_error:
964         g_dbus_connection_signal_unsubscribe(g_dbus_conn_mmsound, *subscribe_id);
965         g_object_unref(g_dbus_conn_mmsound);
966
967 error:
968         if (subscribe_cb)
969                 free (subscribe_cb);
970
971         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
972
973         return ret;
974 }
975
976 EXPORT_API
977 void mm_sound_unsubscribe_signal(unsigned int subscribe_id)
978 {
979         GList *list = NULL;
980         subscribe_cb_t *subscribe_cb = NULL;
981
982         debug_fenter();
983
984         MMSOUND_ENTER_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
985
986         if (g_dbus_conn_mmsound && subscribe_id) {
987                 g_dbus_connection_signal_unsubscribe(g_dbus_conn_mmsound, subscribe_id);
988                 g_object_unref(g_dbus_conn_mmsound);
989                 for (list = g_subscribe_cb_list; list != NULL; list = list->next) {
990                         subscribe_cb = (subscribe_cb_t *)list->data;
991                         if (subscribe_cb && (subscribe_cb->id == subscribe_id)) {
992                                 g_subscribe_cb_list = g_list_remove(g_subscribe_cb_list, subscribe_cb);
993                                 debug_log("subscribe_cb(0x%x) is removed\n", subscribe_cb);
994                                 free (subscribe_cb);
995                         }
996                 }
997         }
998
999         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1000
1001         debug_fleave();
1002 }
1003
1004 EXPORT_API
1005 int mm_sound_send_signal(mm_sound_signal_name_t signal, int value)
1006 {
1007         int ret = MM_ERROR_NONE;
1008         GError *err = NULL;
1009         GDBusConnection *conn = NULL;
1010         gboolean dbus_ret = TRUE;
1011
1012         debug_fenter();
1013
1014         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
1015
1016         if (signal < 0 || signal >= MM_SOUND_SIGNAL_MAX) {
1017                 debug_error ("invalid argument, signal(%d)", signal);
1018                 ret = MM_ERROR_INVALID_ARGUMENT;
1019                 goto error;
1020         }
1021
1022         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1023         if (!conn && err) {
1024                 debug_error ("g_bus_get_sync() error (%s)", err->message);
1025                 ret = MM_ERROR_SOUND_INTERNAL;
1026                 goto error;
1027         }
1028
1029         g_dbus_signal_values[signal] = value;
1030         if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
1031                 /* trigger the signal callback when it comes from the same process */
1032                 value |= ((int)getpid() << 16);
1033         }
1034         dbus_ret = g_dbus_connection_emit_signal (conn,
1035                                 NULL, MM_SOUND_DBUS_OBJECT_PATH, MM_SOUND_DBUS_INTERFACE, dbus_signal_name_str[signal],
1036                                 g_variant_new ("(i)", value),
1037                                 &err);
1038         if (!dbus_ret && err) {
1039                 debug_error ("g_dbus_connection_emit_signal() error (%s)", err->message);
1040                 ret = MM_ERROR_SOUND_INTERNAL;
1041                 goto error;
1042         }
1043
1044         dbus_ret = g_dbus_connection_flush_sync(conn, NULL, &err);
1045         if (!dbus_ret && err) {
1046                 debug_error ("g_dbus_connection_flush_sync() error (%s)", err->message);
1047                 ret = MM_ERROR_SOUND_INTERNAL;
1048                 goto error;
1049         }
1050
1051         g_object_unref(conn);
1052         debug_msg ("sending signal[%s], value[%d] success", dbus_signal_name_str[signal], value);
1053
1054         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1055
1056         debug_fleave();
1057
1058         return ret;
1059
1060 error:
1061         if (err)
1062                 g_error_free (err);
1063         if (conn)
1064                 g_object_unref(conn);
1065
1066         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1067
1068         return ret;
1069 }
1070
1071 EXPORT_API
1072 int mm_sound_get_signal_value(mm_sound_signal_name_t signal, int *value)
1073 {
1074         int ret = MM_ERROR_NONE;
1075
1076         debug_fenter();
1077
1078         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
1079
1080         *value = g_dbus_signal_values[signal];
1081
1082         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1083
1084         debug_fleave();
1085
1086         return ret;
1087 }
1088
1089 __attribute__ ((constructor))
1090 static void _mm_sound_initialize(void)
1091 {
1092         mm_sound_client_initialize();
1093         /* Will be Fixed */
1094 }
1095
1096 __attribute__ ((destructor))
1097 static void _mm_sound_finalize(void)
1098 {
1099         mm_sound_client_finalize();
1100 }
1101
1102