Remove warnings
[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)
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         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_route_get_a2dp_status (bool *connected, char **bt_name)
560 {
561         int ret = MM_ERROR_NONE;
562
563         if (connected == NULL || bt_name == NULL) {
564                 debug_error ("argument is not valid\n");
565                 return MM_ERROR_INVALID_ARGUMENT;
566         }
567
568         ret = mm_sound_client_is_bt_a2dp_on (connected, bt_name);
569         debug_msg ("connected=[%d] bt_name[%s]\n", *connected, *bt_name);
570         if (ret < 0) {
571                 debug_error("MMSoundClientIsBtA2dpOn() Failed\n");
572                 return ret;
573         }
574
575         return ret;
576 }
577
578 EXPORT_API
579 int mm_sound_is_route_available(mm_sound_route route, bool *is_available)
580 {
581         int ret = MM_ERROR_NONE;
582
583         debug_warning ("enter : route=[%x], is_available=[%p]\n", route, is_available);
584
585         if (!mm_sound_util_is_route_valid(route)) {
586                 debug_error("route is invalid %d\n", route);
587                 return MM_ERROR_INVALID_ARGUMENT;
588         }
589         if (!is_available) {
590                 debug_error("is_available is invalid\n");
591                 return MM_ERROR_INVALID_ARGUMENT;
592         }
593
594         ret = mm_sound_client_is_route_available(route, is_available);
595         if (ret < 0) {
596                 debug_error("Can not check given route is available, ret = %x\n", ret);
597         } else {
598                 debug_warning ("success : route=[%x], available=[%d]\n", route, *is_available);
599         }
600
601         return ret;
602 }
603
604 EXPORT_API
605 int mm_sound_foreach_available_route_cb(mm_sound_available_route_cb available_route_cb, void *user_data)
606 {
607         int ret = MM_ERROR_NONE;
608
609         if (!available_route_cb) {
610                 debug_error("available_route_cb is invalid\n");
611                 return MM_ERROR_INVALID_ARGUMENT;
612         }
613
614         ret = mm_sound_client_foreach_available_route_cb(available_route_cb, user_data);
615         if (ret < 0) {
616                 debug_error("Can not set foreach available route callback, ret = %x\n", ret);
617         }
618
619         return ret;
620 }
621
622 EXPORT_API
623 int mm_sound_set_active_route(mm_sound_route route)
624 {
625         int ret = MM_ERROR_NONE;
626
627         debug_warning ("enter : route=[%x]\n", route);
628         if (!mm_sound_util_is_route_valid(route)) {
629                 debug_error("route is invalid %d\n", route);
630                 return MM_ERROR_INVALID_ARGUMENT;
631         }
632
633         ret = mm_sound_client_set_active_route(route, true);
634         if (ret < 0) {
635                 debug_error("Can not set active route, ret = %x\n", ret);
636         } else {
637                 debug_warning ("success : route=[%x]\n", route);
638         }
639
640         return ret;
641 }
642
643 EXPORT_API
644 int mm_sound_set_active_route_auto(void)
645 {
646         int ret = MM_ERROR_NONE;
647
648         ret = mm_sound_client_set_active_route_auto();
649         if (ret < 0) {
650                 debug_error("fail to set active route auto, ret = %x\n", ret);
651         } else {
652                 debug_msg ("success !!\n");
653         }
654
655         return ret;
656 }
657
658 EXPORT_API
659 int mm_sound_set_active_route_without_broadcast(mm_sound_route route)
660 {
661         int ret = MM_ERROR_NONE;
662
663         debug_warning ("enter : route=[%x]\n", route);
664         if (!mm_sound_util_is_route_valid(route)) {
665                 debug_error("route is invalid %d\n", route);
666                 return MM_ERROR_INVALID_ARGUMENT;
667         }
668
669         ret = mm_sound_client_set_active_route(route, false);
670         if (ret < 0) {
671                 debug_error("Can not set active route, ret = %x\n", ret);
672         } else {
673                 debug_warning ("success : route=[%x]\n", route);
674         }
675
676         return ret;
677 }
678
679 EXPORT_API
680 int mm_sound_get_active_device(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_active_device(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_get_audio_path(mm_sound_device_in *device_in, mm_sound_device_out *device_out)
701 {
702         int ret = MM_ERROR_NONE;
703
704         if (device_in == NULL || device_out == NULL) {
705                 debug_error("argument is not valid\n");
706                 return MM_ERROR_INVALID_ARGUMENT;
707         }
708
709         ret = mm_sound_client_get_audio_path(device_in, device_out);
710         if (ret < 0) {
711                 debug_error("Can not add active device callback, ret = %x\n", ret);
712         } else {
713                 debug_msg ("success : in=[%x], out=[%x]\n", *device_in, *device_out);
714         }
715
716         return ret;
717 }
718
719 EXPORT_API
720 int mm_sound_add_active_device_changed_callback(const char *name, mm_sound_active_device_changed_cb func, void *user_data)
721 {
722         int ret = MM_ERROR_NONE;
723
724         debug_warning ("enter %s\n", name);
725         if (func == NULL) {
726                 debug_error("argument is not valid\n");
727                 return MM_ERROR_INVALID_ARGUMENT;
728         }
729
730         ret = mm_sound_client_add_active_device_changed_callback(name, func, user_data);
731         if (ret < 0) {
732                 debug_error("Can not add active device changed callback, ret = %x\n", ret);
733         }
734
735         return ret;
736 }
737
738 EXPORT_API
739 int mm_sound_remove_active_device_changed_callback(const char *name)
740 {
741         int ret = MM_ERROR_NONE;
742
743         debug_warning ("enter name %s \n", name);
744         ret = mm_sound_client_remove_active_device_changed_callback(name);
745         if (ret < 0) {
746                 debug_error("Can not remove active device changed callback, ret = %x\n", ret);
747         }
748
749         return ret;
750 }
751
752 EXPORT_API
753 int mm_sound_add_available_route_changed_callback(mm_sound_available_route_changed_cb func, void *user_data)
754 {
755         int ret = MM_ERROR_NONE;
756
757         if (func == NULL) {
758                 debug_error("argument is not valid\n");
759                 return MM_ERROR_INVALID_ARGUMENT;
760         }
761
762         ret = mm_sound_client_add_available_route_changed_callback(func, user_data);
763         if (ret < 0) {
764                 debug_error("Can not add available route changed callback, ret = %x\n", ret);
765         }
766
767         return ret;
768 }
769
770 EXPORT_API
771 int mm_sound_remove_available_route_changed_callback(void)
772 {
773         int ret = MM_ERROR_NONE;
774
775         ret = mm_sound_client_remove_available_route_changed_callback();
776         if (ret < 0) {
777                 debug_error("Can not remove available route changed callback, ret = %x\n", ret);
778         }
779
780         return ret;
781 }
782
783 EXPORT_API
784 int mm_sound_set_sound_path_for_active_device(mm_sound_device_out device_out, mm_sound_device_in device_in)
785 {
786         int ret = MM_ERROR_NONE;
787
788         ret = mm_sound_client_set_sound_path_for_active_device(device_out, device_in);
789         if (ret < 0) {
790                 debug_error("Can not mm sound set sound path for active device, ret = %x\n", ret);
791         }
792
793         return ret;
794 }
795
796
797 EXPORT_API
798 int mm_sound_test(int a, int b, int* getv)
799 {
800         int ret = MM_ERROR_NONE;
801
802         debug_log("mm_sound_test enter");
803         if (!getv) {
804                 debug_error("argu null");
805                 return MM_ERROR_INVALID_ARGUMENT;
806         }
807         ret = mm_sound_client_test(a, b, getv);
808         if (ret < 0) {
809                 debug_error("Can not mm sound test, ret = %x\n", ret);
810         }
811         debug_log("mm_sound_test leave");
812
813         return ret;
814 }
815
816 EXPORT_API
817 int mm_sound_add_test_callback(mm_sound_test_cb func, void *user_data)
818 {
819         int ret = MM_ERROR_NONE;
820
821         debug_log("mm_sound_add_test_callback enter");
822         if (!func) {
823                 debug_error("argument is not valid\n");
824                 return MM_ERROR_INVALID_ARGUMENT;
825         }
826
827         ret = mm_sound_client_add_test_callback(func, user_data);
828         if (ret < 0) {
829                 debug_error("Can not add test callback, ret = %x\n", ret);
830         }
831         debug_log("mm_sound_add_test_callback leave");
832
833         return ret;
834 }
835
836 EXPORT_API
837 int mm_sound_remove_test_callback(void)
838 {
839         int ret = MM_ERROR_NONE;
840
841         debug_log("mm_sound_remove_test_callback enter");
842         ret = mm_sound_client_remove_test_callback();
843         if (ret < 0) {
844                 debug_error("Can not remove test callback, ret = %x\n", ret);
845         }
846         debug_log("mm_sound_remove_test_callback leave");
847
848         return ret;
849 }
850
851 static int _convert_signal_name_str_to_enum (const char *name_str, mm_sound_signal_name_t *name_enum) {
852         int ret = MM_ERROR_NONE;
853
854         if (!name_str || !name_enum)
855                 return MM_ERROR_INVALID_ARGUMENT;
856
857         if (!strncmp(name_str, "ReleaseInternalFocus", strlen("ReleaseInternalFocus"))) {
858                 *name_enum = MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS;
859         } else {
860                 ret = MM_ERROR_INVALID_ARGUMENT;
861                 LOGE("not supported signal name(%s), err(0x%08x)", name_str, ret);
862         }
863         return ret;
864 }
865
866 static void _dbus_signal_callback (const char *signal_name, int value, void *user_data)
867 {
868         int ret = MM_ERROR_NONE;
869         mm_sound_signal_name_t signal;
870         subscribe_cb_t *subscribe_cb = (subscribe_cb_t*)user_data;
871
872         debug_fenter();
873
874         if (!subscribe_cb)
875                 return;
876
877         ret = _convert_signal_name_str_to_enum(signal_name, &signal);
878         if (ret)
879                 return;
880
881         debug_msg ("signal_name[%s], value[%d], user_data[0x%x]\n", signal_name, value, user_data);
882
883         if (subscribe_cb->signal_type == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
884                 /* trigger the signal callback when it comes from the same process */
885                 if (getpid() == ((value & 0xFFFF0000) >> 16)) {
886                         subscribe_cb->callback(signal, (value & 0x0000FFFF), subscribe_cb->user_data);
887                 }
888         } else {
889                 subscribe_cb->callback(signal, value, subscribe_cb->user_data);
890         }
891
892         debug_fleave();
893
894         return;
895 }
896
897 static void signal_callback(GDBusConnection *conn,
898                                                            const gchar *sender_name,
899                                                            const gchar *object_path,
900                                                            const gchar *interface_name,
901                                                            const gchar *signal_name,
902                                                            GVariant *parameters,
903                                                            gpointer user_data)
904 {
905         int value=0;
906         const GVariantType* value_type;
907
908         debug_msg ("sender : %s, object : %s, interface : %s, signal : %s",
909                         sender_name, object_path, interface_name, signal_name);
910         if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(i)"))) {
911                 g_variant_get(parameters, "(i)",&value);
912                 debug_msg(" - value : %d\n", value);
913                 _dbus_signal_callback(signal_name, value, user_data);
914         } else  {
915                 value_type = g_variant_get_type(parameters);
916                 debug_warning("signal type is %s", value_type);
917         }
918 }
919
920 EXPORT_API
921 int mm_sound_subscribe_signal(mm_sound_signal_name_t signal, unsigned int *subscribe_id, mm_sound_signal_callback callback, void *user_data)
922 {
923         int ret = MM_ERROR_NONE;
924         GError *err = NULL;
925
926         subscribe_cb_t *subscribe_cb = NULL;
927
928         debug_fenter();
929
930         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
931
932         if (signal < 0 || signal >= MM_SOUND_SIGNAL_MAX || !subscribe_id) {
933                 debug_error ("invalid argument, signal(%d), subscribe_id(0x%p)", signal, subscribe_id);
934                 ret = MM_ERROR_INVALID_ARGUMENT;
935                 goto error;
936         }
937
938         subscribe_cb = malloc(sizeof(subscribe_cb_t));
939         if (!subscribe_cb) {
940                 ret = MM_ERROR_SOUND_INTERNAL;
941                 goto error;
942         }
943         memset(subscribe_cb, 0, sizeof(subscribe_cb_t));
944
945         g_type_init();
946
947         g_dbus_conn_mmsound = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
948         if (!g_dbus_conn_mmsound && err) {
949                 debug_error ("g_bus_get_sync() error (%s) ", err->message);
950                 g_error_free (err);
951                 ret = MM_ERROR_SOUND_INTERNAL;
952                 goto error;
953         }
954
955         subscribe_cb->signal_type = signal;
956         subscribe_cb->callback = callback;
957         subscribe_cb->user_data = user_data;
958
959         *subscribe_id = g_dbus_connection_signal_subscribe(g_dbus_conn_mmsound,
960                         NULL, MM_SOUND_DBUS_INTERFACE, dbus_signal_name_str[signal], MM_SOUND_DBUS_OBJECT_PATH, NULL, 0,
961                         signal_callback, subscribe_cb, NULL);
962         if (*subscribe_id == 0) {
963                 debug_error ("g_dbus_connection_signal_subscribe() error (%d)", *subscribe_id);
964                 ret = MM_ERROR_SOUND_INTERNAL;
965                 goto sig_error;
966         }
967
968         subscribe_cb->id = *subscribe_id;
969
970         g_subscribe_cb_list = g_list_append(g_subscribe_cb_list, subscribe_cb);
971         if (g_subscribe_cb_list) {
972                 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);
973         } else {
974                 debug_error("g_list_append failed\n");
975                 ret = MM_ERROR_SOUND_INTERNAL;
976                 goto error;
977         }
978
979         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
980
981         debug_fleave();
982
983         return ret;
984
985 sig_error:
986         g_dbus_connection_signal_unsubscribe(g_dbus_conn_mmsound, *subscribe_id);
987         g_object_unref(g_dbus_conn_mmsound);
988
989 error:
990         if (subscribe_cb)
991                 free (subscribe_cb);
992
993         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
994
995         return ret;
996 }
997
998 EXPORT_API
999 void mm_sound_unsubscribe_signal(unsigned int subscribe_id)
1000 {
1001         GList *list = NULL;
1002         subscribe_cb_t *subscribe_cb = NULL;
1003
1004         debug_fenter();
1005
1006         MMSOUND_ENTER_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1007
1008         if (g_dbus_conn_mmsound && subscribe_id) {
1009                 g_dbus_connection_signal_unsubscribe(g_dbus_conn_mmsound, subscribe_id);
1010                 g_object_unref(g_dbus_conn_mmsound);
1011                 for (list = g_subscribe_cb_list; list != NULL; list = list->next) {
1012                         subscribe_cb = (subscribe_cb_t *)list->data;
1013                         if (subscribe_cb && (subscribe_cb->id == subscribe_id)) {
1014                                 g_subscribe_cb_list = g_list_remove(g_subscribe_cb_list, subscribe_cb);
1015                                 debug_log("subscribe_cb(0x%x) is removed\n", subscribe_cb);
1016                                 free (subscribe_cb);
1017                         }
1018                 }
1019         }
1020
1021         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1022
1023         debug_fleave();
1024 }
1025
1026 EXPORT_API
1027 int mm_sound_send_signal(mm_sound_signal_name_t signal, int value)
1028 {
1029         int ret = MM_ERROR_NONE;
1030         GError *err = NULL;
1031         GDBusConnection *conn = NULL;
1032         gboolean dbus_ret = TRUE;
1033
1034         debug_fenter();
1035
1036         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
1037
1038         if (signal < 0 || signal >= MM_SOUND_SIGNAL_MAX) {
1039                 debug_error ("invalid argument, signal(%d)", signal);
1040                 ret = MM_ERROR_INVALID_ARGUMENT;
1041                 goto error;
1042         }
1043
1044         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1045         if (!conn && err) {
1046                 debug_error ("g_bus_get_sync() error (%s)", err->message);
1047                 ret = MM_ERROR_SOUND_INTERNAL;
1048                 goto error;
1049         }
1050
1051         g_dbus_signal_values[signal] = value;
1052         if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
1053                 /* trigger the signal callback when it comes from the same process */
1054                 value |= ((int)getpid() << 16);
1055         }
1056         dbus_ret = g_dbus_connection_emit_signal (conn,
1057                                 NULL, MM_SOUND_DBUS_OBJECT_PATH, MM_SOUND_DBUS_INTERFACE, dbus_signal_name_str[signal],
1058                                 g_variant_new ("(i)", value),
1059                                 &err);
1060         if (!dbus_ret && err) {
1061                 debug_error ("g_dbus_connection_emit_signal() error (%s)", err->message);
1062                 ret = MM_ERROR_SOUND_INTERNAL;
1063                 goto error;
1064         }
1065
1066         dbus_ret = g_dbus_connection_flush_sync(conn, NULL, &err);
1067         if (!dbus_ret && err) {
1068                 debug_error ("g_dbus_connection_flush_sync() error (%s)", err->message);
1069                 ret = MM_ERROR_SOUND_INTERNAL;
1070                 goto error;
1071         }
1072
1073         g_object_unref(conn);
1074         debug_msg ("sending signal[%s], value[%d] success", dbus_signal_name_str[signal], value);
1075
1076         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1077
1078         debug_fleave();
1079
1080         return ret;
1081
1082 error:
1083         if (err)
1084                 g_error_free (err);
1085         if (conn)
1086                 g_object_unref(conn);
1087
1088         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1089
1090         return ret;
1091 }
1092
1093 EXPORT_API
1094 int mm_sound_get_signal_value(mm_sound_signal_name_t signal, int *value)
1095 {
1096         int ret = MM_ERROR_NONE;
1097
1098         debug_fenter();
1099
1100         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_subscribe_cb_list_mutex, MM_ERROR_SOUND_INTERNAL);
1101
1102         *value = g_dbus_signal_values[signal];
1103
1104         MMSOUND_LEAVE_CRITICAL_SECTION(&g_subscribe_cb_list_mutex);
1105
1106         debug_fleave();
1107
1108         return ret;
1109 }
1110
1111 __attribute__ ((constructor))
1112 static void _mm_sound_initialize(void)
1113 {
1114         mm_sound_client_initialize();
1115         /* Will be Fixed */
1116 }
1117
1118 __attribute__ ((destructor))
1119 static void _mm_sound_finalize(void)
1120 {
1121         mm_sound_client_finalize();
1122 }
1123
1124