mm_sound_testsuite: give an option to use environment value for keytone playback
[platform/core/multimedia/libmm-sound.git] / mm_sound_proxy.c
1 #include <stdint.h>
2 #include <glib.h>
3
4 #ifdef TIZEN_TV
5 #include <vconf.h>
6 #endif
7
8 #include <mm_error.h>
9 #include <mm_debug.h>
10
11 #include "include/mm_sound_proxy.h"
12 #include "include/mm_sound_common.h"
13 #include "include/mm_sound_dbus.h"
14 #include "include/mm_sound_intf.h"
15 #include "include/mm_sound_focus_socket.h"
16 #include "include/mm_sound_focus_private.h"
17
18 struct callback_data {
19         void *user_cb;
20         void *user_data;
21         mm_sound_proxy_userdata_free free_func;
22         uint32_t subs_id;
23 };
24
25 #define CB_DATA_NEW(_cb_data, _func, _userdata, _freefunc) \
26         do { \
27                 _cb_data = (struct callback_data*) g_try_malloc0(sizeof(struct callback_data)); \
28                 if (!_cb_data) { \
29                         debug_error("failed to allocate callback_data"); \
30                         return MM_ERROR_OUT_OF_MEMORY; \
31                 } \
32                 _cb_data->user_cb = _func; \
33                 _cb_data->user_data = _userdata; \
34                 _cb_data->free_func = _freefunc; \
35                 _cb_data->subs_id = 0; \
36         } while (0)
37
38 /* subscribe is true when add callback,
39  * false when remove callback */
40 static int _notify_subscription(audio_event_t event, uint32_t subs_id, gboolean subscribe)
41 {
42         int ret = MM_ERROR_NONE;
43         GVariant *params = NULL;
44         const char *event_name = NULL;
45
46         debug_fenter();
47
48         if ((ret = mm_sound_dbus_get_event_name(event, &event_name)) != MM_ERROR_NONE) {
49                 debug_error("Failed to get event name");
50                 return MM_ERROR_SOUND_INTERNAL;
51         }
52
53         if (!(params = g_variant_new("(sub)", event_name, subs_id, subscribe))) {
54                 debug_error("Construct Param failed");
55                 return MM_ERROR_SOUND_INTERNAL;
56         }
57
58         if ((ret = mm_sound_dbus_emit_signal(AUDIO_PROVIDER_AUDIO_CLIENT, AUDIO_EVENT_CLIENT_SUBSCRIBED, params)))
59                 debug_error("dbus send signal for client subscribed failed");
60
61         debug_fleave();
62         return ret;
63 }
64
65 static int _notify_signal_handled(audio_event_t event, uint32_t event_id, uint32_t subs_id, GVariant *signal_params)
66 {
67         int ret = MM_ERROR_NONE;
68         GVariant *params = NULL;
69         const char *event_name = NULL;
70
71         debug_fenter();
72
73         if ((ret = mm_sound_dbus_get_event_name(event, &event_name)) != MM_ERROR_NONE) {
74                 debug_error("Failed to get event name");
75                 return MM_ERROR_SOUND_INTERNAL;
76         }
77
78         if (!(params = g_variant_new("(usuv)", event_id, event_name, subs_id, signal_params))) {
79                 debug_error("Construct Param failed");
80                 return MM_ERROR_SOUND_INTERNAL;
81         }
82
83         if ((ret = mm_sound_dbus_emit_signal(AUDIO_PROVIDER_AUDIO_CLIENT, AUDIO_EVENT_CLIENT_HANDLED, params)))
84                 debug_error("dbus send signal for client handled failed");
85
86         debug_fleave();
87         return ret;
88 }
89
90 static int parse_device_variant(GVariant *v, int *device_id, const char **device_type, int *direction, int *state,
91                                                 const char **device_name, int *vendor_id, int *product_id, gboolean *is_running, int *stream_id, int *stream_num)
92 {
93         const char *v_type;
94         GVariant *array_v;
95         GVariantIter iter, array_iter;
96         int i = 0;
97         int ret = MM_ERROR_NONE;
98
99         if (v == NULL) {
100                 debug_error("Variant NULL");
101                 return MM_ERROR_NONE;
102         }
103
104         v_type = g_variant_get_type_string(v);
105         if (g_variant_type_equal(v_type, "(isiisiibai)") == FALSE) {
106                 debug_error("device variant type not matching '%s'", v_type);
107                 return MM_ERROR_NONE;
108         }
109
110         g_variant_iter_init(&iter, v);
111         g_variant_iter_next(&iter, "i", device_id);
112         g_variant_iter_next(&iter, "&s", device_type);
113         g_variant_iter_next(&iter, "i", direction);
114         g_variant_iter_next(&iter, "i", state);
115         g_variant_iter_next(&iter, "&s", device_name);
116         g_variant_iter_next(&iter, "i", vendor_id);
117         g_variant_iter_next(&iter, "i", product_id);
118         g_variant_iter_next(&iter, "b", is_running);
119
120         array_v = g_variant_iter_next_value(&iter);
121         if (!array_v) {
122                 debug_error("Error iterate on next value");
123                 return MM_ERROR_SOUND_INTERNAL;
124         }
125
126         *stream_num = g_variant_iter_init(&array_iter, array_v);
127         if (*stream_num > MAX_STREAM_ON_DEVICE) {
128                 debug_error("too many streams on device %d", *stream_num);
129                 ret = MM_ERROR_SOUND_INTERNAL;
130                 goto cleanup;
131         }
132
133         while (g_variant_iter_loop(&array_iter, "i", &stream_id[i++])) {}
134
135 cleanup:
136         g_variant_unref(array_v);
137
138         return ret;
139 }
140
141 /* This callback unmarshall general-formed parameters to subject specific parameters,
142  * and call proper callback */
143 static void dbus_callback(audio_event_t event, GVariant *params, void *userdata)
144 {
145         struct callback_data *cb_data  = (struct callback_data*) userdata;
146         uint32_t event_id;
147         const char *name = NULL, *device_type = NULL;
148         int device_id, direction, state;
149         const gchar *v_type;
150         GVariantIter iter;
151         GVariant *device_v;
152         int stream_id[MAX_STREAM_ON_DEVICE];
153         int stream_num;
154         int vendor_id, product_id;
155         gboolean is_running = FALSE;
156
157         v_type = g_variant_get_type_string(params);
158
159         if (event == AUDIO_EVENT_VOLUME_CHANGED) {
160                 char *volume_type_str = NULL, *direction = NULL;
161                 unsigned volume_level;
162
163                 g_variant_get(params, "(&s&su)", &direction, &volume_type_str, &volume_level);
164                 ((mm_sound_volume_changed_wrapper_cb)(cb_data->user_cb))(direction, volume_type_str, volume_level, cb_data->user_data);
165         } else if (event == AUDIO_EVENT_DEVICE_CONNECTED) {
166                 gboolean is_connected = FALSE;
167
168                 if (g_variant_type_equal(v_type, "(u(isiisiibai)b)") == FALSE) {
169                         debug_error("Device connection changed signature not matching : %s", v_type);
170                         return ;
171                 }
172                 g_variant_iter_init(&iter, params);
173                 g_variant_iter_next(&iter, "u", &event_id);
174                 device_v = g_variant_iter_next_value(&iter);
175                 if (parse_device_variant(device_v, &device_id, &device_type, &direction, &state,
176                                                         &name, &vendor_id, &product_id, &is_running, stream_id, &stream_num) < 0) {
177                         debug_error("Failed to parse device variant");
178                         return ;
179                 }
180                 g_variant_iter_next(&iter, "b", &is_connected);
181
182                 ((mm_sound_device_connected_wrapper_cb)(cb_data->user_cb))(device_id, device_type, direction,
183                         state, name, vendor_id, product_id, (bool)is_running, stream_id, stream_num, (bool)is_connected, cb_data->user_data);
184                 _notify_signal_handled(event, event_id, cb_data->subs_id, g_variant_new("(ib)", device_id, (bool)is_connected));
185         } else if (event == AUDIO_EVENT_DEVICE_INFO_CHANGED) {
186                 int changed_device_info_type = 0;
187
188                 if (g_variant_type_equal(v_type, "(u(isiisiibai)i)") == FALSE) {
189                         debug_error("Device information changed signature not matching : %s", v_type);
190                         return ;
191                 }
192
193                 g_variant_iter_init(&iter, params);
194                 g_variant_iter_next(&iter, "u", &event_id);
195                 device_v = g_variant_iter_next_value(&iter);
196                 if (parse_device_variant(device_v, &device_id, &device_type, &direction, &state,
197                                                         &name, &vendor_id, &product_id, &is_running, stream_id, &stream_num) < 0) {
198                         debug_error("Failed to parse device variant");
199                         return ;
200                 }
201                 g_variant_iter_next(&iter, "i", &changed_device_info_type);
202
203                 ((mm_sound_device_info_changed_wrapper_cb)(cb_data->user_cb))(device_id, device_type, direction,
204                         state, name, vendor_id, product_id, (bool)is_running, stream_id, stream_num, changed_device_info_type, cb_data->user_data);
205         } else if (event == AUDIO_EVENT_DEVICE_STATE_CHANGED) {
206
207                 if (g_variant_type_equal(v_type, "(u(isiisiibai))") == FALSE) {
208                         debug_error("Device state changed signature not matching : %s", v_type);
209                         return ;
210                 }
211
212                 g_variant_iter_init(&iter, params);
213                 g_variant_iter_next(&iter, "u", &event_id);
214                 device_v = g_variant_iter_next_value(&iter);
215                 if (parse_device_variant(device_v, &device_id, &device_type, &direction, &state,
216                                                         &name, &vendor_id, &product_id, &is_running, stream_id, &stream_num) < 0) {
217                         debug_error("Failed to parse device variant");
218                         return ;
219                 }
220
221                 ((mm_sound_device_state_changed_wrapper_cb)(cb_data->user_cb))(device_id, device_type, direction,
222                         state, name, vendor_id, product_id, (bool)is_running, stream_id, stream_num, cb_data->user_data);
223         } else if (event == AUDIO_EVENT_DEVICE_RUNNING_CHANGED) {
224
225                 if (g_variant_type_equal(v_type, "(u(isiisiibai))") == FALSE) {
226                         debug_error("Device state changed signature not matching : %s", v_type);
227                         return ;
228                 }
229
230                 g_variant_iter_init(&iter, params);
231                 g_variant_iter_next(&iter, "u", &event_id);
232                 device_v = g_variant_iter_next_value(&iter);
233                 if (parse_device_variant(device_v, &device_id, &device_type, &direction, &state,
234                                                         &name, &vendor_id, &product_id, &is_running, stream_id, &stream_num) < 0) {
235                         debug_error("Failed to parse device variant");
236                         return ;
237                 }
238
239                 ((mm_sound_device_running_changed_wrapper_cb)(cb_data->user_cb))(device_id, device_type, direction,
240                         state, name, vendor_id, product_id, (bool)is_running, stream_id, stream_num, cb_data->user_data);
241         } else if (event == AUDIO_EVENT_FOCUS_CHANGED) {
242         } else if (event == AUDIO_EVENT_FOCUS_WATCH) {
243         } else if (event == AUDIO_EVENT_TEST) {
244                 int test_var = 0;
245                 g_variant_get(params, "(i)", &test_var);
246                 ((mm_sound_test_cb)(cb_data->user_cb))(test_var, cb_data->user_data);
247         } else if (event == AUDIO_EVENT_DUCKING_STATE_CHANGED) {
248                 int idx = 0;
249                 int is_ducked = 0;
250
251                 g_variant_get(params, "(ii)", &idx, &is_ducked);
252
253                 ((mm_sound_ducking_state_changed_wrapper_cb)(cb_data->user_cb))(idx, is_ducked, cb_data->user_data);
254         }
255 }
256
257 static void simple_callback_data_free_func(void *data)
258 {
259         struct callback_data *cb_data = (struct callback_data*) data;
260
261         if (cb_data) {
262                 if (cb_data->free_func)
263                         cb_data->free_func(cb_data->user_data);
264                 g_free(cb_data);
265         }
266 }
267
268 int mm_sound_proxy_is_stream_on_device(int stream_id, int device_id, bool *is_on)
269 {
270         int ret = MM_ERROR_NONE;
271         GVariant *params = NULL, *result = NULL;
272         gboolean _is_on;
273
274         debug_fenter();
275
276         if (!is_on) {
277                 debug_error("Invalid Parameter, is_on null");
278                 return MM_ERROR_INVALID_ARGUMENT;
279         }
280
281         if ((params = g_variant_new("(ii)", stream_id, device_id)) == NULL) {
282                 debug_error("Construct Param for query is stream on device failed");
283                 return MM_ERROR_SOUND_INTERNAL;
284         }
285
286         if ((ret = mm_sound_dbus_method_call_to(AUDIO_PROVIDER_DEVICE_MANAGER, AUDIO_METHOD_IS_STREAM_ON_DEVICE, params, &result)) != MM_ERROR_NONE) {
287                 debug_error("is stream on device failed");
288                 goto cleanup;
289         }
290
291         if (result) {
292                 g_variant_get(result, "(b)",  &_is_on);
293                 debug_log("is_on : %d", _is_on);
294                 *is_on = (bool)_is_on;
295         } else {
296                 debug_error("reply null");
297                 ret = MM_ERROR_SOUND_INTERNAL;
298         }
299
300 cleanup:
301         if (result)
302                 g_variant_unref(result);
303
304         debug_fleave();
305         return ret;
306 }
307
308 #ifdef TIZEN_TV
309 #define _VCONF_KEY_SOUND_SPEAKER_SELECTION "file/private/sound/feature/SpeakerSelection"
310 #define _AUDIO_TV_OUTPUT_BT_HEADSET 5
311
312 static mm_sound_device_t* _get_tv_bt_device(int device_flags)
313 {
314         int speaker_value = 0;
315         mm_sound_device_t* device_item = NULL;
316
317         /* check precondition mask first here */
318         if (device_flags != DEVICE_ALL_FLAG) {
319                 if (!(device_flags & DEVICE_IO_DIRECTION_OUT_FLAG)) {
320                         debug_warning("no out flag given, skip checking bt a2dp");
321                         return NULL;
322                 }
323                 if (device_flags & DEVICE_TYPE_INTERNAL_FLAG) {
324                         debug_warning("internal flag given, skip checking bt a2dp");
325                         return NULL;
326                 }
327         }
328
329         if (vconf_get_int(_VCONF_KEY_SOUND_SPEAKER_SELECTION, &speaker_value) == VCONF_ERROR) {
330                 debug_error("vconf_get_int(%s) failed..", _VCONF_KEY_SOUND_SPEAKER_SELECTION);
331                 return NULL;
332         }
333
334         debug_warning("speaker selection value = %d", speaker_value);
335         if (speaker_value != _AUDIO_TV_OUTPUT_BT_HEADSET)
336                 return NULL;
337
338         device_item = g_new0(mm_sound_device_t, 1);
339
340         MMSOUND_STRNCPY(device_item->name, "BluetoothMedia", MAX_DEVICE_NAME_NUM);
341         MMSOUND_STRNCPY(device_item->type, "bt-a2dp", MAX_DEVICE_TYPE_STR_LEN);
342         device_item->id = 99;
343         device_item->io_direction = DEVICE_IO_DIRECTION_OUT;
344         device_item->state = DEVICE_STATE_ACTIVATED;
345         device_item->vendor_id = -1;
346         device_item->product_id = -1;
347         device_item->stream_num = -1;
348
349         return device_item;
350 }
351 #endif /* TIZEN_TV */
352
353 int mm_sound_proxy_get_current_connected_device_list(int device_flags, GList** device_list)
354 {
355         int ret = MM_ERROR_NONE;
356         GVariant *result = NULL, *child = NULL;
357         GVariant *params = NULL;
358         GVariantIter iter;
359         mm_sound_device_t* device_item;
360         const gchar *device_name_tmp = NULL, *device_type_tmp = NULL;
361
362         debug_fenter();
363
364         if (!device_list) {
365                 debug_error("Invalid Parameter, device_list null");
366                 ret = MM_ERROR_INVALID_ARGUMENT;
367                 goto cleanup;
368         }
369
370         params = g_variant_new("(i)", device_flags);
371
372         if (params) {
373                 if ((ret = mm_sound_dbus_method_call_to(AUDIO_PROVIDER_DEVICE_MANAGER, AUDIO_METHOD_GET_CONNECTED_DEVICE_LIST, params, &result)) != MM_ERROR_NONE) {
374                         debug_error("Get current connected device list failed");
375                         goto cleanup;
376                 }
377         } else {
378                 debug_error("Construct Param for get current connected device failed");
379                 return MM_ERROR_SOUND_INTERNAL;
380         }
381
382         child = g_variant_get_child_value(result, 0);
383         if (!child) {
384                 debug_error("Error getting child value from result");
385                 goto cleanup;
386         }
387         g_variant_iter_init(&iter, child);
388         while (1) {
389                 device_item = g_malloc0(sizeof(mm_sound_device_t));
390                 if (device_item && g_variant_iter_loop(&iter, "(i&sii&siibiii)",
391                                         &device_item->id, &device_type_tmp, &device_item->io_direction, &device_item->state,
392                                         &device_name_tmp, &device_item->vendor_id, &device_item->product_id, &device_item->is_running,
393                                         &device_item->format, &device_item->samplerate, &device_item->channels)) {
394                         MMSOUND_STRNCPY(device_item->name, device_name_tmp, MAX_DEVICE_NAME_NUM);
395                         MMSOUND_STRNCPY(device_item->type, device_type_tmp, MAX_DEVICE_TYPE_STR_LEN);
396                         *device_list = g_list_append(*device_list, device_item);
397                         debug_log("Added device id(%d) type(%17s) direction(%d) state(%d) name(%s) vendor-id(%04x) "\
398                                         "product-id(%04x) is_running(%d) format(%d), samplerate(%d), channels(%d)",
399                                         device_item->id, device_item->type, device_item->io_direction, device_item->state,
400                                         device_item->name, device_item->vendor_id, device_item->product_id, device_item->is_running,
401                                         device_item->format, device_item->samplerate, device_item->channels);
402                         device_item->stream_num = -1;
403                 } else {
404                         g_free(device_item);
405                         break;
406                 }
407         }
408         g_variant_unref(child);
409
410 #ifdef TIZEN_TV
411         device_item = _get_tv_bt_device(device_flags);
412         if (device_item) {
413                 *device_list = g_list_append(*device_list, device_item);
414                 debug_msg("Added TV bt device id(%d) type(%17s) direction(%d) state(%d) name(%s) vendor-id(%04x) product-id(%04x)",
415                                         device_item->id, device_item->type, device_item->io_direction, device_item->state,
416                                         device_item->name, device_item->vendor_id, device_item->product_id);
417         }
418 #endif /* TIZEN_TV */
419
420 cleanup:
421         if (result)
422                 g_variant_unref(result);
423
424         debug_fleave();
425         return ret;
426 }
427
428 int mm_sound_proxy_get_device_by_id(int device_id, mm_sound_device_t **device)
429 {
430         int ret = MM_ERROR_NONE;
431         GVariant *params = NULL, *result = NULL;
432         mm_sound_device_t* device_item = NULL;
433         const gchar *device_name_tmp = NULL, *device_type_tmp = NULL;
434
435         debug_fenter();
436
437         if (!device || device_id < 1) {
438                 debug_error("Invalid Parameter, device null or improper device id");
439                 return MM_ERROR_INVALID_ARGUMENT;
440         }
441
442         if ((params = g_variant_new("(i)", device_id)) == NULL) {
443                 debug_error("Construct Param for get device by id failed");
444                 return MM_ERROR_SOUND_INTERNAL;
445         }
446
447         if ((ret = mm_sound_dbus_method_call_to(AUDIO_PROVIDER_DEVICE_MANAGER, AUDIO_METHOD_GET_DEVICE_BY_ID, params, &result)) != MM_ERROR_NONE) {
448                 debug_error("get device by id failed");
449                 ret = MM_ERROR_SOUND_NO_DATA;
450                 goto cleanup;
451         }
452
453         if (result) {
454                 if ((device_item = g_malloc0(sizeof(mm_sound_device_t))) == NULL) {
455                         debug_error("Alloc device handle failed");
456                         ret = MM_ERROR_SOUND_INTERNAL;
457                         goto cleanup;
458                 }
459
460                 g_variant_get(result, "(i&sii&sii)",
461                                 &device_item->id, &device_type_tmp, &device_item->io_direction,
462                                 &device_item->state, &device_name_tmp,
463                                 &device_item->vendor_id, &device_item->product_id);
464                 MMSOUND_STRNCPY(device_item->name, device_name_tmp, MAX_DEVICE_NAME_NUM);
465                 MMSOUND_STRNCPY(device_item->type, device_type_tmp, MAX_DEVICE_TYPE_STR_LEN);
466                 debug_log("Get device id(%d) type(%17s) direction(%d) state(%d) name(%s) vendor-id(%04x) product-id(%04x)",
467                                 device_item->id, device_item->type, device_item->io_direction,
468                                 device_item->state, device_item->name,
469                                 device_item->vendor_id, device_item->product_id);
470                 device_item->stream_num = -1;
471                 *device = device_item;
472         } else {
473                 debug_error("reply null");
474                 ret = MM_ERROR_SOUND_INTERNAL;
475         }
476
477 cleanup:
478         if (result)
479                 g_variant_unref(result);
480
481         debug_fleave();
482         return ret;
483 }
484
485 int mm_sound_proxy_add_device_connected_callback(mm_sound_device_connected_wrapper_cb func, void *userdata, mm_sound_proxy_userdata_free freefunc, unsigned *subs_id)
486 {
487         int ret = MM_ERROR_NONE;
488         struct callback_data *cb_data;
489
490         debug_fenter();
491
492         CB_DATA_NEW(cb_data, func, userdata, freefunc);
493
494         if ((ret = mm_sound_dbus_signal_subscribe_to(AUDIO_PROVIDER_DEVICE_MANAGER, AUDIO_EVENT_DEVICE_CONNECTED, dbus_callback, cb_data, simple_callback_data_free_func, &cb_data->subs_id)) != MM_ERROR_NONE) {
495                 debug_error("add device connected callback failed");
496                 goto cleanup;
497         }
498
499         if ((ret = _notify_subscription(AUDIO_EVENT_DEVICE_CONNECTED, cb_data->subs_id, TRUE)) != MM_ERROR_NONE) {
500                 debug_error("failed to notify subscription of device connected event");
501                 goto cleanup;
502         }
503
504         *subs_id = cb_data->subs_id;
505
506 cleanup:
507         debug_fleave();
508         return ret;
509 }
510
511 int mm_sound_proxy_remove_device_connected_callback(unsigned subs_id)
512 {
513         int ret = MM_ERROR_NONE;
514         debug_fenter();
515
516         if ((ret = mm_sound_dbus_signal_unsubscribe(subs_id)) != MM_ERROR_NONE) {
517                 debug_error("remove device connected callback failed");
518                 goto cleanup;
519         }
520
521         if ((ret = _notify_subscription(AUDIO_EVENT_DEVICE_CONNECTED, subs_id, FALSE)) != MM_ERROR_NONE)
522                 debug_error("failed to notify unsubscription of device connected event");
523
524 cleanup:
525         debug_fleave();
526         return ret;
527 }
528
529 int mm_sound_proxy_add_device_info_changed_callback(mm_sound_device_info_changed_wrapper_cb func, void* userdata, mm_sound_proxy_userdata_free freefunc, unsigned *subs_id)
530 {
531         int ret = MM_ERROR_NONE;
532         struct callback_data *cb_data;
533
534         debug_fenter();
535
536         CB_DATA_NEW(cb_data, func, userdata, freefunc);
537
538         if ((ret = mm_sound_dbus_signal_subscribe_to(AUDIO_PROVIDER_DEVICE_MANAGER, AUDIO_EVENT_DEVICE_INFO_CHANGED, dbus_callback, cb_data, simple_callback_data_free_func, &cb_data->subs_id)) != MM_ERROR_NONE)
539                 debug_error("Add device info changed callback failed");
540         else
541                 *subs_id = cb_data->subs_id;
542
543         debug_fleave();
544         return ret;
545 }
546
547 int mm_sound_proxy_remove_device_info_changed_callback(unsigned subs_id)
548 {
549         int ret = MM_ERROR_NONE;
550         debug_fenter();
551
552         if ((ret = mm_sound_dbus_signal_unsubscribe(subs_id)) != MM_ERROR_NONE)
553                 debug_error("remove device info changed callback failed");
554
555         debug_fleave();
556         return ret;
557 }
558
559 int mm_sound_proxy_add_device_state_changed_callback(mm_sound_device_state_changed_wrapper_cb func, void* userdata, mm_sound_proxy_userdata_free freefunc, unsigned *subs_id)
560 {
561         int ret = MM_ERROR_NONE;
562         struct callback_data *cb_data;
563
564         debug_fenter();
565
566         CB_DATA_NEW(cb_data, func, userdata, freefunc);
567
568         if ((ret = mm_sound_dbus_signal_subscribe_to(AUDIO_PROVIDER_DEVICE_MANAGER, AUDIO_EVENT_DEVICE_STATE_CHANGED, dbus_callback, cb_data, simple_callback_data_free_func, &cb_data->subs_id)) != MM_ERROR_NONE)
569                 debug_error("Add device state changed callback failed");
570         else
571                 *subs_id = cb_data->subs_id;
572
573         debug_fleave();
574         return ret;
575 }
576
577 int mm_sound_proxy_remove_device_state_changed_callback(unsigned subs_id)
578 {
579         int ret = MM_ERROR_NONE;
580         debug_fenter();
581
582         if ((ret = mm_sound_dbus_signal_unsubscribe(subs_id)) != MM_ERROR_NONE)
583                 debug_error("remove device state changed callback failed");
584
585         debug_fleave();
586         return ret;
587 }
588
589 int mm_sound_proxy_add_device_running_changed_callback(mm_sound_device_running_changed_wrapper_cb func, void* userdata, mm_sound_proxy_userdata_free freefunc, unsigned *subs_id)
590 {
591         int ret = MM_ERROR_NONE;
592         struct callback_data *cb_data;
593
594         debug_fenter();
595
596         CB_DATA_NEW(cb_data, func, userdata, freefunc);
597
598         if ((ret = mm_sound_dbus_signal_subscribe_to(AUDIO_PROVIDER_DEVICE_MANAGER, AUDIO_EVENT_DEVICE_RUNNING_CHANGED, dbus_callback, cb_data, simple_callback_data_free_func, &cb_data->subs_id)) != MM_ERROR_NONE)
599                 debug_error("Add device running changed callback failed");
600         else
601                 *subs_id = cb_data->subs_id;
602
603         debug_fleave();
604         return ret;
605 }
606
607 int mm_sound_proxy_remove_device_running_changed_callback(unsigned subs_id)
608 {
609         int ret = MM_ERROR_NONE;
610         debug_fenter();
611
612         if ((ret = mm_sound_dbus_signal_unsubscribe(subs_id)) != MM_ERROR_NONE)
613                 debug_error("remove device running changed callback failed");
614
615         debug_fleave();
616         return ret;
617 }
618
619 int mm_sound_proxy_set_volume_by_type(const char *volume_type, const unsigned volume_level)
620 {
621         int ret = MM_ERROR_NONE;
622         const char *reply = NULL, *direction = "out";
623         GVariant *params = NULL, *result = NULL;
624
625         debug_fenter();
626
627         if ((params = g_variant_new("(ssu)", direction, volume_type, volume_level)) == NULL) {
628                 debug_error("Construct Param for method call failed");
629                 return MM_ERROR_SOUND_INTERNAL;
630         }
631
632         if ((ret = mm_sound_dbus_method_call_to(AUDIO_PROVIDER_STREAM_MANAGER, AUDIO_METHOD_SET_VOLUME_LEVEL, params, &result)) != MM_ERROR_NONE) {
633                 debug_error("dbus set volume by type failed");
634                 goto cleanup;
635         }
636
637         if (result) {
638                 g_variant_get(result, "(&s)",  &reply);
639                 debug_log("reply : %s", reply);
640                 if (!strcmp(reply, "STREAM_MANAGER_RETURN_ERROR_INVALID_ARGUMENT"))
641                         ret = MM_ERROR_INVALID_ARGUMENT;
642                 else if (strcmp(reply, "STREAM_MANAGER_RETURN_OK"))
643                         ret = MM_ERROR_SOUND_INTERNAL;
644         } else {
645                 debug_error("reply null");
646                 ret = MM_ERROR_SOUND_INTERNAL;
647         }
648
649 cleanup:
650         if (result)
651                 g_variant_unref(result);
652
653         debug_fleave();
654         return ret;
655 }
656
657 int mm_sound_proxy_add_volume_changed_callback(mm_sound_volume_changed_wrapper_cb func, void* userdata, mm_sound_proxy_userdata_free freefunc, unsigned *subs_id)
658 {
659         int ret = MM_ERROR_NONE;
660         struct callback_data *cb_data;
661
662         debug_fenter();
663
664         CB_DATA_NEW(cb_data, func, userdata, freefunc);
665
666         if ((ret = mm_sound_dbus_signal_subscribe_to(AUDIO_PROVIDER_STREAM_MANAGER, AUDIO_EVENT_VOLUME_CHANGED, dbus_callback, cb_data, simple_callback_data_free_func, &cb_data->subs_id)) != MM_ERROR_NONE)
667                 debug_error("Add Volume changed callback failed");
668         else
669                 *subs_id = cb_data->subs_id;
670
671         debug_fleave();
672
673         return ret;
674 }
675
676 int mm_sound_proxy_remove_volume_changed_callback(unsigned subs_id)
677 {
678         int ret = MM_ERROR_NONE;
679         debug_fenter();
680
681         if ((ret = mm_sound_dbus_signal_unsubscribe(subs_id)) != MM_ERROR_NONE)
682                 debug_error("Remove Volume changed callback failed");
683
684         debug_fleave();
685         return ret;
686 }
687
688 int mm_sound_proxy_add_ducking_state_changed_callback(mm_sound_ducking_state_changed_wrapper_cb func, void* userdata, mm_sound_proxy_userdata_free freefunc, unsigned *subs_id)
689 {
690         int ret = MM_ERROR_NONE;
691         struct callback_data *cb_data;
692
693         debug_fenter();
694
695         CB_DATA_NEW(cb_data, func, userdata, freefunc);
696
697         if ((ret = mm_sound_dbus_signal_subscribe_to(AUDIO_PROVIDER_STREAM_MANAGER, AUDIO_EVENT_DUCKING_STATE_CHANGED, dbus_callback, cb_data, simple_callback_data_free_func, &cb_data->subs_id)) != MM_ERROR_NONE)
698                 debug_error("Add Ducking State changed callback failed");
699         else
700                 *subs_id = cb_data->subs_id;
701
702         debug_fleave();
703
704         return ret;
705 }
706
707 int mm_sound_proxy_remove_ducking_state_changed_callback(unsigned subs_id)
708 {
709         int ret = MM_ERROR_NONE;
710         debug_fenter();
711
712         if ((ret = mm_sound_dbus_signal_unsubscribe(subs_id)) != MM_ERROR_NONE)
713                 debug_error("Remove Ducking State changed callback failed");
714
715         debug_fleave();
716         return ret;
717 }
718
719 int mm_sound_proxy_set_mute_by_type(const char *volume_type, bool mute)
720 {
721         int ret = MM_ERROR_NONE;
722         const char *reply = NULL, *direction = "out";
723         GVariant *params = NULL, *result = NULL;
724
725         debug_fenter();
726
727         if ((params = g_variant_new("(ssu)", direction, volume_type, (unsigned int)mute)) == NULL) {
728                 debug_error("Construct Param for method call failed");
729                 return MM_ERROR_SOUND_INTERNAL;
730         }
731
732         if ((ret = mm_sound_dbus_method_call_to(AUDIO_PROVIDER_STREAM_MANAGER, AUDIO_METHOD_SET_MUTE, params, &result)) != MM_ERROR_NONE) {
733                 debug_error("dbus set mute by type failed");
734                 goto cleanup;
735         }
736
737         if (result) {
738                 g_variant_get(result, "(&s)",  &reply);
739                 debug_log("reply : %s", reply);
740                 if (strcmp(reply, "STREAM_MANAGER_RETURN_OK"))
741                         ret = MM_ERROR_SOUND_INTERNAL;
742         } else {
743                 debug_error("reply null");
744                 ret = MM_ERROR_SOUND_INTERNAL;
745         }
746
747 cleanup:
748         if (result)
749                 g_variant_unref(result);
750
751         debug_fleave();
752         return ret;
753 }
754
755 int mm_sound_proxy_set_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_parameters, const char *filter_group) {
756         int ret = MM_ERROR_NONE;
757         const char *reply = NULL;
758         GVariant *params = NULL, *result = NULL;
759
760         debug_fenter();
761
762         if ((params = g_variant_new("(ssss)", filter_name, filter_parameters, filter_group, stream_type)) == NULL) {
763                 debug_error("construct param for method call failed");
764                 return MM_ERROR_SOUND_INTERNAL;
765         }
766
767         if ((ret = mm_sound_dbus_method_call_to(AUDIO_PROVIDER_STREAM_MANAGER, AUDIO_METHOD_SET_FILTER, params, &result)) != MM_ERROR_NONE) {
768                 debug_error("dbus set filter by type failed");
769                 goto cleanup;
770         }
771
772         /* stream-manager always returns a string as return value */
773         if (result) {
774                 g_variant_get(result, "(&s)", &reply);
775                 debug_log("reply : %s", reply);
776                 if (strcmp(reply, "STREAM_MANAGER_RETURN_OK"))
777                         ret = MM_ERROR_SOUND_INTERNAL;
778         } else {
779                 debug_error("reply null");
780                 ret = MM_ERROR_SOUND_INTERNAL;
781         }
782
783 cleanup:
784         if (result)
785                 g_variant_unref(result);
786
787         debug_fleave();
788         return ret;
789 }
790
791 int mm_sound_proxy_unset_filter_by_type(const char *stream_type)
792 {
793         int ret = MM_ERROR_NONE;
794         const char *reply = NULL;
795         GVariant *params = NULL, *result = NULL;
796
797         debug_fenter();
798
799         if ((params = g_variant_new("(s)", stream_type)) == NULL) {
800                 debug_error("construct param for method call failed");
801                 return MM_ERROR_SOUND_INTERNAL;
802         }
803
804         if ((ret = mm_sound_dbus_method_call_to(AUDIO_PROVIDER_STREAM_MANAGER, AUDIO_METHOD_UNSET_FILTER, params, &result)) != MM_ERROR_NONE) {
805                 debug_error("dbus unset filter by type failed");
806                 goto cleanup;
807         }
808
809         /* stream-manager always returns a string as return value */
810         if (result) {
811                 g_variant_get(result, "(&s)", &reply);
812                 debug_log("reply : %s", reply);
813                 if (strcmp(reply, "STREAM_MANAGER_RETURN_OK"))
814                         ret = MM_ERROR_SOUND_INTERNAL;
815         } else {
816                 debug_error("reply null");
817                 ret = MM_ERROR_SOUND_INTERNAL;
818         }
819
820 cleanup:
821         if (result)
822                 g_variant_unref(result);
823
824         debug_fleave();
825         return ret;
826 }
827
828 int mm_sound_proxy_control_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_controls)
829 {
830         int ret = MM_ERROR_NONE;
831         const char *reply = NULL;
832         GVariant *params = NULL, *result = NULL;
833
834         debug_fenter();
835
836         if ((params = g_variant_new("(sss)", filter_name, filter_controls, stream_type)) == NULL) {
837                 debug_error("construct param for method call failed");
838                 return MM_ERROR_SOUND_INTERNAL;
839         }
840
841         if ((ret = mm_sound_dbus_method_call_to(AUDIO_PROVIDER_STREAM_MANAGER, AUDIO_METHOD_CONTROL_FILTER, params, &result)) != MM_ERROR_NONE) {
842                 debug_error("dbus control filter by type failed");
843                 goto cleanup;
844         }
845         /* stream-manager always returns a string as return value */
846         if (result) {
847                 g_variant_get(result, "(&s)", &reply);
848                 debug_log("reply : %s", reply);
849                 if (strcmp(reply, "STREAM_MANAGER_RETURN_OK"))
850                         ret = MM_ERROR_SOUND_INTERNAL;
851         } else {
852                 debug_error("reply null");
853                 ret = MM_ERROR_SOUND_INTERNAL;
854         }
855
856 cleanup:
857         if (result)
858                 g_variant_unref(result);
859
860         debug_fleave();
861         return ret;
862 }
863
864 int mm_sound_proxy_register_focus(int index, const char *stream_type, int *id)
865 {
866         int ret = MM_ERROR_NONE;
867         int pid = g_focus_sound_handle[index].focus_pid;
868         int client_fd = 0;
869
870 #ifndef TIZEN_TV
871         debug_fenter();
872 #endif
873         ret = mm_sound_focus_socket_register(pid, stream_type, &client_fd, id);
874         if (ret) {
875                 debug_error("failed to mm_sound_focus_socket_register(), ret[0x%x]", ret);
876         } else {
877                 g_focus_sound_handle[index].client_fd = client_fd;
878                 g_focus_sound_handle[index].handle = *id;
879         }
880
881         debug_fleave();
882
883         return ret;
884 }
885
886 int mm_sound_proxy_unregister_focus(int index)
887 {
888         int ret = MM_ERROR_NONE;
889         int pid = g_focus_sound_handle[index].focus_pid;
890         int client_fd = g_focus_sound_handle[index].client_fd;
891         int id = g_focus_sound_handle[index].handle;
892
893         debug_fenter();
894
895         ret = mm_sound_focus_socket_unregister(pid, client_fd, id);
896         if (ret)
897                 debug_error("failed to mm_sound_focus_socket_unregister(), client_fd[%d], id[%d], ret[0x%x]", client_fd, id, ret);
898
899         debug_fleave();
900
901         return ret;
902 }
903
904 int mm_sound_proxy_set_focus_reacquisition(int index, bool reacquisition)
905 {
906         int ret = MM_ERROR_NONE;
907         int pid = g_focus_sound_handle[index].focus_pid;
908         int client_fd = g_focus_sound_handle[index].client_fd;
909         int id = g_focus_sound_handle[index].handle;
910
911         debug_fenter();
912
913         ret = mm_sound_focus_socket_set_reacquisition(pid, client_fd, id, reacquisition);
914         if (ret)
915                 debug_error("failed to mm_sound_focus_socket_set_reacquisition(), ret[0x%x]", ret);
916
917         debug_fleave();
918         return ret;
919 }
920
921 int mm_sound_proxy_get_acquired_focus_stream_type(int focus_type, char **stream_type, int *option, char **ext_info)
922 {
923         int ret = MM_ERROR_NONE;
924
925         debug_fenter();
926
927         ret = mm_sound_focus_socket_get_acquired_focus_stream_type(focus_type, stream_type, option, ext_info);
928         if (ret)
929                 debug_error("failed to mm_sound_focus_socket_get_acquired_focus_stream_type(), ret[0x%x]", ret);
930
931         debug_fleave();
932         return ret;
933 }
934
935 int mm_sound_proxy_acquire_focus(int index, mm_sound_focus_type_e type, int option, const char *ext_info)
936 {
937         int ret = MM_ERROR_NONE;
938         bool is_in_focus_cb_thread = false;
939         int pid = g_focus_sound_handle[index].focus_pid;
940         int client_fd = g_focus_sound_handle[index].client_fd;
941         int id = g_focus_sound_handle[index].handle;
942
943         debug_fenter();
944
945         mm_sound_client_is_focus_cb_thread(g_thread_self(), &is_in_focus_cb_thread, NULL);
946         if (!is_in_focus_cb_thread) {
947                 if ((ret = mm_sound_focus_socket_acquire(pid, client_fd, id,
948                                                                                                 type, option, ext_info ? ext_info : "", true)))
949                         debug_error("failed to mm_sound_focus_socket_acquire(), ret[0x%x]", ret);
950         } else {
951                 GVariant *params = NULL, *result = NULL;
952
953                 if ((params = g_variant_new("(iiiis)", pid, id, type, option, ext_info ? ext_info : "")) == NULL) {
954                         debug_error("Construct Param for method call failed");
955                         return MM_ERROR_SOUND_INTERNAL;
956                 }
957
958                 if ((ret = mm_sound_dbus_method_call_to(AUDIO_PROVIDER_FOCUS_SERVER, AUDIO_METHOD_ACQUIRE_FOCUS, params, &result)) != MM_ERROR_NONE)
959                         debug_error("dbus acquire focus failed");
960
961                 if (result)
962                         g_variant_unref(result);
963         }
964
965         debug_fleave();
966
967         return ret;
968 }
969
970 int mm_sound_proxy_release_focus(int index, mm_sound_focus_type_e type, int option, const char *ext_info)
971 {
972         int ret = MM_ERROR_NONE;
973         bool is_in_focus_cb_thread = false;
974         int pid = g_focus_sound_handle[index].focus_pid;
975         int client_fd = g_focus_sound_handle[index].client_fd;
976         int id = g_focus_sound_handle[index].handle;
977
978         debug_fenter();
979
980         mm_sound_client_is_focus_cb_thread(g_thread_self(), &is_in_focus_cb_thread, NULL);
981         if (!is_in_focus_cb_thread) {
982                 if ((ret = mm_sound_focus_socket_release(pid, client_fd, id, type, option, ext_info ? ext_info : "", true)))
983                         debug_error("failed to mm_sound_focus_socket_release(), ret[0x%x]", ret);
984         } else {
985                 GVariant *params = NULL, *result = NULL;
986
987                 if ((params = g_variant_new("(iiiis)", pid, id, type, option, ext_info ? ext_info : "")) == NULL) {
988                         debug_error("Construct Param for method call failed");
989                         return MM_ERROR_SOUND_INTERNAL;
990                 }
991
992                 if ((ret = mm_sound_dbus_method_call_to(AUDIO_PROVIDER_FOCUS_SERVER, AUDIO_METHOD_RELEASE_FOCUS, params, &result)) != MM_ERROR_NONE)
993                         debug_error("dbus release focus failed");
994
995                 if (result)
996                         g_variant_unref(result);
997         }
998
999         debug_fleave();
1000         return ret;
1001 }
1002
1003 int mm_sound_proxy_update_stream_focus_status(int focus_id, unsigned int status)
1004 {
1005         int ret = MM_ERROR_NONE;
1006         const char *reply = NULL;
1007         GVariant *params = NULL, *result = NULL;
1008
1009         debug_fenter();
1010
1011         if ((params = g_variant_new("(iu)", focus_id, status)) == NULL) {
1012                 debug_error("Construct Param for method call failed");
1013                 return MM_ERROR_SOUND_INTERNAL;
1014         }
1015
1016         if ((ret = mm_sound_dbus_method_call_to(AUDIO_PROVIDER_STREAM_MANAGER, AUDIO_METHOD_UPDATE_STREAM_FOCUS_STATUS, params, &result)) != MM_ERROR_NONE) {
1017                 debug_error("dbus set volume by type failed");
1018                 goto cleanup;
1019         }
1020
1021         /* stream-manager always returns a string as return value */
1022         if (result) {
1023                 g_variant_get(result, "(&s)", &reply);
1024                 debug_log("reply : %s", reply);
1025                 if (strcmp(reply, "STREAM_MANAGER_RETURN_OK"))
1026                         ret = MM_ERROR_SOUND_INTERNAL;
1027         } else {
1028                 debug_error("reply null");
1029                 ret = MM_ERROR_SOUND_INTERNAL;
1030         }
1031
1032 cleanup:
1033         if (result)
1034                 g_variant_unref(result);
1035
1036         debug_fleave();
1037         return ret;
1038 }
1039
1040 int mm_sound_proxy_deliver_focus(int src_index, int dst_index, mm_sound_focus_type_e focus_type)
1041 {
1042         int ret = MM_ERROR_NONE;
1043         int pid = g_focus_sound_handle[src_index].focus_pid;
1044         int src_client_fd = g_focus_sound_handle[src_index].client_fd;
1045         int src_server_fd = g_focus_sound_handle[src_index].handle;
1046         int dst_client_fd = g_focus_sound_handle[dst_index].client_fd;
1047         int dst_server_fd = g_focus_sound_handle[dst_index].handle;
1048
1049         debug_fenter();
1050
1051         ret = mm_sound_focus_socket_deliver(pid, src_client_fd, src_server_fd, dst_client_fd, dst_server_fd, focus_type);
1052         if (ret)
1053                 debug_error("failed to mm_sound_focus_socket_deliver(), ret[0x%x]", ret);
1054
1055         debug_fleave();
1056         return ret;
1057 }
1058
1059 int mm_sound_proxy_add_focus_watch_callback(int index, mm_sound_focus_type_e type)
1060 {
1061         int ret = MM_ERROR_NONE;
1062         int pid = g_focus_sound_handle[index].focus_pid;
1063         int id = 0;
1064         int client_fd = 0;
1065
1066         debug_fenter();
1067
1068         ret = mm_sound_focus_socket_add_watch_cb(pid, type, &client_fd, &id);
1069         if (ret) {
1070                 debug_error("failed to mm_sound_focus_socket_add_watch_cb(), ret[0x%x]", ret);
1071         } else {
1072                 g_focus_sound_handle[index].handle = id;
1073                 g_focus_sound_handle[index].client_fd = client_fd;
1074         }
1075
1076         debug_fleave();
1077
1078         return ret;
1079 }
1080
1081 int mm_sound_proxy_remove_focus_watch_callback(int index)
1082 {
1083         int ret = MM_ERROR_NONE;
1084         int pid = g_focus_sound_handle[index].focus_pid;
1085         int client_fd = g_focus_sound_handle[index].client_fd;
1086         int id = g_focus_sound_handle[index].handle;
1087
1088         debug_fenter();
1089
1090         ret = mm_sound_focus_socket_remove_watch_cb(pid, client_fd, id);
1091         if (ret)
1092                 debug_error("failed to mm_sound_focus_socket_remove_watch_cb(), ret[0x%x]", ret);
1093
1094         debug_fleave();
1095
1096         return ret;
1097 }
1098
1099 int mm_sound_proxy_initialize(void)
1100 {
1101         int ret = MM_ERROR_NONE;
1102
1103         debug_fenter();
1104         debug_fleave();
1105
1106         return ret;
1107 }
1108
1109 int mm_sound_proxy_finalize(void)
1110 {
1111         int ret = MM_ERROR_NONE;
1112
1113         debug_fenter();
1114         debug_fleave();
1115
1116         return ret;
1117 }