fixup! tizen-device: add sample spec and return it for connected device list
[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         is_running = (dbus_bool_t)pa_tz_device_is_running(device);
701
702         format = samplerate = channels = 0;
703         spec = pa_tz_device_get_sample_spec(device);
704         if (spec) {
705             format = (dbus_int32_t)spec->format;
706             samplerate = (dbus_int32_t)spec->rate;
707             channels = (dbus_int32_t)spec->channels;
708         }
709
710         if (device_is_match_with_mask(device, mask)) {
711             simple_device_dump(PA_LOG_INFO, "[MATCH]", device_id, type, name, direction, state);
712             pa_assert_se(dbus_message_iter_open_container(array_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
713             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
714             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
715             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
716             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
717             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
718             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
719             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
720             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
721             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &format);
722             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &samplerate);
723             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &channels);
724
725             pa_assert_se(dbus_message_iter_close_container(array_iter, &device_iter));
726         } else {
727             simple_device_dump(PA_LOG_INFO, "[UNMATCH]", device_id, type, name, direction, state);
728         }
729     }
730 }
731
732 #ifdef __TIZEN_TV_EXTERNAL_BT_SCO__
733 static int include_device_filter_func(const void *d, const void *include_device_type) {
734     pa_tz_device *device = (pa_tz_device *)d;
735
736     pa_assert(device);
737     pa_assert(include_device_type);
738
739     return (int)pa_safe_streq(pa_tz_device_get_type(device), (const char *)include_device_type);
740 }
741
742 static int exclude_device_filter_func(const void *d, const void *exclude_device_type) {
743     pa_tz_device *device = (pa_tz_device *)d;
744
745     pa_assert(device);
746     pa_assert(exclude_device_type);
747
748     return (int)!pa_safe_streq(pa_tz_device_get_type(device), (const char *)exclude_device_type);
749 }
750 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
751
752 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
753     pa_device_manager *dm = (pa_device_manager *)userdata;
754     DBusMessage *reply = NULL;
755     DBusMessageIter msg_iter, array_iter;
756     int mask;
757 #ifdef __TIZEN_TV_EXTERNAL_BT_SCO__
758     pa_idxset *idxset1, *idxset2;
759 #endif
760
761     pa_assert(conn);
762     pa_assert(msg);
763     pa_assert(dm);
764
765     pa_assert_se((reply = dbus_message_new_method_return(msg)));
766
767     pa_assert_se(dbus_message_get_args(msg, NULL,
768                                        DBUS_TYPE_INT32, &mask,
769                                        DBUS_TYPE_INVALID));
770
771     pa_log_info("Get connected device list (mask : %d)", mask);
772
773     dbus_message_iter_init_append(reply, &msg_iter);
774     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiisiibiii)", &array_iter));
775
776 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
777     array_iter_append(&array_iter, dm->device_list, mask);
778 #else
779     /* divide into two groups and merge them because dbus message doesn't support sorting or prepend */
780     idxset1 = pa_idxset_filtered_copy(dm->device_list, NULL, include_device_filter_func, DEVICE_TYPE_BT_SCO);
781     idxset2 = pa_idxset_filtered_copy(dm->device_list, NULL, exclude_device_filter_func, DEVICE_TYPE_BT_SCO);
782
783     array_iter_append(&array_iter, idxset1, mask);
784     array_iter_append(&array_iter, idxset2, mask);
785
786     pa_idxset_free(idxset1, NULL);
787     pa_idxset_free(idxset2, NULL);
788 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
789
790     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
791
792     pa_assert_se(dbus_connection_send(conn, reply, NULL));
793     dbus_message_unref(reply);
794 }
795
796 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
797     pa_device_manager *dm = (pa_device_manager *)userdata;
798     DBusMessage *reply;
799     DBusMessageIter msg_iter;
800     pa_tz_device *device;
801     dbus_int32_t device_id;
802     dbus_int32_t id, direction, state;
803     dbus_int32_t vendor_id, product_id;
804     char *type, *name;
805
806     pa_assert(conn);
807     pa_assert(msg);
808     pa_assert(dm);
809
810     pa_assert_se(dbus_message_get_args(msg, NULL,
811                                        DBUS_TYPE_INT32, &device_id,
812                                        DBUS_TYPE_INVALID));
813
814     pa_log_info("Get device by id(%d)", device_id);
815
816     if ((device = device_list_get_device_by_id(dm, device_id))) {
817         pa_assert_se((reply = dbus_message_new_method_return(msg)));
818         dbus_message_iter_init_append(reply, &msg_iter);
819
820         id = (dbus_int32_t)pa_tz_device_get_id(device);
821         state = pa_tz_device_get_state(device);
822         direction = pa_tz_device_get_direction(device);
823         type = pa_tz_device_get_type(device);
824         name = pa_tz_device_get_name(device);
825         vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
826         product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
827
828         simple_device_dump(PA_LOG_INFO, "[GET_BY_ID]", device_id, type, name, direction, state);
829
830         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &id);
831         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &type);
832         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &direction);
833         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &state);
834         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
835         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &vendor_id);
836         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &product_id);
837
838         pa_assert_se(dbus_connection_send(conn, reply, NULL));
839         dbus_message_unref(reply);
840     } else {
841         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
842     }
843 }
844
845 static void handle_is_device_running_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
846     pa_device_manager *dm = (pa_device_manager *)userdata;
847     pa_tz_device *device;
848     dbus_int32_t device_id;
849     dbus_bool_t is_running;
850
851     pa_assert(conn);
852     pa_assert(msg);
853     pa_assert(dm);
854
855     pa_assert_se(dbus_message_get_args(msg, NULL,
856                                        DBUS_TYPE_INT32, &device_id,
857                                        DBUS_TYPE_INVALID));
858
859     pa_log_info("Is device running by id(%d)", device_id);
860
861     if ((device = device_list_get_device_by_id(dm, device_id))) {
862         is_running = pa_tz_device_is_running(device);
863
864         pa_log_info("device(id:%d) is %s", device_id, is_running ? "Running" : "Not Running");
865
866         pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_running);
867     } else {
868         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
869     }
870 }
871
872 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
873     pa_device_manager *dm = (pa_device_manager *)userdata;
874     pa_tz_device *device;
875     dbus_bool_t is_on = FALSE;
876     dbus_int32_t stream_id, device_id;
877     pa_intset *stream_id_set;
878     int32_t stream_id_val;
879     int ret;
880     dm_device_state_t state;
881
882     pa_assert(conn);
883     pa_assert(msg);
884     pa_assert(dm);
885
886     pa_log_info("Is stream on device");
887
888     pa_assert_se(dbus_message_get_args(msg, NULL,
889                                        DBUS_TYPE_INT32, &stream_id,
890                                        DBUS_TYPE_INT32, &device_id,
891                                        DBUS_TYPE_INVALID));
892
893     if ((device = device_list_get_device_by_id(dm, device_id))) {
894         state = pa_tz_device_get_state(device);
895         if (state == DM_DEVICE_STATE_ACTIVATED) {
896             stream_id_set = pa_tz_device_get_stream_list(device);
897             PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
898                 if (stream_id_val == stream_id) {
899                     is_on = TRUE;
900                     pa_log_info("stream(%d) is on device(%d)", stream_id, device_id);
901                     break;
902                 }
903             }
904             pa_intset_free(stream_id_set);
905         } else {
906             pa_log_info("device(%d) is not activated, regard as no stream on it", device_id);
907             is_on = FALSE;
908         }
909         pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_on);
910     } else {
911         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.Internal");
912     }
913 }
914
915 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
916     pa_device_manager *dm = (pa_device_manager *)userdata;
917     DBusMessage *reply = NULL;
918     pa_tz_device *device;
919     dbus_bool_t is_bt_on = FALSE;
920     const char *bt_name = "none";
921
922     pa_assert(conn);
923     pa_assert(msg);
924     pa_assert(dm);
925
926     pa_log_info("Get BT A2DP list");
927
928     /* FIXME : Give system_id for multi device */
929     if ((device = device_list_get_device(dm, DEVICE_TYPE_BT_A2DP, NULL, NULL)) != NULL) {
930         is_bt_on = TRUE;
931         bt_name = pa_tz_device_get_name(device);
932     }
933
934     pa_assert_se((reply = dbus_message_new_method_return(msg)));
935     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_bt_on,
936                                                  DBUS_TYPE_STRING, &bt_name,
937                                                  DBUS_TYPE_INVALID));
938     pa_assert_se(dbus_connection_send(conn, reply, NULL));
939     dbus_message_unref(reply);
940 }
941
942 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
943     pa_device_manager *dm = (pa_device_manager *)userdata;
944     char *type, *role;
945     pa_sink *sink;
946
947     pa_assert(conn);
948     pa_assert(msg);
949     pa_assert(dm);
950
951     pa_assert_se(dbus_message_get_args(msg, NULL,
952                                        DBUS_TYPE_STRING, &type,
953                                        DBUS_TYPE_STRING, &role,
954                                        DBUS_TYPE_INVALID));
955
956     if (!(sink = pa_device_manager_load_sink(dm, type, role)))
957         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
958     else
959         pa_dbus_send_empty_reply(conn, msg);
960 }
961
962 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
963     pa_device_manager *dm = (pa_device_manager *)userdata;
964     char *type, *role;
965
966     pa_assert(conn);
967     pa_assert(msg);
968     pa_assert(dm);
969
970     pa_assert_se(dbus_message_get_args(msg, NULL,
971                                        DBUS_TYPE_STRING, &type,
972                                        DBUS_TYPE_STRING, &role,
973                                        DBUS_TYPE_INVALID));
974
975     pa_device_manager_unload_sink(dm, type, role);
976
977     pa_dbus_send_empty_reply(conn, msg);
978 }
979
980 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
981     pa_device_manager *dm = (pa_device_manager *)userdata;
982     char *device_string;
983
984     pa_assert(conn);
985     pa_assert(msg);
986     pa_assert(dm);
987
988     pa_assert_se(dbus_message_get_args(msg, NULL,
989                                        DBUS_TYPE_STRING, &device_string,
990                                        DBUS_TYPE_INVALID));
991
992     pa_device_manager_unload_sink_with_device_string(dm, device_string);
993
994     pa_dbus_send_empty_reply(conn, msg);
995 }
996
997 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
998     pa_device_manager *dm = (pa_device_manager *)userdata;
999     char *type, *role;
1000     const char *device_string;
1001     dbus_bool_t is_playback;
1002
1003     pa_assert(conn);
1004     pa_assert(msg);
1005     pa_assert(dm);
1006
1007     pa_assert_se(dbus_message_get_args(msg, NULL,
1008                                        DBUS_TYPE_BOOLEAN, &is_playback,
1009                                        DBUS_TYPE_STRING, &type,
1010                                        DBUS_TYPE_STRING, &role,
1011                                        DBUS_TYPE_INVALID));
1012
1013     device_string = pa_device_manager_get_device_string(dm, is_playback, type, role);
1014     if (device_string == NULL) {
1015         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1016         return;
1017     }
1018
1019     pa_log_info("device string : %s", device_string);
1020
1021     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &device_string);
1022 }
1023
1024 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1025     pa_device_manager *dm = (pa_device_manager *)userdata;
1026     pa_tz_device *device;
1027     uint32_t device_idx;
1028
1029     pa_assert(conn);
1030     pa_assert(msg);
1031     pa_assert(dm);
1032
1033     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
1034         pa_tz_device_dump_info(device, PA_LOG_INFO);
1035     }
1036
1037     pa_dbus_send_empty_reply(conn, msg);
1038 }
1039
1040 static bool is_usb_output_device(pa_tz_device *device) {
1041     char *type;
1042     dm_device_direction_t direction;
1043     pa_sink *sink;
1044
1045     pa_assert(device);
1046
1047     type = pa_tz_device_get_type(device);
1048     if (!pa_safe_streq(type, DEVICE_TYPE_USB_AUDIO)) {
1049         pa_log_error("device(id:%d, %s) is not USB AUDIO type", pa_tz_device_get_id(device), type);
1050         return false;
1051     }
1052     direction = pa_tz_device_get_direction(device);
1053     if (direction & DM_DEVICE_DIRECTION_OUT) {
1054         if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1055             pa_log_error("sink is null");
1056             return false;
1057         }
1058     } else {
1059         pa_log_error("this device is not for output");
1060         return false;
1061     }
1062
1063     return true;
1064 }
1065
1066
1067 static bool is_supported_sample_format(pa_sample_format_t *supported_sample_formats, pa_sample_format_t sample_format) {
1068     int i;
1069
1070     pa_assert(supported_sample_formats);
1071     pa_assert(sample_format != PA_SAMPLE_INVALID);
1072
1073     for (i = 0; supported_sample_formats[i] != PA_SAMPLE_MAX; i++) {
1074         if (supported_sample_formats[i] == sample_format) {
1075             pa_log_info("%s is supported", pa_sample_format_to_string(sample_format));
1076             return true;
1077         }
1078     }
1079     pa_log_error("%s is not supported", pa_sample_format_to_string(sample_format));
1080     return false;
1081 }
1082
1083 static void handle_get_supported_sample_formats(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1084     pa_device_manager *dm = (pa_device_manager *)userdata;
1085     DBusMessage *reply = NULL;
1086     DBusMessageIter msg_iter, array_iter;
1087     dbus_int32_t device_id;
1088     pa_tz_device *device;
1089     pa_sink *sink;
1090     const char *format;
1091     int i;
1092
1093     pa_assert(conn);
1094     pa_assert(msg);
1095     pa_assert(dm);
1096
1097     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1098
1099     pa_assert_se(dbus_message_get_args(msg, NULL,
1100                                        DBUS_TYPE_INT32, &device_id,
1101                                        DBUS_TYPE_INVALID));
1102
1103     pa_log_info("Get supported sample formats of the device(id:%d)", device_id);
1104
1105     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1106         pa_log_error("could not find any device with id:%d", device_id);
1107         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1108         return;
1109     }
1110     if (!is_usb_output_device(device)) {
1111         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1112         return;
1113     }
1114     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1115         pa_log_error("could not get sink for normal role");
1116         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1117         return;
1118     }
1119
1120     if (!sink->supported_sample_formats) {
1121         pa_log_error("supported sample formats is not set on this sink");
1122         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1123         return;
1124     }
1125
1126     dbus_message_iter_init_append(reply, &msg_iter);
1127     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "s", &array_iter));
1128     for (i = 0; sink->supported_sample_formats[i] != PA_SAMPLE_MAX; i++) {
1129         format = pa_sample_format_to_string(sink->supported_sample_formats[i]);
1130         pa_log_info("%s is supported", format);
1131         dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &format);
1132     }
1133     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
1134     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1135     dbus_message_unref(reply);
1136 }
1137
1138 static void handle_set_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1139     pa_device_manager *dm = (pa_device_manager *)userdata;
1140     dbus_int32_t device_id;
1141     char *sample_format;
1142     pa_sample_format_t prev_selected_sample_format;
1143     pa_tz_device *device;
1144     pa_sink *sink;
1145     pa_sample_spec spec;
1146
1147     pa_assert(conn);
1148     pa_assert(msg);
1149     pa_assert(dm);
1150
1151     pa_assert_se(dbus_message_get_args(msg, NULL,
1152                                        DBUS_TYPE_INT32, &device_id,
1153                                        DBUS_TYPE_STRING, &sample_format,
1154                                        DBUS_TYPE_INVALID));
1155
1156     pa_log_info("Set sample format(%s) of the device(id:%d)", sample_format, device_id);
1157
1158     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1159         pa_log_error("could not find any device with id:%d", device_id);
1160         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1161         return;
1162     }
1163     if (!is_usb_output_device(device)) {
1164         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1165         return;
1166     }
1167     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1168         pa_log_error("could not get sink for normal role");
1169         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1170         return;
1171     }
1172
1173     /* use a supported sample format selected by user */
1174     if (!is_supported_sample_format(sink->supported_sample_formats, pa_parse_sample_format(sample_format))) {
1175         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1176         return;
1177     }
1178     prev_selected_sample_format = sink->selected_sample_format;
1179     sink->selected_sample_format = pa_parse_sample_format(sample_format);
1180
1181     if (prev_selected_sample_format != sink->selected_sample_format) {
1182         FILL_SAMPLE_SPEC_WITH_SELECTED(spec, sink);
1183         pa_sink_reconfigure(sink, &spec, false);
1184         if (sink->selected_sample_format != sink->sample_spec.format) {
1185             pa_log_error("failed to reconfigure");
1186             pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1187             sink->selected_sample_format = prev_selected_sample_format;
1188             return;
1189         }
1190         save_preference(dm, sink);
1191     }
1192
1193     pa_log_info("Set sample format(%s) of the device(id:%d) successfully", sample_format, device_id);
1194
1195     pa_dbus_send_empty_reply(conn, msg);
1196 }
1197
1198 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1199     pa_device_manager *dm = (pa_device_manager *)userdata;
1200     dbus_int32_t device_id;
1201     pa_tz_device *device;
1202     pa_sink *sink;
1203     const char *format;
1204
1205     pa_assert(conn);
1206     pa_assert(msg);
1207     pa_assert(dm);
1208
1209     pa_assert_se(dbus_message_get_args(msg, NULL,
1210                                        DBUS_TYPE_INT32, &device_id,
1211                                        DBUS_TYPE_INVALID));
1212
1213     pa_log_info("Get sample format of the device(id:%d)", device_id);
1214
1215     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1216         pa_log_error("could not find any device with id:%d", device_id);
1217         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1218         return;
1219     }
1220     if (!is_usb_output_device(device)) {
1221         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1222         return;
1223     }
1224     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1225         pa_log_error("could not get sink for normal role");
1226         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1227         return;
1228     }
1229
1230     format = pa_sample_format_to_string(sink->selected_sample_format);
1231     pa_log_info("Get sample format(%s) of the device(id:%d) successfully", format, device_id);
1232
1233     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &format);
1234 }
1235
1236 static bool is_supported_sample_rate(uint32_t *supported_sample_rates, uint32_t sample_rate) {
1237     int i;
1238
1239     pa_assert(supported_sample_rates);
1240
1241     for (i = 0; supported_sample_rates[i]; i++) {
1242         if (supported_sample_rates[i] == sample_rate) {
1243             pa_log_info("%u is supported", sample_rate);
1244             return true;
1245         }
1246     }
1247     pa_log_error("%u is not supported", sample_rate);
1248     return false;
1249 }
1250
1251 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1252     pa_device_manager *dm = (pa_device_manager *)userdata;
1253     DBusMessage *reply = NULL;
1254     DBusMessageIter msg_iter, array_iter;
1255     dbus_int32_t device_id;
1256     pa_tz_device *device;
1257     pa_sink *sink;
1258     int i;
1259
1260     pa_assert(conn);
1261     pa_assert(msg);
1262     pa_assert(dm);
1263
1264     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1265
1266     pa_assert_se(dbus_message_get_args(msg, NULL,
1267                                        DBUS_TYPE_INT32, &device_id,
1268                                        DBUS_TYPE_INVALID));
1269
1270     pa_log_info("Get supported sample rates of the device(id:%d)", device_id);
1271
1272     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1273         pa_log_error("could not find any device with id:%d", device_id);
1274         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1275         return;
1276     }
1277     if (!is_usb_output_device(device)) {
1278         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1279         return;
1280     }
1281     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1282         pa_log_error("could not get sink for normal role");
1283         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1284         return;
1285     }
1286
1287     if (!sink->supported_sample_rates) {
1288         pa_log_error("supported sample rates is not set on this sink");
1289         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1290         return;
1291     }
1292
1293     dbus_message_iter_init_append(reply, &msg_iter);
1294     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "u", &array_iter));
1295     for (i = 0; sink->supported_sample_rates[i]; i++) {
1296         pa_log_info("%u is supported", sink->supported_sample_rates[i]);
1297         dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_UINT32, &sink->supported_sample_rates[i]);
1298     }
1299     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
1300     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1301     dbus_message_unref(reply);
1302 }
1303
1304 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1305     pa_device_manager *dm = (pa_device_manager *)userdata;
1306     dbus_int32_t device_id;
1307     dbus_uint32_t sample_rate;
1308     uint32_t prev_selected_sample_rate;
1309     pa_tz_device *device;
1310     pa_sink *sink;
1311     pa_sample_spec spec;
1312
1313     pa_assert(conn);
1314     pa_assert(msg);
1315     pa_assert(dm);
1316
1317     pa_assert_se(dbus_message_get_args(msg, NULL,
1318                                        DBUS_TYPE_INT32, &device_id,
1319                                        DBUS_TYPE_UINT32, &sample_rate,
1320                                        DBUS_TYPE_INVALID));
1321
1322     pa_log_info("Set sample rate(%u) of the device(id:%d)", sample_rate, device_id);
1323
1324     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1325         pa_log_error("could not find any device with id:%d", device_id);
1326         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1327         return;
1328     }
1329     if (!is_usb_output_device(device)) {
1330         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1331         return;
1332     }
1333     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1334         pa_log_error("could not get sink for normal role");
1335         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1336         return;
1337     }
1338
1339     /* use a supported sample rate selected by user */
1340     if (!is_supported_sample_rate(sink->supported_sample_rates, sample_rate)) {
1341         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1342         return;
1343     }
1344     prev_selected_sample_rate = sink->selected_sample_rate;
1345     sink->selected_sample_rate = sample_rate;
1346
1347     if (prev_selected_sample_rate != sink->selected_sample_rate) {
1348         FILL_SAMPLE_SPEC_WITH_SELECTED(spec, sink);
1349         pa_sink_reconfigure(sink, &spec, false);
1350         if (sink->selected_sample_rate != sink->sample_spec.rate) {
1351             pa_log_error("failed to reconfigure");
1352             pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1353             sink->selected_sample_rate = prev_selected_sample_rate;
1354             return;
1355         }
1356         save_preference(dm, sink);
1357     }
1358
1359     pa_log_info("Set sample rate(%u) of the device(id:%d) successfully", sample_rate, device_id);
1360
1361     pa_dbus_send_empty_reply(conn, msg);
1362 }
1363
1364 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1365     pa_device_manager *dm = (pa_device_manager *)userdata;
1366     dbus_int32_t device_id;
1367     pa_tz_device *device;
1368     pa_sink *sink;
1369
1370     pa_assert(conn);
1371     pa_assert(msg);
1372     pa_assert(dm);
1373
1374     pa_assert_se(dbus_message_get_args(msg, NULL,
1375                                        DBUS_TYPE_INT32, &device_id,
1376                                        DBUS_TYPE_INVALID));
1377
1378     pa_log_info("Get sample rate of the device(id:%d)", device_id);
1379
1380     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1381         pa_log_error("could not find any device with id:%d", device_id);
1382         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1383         return;
1384     }
1385     if (!is_usb_output_device(device)) {
1386         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1387         return;
1388     }
1389     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1390         pa_log_error("could not get sink for normal role");
1391         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1392         return;
1393     }
1394
1395     pa_log_info("Get sample rate(%u) of the device(id:%d) successfully", sink->selected_sample_rate, device_id);
1396
1397     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &sink->selected_sample_rate);
1398 }
1399
1400 static void handle_set_specific_stream_only(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1401     pa_device_manager *dm = (pa_device_manager *)userdata;
1402     dbus_int32_t device_id;
1403     char *stream_role;
1404     pa_tz_device *device;
1405
1406     pa_assert(conn);
1407     pa_assert(msg);
1408     pa_assert(dm);
1409
1410     pa_assert_se(dbus_message_get_args(msg, NULL,
1411                                        DBUS_TYPE_INT32, &device_id,
1412                                        DBUS_TYPE_STRING, &stream_role,
1413                                        DBUS_TYPE_INVALID));
1414
1415     pa_log_info("Set the device(id:%d) only for the stream role(%s)", device_id, stream_role);
1416
1417     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1418         pa_log_error("could not find any device with id:%d", device_id);
1419         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1420         return;
1421     }
1422     if (!is_usb_output_device(device)) {
1423         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1424         return;
1425     }
1426     if (!pa_safe_streq(stream_role, "none") && !pa_stream_manager_is_valid_stream_role(dm->core, stream_role)) {
1427         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1428         return;
1429     }
1430
1431     pa_xfree(device->specified_stream_role);
1432     device->specified_stream_role = pa_xstrdup(stream_role);
1433
1434     pa_dbus_send_empty_reply(conn, msg);
1435 }
1436
1437 static void handle_get_specified_stream(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1438     pa_device_manager *dm = (pa_device_manager *)userdata;
1439     dbus_int32_t device_id;
1440     char *specified_stream_role;
1441     pa_tz_device *device;
1442
1443     pa_assert(conn);
1444     pa_assert(msg);
1445     pa_assert(dm);
1446
1447     pa_assert_se(dbus_message_get_args(msg, NULL,
1448                                        DBUS_TYPE_INT32, &device_id,
1449                                        DBUS_TYPE_INVALID));
1450
1451     pa_log_info("Get specified stream role for the device(id:%d)", device_id);
1452
1453     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1454         pa_log_error("could not find any device with id:%d", device_id);
1455         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1456         return;
1457     }
1458     if (!is_usb_output_device(device)) {
1459         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1460         return;
1461     }
1462
1463     specified_stream_role = device->specified_stream_role;
1464
1465     pa_log_info("stream role(%s) is specified for the device(id:%d)", device->specified_stream_role, device_id);
1466
1467     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &specified_stream_role);
1468 }
1469
1470 static void handle_set_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1471     pa_device_manager *dm = (pa_device_manager *)userdata;
1472     dbus_int32_t device_id;
1473     dbus_bool_t avoid_resampling;
1474     pa_tz_device *device;
1475     pa_sink *sink;
1476
1477     pa_assert(conn);
1478     pa_assert(msg);
1479     pa_assert(dm);
1480
1481     pa_assert_se(dbus_message_get_args(msg, NULL,
1482                                        DBUS_TYPE_INT32, &device_id,
1483                                        DBUS_TYPE_BOOLEAN, &avoid_resampling,
1484                                        DBUS_TYPE_INVALID));
1485
1486     pa_log_info("Set the device(id:%d) avoid-resampling(%d)", device_id, avoid_resampling);
1487
1488     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1489         pa_log_error("could not find any device with id:%d", device_id);
1490         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1491         return;
1492     }
1493     if (!is_usb_output_device(device)) {
1494         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1495         return;
1496     }
1497     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1498         pa_log_error("could not get sink for normal role");
1499         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1500         return;
1501     }
1502     if (sink->avoid_resampling == avoid_resampling) {
1503         pa_log_info("already set to %d", avoid_resampling);
1504     } else {
1505         sink->avoid_resampling = avoid_resampling;
1506         save_preference(dm, sink);
1507         pa_log_info("Set avoid-resampling(%d) to the device(id:%d)", avoid_resampling, device_id);
1508     }
1509
1510     pa_dbus_send_empty_reply(conn, msg);
1511 }
1512
1513 static void handle_get_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1514     pa_device_manager *dm = (pa_device_manager *)userdata;
1515     dbus_int32_t device_id;
1516     dbus_bool_t avoid_resampling;
1517     pa_tz_device *device;
1518     pa_sink *sink;
1519
1520     pa_assert(conn);
1521     pa_assert(msg);
1522     pa_assert(dm);
1523
1524     pa_assert_se(dbus_message_get_args(msg, NULL,
1525                                        DBUS_TYPE_INT32, &device_id,
1526                                        DBUS_TYPE_INVALID));
1527
1528     pa_log_info("Get avoid-resampling of the device(id:%d)", device_id);
1529
1530     if (!(device = device_list_get_device_by_id(dm, device_id))) {
1531         pa_log_error("could not find any device with id:%d", device_id);
1532         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1533         return;
1534     }
1535     if (!is_usb_output_device(device)) {
1536         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1537         return;
1538     }
1539     if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1540         pa_log_error("could not get sink for normal role");
1541         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1542         return;
1543     }
1544
1545     avoid_resampling = sink->avoid_resampling;
1546     pa_log_info("got avoid-resampling(%d) of the device(id:%d)", avoid_resampling, device_id);
1547
1548     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &avoid_resampling);
1549 }
1550
1551 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1552     pa_device_manager *dm = (pa_device_manager *)userdata;
1553     char *type;
1554     dbus_int32_t status;
1555
1556     pa_assert(conn);
1557     pa_assert(msg);
1558     pa_assert(dm);
1559
1560     pa_assert_se(dbus_message_get_args(msg, NULL,
1561                                        DBUS_TYPE_STRING, &type,
1562                                        DBUS_TYPE_INT32, &status,
1563                                        DBUS_TYPE_INVALID));
1564
1565     pa_log_debug("handle_test_device_status_change, type:%s, status:%d", type, status);
1566
1567     handle_device_status_changed(dm, type, NULL, NULL, status);
1568
1569     pa_dbus_send_empty_reply(conn, msg);
1570 }
1571
1572 static void handle_set_acm_mode(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1573     pa_device_manager *dm = (pa_device_manager *)userdata;
1574     uint32_t mode = 0;
1575
1576     pa_assert(conn);
1577     pa_assert(msg);
1578     pa_assert(dm);
1579
1580     pa_assert_se(dbus_message_get_args(msg, NULL,
1581                                        DBUS_TYPE_UINT32, &mode,
1582                                        DBUS_TYPE_INVALID));
1583
1584     pa_log_info("Set ACM mode to (%d)", mode);
1585
1586     if (mode == 0) {
1587         unload_acm_sink(dm);
1588     } else {
1589         /* For now, value of not 0 is just loading ACM sink. */
1590         if (!load_acm_sink(dm)) {
1591             pa_log_error("could not load acm sink");
1592             pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1593             return;
1594         }
1595     }
1596
1597     pa_dbus_send_empty_reply(conn, msg);
1598 }
1599
1600 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1601     const char *xml = DEVICE_MANAGER_INTROSPECT_XML;
1602     DBusMessage *r = NULL;
1603
1604     pa_assert(conn);
1605     pa_assert(msg);
1606     pa_assert(userdata);
1607
1608     pa_assert_se(r = dbus_message_new_method_return(msg));
1609     pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
1610
1611     if (r) {
1612         pa_assert_se(dbus_connection_send((conn), r, NULL));
1613         dbus_message_unref(r);
1614     }
1615
1616     return DBUS_HANDLER_RESULT_HANDLED;
1617 }
1618
1619 static DBusHandlerResult handle_device_manager_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1620     int method_idx = 0;
1621
1622     pa_assert(conn);
1623     pa_assert(msg);
1624     pa_assert(userdata);
1625
1626     for (method_idx = 0; method_idx < METHOD_HANDLER_MAX; method_idx++) {
1627         if (dbus_message_is_method_call(msg, DBUS_INTERFACE_DEVICE_MANAGER, method_handlers[method_idx].method_name)) {
1628             method_handlers[method_idx].receive_cb(conn, msg, userdata);
1629             return DBUS_HANDLER_RESULT_HANDLED;
1630         }
1631     }
1632
1633     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1634 }
1635
1636 static DBusHandlerResult method_call_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
1637     struct userdata *u = userdata;
1638     const char *path, *interface, *member;
1639
1640     pa_assert(c);
1641     pa_assert(m);
1642     pa_assert(u);
1643
1644     path = dbus_message_get_path(m);
1645     interface = dbus_message_get_interface(m);
1646     member = dbus_message_get_member(m);
1647
1648     pa_log_info("DeviceManager Method Call Handler : path=%s, interface=%s, member=%s", path, interface, member);
1649
1650     if (!pa_safe_streq(path, DBUS_OBJECT_DEVICE_MANAGER))
1651         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1652
1653     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1654         return handle_introspect(c, m, u);
1655         /*
1656     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get")) {
1657         return handle_get_property(c, m, u);
1658     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set")) {
1659         return  handle_set_property(c, m, u);
1660     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll")) {
1661         return handle_get_all_property(c, m, u);
1662         */
1663     } else {
1664         return handle_device_manager_methods(c, m, u);
1665     }
1666
1667     return DBUS_HANDLER_RESULT_HANDLED;
1668 }
1669
1670 static void fill_signal_msg_with_device(const char *description, DBusMessageIter *msg_iter, uint32_t event_id, pa_tz_device *device) {
1671     DBusMessageIter array_iter, device_iter;
1672     char *type, *name;
1673     dbus_int32_t device_id, direction, state, stream_id;
1674     dbus_int32_t vendor_id, product_id;
1675     dbus_bool_t is_running;
1676     pa_intset *stream_id_set = NULL;
1677     int32_t stream_id_val;
1678     int ret;
1679
1680     pa_assert(msg_iter);
1681     pa_assert(device);
1682
1683     dbus_message_iter_append_basic(msg_iter, DBUS_TYPE_UINT32, &event_id);
1684     pa_assert_se(dbus_message_iter_open_container(msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
1685
1686     direction = (dbus_int32_t)pa_tz_device_get_direction(device);
1687     type = pa_tz_device_get_type(device);
1688     name = pa_tz_device_get_name(device);
1689     device_id = (dbus_int32_t)pa_tz_device_get_id(device);
1690     state = pa_tz_device_get_state(device);
1691     vendor_id = (dbus_int32_t)pa_tz_device_get_vendor_id(device);
1692     product_id = (dbus_int32_t)pa_tz_device_get_product_id(device);
1693     is_running = (dbus_bool_t)pa_tz_device_is_running(device);
1694
1695     simple_device_dump(PA_LOG_INFO, description, device_id, type, name, direction, state);
1696
1697     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
1698     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
1699     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
1700     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
1701     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
1702     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
1703     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
1704     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
1705     if (state == DM_DEVICE_STATE_ACTIVATED)
1706         stream_id_set = pa_tz_device_get_stream_list(device);
1707     pa_assert_se(dbus_message_iter_open_container(&device_iter, DBUS_TYPE_ARRAY, "i", &array_iter));
1708     if (state == DM_DEVICE_STATE_ACTIVATED) {
1709         PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
1710             stream_id = stream_id_val;
1711             dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_INT32, &stream_id);
1712         }
1713     }
1714     pa_assert_se(dbus_message_iter_close_container(&device_iter, &array_iter));
1715     if (stream_id_set)
1716         pa_intset_free(stream_id_set);
1717     pa_assert_se(dbus_message_iter_close_container(msg_iter, &device_iter));
1718     pa_log_info("end of fill signal msg");
1719 }
1720
1721 void send_device_connection_changed_signal(uint32_t event_id, pa_tz_device *device, bool connected, pa_device_manager *dm) {
1722     DBusMessage *signal_msg;
1723     DBusMessageIter msg_iter;
1724     dbus_bool_t _connected = (dbus_bool_t)connected;
1725
1726     pa_assert(device);
1727     pa_assert(dm);
1728
1729     pa_log_info("Send device connection changed signal, event_id(%u)", event_id);
1730
1731     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceConnected"));
1732     dbus_message_iter_init_append(signal_msg, &msg_iter);
1733     fill_signal_msg_with_device(connected ? "[Connected]" : "[Disconnected]", &msg_iter, event_id, device);
1734
1735     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &_connected);
1736
1737     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1738
1739     dbus_message_unref(signal_msg);
1740     pa_log_info("end of send device connection changed signal");
1741 }
1742
1743 void send_device_info_changed_signal(uint32_t event_id, pa_tz_device *device, int changed_type, pa_device_manager *dm) {
1744     DBusMessage *signal_msg;
1745     DBusMessageIter msg_iter;
1746     const char *changed_prefix[] = {"[State Changed]", "[Direction Changed]", "[Avail-Mode Changed]"};
1747
1748     pa_assert(device);
1749     pa_assert(dm);
1750
1751     pa_log_debug("Send device info changed signal, event_id(%u)", event_id);
1752
1753     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceInfoChanged"));
1754     dbus_message_iter_init_append(signal_msg, &msg_iter);
1755     fill_signal_msg_with_device(changed_prefix[changed_type], &msg_iter, event_id, device);
1756     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &changed_type);
1757
1758     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1759
1760     dbus_message_unref(signal_msg);
1761 }
1762
1763 void send_device_state_changed_signal(uint32_t event_id, pa_tz_device *device, bool activated, pa_device_manager *dm) {
1764     DBusMessage *signal_msg;
1765     DBusMessageIter msg_iter;
1766
1767     pa_assert(device);
1768     pa_assert(dm);
1769
1770     pa_log_debug("Send device state changed signal, event_id(%u)", event_id);
1771
1772     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceStateChanged"));
1773     dbus_message_iter_init_append(signal_msg, &msg_iter);
1774     fill_signal_msg_with_device(activated ? "[Activated]" : "[Deactivated]", &msg_iter, event_id, device);
1775
1776     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1777
1778     dbus_message_unref(signal_msg);
1779 }
1780
1781 void send_device_running_changed_signal(uint32_t event_id, pa_tz_device *device, bool is_running, pa_device_manager *dm) {
1782     DBusMessage *signal_msg;
1783     DBusMessageIter msg_iter;
1784
1785     pa_assert(device);
1786     pa_assert(dm);
1787
1788     pa_log_debug("Send device running changed signal, event_id(%u)", event_id);
1789
1790     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceRunningChanged"));
1791     dbus_message_iter_init_append(signal_msg, &msg_iter);
1792     fill_signal_msg_with_device(is_running ? "[Running]" : "[NotRunning]", &msg_iter, event_id, device);
1793
1794     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1795
1796     dbus_message_unref(signal_msg);
1797 }
1798
1799 static void endpoint_init(pa_device_manager *dm) {
1800     static const DBusObjectPathVTable vtable_endpoint = {
1801         .message_function = method_call_handler,
1802     };
1803
1804     pa_log_info("Device manager dbus endpoint init");
1805
1806     if (dm && dm->dbus_conn) {
1807         if (!dbus_connection_register_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER, &vtable_endpoint, dm))
1808             pa_log_error("Failed to register object path");
1809     } else {
1810         pa_log_error("Cannot get dbus connection to register object path");
1811     }
1812 }
1813
1814 static void endpoint_done(pa_device_manager *dm) {
1815     pa_log_info("Device manager dbus endpoint done");
1816     if (dm && dm->dbus_conn) {
1817         if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER))
1818             pa_log_error("Failed to unregister object path");
1819     } else {
1820         pa_log_error("Cannot get dbus connection to unregister object path");
1821     }
1822 }
1823
1824 static int watch_signals(pa_device_manager *dm) {
1825     DBusError error;
1826
1827     pa_assert(dm);
1828     pa_assert(dm->dbus_conn);
1829
1830     dbus_error_init(&error);
1831
1832     pa_log_info("Watch Dbus signals");
1833
1834     if (!dbus_connection_add_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm, NULL)) {
1835         pa_log_error("Unable to add D-Bus filter : %s: %s", error.name, error.message);
1836         goto fail;
1837     }
1838
1839     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) {
1840         pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
1841         goto fail;
1842     }
1843     return 0;
1844
1845 fail:
1846     dbus_error_free(&error);
1847     return -1;
1848 }
1849
1850 static void unwatch_signals(pa_device_manager *dm) {
1851     pa_log_info("Unwatch Dbus signals");
1852
1853     pa_assert(dm);
1854     pa_assert(dm->dbus_conn);
1855
1856     pa_dbus_remove_matches(pa_dbus_connection_get(dm->dbus_conn), FILTER_DEVICED_SYSNOTI, FILTER_SOUND_SERVER, FILTER_BLUEZ, FILTER_MIRRORING, NULL);
1857     dbus_connection_remove_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm);
1858 }
1859
1860 void init_dm_dbus(pa_device_manager *dm) {
1861     DBusError error;
1862     pa_dbus_connection *connection = NULL;
1863
1864     pa_assert(dm);
1865     pa_log_info("init Dbus");
1866     dbus_error_init(&error);
1867
1868     if (!(connection = pa_dbus_bus_get(dm->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
1869         if (connection) {
1870             pa_dbus_connection_unref(connection);
1871         }
1872         pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
1873         goto fail;
1874     } else {
1875         pa_log_info("Got dbus connection");
1876     }
1877
1878     dm->dbus_conn = connection;
1879
1880     if (watch_signals(dm) < 0)
1881         pa_log_error("dbus watch signals failed");
1882     else
1883         pa_log_debug("dbus ready to get signals");
1884
1885     endpoint_init(dm);
1886
1887 fail:
1888     dbus_error_free(&error);
1889 }
1890
1891 void deinit_dm_dbus(pa_device_manager *dm) {
1892     pa_assert(dm);
1893
1894     pa_log_info("deinit Dbus");
1895
1896     endpoint_done(dm);
1897     unwatch_signals(dm);
1898
1899     if (dm->dbus_conn) {
1900         pa_dbus_connection_unref(dm->dbus_conn);
1901         dm->dbus_conn = NULL;
1902     }
1903 }
1904 #endif