6b52c1bfbe4b49acd552961ac932df49f8d62491
[platform/core/multimedia/pulseaudio-modules-tizen.git] / src / device-manager-dbus.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2018 Sangchul Lee <sc11.lee@samsung.com>
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #ifdef HAVE_DBUS
27
28 #include <string.h>
29 #include <stdbool.h>
30 #include <pulse/proplist.h>
31 #include <pulse/util.h>
32 #include <pulsecore/log.h>
33
34 #include "stream-manager.h"
35 #include "device-manager.h"
36 #include "device-manager-priv.h"
37 #include "device-manager-db-priv.h"
38
39 /* Dbus defines */
40 #define DBUS_INTERFACE_DEVICE_MANAGER       "org.pulseaudio.DeviceManager"
41 #define DBUS_OBJECT_DEVICE_MANAGER          "/org/pulseaudio/DeviceManager"
42
43 #define DBUS_INTERFACE_DEVICED_SYSNOTI      "org.tizen.system.deviced.SysNoti"
44 #define DBUS_OBJECT_DEVICED_SYSNOTI         "/Org/Tizen/System/DeviceD/SysNoti"
45
46 #define DBUS_INTERFACE_SOUND_SERVER         "org.tizen.SoundServer1"
47 #define DBUS_OBJECT_SOUND_SERVER            "/org/tizen/SoundServer1"
48
49 #define DBUS_SERVICE_BLUEZ                  "org.bluez"
50 #define DBUS_INTERFACE_BLUEZ_HEADSET        "org.bluez.Headset"
51 #define DBUS_INTERFACE_BLUEZ_DEVICE         "org.bluez.Device1"
52 #define DBUS_OBJECT_BLUEZ                   "/org/bluez"
53
54 #define DBUS_INTERFACE_MIRRORING_SERVER     "org.tizen.scmirroring.server"
55 #define DBUS_OBJECT_MIRRORING_SERVER        "/org/tizen/scmirroring/server"
56
57 #define DBUS_SERVICE_HFP_AGENT "org.bluez.ag_agent"
58 #define DBUS_OBJECT_HFP_AGENT "/org/bluez/hfp_agent"
59 #define DBUS_INTERFACE_HFP_AGENT "Org.Hfp.App.Interface"
60
61 #define DEVICE_MANAGER_INTROSPECT_XML                                                       \
62     DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                                               \
63     "<node>\n"                                                                              \
64     " <interface name=\"" DBUS_INTERFACE_DEVICE_MANAGER "\">\n"                             \
65     "  <method name=\"GetConnectedDeviceList\">\n"                                          \
66     "   <arg name=\"mask_flags\" direction=\"in\" type=\"i\"/>\n"                           \
67     "   <arg name=\"ConnectedDeviceList\" direction=\"out\" type=\"a(isiisiibiii)\"/>\n"    \
68     "  </method>\n"                                                                         \
69     "  <method name=\"GetDeviceById\">\n"                                                   \
70     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
71     "   <arg name=\"device\" direction=\"out\" type=\"(isiisii)\"/>\n"                      \
72     "  </method>\n"                                                                         \
73     "  <method name=\"IsDeviceRunningById\">\n"                                             \
74     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
75     "   <arg name=\"is_running\" direction=\"out\" type=\"b\"/>\n"                          \
76     "  </method>\n"                                                                         \
77     "  <method name=\"IsStreamOnDevice\">\n"                                                \
78     "   <arg name=\"stream_id\" direction=\"in\" type=\"i\"/>\n"                            \
79     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
80     "   <arg name=\"is_on\" direction=\"out\" type=\"b\"/>\n"                               \
81     "  </method>\n"                                                                         \
82     "  <method name='GetBTA2DPStatus'>"                                                     \
83     "    <arg type='b' name='is_bt_on' direction='out'/>"                                   \
84     "    <arg type='s' name='bt_name' direction='out'/>"                                    \
85     "  </method>"                                                                           \
86     "  <method name=\"LoadSink\">\n"                                                        \
87     "   <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n"                          \
88     "   <arg name=\"role\" direction=\"in\" type=\"s\"/>\n"                                 \
89     "  </method>\n"                                                                         \
90     "  <method name=\"UnloadSink\">\n"                                                      \
91     "   <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n"                          \
92     "   <arg name=\"role\" direction=\"in\" type=\"s\"/>\n"                                 \
93     "  </method>\n"                                                                         \
94     "  <method name=\"GetSupportedSampleFormats\">\n"                                       \
95     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
96     "   <arg name=\"sample_formats\" direction=\"out\" type=\"a(s)\"/>\n"                   \
97     "  </method>\n"                                                                         \
98     "  <method name=\"SetSampleFormat\">\n"                                                 \
99     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
100     "   <arg name=\"sample_format\" direction=\"in\" type=\"s\"/>\n"                        \
101     "  </method>\n"                                                                         \
102     "  <method name=\"GetSampleFormat\">\n"                                                 \
103     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
104     "   <arg name=\"sample_format\" direction=\"out\" type=\"s\"/>\n"                       \
105     "  </method>\n"                                                                         \
106     "  <method name=\"GetSupportedSampleRates\">\n"                                         \
107     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
108     "   <arg name=\"sample_rates\" direction=\"out\" type=\"a(u)\"/>\n"                     \
109     "  </method>\n"                                                                         \
110     "  <method name=\"SetSampleRate\">\n"                                                   \
111     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
112     "   <arg name=\"sample_rate\" direction=\"in\" type=\"u\"/>\n"                          \
113     "  </method>\n"                                                                         \
114     "  <method name=\"GetSampleRate\">\n"                                                   \
115     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
116     "   <arg name=\"sample_rate\" direction=\"out\" type=\"u\"/>\n"                         \
117     "  </method>\n"                                                                         \
118     "  <method name=\"SetSpecificStreamOnly\">\n"                                           \
119     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
120     "   <arg name=\"stream_role\" direction=\"in\" type=\"s\"/>\n"                          \
121     "  </method>\n"                                                                         \
122     "  <method name=\"GetSpecifiedStream\">\n"                                              \
123     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
124     "   <arg name=\"stream_role\" direction=\"out\" type=\"s\"/>\n"                         \
125     "  </method>\n"                                                                         \
126     "  <method name=\"SetAvoidResampling\">\n"                                              \
127     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
128     "   <arg name=\"avoid_resampling\" direction=\"in\" type=\"b\"/>\n"                     \
129     "  </method>\n"                                                                         \
130     "  <method name=\"GetAvoidResampling\">\n"                                              \
131     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
132     "   <arg name=\"avoid_resampling\" direction=\"out\" type=\"b\"/>\n"                    \
133     "  </method>\n"                                                                         \
134     "  <method name=\"DumpDeviceList\">\n"                                                  \
135     "  </method>\n"                                                                         \
136     "  <method name=\"TestStatusChange\">\n"                                                \
137     "   <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n"                          \
138     "   <arg name=\"status\" direction=\"in\" type=\"i\"/>\n"                               \
139     "  </method>\n"                                                                         \
140     "  <method name=\"SetAcmMode\">\n"                                                      \
141     "   <arg name=\"mode\" direction=\"in\" type=\"u\"/>\n"                                 \
142     "  </method>\n"                                                                         \
143     "  <property name=\"PropertyTest1\" type=\"i\" access=\"readwrite\"/>\n"                \
144     "  <property name=\"PropertyTest2\" type=\"s\" access=\"read\"/>\n"                     \
145     "  <signal name=\"DeviceConnected\">\n"                                                 \
146     "   <arg name=\"arg1\" type=\"i\"/>\n"                                                  \
147     "  </signal>\n"                                                                         \
148     "  <signal name=\"DeviceInfoChanged\">\n"                                               \
149     "   <arg name=\"arg1\" type=\"s\"/>\n"                                                  \
150     "  </signal>\n"                                                                         \
151     " </interface>\n"                                                                       \
152     " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n"                             \
153     "  <method name=\"Introspect\">\n"                                                      \
154     "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"                                \
155     "  </method>\n"                                                                         \
156     " </interface>\n"                                                                       \
157     " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n"                                 \
158     "  <method name=\"Get\">\n"                                                             \
159     "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"                       \
160     "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"                        \
161     "   <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"                               \
162     "  </method>\n"                                                                         \
163     "  <method name=\"Set\">\n"                                                             \
164     "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"                       \
165     "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"                        \
166     "   <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"                                \
167     "  </method>\n"                                                                         \
168     "  <method name=\"GetAll\">\n"                                                          \
169     "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"                       \
170     "   <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n"                           \
171     "  </method>\n"                                                                         \
172     " </interface>\n"                                                                       \
173     "</node>\n"
174
175 #define FILTER_DEVICED_SYSNOTI                             \
176     "type='signal',"                                       \
177     " interface='" DBUS_INTERFACE_DEVICED_SYSNOTI "'"
178
179 #define FILTER_SOUND_SERVER                                \
180     "type='signal',"                                       \
181     " interface='" DBUS_INTERFACE_SOUND_SERVER "'"
182
183 #define FILTER_MIRRORING                                   \
184     "type='signal',"                                       \
185     " interface='" DBUS_INTERFACE_MIRRORING_SERVER "', member='miracast_wfd_source_status_changed'"
186
187 #define FILTER_BLUEZ                                       \
188     "type='signal',"                                       \
189     " interface='" DBUS_INTERFACE_BLUEZ_HEADSET "', member='PropertyChanged'"
190
191 #define FILL_SAMPLE_SPEC_WITH_SELECTED(x_spec, x_sink) \
192 do { \
193     x_spec.format = x_sink->selected_sample_format; \
194     x_spec.rate = x_sink->selected_sample_rate; \
195     x_spec.channels = 2; \
196 } while(0)
197
198 /*** Defines for method handle ***/
199 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
200 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata);
201 static void handle_is_device_running_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata);
202 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
203 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
204 static void handle_get_supported_sample_formats(DBusConnection *conn, DBusMessage *msg, void *userdata);
205 static void handle_set_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
206 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
207 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata);
208 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
209 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
210 static void handle_set_specific_stream_only(DBusConnection *conn, DBusMessage *msg, void *userdata);
211 static void handle_get_specified_stream(DBusConnection *conn, DBusMessage *msg, void *userdata);
212 static void handle_set_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata);
213 static void handle_get_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata);
214 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
215 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
216 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata);
217 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata);
218 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
219 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata);
220 static void handle_set_acm_mode(DBusConnection *conn, DBusMessage *msg, void *userdata);
221
222 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
223 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name);
224 #endif
225
226 enum method_handler_index {
227     METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST,
228     METHOD_HANDLER_GET_DEVICE_BY_ID,
229     METHOD_HANDLER_IS_DEVICE_RUNNING_BY_ID,
230     METHOD_HANDLER_IS_STREAM_ON_DEVICE,
231     METHOD_HANDLER_GET_BT_A2DP_STATUS,
232     METHOD_HANDLER_LOAD_SINK,
233     METHOD_HANDLER_UNLOAD_SINK,
234     METHOD_HANDLER_UNLOAD_SINK_WITH_DEVICE_STRING,
235     METHOD_HANDLER_GET_DEVICE_STRING,
236     METHOD_HANDLER_GET_SUPPORTED_SAMPLE_FORMATS,
237     METHOD_HANDLER_SET_SAMPLE_FORMAT,
238     METHOD_HANDLER_GET_SAMPLE_FORMAT,
239     METHOD_HANDLER_GET_SUPPORTED_SAMPLE_RATES,
240     METHOD_HANDLER_SET_SAMPLE_RATE,
241     METHOD_HANDLER_GET_SAMPLE_RATE,
242     METHOD_HANDLER_SET_SPECIFIC_STREAM_ONLY,
243     METHOD_HANDLER_GET_SPECIFIED_STREAM,
244     METHOD_HANDLER_SET_AVOID_RESAMPLING,
245     METHOD_HANDLER_GET_AVOID_RESAMPLING,
246     METHOD_HANDLER_DUMP_DEVICE_LIST,
247     METHOD_HANDLER_STATUS_TEST,
248     METHOD_HANDLER_SET_ACM_MODE,
249     METHOD_HANDLER_MAX
250 };
251
252 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
253     [METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST] = {
254         .method_name = "GetConnectedDeviceList",
255         .receive_cb = handle_get_connected_device_list },
256     [METHOD_HANDLER_GET_DEVICE_BY_ID] = {
257         .method_name = "GetDeviceById",
258         .receive_cb = handle_get_device_by_id },
259     [METHOD_HANDLER_IS_DEVICE_RUNNING_BY_ID] = {
260         .method_name = "IsDeviceRunningById",
261         .receive_cb = handle_is_device_running_by_id },
262     [METHOD_HANDLER_IS_STREAM_ON_DEVICE] = {
263         .method_name = "IsStreamOnDevice",
264         .receive_cb = handle_is_stream_on_device },
265     [METHOD_HANDLER_GET_BT_A2DP_STATUS] = {
266         .method_name = "GetBTA2DPStatus",
267         .receive_cb = handle_get_bt_a2dp_status },
268     [METHOD_HANDLER_LOAD_SINK] = {
269         .method_name = "LoadSink",
270         .receive_cb = handle_load_sink },
271     [METHOD_HANDLER_UNLOAD_SINK] = {
272         .method_name = "UnloadSink",
273         .receive_cb = handle_unload_sink },
274     [METHOD_HANDLER_UNLOAD_SINK_WITH_DEVICE_STRING] = {
275         .method_name = "UnloadSinkWithDeviceString",
276         .receive_cb = handle_unload_sink_with_device_string },
277     [METHOD_HANDLER_GET_DEVICE_STRING] = {
278         .method_name = "GetDeviceString",
279         .receive_cb = handle_get_device_string },
280     [METHOD_HANDLER_GET_SUPPORTED_SAMPLE_FORMATS] = {
281         .method_name = "GetSupportedSampleFormats",
282         .receive_cb = handle_get_supported_sample_formats },
283     [METHOD_HANDLER_SET_SAMPLE_FORMAT] = {
284         .method_name = "SetSampleFormat",
285         .receive_cb = handle_set_sample_format },
286     [METHOD_HANDLER_GET_SAMPLE_FORMAT] = {
287         .method_name = "GetSampleFormat",
288         .receive_cb = handle_get_sample_format },
289     [METHOD_HANDLER_GET_SUPPORTED_SAMPLE_RATES] = {
290         .method_name = "GetSupportedSampleRates",
291         .receive_cb = handle_get_supported_sample_rates },
292     [METHOD_HANDLER_SET_SAMPLE_RATE] = {
293         .method_name = "SetSampleRate",
294         .receive_cb = handle_set_sample_rate },
295     [METHOD_HANDLER_GET_SAMPLE_RATE] = {
296         .method_name = "GetSampleRate",
297         .receive_cb = handle_get_sample_rate },
298     [METHOD_HANDLER_SET_SPECIFIC_STREAM_ONLY] = {
299         .method_name = "SetSpecificStreamOnly",
300         .receive_cb = handle_set_specific_stream_only },
301     [METHOD_HANDLER_GET_SPECIFIED_STREAM] = {
302         .method_name = "GetSpecifiedStream",
303         .receive_cb = handle_get_specified_stream },
304     [METHOD_HANDLER_SET_AVOID_RESAMPLING] = {
305         .method_name = "SetAvoidResampling",
306         .receive_cb = handle_set_avoid_resampling },
307     [METHOD_HANDLER_GET_AVOID_RESAMPLING] = {
308         .method_name = "GetAvoidResampling",
309         .receive_cb = handle_get_avoid_resampling },
310     [METHOD_HANDLER_DUMP_DEVICE_LIST] = {
311         .method_name = "DumpDeviceList",
312         .receive_cb = handle_dump_device_list },
313     [METHOD_HANDLER_STATUS_TEST] = {
314         .method_name = "TestStatusChange",
315         .receive_cb = handle_test_device_status_change },
316     [METHOD_HANDLER_SET_ACM_MODE] = {
317         .method_name = "SetAcmMode",
318         .receive_cb = handle_set_acm_mode },
319 };
320
321 static void save_preference(pa_device_manager *dm, pa_sink *sink) {
322     const char *key;
323     prefer_entry e;
324
325     pa_assert(dm);
326     pa_assert(sink);
327
328     e.avoid_resampling = sink->avoid_resampling;
329     e.format = sink->selected_sample_format;
330     e.rate = sink->selected_sample_rate;
331     if ((key = build_key_from_proplist(sink->proplist)))
332         write_prefer_entry(dm, key, &e);
333 }
334
335 /*
336     Handle device disconnection detected through dbus.
337     First, update device-status hashmap.
338     And if there is device which has the device_type, remove it.
339 */
340 static int handle_device_disconnected(pa_device_manager *dm, const char *type, const char *system_id) {
341     pa_tz_device *device;
342
343     pa_assert(dm);
344     pa_assert(dm->device_status);
345
346     pa_log_info("Device type(%s) system_id(%s) disconnected",
347             type, pa_strempty(system_id));
348
349     device = device_list_get_device(dm, type, NULL, system_id);
350     if (!device) {
351         pa_log_error("Disconnection detected but no device for that");
352         return -1;
353     }
354
355     pa_tz_device_free(device);
356
357     return 0;
358 }
359
360 /*
361    look detected status which is external value, make conversion to internal consistent value, and handle it
362    device_type, which type of device is detected
363    system_id : system_id among same device types for support multi-device
364 */
365 static int handle_device_status_changed(pa_device_manager *dm, const char *type,
366         const char *name, const char *system_id, device_detected_type_t detected) {
367     pa_assert(dm);
368
369     pa_log_info("Device Status Changed, type(%s) system_id(%s), detected_type(%d)",
370             type, pa_strempty(system_id), detected);
371
372     if (!device_type_is_valid(type)) {
373         pa_log_error("Invalid device type %s", type);
374         return -1;
375     } else if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
376         device_set_detected(dm, type, name, system_id, detected);
377         if (detected == DEVICE_DISCONNECTED)
378             handle_device_disconnected(dm, type, system_id);
379         else
380             handle_device_connected(dm, type, name, system_id, detected, NULL);
381     } else if (device_type_is_need_detect(type)) {
382         device_set_detected(dm, type, name, system_id, detected);
383         if (detected == DEVICE_DISCONNECTED)
384             handle_device_disconnected(dm, type, system_id);
385         else
386             handle_device_connected(dm, type, name, system_id, detected, NULL);
387     } else {
388         pa_log_debug("No need to detect type %s", type);
389     }
390
391     return 0;
392 }
393
394 static int _translate_external_value(const char *type, int value, device_detected_type_t *detected) {
395
396     if (!type || !detected) {
397         pa_log_error("Invalid Parameter for translate");
398         return -1;
399     }
400
401     if (device_type_is_equal(DEVICE_TYPE_AUDIO_JACK, type)) {
402         if (value == EARJACK_DISCONNECTED)
403             *detected = DEVICE_DISCONNECTED;
404         else if (value == EARJACK_TYPE_SPK_ONLY)
405             *detected = DEVICE_CONNECTED_AUDIO_JACK_3P;
406         else if (value == EARJACK_TYPE_SPK_WITH_MIC)
407             *detected = DEVICE_CONNECTED_AUDIO_JACK_4P;
408         else
409             return -1;
410     } else if (device_type_is_equal(DEVICE_TYPE_FORWARDING, type)) {
411         if (value == FORWARDING_DISCONNECTED)
412             *detected = DEVICE_DISCONNECTED;
413         else if (value == FORWARDING_CONNECTED)
414             *detected = DEVICE_CONNECTED;
415         else
416             return -1;
417     } else if (device_type_is_equal(DEVICE_TYPE_BT_SCO, type)) {
418         if (value == BT_SCO_DISCONNECTED)
419             *detected = DEVICE_DISCONNECTED;
420         else if (value == BT_SCO_CONNECTED)
421             *detected = DEVICE_CONNECTED_SCO;
422         else
423             return -1;
424     }
425
426     return 0;
427 }
428
429 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
430 static int handle_bluez_headset_property_changed(DBusConnection *c, DBusMessage *s, pa_device_manager *dm) {
431     DBusMessageIter msg_iter, variant_iter;
432     char *property_name;
433     dbus_bool_t value;
434     char *name = NULL;
435
436     pa_assert(c);
437     pa_assert(s);
438     pa_assert(dm);
439
440     pa_log_debug("Got %s PropertyChanged signal", DBUS_INTERFACE_BLUEZ_HEADSET);
441     dbus_message_iter_init(s, &msg_iter);
442     if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_STRING) {
443         pa_log_error("Property name not string");
444         return -1;
445     }
446     dbus_message_iter_get_basic(&msg_iter, &property_name);
447     pa_log_info("Changed Property name : %s", property_name);
448
449     if (!dbus_message_iter_next(&msg_iter)) {
450         pa_log_debug("Property value missing");
451         return -1;
452     }
453
454     if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_VARIANT) {
455         pa_log_debug("Property value not a variant.");
456         return -1;
457     }
458
459     dbus_message_iter_recurse(&msg_iter, &variant_iter);
460
461     if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_BOOLEAN)
462         return 0; /* Returning 0 here to keep the same behavior comparing with the previous codes */
463
464     dbus_message_iter_get_basic(&variant_iter, &value);
465     if (pa_safe_streq(property_name, "Connected")) {
466         device_detected_type_t detected;
467         int status = 0;
468         pa_log_info("HFP Connection : %d", value);
469         if (value) {
470             method_call_bt_get_name(c, dbus_message_get_path(s), &name);
471             status = BT_SCO_CONNECTED;
472         } else {
473             status = BT_SCO_DISCONNECTED;
474         }
475         if (_translate_external_value(DEVICE_TYPE_BT_SCO, status, &detected) < 0) {
476             pa_log_warn("failed to translate bt-sco detected value");
477             pa_xfree(name);
478             return -1;
479         }
480         handle_device_status_changed(dm, DEVICE_TYPE_BT_SCO, name, dbus_message_get_path(s),  detected);
481         pa_xfree(name);
482     } else if (pa_safe_streq(property_name, "Playing")) {
483         pa_tz_device *device;
484         pa_log_info("SCO Playing : %d", value);
485         if ((device = device_list_get_device(dm, DEVICE_TYPE_BT_SCO, NULL, NULL)) != NULL) {
486             device->sco_opened = value;
487             if (value) {
488                 /* update BT band/nrec information */
489                 bool is_wide_band = false;
490                 bool nrec = false;
491                 pa_tz_device_sco_get_property(device, &is_wide_band, &nrec);
492                 pa_log_info("got new wideband:%d, nrec:%d", is_wide_band, nrec);
493
494                 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-wideband", is_wide_band);
495                 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-nrec", nrec);
496             }
497         }
498         UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-sco-ready", value);
499     }
500
501     return 0;
502 }
503 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
504
505 static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
506     DBusError error;
507     int status = 0;
508     pa_device_manager *dm = (pa_device_manager *)userdata;
509     device_detected_type_t detected;
510
511     pa_assert(dm);
512
513     if (dbus_message_get_type(s) != DBUS_MESSAGE_TYPE_SIGNAL)
514         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
515
516     pa_log_info("Device detect handler : Path(%s) Intf(%s) Member(%s) Signature(%s)",
517             dbus_message_get_path(s), dbus_message_get_interface(s), dbus_message_get_member(s), dbus_message_get_signature(s));
518
519     dbus_error_init(&error);
520
521     if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedEarjack")) {
522         if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID))
523             goto fail;
524
525         if (_translate_external_value(DEVICE_TYPE_AUDIO_JACK, status, &detected) < 0) {
526             pa_log_warn("failed to translate audio-jack detected value");
527             goto fail;
528         }
529         handle_device_status_changed(dm, DEVICE_TYPE_AUDIO_JACK, NULL, NULL, detected);
530
531     } else if (dbus_message_is_signal(s, DBUS_INTERFACE_MIRRORING_SERVER, "miracast_wfd_source_status_changed")) {
532         if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID))
533             goto fail;
534
535         if (_translate_external_value(DEVICE_TYPE_FORWARDING, status, &detected) < 0) {
536             pa_log_warn("failed to translate forwarding detected value");
537             goto fail;
538         }
539         handle_device_status_changed(dm, DEVICE_TYPE_FORWARDING, NULL, NULL, detected);
540 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
541     } else if (dbus_message_is_signal(s, DBUS_INTERFACE_BLUEZ_HEADSET, "PropertyChanged")) {
542         if (handle_bluez_headset_property_changed(c, s, dm) < 0)
543             goto fail;
544 #endif
545     } else {
546         pa_log_debug("Unknown message, not handle it");
547         dbus_error_free(&error);
548         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
549     }
550
551     pa_log_debug("Dbus Message handled");
552
553     dbus_error_free(&error);
554     return DBUS_HANDLER_RESULT_HANDLED;
555
556 fail:
557     pa_log_error("Fail to handle dbus signal");
558     dbus_error_free(&error);
559     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
560 }
561
562 static bool device_is_match_direction(pa_tz_device *device, int direction_mask) {
563     dm_device_direction_t direction;
564
565     if (direction_mask == DEVICE_IO_DIRECTION_FLAGS || direction_mask == 0)
566         return true;
567
568     direction = pa_tz_device_get_direction(device);
569
570     if ((direction_mask & DEVICE_IO_DIRECTION_IN_FLAG) && (direction & DM_DEVICE_DIRECTION_IN))
571         return true;
572     if ((direction_mask & DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & DM_DEVICE_DIRECTION_OUT))
573         return true;
574     if ((direction_mask & DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction == DM_DEVICE_DIRECTION_BOTH))
575         return true;
576
577     return false;
578 }
579
580 static bool device_is_match_state(pa_tz_device *device, int state_mask) {
581     dm_device_state_t state;
582
583     if (state_mask == DEVICE_STATE_FLAGS || state_mask == 0)
584         return true;
585
586     state = pa_tz_device_get_state(device);
587
588     if ((state_mask & DEVICE_STATE_DEACTIVATED_FLAG) && (state == DM_DEVICE_STATE_DEACTIVATED))
589         return true;
590     if ((state_mask & DEVICE_STATE_ACTIVATED_FLAG) && (state == DM_DEVICE_STATE_ACTIVATED))
591         return true;
592
593     return false;
594 }
595
596 static bool device_is_match_type(pa_tz_device *device, int type_mask) {
597     char *type;
598     bool is_builtin;
599
600     if (type_mask == DEVICE_TYPE_FLAGS || type_mask == 0)
601         return true;
602
603     type = pa_tz_device_get_type(device);
604     is_builtin = device_type_is_builtin(type);
605
606     if ((type_mask & DEVICE_TYPE_INTERNAL_FLAG) && is_builtin)
607         return true;
608     if ((type_mask & DEVICE_TYPE_EXTERNAL_FLAG) && !is_builtin)
609         return true;
610
611     return false;
612 }
613
614 static bool device_is_match_with_mask(pa_tz_device *device, int mask) {
615     pa_assert(device);
616
617     if (mask == DEVICE_ALL_FLAG)
618         return true;
619
620     return (device_is_match_direction(device, mask & DEVICE_IO_DIRECTION_FLAGS) &&
621             device_is_match_state(device, mask & DEVICE_STATE_FLAGS) &&
622             device_is_match_type(device, mask & DEVICE_TYPE_FLAGS));
623 }
624
625 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
626 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name) {
627     const char *intf = DBUS_INTERFACE_BLUEZ_DEVICE, *prop = "Alias";
628     DBusMessage *msg, *reply;
629     DBusMessageIter reply_iter, variant_iter;
630     DBusError err;
631     const char *_name;
632
633     pa_assert(conn);
634     pa_assert(device_path);
635     pa_assert(name);
636
637     if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_BLUEZ, device_path, "org.freedesktop.DBus.Properties", "Get"))) {
638         pa_log_error("dbus method call failed");
639         return -1;
640     }
641
642     pa_assert_se(dbus_message_append_args(msg, DBUS_TYPE_STRING, &intf,
643                                                DBUS_TYPE_STRING, &prop,
644                                                DBUS_TYPE_INVALID));
645
646     dbus_error_init(&err);
647
648     reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_TIMEOUT_USE_DEFAULT, &err);
649     dbus_message_unref(msg);
650     if (!reply) {
651         pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_BLUEZ_DEVICE, "Get", err.message);
652         dbus_error_free(&err);
653         return -1;
654     }
655
656     dbus_message_iter_init(reply, &reply_iter);
657
658     if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_VARIANT) {
659         pa_log_error("Cannot get reply argument");
660         return -1;
661     }
662
663     dbus_message_iter_recurse(&reply_iter, &variant_iter);
664
665     if (dbus_message_iter_get_arg_type(&variant_iter) == DBUS_TYPE_STRING) {
666         dbus_message_iter_get_basic(&variant_iter, &_name);
667         *name = pa_xstrdup(_name);
668     }
669
670     dbus_message_unref(reply);
671     return 0;
672 }
673 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
674
675 static void array_iter_append(DBusMessageIter *array_iter, pa_idxset *device_list, int mask) {
676     uint32_t device_idx;
677     dm_device_state_t state;
678     dbus_int32_t device_id, direction;
679     char *type, *name;
680     dbus_int32_t vendor_id, product_id;
681     dbus_bool_t is_running;
682     pa_tz_device *device;
683     DBusMessageIter device_iter;
684     const pa_sample_spec *spec = NULL;
685     dbus_int32_t format, samplerate, channels;
686
687     pa_assert(array_iter);
688
689     if (!device_list)
690         return;
691
692     PA_IDXSET_FOREACH(device, device_list, device_idx) {
693         device_id = (dbus_int32_t)pa_tz_device_get_id(device);
694         state = pa_tz_device_get_state(device);
695         direction = pa_tz_device_get_direction(device);
696         type = pa_tz_device_get_type(device);
697         name = pa_tz_device_get_name(device);
698         vendor_id = (dbus_int32_t)pa_tz_device_get_vendor_id(device);
699         product_id = (dbus_int32_t)pa_tz_device_get_product_id(device);
700         product_id = (dbus_int32_t)pa_tz_device_get_product_id(device);
701         is_running = (dbus_bool_t)pa_tz_device_is_running(device);
702
703         spec = pa_tz_device_get_sample_spec(device);
704         format = (dbus_int32_t)spec->format;
705         samplerate = (dbus_int32_t)spec->rate;
706         channels = (dbus_int32_t)spec->channels;
707
708         if (device_is_match_with_mask(device, mask)) {
709             simple_device_dump(PA_LOG_INFO, "[MATCH]", device_id, type, name, direction, state);
710             pa_assert_se(dbus_message_iter_open_container(array_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
711             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
712             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
713             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
714             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
715             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
716             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
717             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
718             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
719             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &format);
720             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &samplerate);
721             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &channels);
722
723             pa_assert_se(dbus_message_iter_close_container(array_iter, &device_iter));
724         } else {
725             simple_device_dump(PA_LOG_INFO, "[UNMATCH]", device_id, type, name, direction, state);
726         }
727     }
728 }
729
730 #ifdef __TIZEN_TV_EXTERNAL_BT_SCO__
731 static int include_device_filter_func(const void *d, const void *include_device_type) {
732     pa_tz_device *device = (pa_tz_device *)d;
733
734     pa_assert(device);
735     pa_assert(include_device_type);
736
737     return (int)pa_safe_streq(pa_tz_device_get_type(device), (const char *)include_device_type);
738 }
739
740 static int exclude_device_filter_func(const void *d, const void *exclude_device_type) {
741     pa_tz_device *device = (pa_tz_device *)d;
742
743     pa_assert(device);
744     pa_assert(exclude_device_type);
745
746     return (int)!pa_safe_streq(pa_tz_device_get_type(device), (const char *)exclude_device_type);
747 }
748 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
749
750 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
751     pa_device_manager *dm = (pa_device_manager *)userdata;
752     DBusMessage *reply = NULL;
753     DBusMessageIter msg_iter, array_iter;
754     int mask;
755 #ifdef __TIZEN_TV_EXTERNAL_BT_SCO__
756     pa_idxset *idxset1, *idxset2;
757 #endif
758
759     pa_assert(conn);
760     pa_assert(msg);
761     pa_assert(dm);
762
763     pa_assert_se((reply = dbus_message_new_method_return(msg)));
764
765     pa_assert_se(dbus_message_get_args(msg, NULL,
766                                        DBUS_TYPE_INT32, &mask,
767                                        DBUS_TYPE_INVALID));
768
769     pa_log_info("Get connected device list (mask : %d)", mask);
770
771     dbus_message_iter_init_append(reply, &msg_iter);
772     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiisiibiii)", &array_iter));
773
774 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
775     array_iter_append(&array_iter, dm->device_list, mask);
776 #else
777     /* divide into two groups and merge them because dbus message doesn't support sorting or prepend */
778     idxset1 = pa_idxset_filtered_copy(dm->device_list, NULL, include_device_filter_func, DEVICE_TYPE_BT_SCO);
779     idxset2 = pa_idxset_filtered_copy(dm->device_list, NULL, exclude_device_filter_func, DEVICE_TYPE_BT_SCO);
780
781     array_iter_append(&array_iter, idxset1, mask);
782     array_iter_append(&array_iter, idxset2, mask);
783
784     pa_idxset_free(idxset1, NULL);
785     pa_idxset_free(idxset2, NULL);
786 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
787
788     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
789
790     pa_assert_se(dbus_connection_send(conn, reply, NULL));
791     dbus_message_unref(reply);
792 }
793
794 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
795     pa_device_manager *dm = (pa_device_manager *)userdata;
796     DBusMessage *reply;
797     DBusMessageIter msg_iter;
798     pa_tz_device *device;
799     dbus_int32_t device_id;
800     dbus_int32_t id, direction, state;
801     dbus_int32_t vendor_id, product_id;
802     char *type, *name;
803
804     pa_assert(conn);
805     pa_assert(msg);
806     pa_assert(dm);
807
808     pa_assert_se(dbus_message_get_args(msg, NULL,
809                                        DBUS_TYPE_INT32, &device_id,
810                                        DBUS_TYPE_INVALID));
811
812     pa_log_info("Get device by id(%d)", device_id);
813
814     if ((device = device_list_get_device_by_id(dm, device_id))) {
815         pa_assert_se((reply = dbus_message_new_method_return(msg)));
816         dbus_message_iter_init_append(reply, &msg_iter);
817
818         id = (dbus_int32_t)pa_tz_device_get_id(device);
819         state = pa_tz_device_get_state(device);
820         direction = pa_tz_device_get_direction(device);
821         type = pa_tz_device_get_type(device);
822         name = pa_tz_device_get_name(device);
823         vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
824         product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
825
826         simple_device_dump(PA_LOG_INFO, "[GET_BY_ID]", device_id, type, name, direction, state);
827
828         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &id);
829         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &type);
830         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &direction);
831         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &state);
832         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
833         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &vendor_id);
834         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &product_id);
835
836         pa_assert_se(dbus_connection_send(conn, reply, NULL));
837         dbus_message_unref(reply);
838     } else {
839         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
840     }
841 }
842
843 static void handle_is_device_running_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
844     pa_device_manager *dm = (pa_device_manager *)userdata;
845     pa_tz_device *device;
846     dbus_int32_t device_id;
847     dbus_bool_t is_running;
848
849     pa_assert(conn);
850     pa_assert(msg);
851     pa_assert(dm);
852
853     pa_assert_se(dbus_message_get_args(msg, NULL,
854                                        DBUS_TYPE_INT32, &device_id,
855                                        DBUS_TYPE_INVALID));
856
857     pa_log_info("Is device running by id(%d)", device_id);
858
859     if ((device = device_list_get_device_by_id(dm, device_id))) {
860         is_running = pa_tz_device_is_running(device);
861
862         pa_log_info("device(id:%d) is %s", device_id, is_running ? "Running" : "Not Running");
863
864         pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_running);
865     } else {
866         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
867     }
868 }
869
870 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
871     pa_device_manager *dm = (pa_device_manager *)userdata;
872     pa_tz_device *device;
873     dbus_bool_t is_on = FALSE;
874     dbus_int32_t stream_id, device_id;
875     pa_intset *stream_id_set;
876     int32_t stream_id_val;
877     int ret;
878     dm_device_state_t state;
879
880     pa_assert(conn);
881     pa_assert(msg);
882     pa_assert(dm);
883
884     pa_log_info("Is stream on device");
885
886     pa_assert_se(dbus_message_get_args(msg, NULL,
887                                        DBUS_TYPE_INT32, &stream_id,
888                                        DBUS_TYPE_INT32, &device_id,
889                                        DBUS_TYPE_INVALID));
890
891     if ((device = device_list_get_device_by_id(dm, device_id))) {
892         state = pa_tz_device_get_state(device);
893         if (state == DM_DEVICE_STATE_ACTIVATED) {
894             stream_id_set = pa_tz_device_get_stream_list(device);
895             PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
896                 if (stream_id_val == stream_id) {
897                     is_on = TRUE;
898                     pa_log_info("stream(%d) is on device(%d)", stream_id, device_id);
899                     break;
900                 }
901             }
902             pa_intset_free(stream_id_set);
903         } else {
904             pa_log_info("device(%d) is not activated, regard as no stream on it", device_id);
905             is_on = FALSE;
906         }
907         pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_on);
908     } else {
909         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.Internal");
910     }
911 }
912
913 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
914     pa_device_manager *dm = (pa_device_manager *)userdata;
915     DBusMessage *reply = NULL;
916     pa_tz_device *device;
917     dbus_bool_t is_bt_on = FALSE;
918     const char *bt_name = "none";
919
920     pa_assert(conn);
921     pa_assert(msg);
922     pa_assert(dm);
923
924     pa_log_info("Get BT A2DP list");
925
926     /* FIXME : Give system_id for multi device */
927     if ((device = device_list_get_device(dm, DEVICE_TYPE_BT_A2DP, NULL, NULL)) != NULL) {
928         is_bt_on = TRUE;
929         bt_name = pa_tz_device_get_name(device);
930     }
931
932     pa_assert_se((reply = dbus_message_new_method_return(msg)));
933     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_bt_on,
934                                                  DBUS_TYPE_STRING, &bt_name,
935                                                  DBUS_TYPE_INVALID));
936     pa_assert_se(dbus_connection_send(conn, reply, NULL));
937     dbus_message_unref(reply);
938 }
939
940 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
941     pa_device_manager *dm = (pa_device_manager *)userdata;
942     char *type, *role;
943     pa_sink *sink;
944
945     pa_assert(conn);
946     pa_assert(msg);
947     pa_assert(dm);
948
949     pa_assert_se(dbus_message_get_args(msg, NULL,
950                                        DBUS_TYPE_STRING, &type,
951                                        DBUS_TYPE_STRING, &role,
952                                        DBUS_TYPE_INVALID));
953
954     if (!(sink = pa_device_manager_load_sink(dm, type, role)))
955         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
956     else
957         pa_dbus_send_empty_reply(conn, msg);
958 }
959
960 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
961     pa_device_manager *dm = (pa_device_manager *)userdata;
962     char *type, *role;
963
964     pa_assert(conn);
965     pa_assert(msg);
966     pa_assert(dm);
967
968     pa_assert_se(dbus_message_get_args(msg, NULL,
969                                        DBUS_TYPE_STRING, &type,
970                                        DBUS_TYPE_STRING, &role,
971                                        DBUS_TYPE_INVALID));
972
973     pa_device_manager_unload_sink(dm, type, role);
974
975     pa_dbus_send_empty_reply(conn, msg);
976 }
977
978 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
979     pa_device_manager *dm = (pa_device_manager *)userdata;
980     char *device_string;
981
982     pa_assert(conn);
983     pa_assert(msg);
984     pa_assert(dm);
985
986     pa_assert_se(dbus_message_get_args(msg, NULL,
987                                        DBUS_TYPE_STRING, &device_string,
988                                        DBUS_TYPE_INVALID));
989
990     pa_device_manager_unload_sink_with_device_string(dm, device_string);
991
992     pa_dbus_send_empty_reply(conn, msg);
993 }
994
995 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
996     pa_device_manager *dm = (pa_device_manager *)userdata;
997     char *type, *role;
998     const char *device_string;
999     dbus_bool_t is_playback;
1000
1001     pa_assert(conn);
1002     pa_assert(msg);
1003     pa_assert(dm);
1004
1005     pa_assert_se(dbus_message_get_args(msg, NULL,
1006                                        DBUS_TYPE_BOOLEAN, &is_playback,
1007                                        DBUS_TYPE_STRING, &type,
1008                                        DBUS_TYPE_STRING, &role,
1009                                        DBUS_TYPE_INVALID));
1010
1011     device_string = pa_device_manager_get_device_string(dm, is_playback, type, role);
1012     if (device_string == NULL) {
1013         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1014         return;
1015     }
1016
1017     pa_log_info("device string : %s", device_string);
1018
1019     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &device_string);
1020 }
1021
1022 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1023     pa_device_manager *dm = (pa_device_manager *)userdata;
1024     pa_tz_device *device;
1025     uint32_t device_idx;
1026
1027     pa_assert(conn);
1028     pa_assert(msg);
1029     pa_assert(dm);
1030
1031     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
1032         pa_tz_device_dump_info(device, PA_LOG_INFO);
1033     }
1034
1035     pa_dbus_send_empty_reply(conn, msg);
1036 }
1037
1038 static bool is_usb_output_device(pa_tz_device *device) {
1039     char *type;
1040     dm_device_direction_t direction;
1041     pa_sink *sink;
1042
1043     pa_assert(device);
1044
1045     type = pa_tz_device_get_type(device);
1046     if (!pa_safe_streq(type, DEVICE_TYPE_USB_AUDIO)) {
1047         pa_log_error("device(id:%d, %s) is not USB AUDIO type", pa_tz_device_get_id(device), type);
1048         return false;
1049     }
1050     direction = pa_tz_device_get_direction(device);
1051     if (direction & DM_DEVICE_DIRECTION_OUT) {
1052         if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1053             pa_log_error("sink is null");
1054             return false;
1055         }
1056     } else {
1057         pa_log_error("this device is not for output");
1058         return false;
1059     }
1060
1061     return true;
1062 }
1063
1064
1065 static bool is_supported_sample_format(pa_sample_format_t *supported_sample_formats, pa_sample_format_t sample_format) {
1066     int i;
1067
1068     pa_assert(supported_sample_formats);
1069     pa_assert(sample_format != PA_SAMPLE_INVALID);
1070
1071     for (i = 0; supported_sample_formats[i] != PA_SAMPLE_MAX; i++) {
1072         if (supported_sample_formats[i] == sample_format) {
1073             pa_log_info("%s is supported", pa_sample_format_to_string(sample_format));
1074             return true;
1075         }
1076     }
1077     pa_log_error("%s is not supported", pa_sample_format_to_string(sample_format));
1078     return false;
1079 }
1080
1081 static void handle_get_supported_sample_formats(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1082     pa_device_manager *dm = (pa_device_manager *)userdata;
1083     DBusMessage *reply = NULL;
1084     DBusMessageIter msg_iter, array_iter;
1085     dbus_int32_t device_id;
1086     pa_tz_device *device;
1087     pa_sink *sink;
1088     const char *format;
1089     int i;
1090
1091     pa_assert(conn);
1092     pa_assert(msg);
1093     pa_assert(dm);
1094
1095     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1096
1097     pa_assert_se(dbus_message_get_args(msg, NULL,
1098                                        DBUS_TYPE_INT32, &device_id,
1099                                        DBUS_TYPE_INVALID));
1100
1101     pa_log_info("Get supported sample formats of the device(id:%d)", device_id);
1102
1103     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1104         pa_log_error("could not find any device with id:%d", device_id);
1105         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1106         return;
1107     }
1108     if (!is_usb_output_device(device)) {
1109         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1110         return;
1111     }
1112     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1113         pa_log_error("could not get sink for normal role");
1114         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1115         return;
1116     }
1117
1118     if (!sink->supported_sample_formats) {
1119         pa_log_error("supported sample formats is not set on this sink");
1120         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1121         return;
1122     }
1123
1124     dbus_message_iter_init_append(reply, &msg_iter);
1125     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "s", &array_iter));
1126     for (i = 0; sink->supported_sample_formats[i] != PA_SAMPLE_MAX; i++) {
1127         format = pa_sample_format_to_string(sink->supported_sample_formats[i]);
1128         pa_log_info("%s is supported", format);
1129         dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &format);
1130     }
1131     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
1132     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1133     dbus_message_unref(reply);
1134 }
1135
1136 static void handle_set_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1137     pa_device_manager *dm = (pa_device_manager *)userdata;
1138     dbus_int32_t device_id;
1139     char *sample_format;
1140     pa_sample_format_t prev_selected_sample_format;
1141     pa_tz_device *device;
1142     pa_sink *sink;
1143     pa_sample_spec spec;
1144
1145     pa_assert(conn);
1146     pa_assert(msg);
1147     pa_assert(dm);
1148
1149     pa_assert_se(dbus_message_get_args(msg, NULL,
1150                                        DBUS_TYPE_INT32, &device_id,
1151                                        DBUS_TYPE_STRING, &sample_format,
1152                                        DBUS_TYPE_INVALID));
1153
1154     pa_log_info("Set sample format(%s) of the device(id:%d)", sample_format, device_id);
1155
1156     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1157         pa_log_error("could not find any device with id:%d", device_id);
1158         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1159         return;
1160     }
1161     if (!is_usb_output_device(device)) {
1162         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1163         return;
1164     }
1165     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1166         pa_log_error("could not get sink for normal role");
1167         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1168         return;
1169     }
1170
1171     /* use a supported sample format selected by user */
1172     if (!is_supported_sample_format(sink->supported_sample_formats, pa_parse_sample_format(sample_format))) {
1173         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1174         return;
1175     }
1176     prev_selected_sample_format = sink->selected_sample_format;
1177     sink->selected_sample_format = pa_parse_sample_format(sample_format);
1178
1179     if (prev_selected_sample_format != sink->selected_sample_format) {
1180         FILL_SAMPLE_SPEC_WITH_SELECTED(spec, sink);
1181         pa_sink_reconfigure(sink, &spec, false);
1182         if (sink->selected_sample_format != sink->sample_spec.format) {
1183             pa_log_error("failed to reconfigure");
1184             pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1185             sink->selected_sample_format = prev_selected_sample_format;
1186             return;
1187         }
1188         save_preference(dm, sink);
1189     }
1190
1191     pa_log_info("Set sample format(%s) of the device(id:%d) successfully", sample_format, device_id);
1192
1193     pa_dbus_send_empty_reply(conn, msg);
1194 }
1195
1196 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1197     pa_device_manager *dm = (pa_device_manager *)userdata;
1198     dbus_int32_t device_id;
1199     pa_tz_device *device;
1200     pa_sink *sink;
1201     const char *format;
1202
1203     pa_assert(conn);
1204     pa_assert(msg);
1205     pa_assert(dm);
1206
1207     pa_assert_se(dbus_message_get_args(msg, NULL,
1208                                        DBUS_TYPE_INT32, &device_id,
1209                                        DBUS_TYPE_INVALID));
1210
1211     pa_log_info("Get sample format of the device(id:%d)", device_id);
1212
1213     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1214         pa_log_error("could not find any device with id:%d", device_id);
1215         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1216         return;
1217     }
1218     if (!is_usb_output_device(device)) {
1219         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1220         return;
1221     }
1222     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1223         pa_log_error("could not get sink for normal role");
1224         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1225         return;
1226     }
1227
1228     format = pa_sample_format_to_string(sink->selected_sample_format);
1229     pa_log_info("Get sample format(%s) of the device(id:%d) successfully", format, device_id);
1230
1231     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &format);
1232 }
1233
1234 static bool is_supported_sample_rate(uint32_t *supported_sample_rates, uint32_t sample_rate) {
1235     int i;
1236
1237     pa_assert(supported_sample_rates);
1238
1239     for (i = 0; supported_sample_rates[i]; i++) {
1240         if (supported_sample_rates[i] == sample_rate) {
1241             pa_log_info("%u is supported", sample_rate);
1242             return true;
1243         }
1244     }
1245     pa_log_error("%u is not supported", sample_rate);
1246     return false;
1247 }
1248
1249 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1250     pa_device_manager *dm = (pa_device_manager *)userdata;
1251     DBusMessage *reply = NULL;
1252     DBusMessageIter msg_iter, array_iter;
1253     dbus_int32_t device_id;
1254     pa_tz_device *device;
1255     pa_sink *sink;
1256     int i;
1257
1258     pa_assert(conn);
1259     pa_assert(msg);
1260     pa_assert(dm);
1261
1262     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1263
1264     pa_assert_se(dbus_message_get_args(msg, NULL,
1265                                        DBUS_TYPE_INT32, &device_id,
1266                                        DBUS_TYPE_INVALID));
1267
1268     pa_log_info("Get supported sample rates of the device(id:%d)", device_id);
1269
1270     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1271         pa_log_error("could not find any device with id:%d", device_id);
1272         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1273         return;
1274     }
1275     if (!is_usb_output_device(device)) {
1276         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1277         return;
1278     }
1279     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1280         pa_log_error("could not get sink for normal role");
1281         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1282         return;
1283     }
1284
1285     if (!sink->supported_sample_rates) {
1286         pa_log_error("supported sample rates is not set on this sink");
1287         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1288         return;
1289     }
1290
1291     dbus_message_iter_init_append(reply, &msg_iter);
1292     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "u", &array_iter));
1293     for (i = 0; sink->supported_sample_rates[i]; i++) {
1294         pa_log_info("%u is supported", sink->supported_sample_rates[i]);
1295         dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_UINT32, &sink->supported_sample_rates[i]);
1296     }
1297     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
1298     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1299     dbus_message_unref(reply);
1300 }
1301
1302 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1303     pa_device_manager *dm = (pa_device_manager *)userdata;
1304     dbus_int32_t device_id;
1305     dbus_uint32_t sample_rate;
1306     uint32_t prev_selected_sample_rate;
1307     pa_tz_device *device;
1308     pa_sink *sink;
1309     pa_sample_spec spec;
1310
1311     pa_assert(conn);
1312     pa_assert(msg);
1313     pa_assert(dm);
1314
1315     pa_assert_se(dbus_message_get_args(msg, NULL,
1316                                        DBUS_TYPE_INT32, &device_id,
1317                                        DBUS_TYPE_UINT32, &sample_rate,
1318                                        DBUS_TYPE_INVALID));
1319
1320     pa_log_info("Set sample rate(%u) of the device(id:%d)", sample_rate, device_id);
1321
1322     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1323         pa_log_error("could not find any device with id:%d", device_id);
1324         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1325         return;
1326     }
1327     if (!is_usb_output_device(device)) {
1328         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1329         return;
1330     }
1331     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1332         pa_log_error("could not get sink for normal role");
1333         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1334         return;
1335     }
1336
1337     /* use a supported sample rate selected by user */
1338     if (!is_supported_sample_rate(sink->supported_sample_rates, sample_rate)) {
1339         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1340         return;
1341     }
1342     prev_selected_sample_rate = sink->selected_sample_rate;
1343     sink->selected_sample_rate = sample_rate;
1344
1345     if (prev_selected_sample_rate != sink->selected_sample_rate) {
1346         FILL_SAMPLE_SPEC_WITH_SELECTED(spec, sink);
1347         pa_sink_reconfigure(sink, &spec, false);
1348         if (sink->selected_sample_rate != sink->sample_spec.rate) {
1349             pa_log_error("failed to reconfigure");
1350             pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1351             sink->selected_sample_rate = prev_selected_sample_rate;
1352             return;
1353         }
1354         save_preference(dm, sink);
1355     }
1356
1357     pa_log_info("Set sample rate(%u) of the device(id:%d) successfully", sample_rate, device_id);
1358
1359     pa_dbus_send_empty_reply(conn, msg);
1360 }
1361
1362 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1363     pa_device_manager *dm = (pa_device_manager *)userdata;
1364     dbus_int32_t device_id;
1365     pa_tz_device *device;
1366     pa_sink *sink;
1367
1368     pa_assert(conn);
1369     pa_assert(msg);
1370     pa_assert(dm);
1371
1372     pa_assert_se(dbus_message_get_args(msg, NULL,
1373                                        DBUS_TYPE_INT32, &device_id,
1374                                        DBUS_TYPE_INVALID));
1375
1376     pa_log_info("Get sample rate of the device(id:%d)", device_id);
1377
1378     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1379         pa_log_error("could not find any device with id:%d", device_id);
1380         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1381         return;
1382     }
1383     if (!is_usb_output_device(device)) {
1384         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1385         return;
1386     }
1387     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1388         pa_log_error("could not get sink for normal role");
1389         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1390         return;
1391     }
1392
1393     pa_log_info("Get sample rate(%u) of the device(id:%d) successfully", sink->selected_sample_rate, device_id);
1394
1395     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &sink->selected_sample_rate);
1396 }
1397
1398 static void handle_set_specific_stream_only(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1399     pa_device_manager *dm = (pa_device_manager *)userdata;
1400     dbus_int32_t device_id;
1401     char *stream_role;
1402     pa_tz_device *device;
1403
1404     pa_assert(conn);
1405     pa_assert(msg);
1406     pa_assert(dm);
1407
1408     pa_assert_se(dbus_message_get_args(msg, NULL,
1409                                        DBUS_TYPE_INT32, &device_id,
1410                                        DBUS_TYPE_STRING, &stream_role,
1411                                        DBUS_TYPE_INVALID));
1412
1413     pa_log_info("Set the device(id:%d) only for the stream role(%s)", device_id, stream_role);
1414
1415     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1416         pa_log_error("could not find any device with id:%d", device_id);
1417         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1418         return;
1419     }
1420     if (!is_usb_output_device(device)) {
1421         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1422         return;
1423     }
1424     if (!pa_safe_streq(stream_role, "none") && !pa_stream_manager_is_valid_stream_role(dm->core, stream_role)) {
1425         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1426         return;
1427     }
1428
1429     pa_xfree(device->specified_stream_role);
1430     device->specified_stream_role = pa_xstrdup(stream_role);
1431
1432     pa_dbus_send_empty_reply(conn, msg);
1433 }
1434
1435 static void handle_get_specified_stream(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1436     pa_device_manager *dm = (pa_device_manager *)userdata;
1437     dbus_int32_t device_id;
1438     char *specified_stream_role;
1439     pa_tz_device *device;
1440
1441     pa_assert(conn);
1442     pa_assert(msg);
1443     pa_assert(dm);
1444
1445     pa_assert_se(dbus_message_get_args(msg, NULL,
1446                                        DBUS_TYPE_INT32, &device_id,
1447                                        DBUS_TYPE_INVALID));
1448
1449     pa_log_info("Get specified stream role for the device(id:%d)", device_id);
1450
1451     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1452         pa_log_error("could not find any device with id:%d", device_id);
1453         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1454         return;
1455     }
1456     if (!is_usb_output_device(device)) {
1457         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1458         return;
1459     }
1460
1461     specified_stream_role = device->specified_stream_role;
1462
1463     pa_log_info("stream role(%s) is specified for the device(id:%d)", device->specified_stream_role, device_id);
1464
1465     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &specified_stream_role);
1466 }
1467
1468 static void handle_set_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1469     pa_device_manager *dm = (pa_device_manager *)userdata;
1470     dbus_int32_t device_id;
1471     dbus_bool_t avoid_resampling;
1472     pa_tz_device *device;
1473     pa_sink *sink;
1474
1475     pa_assert(conn);
1476     pa_assert(msg);
1477     pa_assert(dm);
1478
1479     pa_assert_se(dbus_message_get_args(msg, NULL,
1480                                        DBUS_TYPE_INT32, &device_id,
1481                                        DBUS_TYPE_BOOLEAN, &avoid_resampling,
1482                                        DBUS_TYPE_INVALID));
1483
1484     pa_log_info("Set the device(id:%d) avoid-resampling(%d)", device_id, avoid_resampling);
1485
1486     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1487         pa_log_error("could not find any device with id:%d", device_id);
1488         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1489         return;
1490     }
1491     if (!is_usb_output_device(device)) {
1492         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1493         return;
1494     }
1495     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1496         pa_log_error("could not get sink for normal role");
1497         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1498         return;
1499     }
1500     if (sink->avoid_resampling == avoid_resampling) {
1501         pa_log_info("already set to %d", avoid_resampling);
1502     } else {
1503         sink->avoid_resampling = avoid_resampling;
1504         save_preference(dm, sink);
1505         pa_log_info("Set avoid-resampling(%d) to the device(id:%d)", avoid_resampling, device_id);
1506     }
1507
1508     pa_dbus_send_empty_reply(conn, msg);
1509 }
1510
1511 static void handle_get_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1512     pa_device_manager *dm = (pa_device_manager *)userdata;
1513     dbus_int32_t device_id;
1514     dbus_bool_t avoid_resampling;
1515     pa_tz_device *device;
1516     pa_sink *sink;
1517
1518     pa_assert(conn);
1519     pa_assert(msg);
1520     pa_assert(dm);
1521
1522     pa_assert_se(dbus_message_get_args(msg, NULL,
1523                                        DBUS_TYPE_INT32, &device_id,
1524                                        DBUS_TYPE_INVALID));
1525
1526     pa_log_info("Get avoid-resampling of the device(id:%d)", device_id);
1527
1528     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1529         pa_log_error("could not find any device with id:%d", device_id);
1530         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1531         return;
1532     }
1533     if (!is_usb_output_device(device)) {
1534         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1535         return;
1536     }
1537     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1538         pa_log_error("could not get sink for normal role");
1539         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1540         return;
1541     }
1542
1543     avoid_resampling = sink->avoid_resampling;
1544     pa_log_info("got avoid-resampling(%d) of the device(id:%d)", avoid_resampling, device_id);
1545
1546     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &avoid_resampling);
1547 }
1548
1549 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1550     pa_device_manager *dm = (pa_device_manager *)userdata;
1551     char *type;
1552     dbus_int32_t status;
1553
1554     pa_assert(conn);
1555     pa_assert(msg);
1556     pa_assert(dm);
1557
1558     pa_assert_se(dbus_message_get_args(msg, NULL,
1559                                        DBUS_TYPE_STRING, &type,
1560                                        DBUS_TYPE_INT32, &status,
1561                                        DBUS_TYPE_INVALID));
1562
1563     pa_log_debug("handle_test_device_status_change, type:%s, status:%d", type, status);
1564
1565     handle_device_status_changed(dm, type, NULL, NULL, status);
1566
1567     pa_dbus_send_empty_reply(conn, msg);
1568 }
1569
1570 static void handle_set_acm_mode(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1571     pa_device_manager *dm = (pa_device_manager *)userdata;
1572     uint32_t mode = 0;
1573
1574     pa_assert(conn);
1575     pa_assert(msg);
1576     pa_assert(dm);
1577
1578     pa_assert_se(dbus_message_get_args(msg, NULL,
1579                                        DBUS_TYPE_UINT32, &mode,
1580                                        DBUS_TYPE_INVALID));
1581
1582     pa_log_info("Set ACM mode to (%d)", mode);
1583
1584     if (mode == 0) {
1585         unload_acm_sink(dm);
1586     } else {
1587         /* For now, value of not 0 is just loading ACM sink. */
1588         if (!load_acm_sink(dm)) {
1589             pa_log_error("could not load acm sink");
1590             pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1591             return;
1592         }
1593     }
1594
1595     pa_dbus_send_empty_reply(conn, msg);
1596 }
1597
1598 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1599     const char *xml = DEVICE_MANAGER_INTROSPECT_XML;
1600     DBusMessage *r = NULL;
1601
1602     pa_assert(conn);
1603     pa_assert(msg);
1604     pa_assert(userdata);
1605
1606     pa_assert_se(r = dbus_message_new_method_return(msg));
1607     pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
1608
1609     if (r) {
1610         pa_assert_se(dbus_connection_send((conn), r, NULL));
1611         dbus_message_unref(r);
1612     }
1613
1614     return DBUS_HANDLER_RESULT_HANDLED;
1615 }
1616
1617 static DBusHandlerResult handle_device_manager_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1618     int method_idx = 0;
1619
1620     pa_assert(conn);
1621     pa_assert(msg);
1622     pa_assert(userdata);
1623
1624     for (method_idx = 0; method_idx < METHOD_HANDLER_MAX; method_idx++) {
1625         if (dbus_message_is_method_call(msg, DBUS_INTERFACE_DEVICE_MANAGER, method_handlers[method_idx].method_name)) {
1626             method_handlers[method_idx].receive_cb(conn, msg, userdata);
1627             return DBUS_HANDLER_RESULT_HANDLED;
1628         }
1629     }
1630
1631     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1632 }
1633
1634 static DBusHandlerResult method_call_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
1635     struct userdata *u = userdata;
1636     const char *path, *interface, *member;
1637
1638     pa_assert(c);
1639     pa_assert(m);
1640     pa_assert(u);
1641
1642     path = dbus_message_get_path(m);
1643     interface = dbus_message_get_interface(m);
1644     member = dbus_message_get_member(m);
1645
1646     pa_log_info("DeviceManager Method Call Handler : path=%s, interface=%s, member=%s", path, interface, member);
1647
1648     if (!pa_safe_streq(path, DBUS_OBJECT_DEVICE_MANAGER))
1649         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1650
1651     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1652         return handle_introspect(c, m, u);
1653         /*
1654     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get")) {
1655         return handle_get_property(c, m, u);
1656     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set")) {
1657         return  handle_set_property(c, m, u);
1658     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll")) {
1659         return handle_get_all_property(c, m, u);
1660         */
1661     } else {
1662         return handle_device_manager_methods(c, m, u);
1663     }
1664
1665     return DBUS_HANDLER_RESULT_HANDLED;
1666 }
1667
1668 static void fill_signal_msg_with_device(const char *description, DBusMessageIter *msg_iter, uint32_t event_id, pa_tz_device *device) {
1669     DBusMessageIter array_iter, device_iter;
1670     char *type, *name;
1671     dbus_int32_t device_id, direction, state, stream_id;
1672     dbus_int32_t vendor_id, product_id;
1673     dbus_bool_t is_running;
1674     pa_intset *stream_id_set = NULL;
1675     int32_t stream_id_val;
1676     int ret;
1677
1678     pa_assert(msg_iter);
1679     pa_assert(device);
1680
1681     dbus_message_iter_append_basic(msg_iter, DBUS_TYPE_UINT32, &event_id);
1682     pa_assert_se(dbus_message_iter_open_container(msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
1683
1684     direction = (dbus_int32_t)pa_tz_device_get_direction(device);
1685     type = pa_tz_device_get_type(device);
1686     name = pa_tz_device_get_name(device);
1687     device_id = (dbus_int32_t)pa_tz_device_get_id(device);
1688     state = pa_tz_device_get_state(device);
1689     vendor_id = (dbus_int32_t)pa_tz_device_get_vendor_id(device);
1690     product_id = (dbus_int32_t)pa_tz_device_get_product_id(device);
1691     is_running = (dbus_bool_t)pa_tz_device_is_running(device);
1692
1693     simple_device_dump(PA_LOG_INFO, description, device_id, type, name, direction, state);
1694
1695     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
1696     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
1697     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
1698     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
1699     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
1700     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
1701     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
1702     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
1703     if (state == DM_DEVICE_STATE_ACTIVATED)
1704         stream_id_set = pa_tz_device_get_stream_list(device);
1705     pa_assert_se(dbus_message_iter_open_container(&device_iter, DBUS_TYPE_ARRAY, "i", &array_iter));
1706     if (state == DM_DEVICE_STATE_ACTIVATED) {
1707         PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
1708             stream_id = stream_id_val;
1709             dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_INT32, &stream_id);
1710         }
1711     }
1712     pa_assert_se(dbus_message_iter_close_container(&device_iter, &array_iter));
1713     if (stream_id_set)
1714         pa_intset_free(stream_id_set);
1715     pa_assert_se(dbus_message_iter_close_container(msg_iter, &device_iter));
1716     pa_log_info("end of fill signal msg");
1717 }
1718
1719 void send_device_connection_changed_signal(uint32_t event_id, pa_tz_device *device, bool connected, pa_device_manager *dm) {
1720     DBusMessage *signal_msg;
1721     DBusMessageIter msg_iter;
1722     dbus_bool_t _connected = (dbus_bool_t)connected;
1723
1724     pa_assert(device);
1725     pa_assert(dm);
1726
1727     pa_log_info("Send device connection changed signal, event_id(%u)", event_id);
1728
1729     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceConnected"));
1730     dbus_message_iter_init_append(signal_msg, &msg_iter);
1731     fill_signal_msg_with_device(connected ? "[Connected]" : "[Disconnected]", &msg_iter, event_id, device);
1732
1733     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &_connected);
1734
1735     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1736
1737     dbus_message_unref(signal_msg);
1738     pa_log_info("end of send device connection changed signal");
1739 }
1740
1741 void send_device_info_changed_signal(uint32_t event_id, pa_tz_device *device, int changed_type, pa_device_manager *dm) {
1742     DBusMessage *signal_msg;
1743     DBusMessageIter msg_iter;
1744     const char *changed_prefix[] = {"[State Changed]", "[Direction Changed]", "[Avail-Mode Changed]"};
1745
1746     pa_assert(device);
1747     pa_assert(dm);
1748
1749     pa_log_debug("Send device info changed signal, event_id(%u)", event_id);
1750
1751     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceInfoChanged"));
1752     dbus_message_iter_init_append(signal_msg, &msg_iter);
1753     fill_signal_msg_with_device(changed_prefix[changed_type], &msg_iter, event_id, device);
1754     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &changed_type);
1755
1756     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1757
1758     dbus_message_unref(signal_msg);
1759 }
1760
1761 void send_device_state_changed_signal(uint32_t event_id, pa_tz_device *device, bool activated, pa_device_manager *dm) {
1762     DBusMessage *signal_msg;
1763     DBusMessageIter msg_iter;
1764
1765     pa_assert(device);
1766     pa_assert(dm);
1767
1768     pa_log_debug("Send device state changed signal, event_id(%u)", event_id);
1769
1770     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceStateChanged"));
1771     dbus_message_iter_init_append(signal_msg, &msg_iter);
1772     fill_signal_msg_with_device(activated ? "[Activated]" : "[Deactivated]", &msg_iter, event_id, device);
1773
1774     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1775
1776     dbus_message_unref(signal_msg);
1777 }
1778
1779 void send_device_running_changed_signal(uint32_t event_id, pa_tz_device *device, bool is_running, pa_device_manager *dm) {
1780     DBusMessage *signal_msg;
1781     DBusMessageIter msg_iter;
1782
1783     pa_assert(device);
1784     pa_assert(dm);
1785
1786     pa_log_debug("Send device running changed signal, event_id(%u)", event_id);
1787
1788     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceRunningChanged"));
1789     dbus_message_iter_init_append(signal_msg, &msg_iter);
1790     fill_signal_msg_with_device(is_running ? "[Running]" : "[NotRunning]", &msg_iter, event_id, device);
1791
1792     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1793
1794     dbus_message_unref(signal_msg);
1795 }
1796
1797 static void endpoint_init(pa_device_manager *dm) {
1798     static const DBusObjectPathVTable vtable_endpoint = {
1799         .message_function = method_call_handler,
1800     };
1801
1802     pa_log_info("Device manager dbus endpoint init");
1803
1804     if (dm && dm->dbus_conn) {
1805         if (!dbus_connection_register_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER, &vtable_endpoint, dm))
1806             pa_log_error("Failed to register object path");
1807     } else {
1808         pa_log_error("Cannot get dbus connection to register object path");
1809     }
1810 }
1811
1812 static void endpoint_done(pa_device_manager *dm) {
1813     pa_log_info("Device manager dbus endpoint done");
1814     if (dm && dm->dbus_conn) {
1815         if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER))
1816             pa_log_error("Failed to unregister object path");
1817     } else {
1818         pa_log_error("Cannot get dbus connection to unregister object path");
1819     }
1820 }
1821
1822 static int watch_signals(pa_device_manager *dm) {
1823     DBusError error;
1824
1825     pa_assert(dm);
1826     pa_assert(dm->dbus_conn);
1827
1828     dbus_error_init(&error);
1829
1830     pa_log_info("Watch Dbus signals");
1831
1832     if (!dbus_connection_add_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm, NULL)) {
1833         pa_log_error("Unable to add D-Bus filter : %s: %s", error.name, error.message);
1834         goto fail;
1835     }
1836
1837     if (pa_dbus_add_matches(pa_dbus_connection_get(dm->dbus_conn), &error, FILTER_DEVICED_SYSNOTI, FILTER_SOUND_SERVER, FILTER_BLUEZ, FILTER_MIRRORING, NULL) < 0) {
1838         pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
1839         goto fail;
1840     }
1841     return 0;
1842
1843 fail:
1844     dbus_error_free(&error);
1845     return -1;
1846 }
1847
1848 static void unwatch_signals(pa_device_manager *dm) {
1849     pa_log_info("Unwatch Dbus signals");
1850
1851     pa_assert(dm);
1852     pa_assert(dm->dbus_conn);
1853
1854     pa_dbus_remove_matches(pa_dbus_connection_get(dm->dbus_conn), FILTER_DEVICED_SYSNOTI, FILTER_SOUND_SERVER, FILTER_BLUEZ, FILTER_MIRRORING, NULL);
1855     dbus_connection_remove_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm);
1856 }
1857
1858 void init_dm_dbus(pa_device_manager *dm) {
1859     DBusError error;
1860     pa_dbus_connection *connection = NULL;
1861
1862     pa_assert(dm);
1863     pa_log_info("init Dbus");
1864     dbus_error_init(&error);
1865
1866     if (!(connection = pa_dbus_bus_get(dm->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
1867         if (connection) {
1868             pa_dbus_connection_unref(connection);
1869         }
1870         pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
1871         goto fail;
1872     } else {
1873         pa_log_info("Got dbus connection");
1874     }
1875
1876     dm->dbus_conn = connection;
1877
1878     if (watch_signals(dm) < 0)
1879         pa_log_error("dbus watch signals failed");
1880     else
1881         pa_log_debug("dbus ready to get signals");
1882
1883     endpoint_init(dm);
1884
1885 fail:
1886     dbus_error_free(&error);
1887 }
1888
1889 void deinit_dm_dbus(pa_device_manager *dm) {
1890     pa_assert(dm);
1891
1892     pa_log_info("deinit Dbus");
1893
1894     endpoint_done(dm);
1895     unwatch_signals(dm);
1896
1897     if (dm->dbus_conn) {
1898         pa_dbus_connection_unref(dm->dbus_conn);
1899         dm->dbus_conn = NULL;
1900     }
1901 }
1902 #endif