275c439a319d12b02c4f1be819455f78ef0933d7
[platform/core/multimedia/pulseaudio-modules-tizen.git] / src / device-manager.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2015-2016 Jeonho Mok <jho.mok@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 #include <string.h>
27 #include <ctype.h>
28 #include <stdbool.h>
29 #include <json.h>
30 #include <pulse/proplist.h>
31 #include <pulse/util.h>
32 #include <pulse/rtclock.h>
33 #include <pulsecore/core-subscribe.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/log.h>
36 #include <pulsecore/strbuf.h>
37 #include <pulsecore/modargs.h>
38 #include <pulsecore/namereg.h>
39 #include <pulsecore/shared.h>
40 #include <pulsecore/dynarray.h>
41 #include <pulsecore/hashmap.h>
42
43 #include <vconf.h>
44 #include <vconf-keys.h>
45 #ifdef HAVE_DBUS
46 #include <pulsecore/dbus-shared.h>
47 #include <pulsecore/dbus-util.h>
48 #include <pulsecore/protocol-dbus.h>
49 #endif
50
51 #include "communicator.h"
52 #include "hal-interface.h"
53 #include "device-manager.h"
54
55 #define SHARED_DEVICE_MANAGER "tizen-device-manager"
56
57 #define DEVICE_MAP_FILE                    "/etc/pulse/device-map.json"
58 #define DEVICE_STR_MAX                      30
59 #define DEVICE_DIRECTION_MAX                3
60 #define DEVICE_PARAM_STRING_MAX             150
61 #define DEVICE_AVAIL_COND_NUM_MAX           2
62 #define DEVICE_AVAIL_COND_STR_MAX           6
63 #define DEVICE_FILE_PER_TYPE_MAX            4
64 #define DEVICE_FILE_STRING_MAX              4
65 #define DEVICE_TYPE_STR_MAX                 20
66 #define DEVICE_ROLE_STR_MAX                 15
67
68 #define DEVICE_TYPE_OBJECT                  "device-types"
69 #define DEVICE_FILE_OBJECT                  "device-files"
70 #define DEVICE_TYPE_PROP_DEVICE_TYPE        "device-type"
71 #define DEVICE_TYPE_PROP_PLAYBACK_DEVICES   "playback-devices"
72 #define DEVICE_TYPE_PROP_CAPTURE_DEVICES    "capture-devices"
73 #define DEVICE_TYPE_PROP_DEVICE_STRING      "device-string"
74 #define DEVICE_TYPE_PROP_ROLE               "role"
75
76 #define DEVICE_TYPE_STR_MAX                 20
77
78 /* Properties of sink/sources */
79 #define DEVICE_API_BLUEZ                    "bluez"
80 #define DEVICE_API_ALSA                     "alsa"
81 #define DEVICE_API_NULL                     "null"
82 #define DEVICE_BUS_USB                      "usb"
83 #define DEVICE_CLASS_SOUND                  "sound"
84 #define DEVICE_CLASS_MONITOR                "monitor"
85
86 /* Dbus defines */
87 #define DBUS_INTERFACE_DEVICE_MANAGER       "org.pulseaudio.DeviceManager"
88 #define DBUS_OBJECT_DEVICE_MANAGER          "/org/pulseaudio/DeviceManager"
89
90 #define DBUS_INTERFACE_DEVICED_SYSNOTI      "org.tizen.system.deviced.SysNoti"
91 #define DBUS_OBJECT_DEVICED_SYSNOTI         "/Org/Tizen/System/DeviceD/SysNoti"
92
93 #define DBUS_INTERFACE_SOUND_SERVER         "org.tizen.SoundServer1"
94 #define DBUS_OBJECT_SOUND_SERVER            "/org/tizen/SoundServer1"
95
96 #define DBUS_SERVICE_BLUEZ                  "org.bluez"
97 #define DBUS_INTERFACE_BLUEZ_HEADSET        "org.bluez.Headset"
98 #define DBUS_INTERFACE_BLUEZ_DEVICE         "org.bluez.Device1"
99 #define DBUS_OBJECT_BLUEZ                   "/org/bluez"
100
101 #define DBUS_INTERFACE_MIRRORING_SERVER     "org.tizen.scmirroring.server"
102 #define DBUS_OBJECT_MIRRORING_SERVER        "/org/tizen/scmirroring/server"
103
104 #define DBUS_SERVICE_HFP_AGENT "org.bluez.ag_agent"
105 #define DBUS_OBJECT_HFP_AGENT "/org/bluez/hfp_agent"
106 #define DBUS_INTERFACE_HFP_AGENT "Org.Hfp.App.Interface"
107
108 #define DEVICE_MANAGER_INTROSPECT_XML                                                       \
109     DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                                               \
110     "<node>\n"                                                                              \
111     " <interface name=\"" DBUS_INTERFACE_DEVICE_MANAGER "\">\n"                             \
112     "  <method name=\"GetConnectedDeviceList\">\n"                                          \
113     "   <arg name=\"mask_flags\" direction=\"in\" type=\"i\"/>\n"                           \
114     "   <arg name=\"ConnectedDeviceList\" direction=\"out\" type=\"a(isiisii)\"/>\n"        \
115     "  </method>\n"                                                                         \
116     "  <method name=\"GetDeviceById\">\n"                                                   \
117     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
118     "   <arg name=\"device\" direction=\"out\" type=\"(isiisii)\"/>\n"                      \
119     "  </method>\n"                                                                         \
120     "  <method name=\"IsStreamOnDevice\">\n"                                                \
121     "   <arg name=\"stream_id\" direction=\"in\" type=\"i\"/>\n"                            \
122     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
123     "   <arg name=\"is_on\" direction=\"out\" type=\"b\"/>\n"                               \
124     "  </method>\n"                                                                         \
125     "  <method name='GetBTA2DPStatus'>"                                                     \
126     "    <arg type='b' name='is_bt_on' direction='out'/>"                                   \
127     "    <arg type='s' name='bt_name' direction='out'/>"                                    \
128     "  </method>"                                                                           \
129     "  <method name=\"LoadSink\">\n"                                                        \
130     "   <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n"                          \
131     "   <arg name=\"role\" direction=\"in\" type=\"s\"/>\n"                                 \
132     "  </method>\n"                                                                         \
133     "  <method name=\"UnloadSink\">\n"                                                      \
134     "   <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n"                          \
135     "   <arg name=\"role\" direction=\"in\" type=\"s\"/>\n"                                 \
136     "  </method>\n"                                                                         \
137     "  <method name=\"GetSupportedSampleRates\">\n"                                         \
138     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
139     "   <arg name=\"sample_rates\" direction=\"out\" type=\"a(u)\"/>\n"                     \
140     "  </method>\n"                                                                         \
141     "  <method name=\"SetSampleRate\">\n"                                                   \
142     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
143     "   <arg name=\"sample_rate\" direction=\"in\" type=\"u\"/>\n"                          \
144     "  </method>\n"                                                                         \
145     "  <method name=\"GetSampleRate\">\n"                                                   \
146     "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
147     "   <arg name=\"sample_rate\" direction=\"out\" type=\"u\"/>\n"                         \
148     "  </method>\n"                                                                         \
149     "  <method name=\"DumpDeviceList\">\n"                                                  \
150     "  </method>\n"                                                                         \
151     "  <method name=\"TestStatusChange\">\n"                                                \
152     "   <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n"                          \
153     "   <arg name=\"status\" direction=\"in\" type=\"i\"/>\n"                               \
154     "  </method>\n"                                                                         \
155     "  <property name=\"PropertyTest1\" type=\"i\" access=\"readwrite\"/>\n"                \
156     "  <property name=\"PropertyTest2\" type=\"s\" access=\"read\"/>\n"                     \
157     "  <signal name=\"DeviceConnected\">\n"                                                 \
158     "   <arg name=\"arg1\" type=\"i\"/>\n"                                                  \
159     "  </signal>\n"                                                                         \
160     "  <signal name=\"DeviceInfoChanged\">\n"                                               \
161     "   <arg name=\"arg1\" type=\"s\"/>\n"                                                  \
162     "  </signal>\n"                                                                         \
163     " </interface>\n"                                                                       \
164     " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n"                             \
165     "  <method name=\"Introspect\">\n"                                                      \
166     "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"                                \
167     "  </method>\n"                                                                         \
168     " </interface>\n"                                                                       \
169     " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n"                                 \
170     "  <method name=\"Get\">\n"                                                             \
171     "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"                       \
172     "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"                        \
173     "   <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"                               \
174     "  </method>\n"                                                                         \
175     "  <method name=\"Set\">\n"                                                             \
176     "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"                       \
177     "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"                        \
178     "   <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"                                \
179     "  </method>\n"                                                                         \
180     "  <method name=\"GetAll\">\n"                                                          \
181     "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"                       \
182     "   <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n"                           \
183     "  </method>\n"                                                                         \
184     " </interface>\n"                                                                       \
185     "</node>\n"
186
187 #define FILTER_DEVICED_SYSNOTI                             \
188     "type='signal',"                                       \
189     " interface='" DBUS_INTERFACE_DEVICED_SYSNOTI "'"
190
191 #define FILTER_SOUND_SERVER                                \
192     "type='signal',"                                       \
193     " interface='" DBUS_INTERFACE_SOUND_SERVER "'"
194
195 #define FILTER_MIRRORING                                   \
196     "type='signal',"                                       \
197     " interface='" DBUS_INTERFACE_MIRRORING_SERVER "', member='miracast_wfd_source_status_changed'"
198
199 #define FILTER_BLUEZ                                       \
200     "type='signal',"                                       \
201     " interface='" DBUS_INTERFACE_BLUEZ_HEADSET "', member='PropertyChanged'"
202
203 static const char* const valid_alsa_device_modargs[] = {
204     "name",
205     "sink_name",
206     "sink_properties",
207     "source_name",
208     "source_properties",
209     "namereg_fail",
210     "device",
211     "device_id",
212     "format",
213     "rate",
214     "alternate_rate",
215     "channels",
216     "channel_map",
217     "fragments",
218     "fragment_size",
219     "mmap",
220     "tsched",
221     "tsched_buffer_size",
222     "tsched_buffer_watermark",
223     "ignore_dB",
224     "control",
225     "rewind_safeguard",
226     "deferred_volume",
227     "deferred_volume_safety_margin",
228     "deferred_volume_extra_delay",
229     "fixed_latency_range",
230     "need_audio_pm",
231     "start_threshold",
232     NULL
233 };
234
235 #define BT_CVSD_CODEC_ID 1 // narrow-band
236 #define BT_MSBC_CODEC_ID 2 // wide-band
237 /*
238     Enums for represent values which is defined on other module.
239     This is needed to identify values which are sent by dbus or vconf.
240 */
241 typedef enum external_value_earjack_type {
242     EARJACK_DISCONNECTED = 0,
243     EARJACK_TYPE_SPK_ONLY = 1,
244     EARJACK_TYPE_SPK_WITH_MIC = 3,
245 } external_value_earjack_t;
246
247 typedef enum external_value_bt_sco_type {
248     BT_SCO_DISCONNECTED = 0,
249     BT_SCO_CONNECTED = 1,
250 } external_value_bt_sco_t;
251
252 typedef enum external_value_forwarding_type {
253     FORWARDING_DISCONNECTED = 0,
254     FORWARDING_CONNECTED = 1,
255 } external_value_mirroring_t;
256
257 typedef enum external_value_hdmi_type {
258     HDMI_AUDIO_DISCONNECTED = -1,
259     HDMI_AUDIO_NOT_AVAILABLE = 0,
260     HDMI_AUDIO_AVAILABLE = 1,
261 } external_value_hdmi_t;
262
263
264 /*
265     Enums for represent device detected status (through dbus)
266     When some device is detected, one of these values should be saved in device_status hashmap.
267     device_detected_type_t is needed to distinguish detected device-types ( ex. earjack which can be out or both way)
268     So If you just want to know whether detected or not, can device_detected_t as mask.
269 */
270
271 typedef enum device_detected_type {
272     DEVICE_DISCONNECTED = 0x0,
273     DEVICE_CONNECTED = 0x1,
274     DEVICE_CONNECTED_AUDIO_JACK_4P = DEVICE_CONNECTED | 0x2,
275     DEVICE_CONNECTED_AUDIO_JACK_3P = DEVICE_CONNECTED | 0x4,
276     DEVICE_CONNECTED_SCO = DEVICE_CONNECTED | 0x8,
277     DEVICE_OPENED_SCO = DEVICE_CONNECTED | 0xF,
278 } device_detected_type_t;
279
280 typedef enum dm_device_class_type {
281     DM_DEVICE_CLASS_NONE,
282     DM_DEVICE_CLASS_ALSA,
283     DM_DEVICE_CLASS_TIZEN,
284     DM_DEVICE_CLASS_BT,
285     DM_DEVICE_CLASS_NULL,
286     DM_DEVICE_CLASS_MAX,
287 } dm_device_class_t;
288
289 typedef enum {
290     DEVICE_IO_DIRECTION_IN_FLAG      = 0x0001,  /**< Flag for input devices */
291     DEVICE_IO_DIRECTION_OUT_FLAG     = 0x0002,  /**< Flag for output devices */
292     DEVICE_IO_DIRECTION_BOTH_FLAG    = 0x0004,  /**< Flag for input/output devices (both directions are available) */
293     DEVICE_TYPE_INTERNAL_FLAG        = 0x0010,  /**< Flag for built-in devices */
294     DEVICE_TYPE_EXTERNAL_FLAG        = 0x0020,  /**< Flag for external devices */
295     DEVICE_STATE_DEACTIVATED_FLAG    = 0x1000,  /**< Flag for deactivated devices */
296     DEVICE_STATE_ACTIVATED_FLAG      = 0x2000,  /**< Flag for activated devices */
297     DEVICE_ALL_FLAG                  = 0xFFFF,  /**< Flag for all devices */
298 } device_flag_t;
299
300 typedef enum {
301     DEVICE_IO_DIRECTION_FLAGS        = 0x000F,  /**< Flag for io direction */
302     DEVICE_TYPE_FLAGS                = 0x00F0,  /**< Flag for device type */
303     DEVICE_STATE_FLAGS               = 0xF000,  /**< Flag for device state */
304 } device_flags_type_t;
305
306 typedef enum dm_device_bt_mode_type {
307     DM_DEVICE_BT_MODE_MEDIA = 0x1,
308     DM_DEVICE_BT_MODE_VOICE = 0x2
309 } dm_device_bt_mode_t;
310
311 typedef enum dm_device_changed_into_type {
312     DM_DEVICE_CHANGED_INFO_STATE,
313     DM_DEVICE_CHANGED_INFO_IO_DIRECTION,
314     DM_DEVICE_CHANGED_INFO_MAX
315 } dm_device_changed_info_t;
316
317
318 /*
319     Structure to save parsed information about device-file.
320 */
321 struct device_file_map {
322     /* { key:device_string -> value:device_file_prop } */
323     pa_idxset *playback;
324     pa_idxset *capture;
325 };
326
327 /***************** structures for static information get from json *********/
328
329 /*
330     Structure for informations related to some device-file(ex. 0:0)
331 */
332 struct device_file_info {
333     /*
334         String for identify target device.
335         ex) alsa:0,0  or null ..
336     */
337     const char *device_string;
338     /*
339         For save roles which are supported on device file, and parameters.
340         { key:device_role -> value:parameters for load sink/source }
341         ex) "normal"->"rate=44100 tsched=0", "uhqa"->"rate=192000 mmap=1"
342     */
343     pa_hashmap *roles;
344     /*
345         For save device-types related to device file.
346         { key:device_type-> value:pulse_device_prop }
347     */
348     pa_hashmap *device_types;
349 };
350
351 /* structure for represent device-types(ex. builtin-speaker) properties*/
352 struct device_type_info {
353     const char *type;
354     /*
355         For save supported roles and related device-file.
356         { key:role -> value:device_string ]
357     */
358     pa_hashmap *playback_devices;
359     pa_hashmap *capture_devices;
360 };
361
362 struct device_status_info {
363     char *type;
364     char *name;
365     /* Identify devices among same device-types (for multi-device), currently not works*/
366     char *system_id;
367     device_detected_type_t detected;
368 };
369
370 struct pulse_device_prop {
371     /* roles related to (device_type + device_file)*/
372     pa_idxset *roles;
373     /* For save that this devie_type is activated or not on sink/source */
374     int status;
375 };
376 /******************************************************************************/
377 struct pa_device_manager {
378     PA_REFCNT_DECLARE;
379
380     pa_core *core;
381     pa_hook_slot *sink_put_hook_slot, *sink_unlink_hook_slot, *sink_state_changed_slot;
382     pa_hook_slot *source_put_hook_slot, *source_unlink_hook_slot, *source_state_changed_slot;
383     pa_hook_slot *comm_hook_device_connection_changed_slot;
384     pa_hook_slot *comm_hook_device_state_changed_slot;
385     pa_hook_slot *comm_hook_device_running_changed_slot;
386     pa_communicator *comm;
387     pa_hal_interface *hal_interface;
388
389     /*
390        Idxset for save parsed information about device-type.
391        { device_type_info }
392     */
393     pa_idxset *type_infos;
394     /* For save Parsed information about device-file */
395     struct device_file_map *file_map;
396
397     /* device list */
398     pa_idxset *device_list;
399     /*
400        Hashmap for save statuses got through dbus.
401        { key:device_type -> value:(audio_detected_type_t or device_detected_t) }
402     */
403     pa_idxset *device_status;
404     pa_dbus_connection *dbus_conn;
405 };
406
407 struct composite_type {
408     const char *type;
409     const char *role;
410 };
411
412 #ifdef HAVE_DBUS
413
414 /*** Defines for method handle ***/
415 /* method handlers */
416 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
417 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata);
418 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
419 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
420 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata);
421 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
422 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
423 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
424 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
425 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata);
426 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata);
427 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
428 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata);
429
430 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name);
431
432 enum method_handler_index {
433     METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST,
434     METHOD_HANDLER_GET_DEVICE_BY_ID,
435     METHOD_HANDLER_IS_STREAM_ON_DEVICE,
436     METHOD_HANDLER_GET_BT_A2DP_STATUS,
437     METHOD_HANDLER_LOAD_SINK,
438     METHOD_HANDLER_UNLOAD_SINK,
439     METHOD_HANDLER_UNLOAD_SINK_WITH_DEVICE_STRING,
440     METHOD_HANDLER_GET_DEVICE_STRING,
441     METHOD_HANDLER_GET_SUPPORTED_SAMPLE_RATES,
442     METHOD_HANDLER_SET_SAMPLE_RATE,
443     METHOD_HANDLER_GET_SAMPLE_RATE,
444     METHOD_HANDLER_DUMP_DEVICE_LIST,
445     METHOD_HANDLER_STATUS_TEST,
446     METHOD_HANDLER_MAX
447 };
448
449 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
450     [METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST] = {
451         .method_name = "GetConnectedDeviceList",
452         .receive_cb = handle_get_connected_device_list },
453     [METHOD_HANDLER_GET_DEVICE_BY_ID] = {
454         .method_name = "GetDeviceById",
455         .receive_cb = handle_get_device_by_id },
456     [METHOD_HANDLER_IS_STREAM_ON_DEVICE] = {
457         .method_name = "IsStreamOnDevice",
458         .receive_cb = handle_is_stream_on_device },
459     [METHOD_HANDLER_GET_BT_A2DP_STATUS] = {
460         .method_name = "GetBTA2DPStatus",
461         .receive_cb = handle_get_bt_a2dp_status },
462     [METHOD_HANDLER_LOAD_SINK] = {
463         .method_name = "LoadSink",
464         .receive_cb = handle_load_sink },
465     [METHOD_HANDLER_UNLOAD_SINK] = {
466         .method_name = "UnloadSink",
467         .receive_cb = handle_unload_sink },
468     [METHOD_HANDLER_UNLOAD_SINK_WITH_DEVICE_STRING] = {
469         .method_name = "UnloadSinkWithDeviceString",
470         .receive_cb = handle_unload_sink_with_device_string },
471     [METHOD_HANDLER_GET_DEVICE_STRING] = {
472         .method_name = "GetDeviceString",
473         .receive_cb = handle_get_device_string },
474     [METHOD_HANDLER_GET_SUPPORTED_SAMPLE_RATES] = {
475         .method_name = "GetSupportedSampleRates",
476         .receive_cb = handle_get_supported_sample_rates },
477     [METHOD_HANDLER_SET_SAMPLE_RATE] = {
478         .method_name = "SetSampleRate",
479         .receive_cb = handle_set_sample_rate },
480     [METHOD_HANDLER_GET_SAMPLE_RATE] = {
481         .method_name = "GetSampleRate",
482         .receive_cb = handle_get_sample_rate },
483     [METHOD_HANDLER_DUMP_DEVICE_LIST] = {
484         .method_name = "DumpDeviceList",
485         .receive_cb = handle_dump_device_list },
486     [METHOD_HANDLER_STATUS_TEST] = {
487         .method_name = "TestStatusChange",
488         .receive_cb = handle_test_device_status_change },
489 };
490
491 #endif
492
493 enum internal_codec_device_index {
494     DEVICE_INDEX_BUILTIN_SPEAKER,
495     DEVICE_INDEX_BUILTIN_RECEIVER,
496     DEVICE_INDEX_BUILTIN_MIC,
497     DEVICE_INDEX_AUDIO_JACK,
498     DEVICE_INDEX_BT_SCO,
499     DEVICE_INDEX_MAX
500 };
501
502 typedef struct _internal_codec_device {
503     const char *type;
504     bool is_running[2]; /* index[in:0, out:1] */
505 } internal_codec_device;
506
507 static internal_codec_device internal_codec_devices[DEVICE_INDEX_MAX] = {
508     [DEVICE_INDEX_BUILTIN_SPEAKER] = {
509         .type = DEVICE_TYPE_SPEAKER,
510         .is_running[0] = false,
511         .is_running[1] = false },
512     [DEVICE_INDEX_BUILTIN_RECEIVER] = {
513         .type = DEVICE_TYPE_RECEIVER,
514         .is_running[0] = false,
515         .is_running[1] = false },
516     [DEVICE_INDEX_BUILTIN_MIC] = {
517         .type = DEVICE_TYPE_MIC,
518         .is_running[0] = false,
519         .is_running[1] = false },
520     [DEVICE_INDEX_AUDIO_JACK] = {
521         .type = DEVICE_TYPE_AUDIO_JACK,
522         .is_running[0] = false,
523         .is_running[1] = false },
524     [DEVICE_INDEX_BT_SCO] = {
525         .type = DEVICE_TYPE_BT_SCO,
526         .is_running[0] = false,
527         .is_running[1] = false },
528 };
529
530 static inline void internal_codec_devices_dump() {
531     uint32_t i;
532     pa_log_info("========== devices using internal codec ==========");
533     for (i = 0; i < DEVICE_INDEX_MAX; i++)
534         pa_log_info(" type[%18s], is_running[in:%d,out:%d]", internal_codec_devices[i].type,
535                      internal_codec_devices[i].is_running[0], internal_codec_devices[i].is_running[1]);
536     pa_log_info("==================================================");
537 }
538
539 static inline void simple_device_dump(pa_log_level_t level, const char *prefix, int id, const char *type, const char *name, int direction, int state) {
540     pa_logl(level, "%s device id(%d) type(%s) name (%s) direction(%d) state(%d)",
541             pa_strempty(prefix), id, pa_strnull(type), pa_strnull(name), direction, state);
542 }
543
544 static void find_device_and_set_running(pa_device_manager *dm, const char *type, bool is_running) {
545     pa_tz_device* device;
546
547     pa_assert(dm);
548
549     if (!type)
550         return;
551
552     pa_log_info("find device [%s]", type);
553
554     if ((device = pa_device_manager_get_device(dm, type))) {
555         if (pa_tz_device_is_use_internal_codec(device))
556             pa_tz_device_set_running_and_notify(device, is_running);
557         else
558             pa_log_warn("this device [%s] does not use internal codec, skip it", type);
559     } else {
560         pa_log_warn("cound not find a device of [%s]", type);
561     }
562 }
563
564 static void type_info_free_func(struct device_type_info *type_info) {
565     if (!type_info)
566         return;
567
568     if (type_info->playback_devices)
569         pa_hashmap_free(type_info->playback_devices);
570     if (type_info->capture_devices)
571         pa_hashmap_free(type_info->capture_devices);
572
573 }
574
575 static void file_info_free_func(struct device_file_info *file_info) {
576     if (!file_info)
577         return;
578
579     if (file_info->roles)
580         pa_hashmap_free(file_info->roles);
581 }
582
583 static dm_device_class_t device_string_get_class(const char *device_string) {
584     if (!device_string) {
585         return DM_DEVICE_CLASS_NONE;
586     }
587
588     if (device_string == strstr(device_string, "alsa")) {
589         return DM_DEVICE_CLASS_ALSA;
590     } else if (device_string == strstr(device_string, "null")) {
591         return DM_DEVICE_CLASS_NULL;
592     } else if (device_string == strstr(device_string, "tizen")) {
593         return DM_DEVICE_CLASS_TIZEN;
594     } else {
595         return DM_DEVICE_CLASS_NONE;
596     }
597 }
598
599 static const char* device_string_get_value(const char *device_string) {
600     int len;
601     const char *end_p, *value_p;
602
603     if (!device_string) {
604         return NULL;
605     }
606
607     len = strlen(device_string);
608     end_p = device_string + len -1;
609
610     if (!(value_p = strchr(device_string, ':'))) {
611         return NULL;
612     }
613     if (value_p < end_p) {
614         return value_p + 1;
615     } else {
616         return NULL;
617     }
618 }
619
620 static pa_proplist* pulse_device_get_proplist(pa_object *pdevice) {
621     if (pa_sink_isinstance(pdevice))
622         return PA_SINK(pdevice)->proplist;
623     else
624         return PA_SOURCE(pdevice)->proplist;
625 }
626
627 static bool pulse_device_is_alsa(pa_object *pdevice) {
628     const char *api_name = NULL;
629     pa_proplist *prop;
630
631     if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
632         return false;
633
634     if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
635         if (pa_streq(api_name, DEVICE_API_ALSA)) {
636             return true;
637         } else {
638             return false;
639         }
640     } else {
641         return false;
642     }
643 }
644
645 static bool pulse_device_is_bluez(pa_object *pdevice) {
646     const char *api_name = NULL;
647     pa_proplist *prop;
648
649     if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
650         return false;
651
652     if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
653         if (pa_streq(api_name, DEVICE_API_BLUEZ)) {
654             return true;
655         } else {
656             return false;
657         }
658     } else {
659         return false;
660     }
661 }
662
663 static bool pulse_device_is_tizenaudio(pa_object *pdevice) {
664     if (!pdevice)
665         return false;
666
667     if (pa_sink_isinstance(pdevice)) {
668         pa_sink *sink = PA_SINK(pdevice);
669         return pa_streq(sink->module->name, "module-tizenaudio-sink");
670     } else {
671         pa_source *source = PA_SOURCE(pdevice);
672         return pa_streq(source->module->name, "module-tizenaudio-source");
673     }
674 }
675
676 static bool pulse_device_is_usb(pa_object *pdevice) {
677     const char *bus_name = NULL;
678     pa_proplist *prop;
679
680     if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
681         return false;
682
683     if ((bus_name = pa_proplist_gets(prop, PA_PROP_DEVICE_BUS))) {
684         if (pa_streq(bus_name, DEVICE_BUS_USB)) {
685             return true;
686         } else {
687             return false;
688         }
689     } else {
690         pa_log_debug("This device doesn't have property '%s'", PA_PROP_DEVICE_BUS);
691         return false;
692     }
693 }
694
695 static bool pulse_device_is_null(pa_object *pdevice) {
696     pa_sink *sink;
697     pa_source *source;
698
699     if (!pdevice)
700         return false;
701
702     if (pa_sink_isinstance(pdevice)) {
703         sink = PA_SINK(pdevice);
704         return pa_streq(sink->module->name, "module-null-sink");
705     } else {
706         source = PA_SOURCE(pdevice);
707         return pa_streq(source->module->name, "module-null-source");
708     }
709 }
710
711 static const char* pulse_device_get_device_string_removed_argument(pa_object *pdevice) {
712     static char removed_param[DEVICE_PARAM_STRING_MAX] = {0,};
713     char *device_string_p = NULL;
714     char *next_p = NULL;
715     const char *params_p, *params;
716     char *end_p = NULL;
717     int len = 0, prev_len = 0;
718     pa_sink *sink;
719     pa_source *source;
720
721     if (pa_sink_isinstance(pdevice)) {
722         sink = PA_SINK(pdevice);
723         params = sink->module->argument;
724     } else {
725         source = PA_SOURCE(pdevice);
726         params = source->module->argument;
727     }
728
729     params_p = params;
730
731     if (!params) {
732         return NULL;
733     }
734     if (!(device_string_p = strstr(params, "device="))) {
735         return params;
736     }
737
738     next_p = device_string_p;
739     while (!isblank(*next_p)) {
740         next_p++;
741     }
742     while (isblank(*next_p)) {
743         next_p++;
744     }
745
746     pa_strlcpy(removed_param, next_p, DEVICE_PARAM_STRING_MAX);
747
748     if (device_string_p > params_p) {
749         prev_len = device_string_p - params_p;
750         len = strlen(removed_param);
751         end_p = removed_param + len;
752         *end_p = ' ';
753         end_p++;
754         strncpy(end_p, params_p, prev_len);
755     }
756
757     return removed_param;
758 }
759
760 static dm_device_class_t pulse_device_get_class(pa_object *pdevice) {
761
762     if (!pdevice) {
763         pa_log_error("pdevice null");
764         return DM_DEVICE_CLASS_NONE;
765     }
766
767     if (pulse_device_is_null(pdevice)) {
768         return DM_DEVICE_CLASS_NULL;
769     } else if (pulse_device_is_alsa(pdevice)) {
770         return DM_DEVICE_CLASS_ALSA;
771     } else if (pulse_device_is_tizenaudio(pdevice)) {
772         return DM_DEVICE_CLASS_TIZEN;
773     } else if (pulse_device_is_bluez(pdevice)) {
774         return DM_DEVICE_CLASS_BT;
775     } else {
776         return DM_DEVICE_CLASS_NONE;
777     }
778 }
779
780 static dm_device_direction_t pulse_device_get_direction(pa_object *pdevice) {
781     if (pa_sink_isinstance(pdevice))
782         return DM_DEVICE_DIRECTION_OUT;
783     else
784         return DM_DEVICE_DIRECTION_IN;
785 }
786
787 static bool pulse_device_is_monitor(pa_object *pdevice) {
788     const char *device_class = NULL;
789     pa_proplist *prop;
790
791     prop = pulse_device_get_proplist(pdevice);
792
793     if ((device_class = pa_proplist_gets(prop, PA_PROP_DEVICE_CLASS))) {
794         if (device_class && pa_streq(device_class, DEVICE_CLASS_MONITOR)) {
795             return true;
796         } else {
797             return false;
798         }
799     } else {
800         return false;
801     }
802 }
803
804 static int pulse_device_get_alsa_device_string(pa_proplist *prop, char **device_string) {
805     const char *device_string_prop = NULL;
806     char *device_string_tmp;
807
808     if (!prop || !device_string) {
809         pa_log_error("Invalid Parameter");
810         return -1;
811     }
812
813     if (!(device_string_prop = pa_proplist_gets(prop, "device.string"))) {
814         pa_log_error("failed to get property 'device.string'");
815         return -1;
816     }
817     if (!(device_string_tmp = strchr(device_string_prop, ':'))) {
818         pa_log_error("failed to parse device string");
819         return -1;
820     }
821
822     *device_string = device_string_tmp + 1;
823
824     return 0;
825 }
826
827 static const char* device_class_get_module_name(dm_device_class_t device_class, bool is_sink) {
828     if (device_class == DM_DEVICE_CLASS_NONE) {
829         return NULL;
830     } else if (device_class == DM_DEVICE_CLASS_ALSA) {
831         return is_sink ? "module-alsa-sink" : "module-alsa-source";
832     } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
833         return is_sink ? "module-tizenaudio-sink" : NULL;
834     } else if (device_class == DM_DEVICE_CLASS_BT) {
835         return is_sink ? "module-bluez5-device" : NULL;
836     } else if (device_class == DM_DEVICE_CLASS_NULL) {
837         return is_sink ? "module-null-sink" : "module-null-source";
838     } else {
839         return NULL;
840     }
841 }
842
843 static struct device_type_info* _device_manager_get_type_info(pa_idxset *type_infos, const char *type) {
844     struct device_type_info *type_info;
845     uint32_t type_idx;
846
847     PA_IDXSET_FOREACH(type_info, type_infos, type_idx) {
848         if (device_type_is_equal(type_info->type, type)) {
849             return type_info;
850         }
851     }
852
853     return NULL;
854 }
855
856 static struct device_file_info* _device_manager_get_file_info(pa_idxset *file_infos, const char *device_string) {
857     struct device_file_info *file_info;
858     uint32_t file_idx;
859
860     pa_assert(file_infos);
861
862     PA_IDXSET_FOREACH(file_info, file_infos, file_idx) {
863         if (file_info->device_string) {
864             if (pa_streq(file_info->device_string, device_string)) {
865                 return file_info;
866             }
867         }
868     }
869
870     return NULL;
871 }
872
873 static struct device_status_info* _device_status_new(const char *type,
874         const char *name, const char *system_id) {
875     struct device_status_info *status_info;
876
877     status_info = (struct device_status_info *) pa_xmalloc0(sizeof(struct device_status_info));
878     status_info->type = pa_xstrdup(type);
879     status_info->name = pa_xstrdup(name);
880     status_info->system_id = pa_xstrdup(system_id);
881     status_info->detected = DEVICE_DISCONNECTED;
882
883     return status_info;
884 }
885
886 static void _device_status_free(struct device_status_info *status_info) {
887     if (!status_info)
888         return ;
889
890     pa_xfree(status_info->type);
891     pa_xfree(status_info->name);
892     pa_xfree(status_info->system_id);
893     pa_xfree(status_info);
894 }
895
896 static struct device_status_info* _get_device_status(pa_device_manager *manager, const char *type,
897         const char *system_id) {
898     struct device_status_info *status_info = NULL;
899     uint32_t status_idx;
900
901     pa_assert(manager);
902     pa_assert(manager->device_status);
903
904     PA_IDXSET_FOREACH(status_info, manager->device_status, status_idx) {
905         if (device_type_is_equal(status_info->type, type)) {
906             if (device_type_is_avail_multi_device(type)) {
907                 /* if system_id is null, just compare type */
908                 if (system_id == NULL)
909                     return status_info;
910                 else if (status_info->system_id == NULL)
911                     continue;
912                 else if (pa_streq(status_info->system_id, system_id))
913                     return status_info;
914                 else
915                     continue;
916             } else {
917                 return status_info;
918             }
919         }
920     }
921
922     return NULL;
923 }
924
925 static const char* _file_infos_get_param(pa_idxset *file_infos, const char *device_string, const char *role) {
926     struct device_file_info *file_info;
927     const char *params;
928
929     if (!(file_info = _device_manager_get_file_info(file_infos, device_string))) {
930         pa_log_error("No file map for '%s'", device_string);
931         return NULL;
932     }
933
934     if (!(params = pa_hashmap_get(file_info->roles, role)))
935         pa_log_error("No params for '%s:%s'", device_string, role);
936
937     return params;
938 }
939
940 static device_detected_type_t _device_get_detected(pa_device_manager *manager, const char *type,
941         const char *system_id) {
942     struct device_status_info *status_info;
943
944     pa_assert(manager);
945     pa_assert(manager->device_status);
946     pa_assert(type);
947
948     if (!device_type_is_need_detect(type))
949         return DEVICE_CONNECTED;
950
951     status_info = _get_device_status(manager, type, system_id);
952     if (!status_info) {
953         pa_log_info("No status info for type(%s) system_id(%s)",
954                 type, pa_strempty(system_id));
955         return DEVICE_DISCONNECTED;
956     }
957
958     pa_log_debug("Get device detected, type(%s) system_id(%s) : %s(%d)",
959             type, pa_strempty(system_id),
960              (status_info->detected & DEVICE_CONNECTED) ? "Connected" : "Disconnected", status_info->detected);
961
962     return status_info->detected;
963 }
964
965 static void _device_set_detected(pa_device_manager *manager, const char *type,
966         const char *name, const char *system_id, device_detected_type_t detected_type) {
967     struct device_status_info *status_info;
968
969     pa_assert(manager);
970     pa_assert(manager->device_status);
971     pa_assert(type);
972
973     if (!device_type_is_need_detect(type))
974         return ;
975
976     pa_log_info("Set device detected, type(%s) system_id(%s) -> %s(%d)",
977             type, pa_strempty(system_id),
978             (detected_type & DEVICE_CONNECTED) ? "Connected" : "Disconnected", detected_type);
979
980     if (detected_type & DEVICE_CONNECTED) {
981         status_info = _get_device_status(manager, type, system_id);
982         if (!status_info) {
983             status_info = _device_status_new(type, name, system_id);
984             pa_idxset_put(manager->device_status, status_info, NULL);
985         }
986         status_info->detected = detected_type;
987     } else {
988         status_info = _get_device_status(manager, type, system_id);
989         if (status_info) {
990             pa_idxset_remove_by_data(manager->device_status, status_info, NULL);
991             _device_status_free(status_info);
992         }
993     }
994 }
995
996 static pa_tz_device* _device_list_get_device(pa_device_manager *manager, const char *type, const char *system_id) {
997     pa_tz_device *device;
998     uint32_t idx;
999     char *_type, *_system_id;
1000
1001     pa_assert(manager);
1002     pa_assert(manager->device_list);
1003     pa_assert(type);
1004
1005     PA_IDXSET_FOREACH(device, manager->device_list, idx) {
1006         _type = pa_tz_device_get_type(device);
1007         _system_id = pa_tz_device_get_system_id(device);
1008         if (pa_streq(_type, type)) {
1009             if (device_type_is_avail_multi_device(type)) {
1010                 if (system_id == NULL)
1011                     return device;
1012                 else if (_system_id == NULL)
1013                     continue;
1014                 else if (pa_streq(_system_id, system_id))
1015                     return device;
1016                 else
1017                     continue;
1018             } else {
1019                 return device;
1020             }
1021         }
1022     }
1023
1024     return NULL;
1025 }
1026
1027
1028 static pa_tz_device* _device_list_get_device_by_id(pa_device_manager *manager, uint32_t id) {
1029     pa_tz_device *device;
1030     uint32_t idx;
1031
1032     pa_assert(manager);
1033     pa_assert(manager->device_list);
1034
1035     PA_IDXSET_FOREACH(device, manager->device_list, idx) {
1036         if (pa_tz_device_get_id(device) == id) {
1037             return device;
1038         }
1039     }
1040     return NULL;
1041 }
1042
1043 static const char* build_params_to_load_device(const char *device_string, const char *params, dm_device_class_t device_class) {
1044     pa_strbuf *args_buf;
1045     static char args[DEVICE_PARAM_STRING_MAX] = {0,};
1046
1047     if (!device_string) {
1048         pa_log_error("device string null");
1049         return NULL;
1050     }
1051
1052     if (device_class == DM_DEVICE_CLASS_NULL) {
1053         return params;
1054     } else if (device_class == DM_DEVICE_CLASS_ALSA) {
1055         const char *alsa_device_name;
1056         if (!(alsa_device_name = device_string_get_value(device_string))) {
1057             pa_log_error("Invalid device string for alsa-device, '%s'", device_string);
1058             return NULL;
1059         }
1060         args_buf = pa_strbuf_new();
1061         pa_strbuf_printf(args_buf, "device=hw:%s ", alsa_device_name);
1062         if (params) {
1063             pa_strbuf_printf(args_buf, "%s", params);
1064         }
1065         pa_strlcpy(args, pa_strbuf_to_string_free(args_buf), DEVICE_PARAM_STRING_MAX);
1066     } else {
1067         return params;
1068     }
1069
1070     return (const char*) args;
1071 }
1072
1073 static bool device_params_is_equal(const char *params1, const char *params2) {
1074     const char *key = NULL;
1075     const char *value1, *value2;
1076     pa_modargs *modargs1, *modargs2;
1077     void *state = NULL;
1078     bool equal = true;
1079
1080     if (!params1 && !params2)
1081         return true;
1082     if (!params1 || !params2)
1083         return false;
1084
1085     modargs1 = pa_modargs_new(params1, valid_alsa_device_modargs);
1086     modargs2 = pa_modargs_new(params2, valid_alsa_device_modargs);
1087
1088     if (!modargs1 || !modargs2) {
1089         equal = false;
1090         goto finish;
1091     }
1092
1093     for (state = NULL, key = pa_modargs_iterate(modargs1, &state); key; key = pa_modargs_iterate(modargs1, &state)) {
1094         value1 = pa_modargs_get_value(modargs1, key, NULL);
1095         value2 = pa_modargs_get_value(modargs2, key, NULL);
1096         if (!value1 || !value2 || !pa_streq(value1, value2)) {
1097             equal = false;
1098             goto finish;
1099         }
1100     }
1101
1102     for (state = NULL, key = pa_modargs_iterate(modargs2, &state); key; key = pa_modargs_iterate(modargs2, &state)) {
1103         value1 = pa_modargs_get_value(modargs1, key, NULL);
1104         value2 = pa_modargs_get_value(modargs2, key, NULL);
1105         if (!value1 || !value2 || !pa_streq(value1, value2)) {
1106             equal = false;
1107             goto finish;
1108         }
1109     }
1110
1111 finish:
1112
1113     if (modargs1)
1114         pa_modargs_free(modargs1);
1115     if (modargs2)
1116         pa_modargs_free(modargs2);
1117
1118
1119     return equal;
1120 }
1121
1122 static bool pulse_device_params_is_equal(pa_object *pdevice, const char *params) {
1123     const char *removed_module_args;
1124     const char *module_args;
1125     pa_sink *sink;
1126     pa_source *source;
1127
1128     pa_assert(pdevice);
1129
1130     if (pa_sink_isinstance(pdevice)) {
1131         sink = PA_SINK(pdevice);
1132         module_args = sink->module->argument;
1133     } else {
1134         source = PA_SOURCE(pdevice);
1135         module_args = source->module->argument;
1136     }
1137
1138     if (!params && !module_args)
1139         return 0;
1140     if (!params || !module_args)
1141         return -1;
1142
1143     removed_module_args = pulse_device_get_device_string_removed_argument(pdevice);
1144     return device_params_is_equal(params, removed_module_args);
1145 }
1146
1147 static const char* pulse_device_get_device_string(pa_object *pdevice) {
1148     dm_device_class_t device_class;
1149     static char device_string[DEVICE_STR_MAX] = {0,};
1150     char *device_string_val = NULL;
1151     pa_proplist *prop;
1152
1153     pa_assert(pdevice);
1154
1155     device_class = pulse_device_get_class(pdevice);
1156     prop = pulse_device_get_proplist(pdevice);
1157
1158     if (device_class == DM_DEVICE_CLASS_ALSA) {
1159         if (pulse_device_get_alsa_device_string(prop, &device_string_val) < 0)
1160             return NULL;
1161         snprintf(device_string, DEVICE_STR_MAX, "alsa:%s", device_string_val);
1162         return device_string;
1163     } else if (device_class == DM_DEVICE_CLASS_NULL) {
1164         return "null";
1165     } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
1166         return "tizen";
1167     } else if (device_class == DM_DEVICE_CLASS_BT) {
1168         return "bt";
1169     } else {
1170         return device_string;
1171     }
1172 }
1173
1174 /*  pdevice is sink or source */
1175 static bool pulse_device_same_device_string(pa_object *pdevice, const char *device_string) {
1176     const char *_device_string;
1177
1178     pa_assert(pdevice);
1179     pa_assert(device_string);
1180
1181     if (!(_device_string = pulse_device_get_device_string(pdevice)))
1182         return false;
1183
1184     return pa_streq(_device_string, device_string);
1185 }
1186
1187 static const char* device_type_info_get_device_string(struct device_type_info *type_info, bool is_playback, const char *role) {
1188     const char *_role, *device_string;
1189     void *state;
1190     pa_hashmap *pcm_devices;
1191
1192     pcm_devices = is_playback ? type_info->playback_devices : type_info->capture_devices;
1193     if (pcm_devices == NULL) {
1194         pa_log_error("No pcm device config for %s %s %s", is_playback ? "Playback" : "Capture", type_info->type, role);
1195         return NULL;
1196     }
1197
1198     PA_HASHMAP_FOREACH_KV(_role, device_string, pcm_devices, state) {
1199         if (pa_safe_streq(role, _role))
1200             return device_string;
1201     }
1202
1203     return NULL;
1204 }
1205
1206 pa_dynarray* pulse_device_get_belongs_type(pa_object *pdevice, pa_device_manager *dm) {
1207     pa_dynarray *ctypes;
1208     struct composite_type *ctype;
1209     struct device_type_info *type_info;
1210     const char *device_string, *role, *param;
1211     uint32_t type_idx;
1212     pa_device_type_t pdt;
1213     pa_idxset *file_infos;
1214     pa_hashmap *pcm_devices;
1215     void *state;
1216
1217     pa_assert(pdevice);
1218     pa_assert(dm);
1219
1220     pa_log_info("pulse device get belongs type");
1221
1222     if (pulse_device_is_monitor(pdevice))
1223         return NULL;
1224     if (pulse_device_is_usb(pdevice))
1225         return NULL;
1226     if (pulse_device_is_bluez(pdevice))
1227         return NULL;
1228
1229     ctypes = pa_dynarray_new(pa_xfree);
1230
1231     if (pa_sink_isinstance(pdevice)) {
1232         pdt = PA_DEVICE_TYPE_SINK;
1233         file_infos = dm->file_map->playback;
1234     } else {
1235         pdt = PA_DEVICE_TYPE_SOURCE;
1236         file_infos = dm->file_map->capture;
1237     }
1238
1239     /* iterate "device-types" in device-map.json */
1240     PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
1241         if (pdt == PA_DEVICE_TYPE_SINK)
1242             pcm_devices = type_info->playback_devices;
1243         else
1244             pcm_devices = type_info->capture_devices;
1245         if (pcm_devices == NULL)
1246             continue;
1247         /* iterate "{playback,capture}-devices" in specific device-type */
1248         PA_HASHMAP_FOREACH_KV(role, device_string, pcm_devices, state) {
1249             if (pulse_device_same_device_string(pdevice, device_string) == false)
1250                 continue;
1251             param = _file_infos_get_param(file_infos, device_string, role);
1252             if (pulse_device_params_is_equal(pdevice, param) == false)
1253                 continue;
1254             /* Found type.role which is matching with pulse_device */
1255             ctype = pa_xmalloc0(sizeof(struct composite_type));
1256             ctype->type = type_info->type;
1257             ctype->role = role;
1258             pa_dynarray_append(ctypes, ctype);
1259         }
1260     }
1261
1262     if (pa_dynarray_size(ctypes) == 0) {
1263         pa_dynarray_free(ctypes);
1264         ctypes = NULL;
1265     }
1266
1267     return ctypes;
1268 }
1269
1270 static const char* pulse_device_get_device_name(pa_object *pdevice, const char *type) {
1271     pa_proplist *prop;
1272
1273     pa_assert(pdevice);
1274     pa_assert(device_type_is_valid(type));
1275
1276     prop = pulse_device_get_proplist(pdevice);
1277
1278     if (pa_streq(type, DEVICE_TYPE_USB_AUDIO))
1279         return pa_proplist_gets(prop, "udev.id");
1280     else if (pa_streq(type, DEVICE_TYPE_BT_A2DP))
1281         return pa_proplist_gets(prop, "bluez.alias");
1282     else
1283         return NULL;
1284 }
1285
1286 /* If fails return -1 */
1287 static int atoi_base16(const char *s) {
1288     char *x = NULL;
1289     long l;
1290
1291     pa_assert(s);
1292
1293     errno = 0;
1294     l = strtol(s, &x, 16);
1295
1296     if (!x || *x || errno) {
1297         pa_log_error("Convert Failed");
1298         return -1;
1299     }
1300
1301     if ((int) l != l) {
1302         pa_log_error("Range error, does not fit into int");
1303         return -1;
1304     }
1305
1306     return (int) l;
1307 }
1308
1309 static int pulse_device_get_vendor_id(pa_object *pdevice) {
1310     pa_proplist *prop;
1311     const char *vendor_id_s;
1312     int vendor_id;
1313
1314     pa_assert(pdevice);
1315
1316     if (pulse_device_is_usb(pdevice) == false) {
1317         pa_log_warn("Not USB device");
1318         return -1;
1319     }
1320
1321     prop = pulse_device_get_proplist(pdevice);
1322
1323     if ((vendor_id_s = pa_proplist_gets(prop, PA_PROP_DEVICE_VENDOR_ID)) == NULL) {
1324         pa_log_error("No vendor id");
1325         return -1;
1326     }
1327
1328     if ((vendor_id = atoi_base16(vendor_id_s)) == -1) {
1329         pa_log_error("Failed to convert to int");
1330         return -1;
1331     }
1332
1333     return vendor_id;
1334 }
1335
1336 static int pulse_device_get_product_id(pa_object *pdevice) {
1337     pa_proplist *prop;
1338     const char *product_id_s;
1339     int product_id;
1340
1341     pa_assert(pdevice);
1342
1343     if (pulse_device_is_usb(pdevice) == false) {
1344         pa_log_warn("Not USB device");
1345         return -1;
1346     }
1347
1348     prop = pulse_device_get_proplist(pdevice);
1349
1350     if ((product_id_s = pa_proplist_gets(prop, PA_PROP_DEVICE_PRODUCT_ID)) == NULL) {
1351         pa_log_error("No product id");
1352         return -1;
1353     }
1354
1355     if ((product_id = atoi_base16(product_id_s)) == -1) {
1356         pa_log_error("Failed to convert to int");
1357         return -1;
1358     }
1359
1360     return product_id;
1361 }
1362
1363 static void pulse_device_set_use_internal_codec(pa_object *pdevice, bool use_internal_codec) {
1364     pa_assert(pdevice);
1365
1366     if (pa_sink_isinstance(pdevice)) {
1367         pa_sink *sink = PA_SINK(pdevice);
1368         sink->use_internal_codec = use_internal_codec;
1369     } else {
1370         pa_source *source = PA_SOURCE(pdevice);
1371         source->use_internal_codec = use_internal_codec;
1372     }
1373 }
1374
1375 /* Get system_id of physical device, if external device */
1376 static const char* pulse_device_get_system_id(pa_object *pdevice) {
1377     pa_proplist *prop;
1378
1379     prop = pulse_device_get_proplist(pdevice);
1380     if (pulse_device_is_usb(pdevice))
1381         return pa_proplist_gets(prop, "sysfs.path");
1382     else if (pulse_device_is_bluez(pdevice))
1383         return pa_proplist_gets(prop, "bluez.path");
1384     else
1385         return NULL;
1386 }
1387
1388 static pa_sink* _core_get_sink(pa_core *core, const char *device_string, const char *params) {
1389     uint32_t device_idx;
1390     pa_sink *sink;
1391
1392     pa_assert(core);
1393     pa_assert(device_string);
1394
1395     PA_IDXSET_FOREACH(sink, core->sinks, device_idx) {
1396         if (pulse_device_is_monitor(PA_OBJECT(sink)))
1397             continue;
1398         if (pulse_device_same_device_string(PA_OBJECT(sink), device_string)) {
1399             if (params == NULL)
1400                 return sink;
1401             else if (pulse_device_params_is_equal(PA_OBJECT(sink), params))
1402                 return sink;
1403         }
1404     }
1405
1406     return NULL;
1407 }
1408
1409 static pa_source* _core_get_source(pa_core *core, const char *device_string, const char *params) {
1410     uint32_t device_idx;
1411     pa_source *source;
1412
1413     pa_assert(core);
1414     pa_assert(device_string);
1415
1416     PA_IDXSET_FOREACH(source, core->sources, device_idx) {
1417         if (pulse_device_is_monitor(PA_OBJECT(source)))
1418             continue;
1419         if (pulse_device_same_device_string(PA_OBJECT(source), device_string)) {
1420             if (params == NULL)
1421                 return source;
1422             else if (pulse_device_params_is_equal(PA_OBJECT(source), params))
1423                 return source;
1424         }
1425     }
1426
1427     return NULL;
1428 }
1429
1430
1431 static void _fill_new_data_basic(pa_tz_device_new_data *data, const char *type,
1432         dm_device_direction_t direction, bool use_internal_codec, pa_device_manager *dm) {
1433     pa_assert(data);
1434
1435     pa_tz_device_new_data_set_type(data, type);
1436     pa_tz_device_new_data_set_direction(data, direction);
1437     pa_tz_device_new_data_set_use_internal_codec(data, use_internal_codec);
1438 }
1439
1440 static int _fill_new_data_sinks(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
1441     pa_sink *sink;
1442     const char *device_string, *role, *param;
1443     void *state;
1444     pa_idxset *file_infos;
1445
1446     pa_assert(data);
1447     pa_assert(type_info);
1448
1449     if (type_info->playback_devices == NULL) {
1450         pa_log_error("No playback devices for %s", type_info->type);
1451         return -1;
1452     }
1453
1454     file_infos = dm->file_map->playback;
1455     if (file_infos == NULL) {
1456         pa_log_error("No playback pcm device config");
1457         return -1;
1458     }
1459
1460     PA_HASHMAP_FOREACH_KV(role, device_string, type_info->playback_devices, state) {
1461         param = _file_infos_get_param(file_infos, device_string, role);
1462         sink = _core_get_sink(dm->core, device_string, param);
1463         if (sink)
1464             pa_tz_device_new_data_add_sink(data, role, sink);
1465         else
1466             pa_log_warn("No matching sink for %s %s", device_string, role);
1467     }
1468
1469     return 0;
1470 }
1471
1472 static int _fill_new_data_sources(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
1473     pa_source *source;
1474     const char *device_string, *role, *param;
1475     void *state;
1476     pa_idxset *file_infos;
1477
1478     pa_assert(data);
1479     pa_assert(type_info);
1480
1481     if (type_info->capture_devices == NULL) {
1482         pa_log_error("No capture devices for %s", type_info->type);
1483         return -1;
1484     }
1485
1486     file_infos = dm->file_map->capture;
1487     if (file_infos == NULL) {
1488         pa_log_error("No capture pcm device config");
1489         return -1;
1490     }
1491
1492     PA_HASHMAP_FOREACH_KV(role, device_string, type_info->capture_devices, state) {
1493         param = _file_infos_get_param(file_infos, device_string, role);
1494         source = _core_get_source(dm->core, device_string, param);
1495         if (source)
1496             pa_tz_device_new_data_add_source(data, role, source);
1497         else
1498             pa_log_warn("No matching source for %s %s", device_string, role);
1499     }
1500
1501     return 0;
1502 }
1503
1504 static pa_sink* _device_manager_set_default_sink(pa_device_manager *dm,  const char *type, const char *role) {
1505     pa_tz_device *device;
1506     pa_sink *sink;
1507
1508     if (!type || !role) {
1509         pa_log_warn("Argument for set_default_sink invalid");
1510         return NULL;
1511     }
1512
1513     if (!(device = _device_list_get_device(dm, type, NULL))) {
1514         pa_log_warn("cannot get device item for %s", type);
1515         return NULL;
1516     }
1517
1518     if (!(sink = pa_tz_device_get_sink(device, role))) {
1519         pa_log_warn("cannot get sink for %s", role);
1520         return NULL;
1521     }
1522
1523 //    sink = pa_namereg_set_default_sink(dm->core, sink);
1524     return sink;
1525 }
1526
1527 static pa_source* _device_manager_set_default_source(pa_device_manager *dm,  const char *type, const char *role) {
1528     pa_tz_device *device;
1529     pa_source *source;
1530
1531     if (!type || !role) {
1532         pa_log_warn("Argument for set_default_source invalid");
1533         return NULL;
1534     }
1535
1536     if (!(device = _device_list_get_device(dm, type, NULL))) {
1537         pa_log_warn("cannot get device item for %s", type);
1538         return NULL;
1539     }
1540
1541     if (!(source = pa_tz_device_get_source(device, role))) {
1542         pa_log_warn("cannot get source for %s", role);
1543         return NULL;
1544     }
1545
1546  //   source = pa_namereg_set_default_source(dm->core, source);
1547     return source;
1548 }
1549
1550 static void handle_usb_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1551     const char *name, *system_id;
1552     dm_device_direction_t direction;
1553     pa_tz_device *device;
1554
1555     pa_assert(pdevice);
1556     pa_assert(manager);
1557
1558     pa_log_info("Handle usb pulse device");
1559
1560     system_id = pulse_device_get_system_id(pdevice);
1561     direction = pulse_device_get_direction(pdevice);
1562
1563     if (is_loaded) {
1564         pa_tz_device_new_data data;
1565         int product_id, vendor_id;
1566
1567         name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_USB_AUDIO);
1568         vendor_id = pulse_device_get_vendor_id(pdevice);
1569         product_id = pulse_device_get_product_id(pdevice);
1570
1571         pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, NULL);
1572         pa_tz_device_new_data_set_type(&data, DEVICE_TYPE_USB_AUDIO);
1573         pa_tz_device_new_data_set_name(&data, name);
1574         pa_tz_device_new_data_set_direction(&data, direction);
1575         pa_tz_device_new_data_set_system_id(&data, system_id);
1576         if (vendor_id > 0)
1577             pa_tz_device_new_data_set_vendor_id(&data, vendor_id);
1578         if (product_id > 0)
1579             pa_tz_device_new_data_set_product_id(&data, product_id);
1580         pa_tz_device_new_data_set_use_internal_codec(&data, false);
1581         if (direction == DM_DEVICE_DIRECTION_OUT)
1582             pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
1583         else
1584             pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1585
1586         pa_tz_device_new(&data);
1587         pa_tz_device_new_data_done(&data);
1588     } else {
1589         if (!(device = _device_list_get_device(manager, DEVICE_TYPE_USB_AUDIO, system_id)))
1590             pa_log_warn("Can't get usb device for %s", system_id);
1591         else
1592             pa_tz_device_free(device);
1593     }
1594 }
1595
1596 static void handle_bt_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1597     dm_device_direction_t direction;
1598     pa_tz_device *device;
1599     const char *system_id;
1600
1601     pa_assert(pdevice);
1602     pa_assert(manager);
1603
1604     pa_log_info("Handle bt pulse device");
1605
1606     direction = pulse_device_get_direction(pdevice);
1607     system_id = pulse_device_get_system_id(pdevice);
1608
1609     if (is_loaded) {
1610         pa_tz_device_new_data data;
1611
1612         const char *name;
1613         name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_BT_A2DP);
1614
1615         pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, manager->dbus_conn);
1616         _fill_new_data_basic(&data, DEVICE_TYPE_BT_A2DP, direction, false, manager);
1617         pa_tz_device_new_data_set_name(&data, name);
1618         pa_tz_device_new_data_set_system_id(&data, system_id);
1619         if (direction == DM_DEVICE_DIRECTION_OUT)
1620             pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
1621         else
1622             pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1623
1624         pa_tz_device_new(&data);
1625         pa_tz_device_new_data_done(&data);
1626     } else {
1627
1628         if (!(device = _device_list_get_device(manager, DEVICE_TYPE_BT_A2DP, system_id)))
1629             pa_log_warn("Can't get bt device for %s", system_id);
1630         else
1631             pa_tz_device_free(device);
1632     }
1633 }
1634
1635 static void handle_internal_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1636     pa_tz_device *device;
1637     struct composite_type *ctype;
1638     pa_dynarray *ctypes;
1639     dm_device_direction_t direction;
1640
1641     pa_assert(pdevice);
1642     pa_assert(manager);
1643
1644     pa_log_info("Handle internal pulse device");
1645     direction = pulse_device_get_direction(pdevice);
1646
1647     /* Get types which this pulse_device belongs to */
1648     if ((ctypes = pulse_device_get_belongs_type(pdevice, manager)) == NULL) {
1649         pa_log_debug("Failed to get device type. Skip this");
1650         return ;
1651     }
1652
1653     if (is_loaded) {
1654         /* Put this pulse_device to already loaded devices */
1655         for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
1656             ctype = pa_dynarray_get(ctypes, i);
1657             pa_log_info("Found belongs type %s %s", ctype->type, ctype->role);
1658             if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
1659                 pa_log_info("Add this pulse_device to device(%u)", pa_tz_device_get_id(device));
1660                 if (direction == DM_DEVICE_DIRECTION_OUT)
1661                     pa_tz_device_add_sink(device, ctype->role, PA_SINK(pdevice));
1662                 else
1663                     pa_tz_device_add_source(device, ctype->role, PA_SOURCE(pdevice));
1664             } else {
1665                 pa_log_info("No device for %s", ctype->type);
1666             }
1667         }
1668     } else {
1669         /* Remove this pulse_device from already loaded devices */
1670         for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
1671             ctype = pa_dynarray_get(ctypes, i);
1672             pa_log_info("Found belongs type %s %s", ctype->type, ctype->role);
1673             if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
1674                 pa_log_info("Remove this pulse_device from device(%u)", pa_tz_device_get_id(device));
1675                 if (direction == DM_DEVICE_DIRECTION_OUT)
1676                     pa_tz_device_remove_sink(device, PA_SINK(pdevice));
1677                 else
1678                     pa_tz_device_remove_source(device, PA_SOURCE(pdevice));
1679             } else {
1680                 pa_log_info("No device for %s", ctype->type);
1681             }
1682         }
1683     }
1684
1685     pa_dynarray_free(ctypes);
1686 }
1687
1688 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1689     pa_assert(c);
1690     pa_assert(sink);
1691     pa_assert(dm);
1692
1693     pa_log_info("========== Sink Put Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1694
1695     if (pulse_device_is_monitor(PA_OBJECT(sink)))
1696         return PA_HOOK_OK;
1697
1698     if (pulse_device_is_usb(PA_OBJECT(sink))) {
1699         pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
1700         handle_usb_pulse_device(PA_OBJECT(sink), true, dm);
1701         return PA_HOOK_OK;
1702     } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
1703         pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
1704         handle_bt_pulse_device(PA_OBJECT(sink), true, dm);
1705         return PA_HOOK_OK;
1706     } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
1707         pulse_device_set_use_internal_codec(PA_OBJECT(sink), true);
1708         handle_internal_pulse_device(PA_OBJECT(sink), true, dm);
1709         return PA_HOOK_OK;
1710     } else {
1711         pa_log_debug("Don't care this sink");
1712     }
1713
1714     return PA_HOOK_OK;
1715 }
1716
1717 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1718     pa_assert(c);
1719     pa_assert(sink);
1720     pa_assert(dm);
1721
1722     pa_log_info("=========== Sink unlink Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1723
1724     if (pulse_device_is_monitor(PA_OBJECT(sink)))
1725         return PA_HOOK_OK;
1726
1727     if (pulse_device_is_usb(PA_OBJECT(sink))) {
1728         handle_usb_pulse_device(PA_OBJECT(sink), false, dm);
1729         return PA_HOOK_OK;
1730     } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
1731         handle_bt_pulse_device(PA_OBJECT(sink), false, dm);
1732         return PA_HOOK_OK;
1733     } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
1734         handle_internal_pulse_device(PA_OBJECT(sink), false, dm);
1735         return PA_HOOK_OK;
1736     } else {
1737         pa_log_debug("Don't care this sink");
1738     }
1739
1740     return PA_HOOK_OK;
1741 }
1742
1743 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1744     pa_assert(c);
1745     pa_assert(source);
1746     pa_assert(dm);
1747
1748     pa_log_info("========== source Put Hook Callback '%s'(%d) ==========", source->name, source->index);
1749
1750     if (pulse_device_is_monitor(PA_OBJECT(source)))
1751         return PA_HOOK_OK;
1752
1753     if (pulse_device_is_usb(PA_OBJECT(source))) {
1754         pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
1755         handle_usb_pulse_device(PA_OBJECT(source), true, dm);
1756         return PA_HOOK_OK;
1757     } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
1758         pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
1759         handle_bt_pulse_device(PA_OBJECT(source), true, dm);
1760         return PA_HOOK_OK;
1761     } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
1762         pulse_device_set_use_internal_codec(PA_OBJECT(source), true);
1763         handle_internal_pulse_device(PA_OBJECT(source), true, dm);
1764         return PA_HOOK_OK;
1765     } else {
1766         pa_log_debug("Don't care this source");
1767     }
1768
1769     return PA_HOOK_OK;
1770 }
1771
1772 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1773     pa_assert(c);
1774     pa_assert(source);
1775     pa_assert(dm);
1776
1777     pa_log_info("=========== source unlink Hook Callback '%s'(%d) ==========", source->name, source->index);
1778
1779     if (pulse_device_is_monitor(PA_OBJECT(source)))
1780         return PA_HOOK_OK;
1781
1782     if (pulse_device_is_usb(PA_OBJECT(source))) {
1783         handle_usb_pulse_device(PA_OBJECT(source), false, dm);
1784         return PA_HOOK_OK;
1785     } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
1786         handle_bt_pulse_device(PA_OBJECT(source), false, dm);
1787         return PA_HOOK_OK;
1788     } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
1789         handle_internal_pulse_device(PA_OBJECT(source), false, dm);
1790         return PA_HOOK_OK;
1791     } else {
1792         pa_log_debug("Don't care this source");
1793     }
1794
1795     return PA_HOOK_OK;
1796 }
1797
1798 #define SINK_NAME_NULL "sink_null"
1799 #define SOURCE_NAME_NULL "source_null"
1800 static pa_hook_result_t sink_source_state_changed_hook_cb(pa_core *c, pa_object *pdevice, pa_device_manager *dm) {
1801     pa_tz_device *device;
1802
1803     pa_assert(c);
1804     pa_object_assert_ref(pdevice);
1805     pa_assert(dm);
1806
1807     if (pa_sink_isinstance(pdevice)) {
1808         pa_sink *s = PA_SINK(pdevice);
1809         pa_sink_state_t state = pa_sink_get_state(s);
1810         pa_log_debug("=========== Sink(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
1811         if (!s->use_internal_codec && !pa_streq(s->name, SINK_NAME_NULL))
1812             if ((device = pa_device_manager_get_device_with_sink(s)))
1813                 pa_tz_device_set_running_and_notify(device, (state == PA_SINK_RUNNING));
1814     } else if (pa_source_isinstance(pdevice)) {
1815         pa_source *s = PA_SOURCE(pdevice);
1816         pa_source_state_t state = pa_source_get_state(s);
1817         pa_log_debug("=========== Source(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
1818         if (!s->use_internal_codec && !pa_streq(s->name, SOURCE_NAME_NULL))
1819             if ((device = pa_device_manager_get_device_with_source(s)))
1820                 pa_tz_device_set_running_and_notify(device, (state == PA_SOURCE_RUNNING));
1821     }
1822     pa_log_debug("========= sink_source_state_changed_hook_cb END =====");
1823
1824     return PA_HOOK_OK;
1825 }
1826
1827 /*
1828     Build params for load sink or source, and load it.
1829 */
1830
1831 static void* load_device(pa_core *c, bool is_sink, const char *device_string, const char *device_params) {
1832     const char *args = NULL;
1833     const char *module_name;
1834     pa_module *module;
1835     pa_sink *sink;
1836     pa_source *source;
1837     uint32_t device_idx;
1838     dm_device_class_t device_class;
1839
1840     pa_assert(c);
1841     pa_assert(device_string);
1842     pa_assert(device_params);
1843
1844     pa_log_info("Load %s Device : String'%s' Param'%s'", is_sink ? "Playback" : "Capture", device_string, device_params);
1845
1846     device_class = device_string_get_class(device_string);
1847     if (device_class <= DM_DEVICE_CLASS_NONE || device_class >= DM_DEVICE_CLASS_MAX) {
1848         pa_log_warn("Invalid device_string '%s'", device_string);
1849         return NULL;
1850     }
1851
1852     if (!(module_name = device_class_get_module_name(device_class, is_sink))) {
1853         pa_log_error("Get proper module name to load failed");
1854         return NULL;
1855     }
1856     if (!(args = build_params_to_load_device(device_string, device_params, device_class))) {
1857         pa_log_error("Get proper module name to load failed");
1858         return NULL;
1859     }
1860     if (!(module = pa_module_load(c, module_name, args))) {
1861         pa_log_error("Load module with name '%s' argu '%s' failed", module_name, args);
1862         return NULL;
1863     }
1864
1865
1866     if (is_sink) {
1867         PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
1868             if (sink->module == module) {
1869                 return sink;
1870             }
1871         }
1872     } else {
1873         PA_IDXSET_FOREACH(source, c->sources, device_idx) {
1874             if (source->module == module) {
1875                 return source;
1876             }
1877         }
1878     }
1879
1880     return NULL;
1881 }
1882
1883 static void unload_device(pa_core *c, bool is_sink, const char *device_string) {
1884     uint32_t device_idx;
1885
1886     pa_assert(c);
1887     pa_assert(device_string);
1888
1889     pa_log_info("Unload %s Device : String'%s'", is_sink ? "Playback" : "Capture", device_string);
1890
1891     if (is_sink) {
1892         pa_sink *sink;
1893
1894         PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
1895             if (pulse_device_is_monitor(PA_OBJECT(sink)))
1896                 continue;
1897             if (pulse_device_same_device_string(PA_OBJECT(sink), device_string))
1898                 pa_module_unload(sink->module, true);
1899         }
1900     } else {
1901         pa_source *source;
1902
1903         PA_IDXSET_FOREACH(source, c->sources, device_idx) {
1904             if (pulse_device_is_monitor(PA_OBJECT(source)))
1905                 continue;
1906             if (pulse_device_same_device_string(PA_OBJECT(source), device_string))
1907                 pa_module_unload(source->module, true);
1908         }
1909     }
1910 }
1911
1912 static int _load_type_devices(struct device_type_info *type_info, bool is_playback, pa_device_manager *dm) {
1913     pa_hashmap *pcm_devices;
1914     pa_idxset *file_infos;
1915     void *state;
1916     char *role;
1917     const char *device_string, *params;
1918
1919     pa_assert(dm);
1920     pa_assert(type_info);
1921
1922     pa_log_info("Load type devices : %s %s", type_info->type, is_playback ? "playback" : "capture");
1923
1924     if (is_playback) {
1925         pcm_devices = type_info->playback_devices;
1926         file_infos = dm->file_map->playback;
1927     } else {
1928         pcm_devices = type_info->capture_devices;
1929         file_infos = dm->file_map->capture;
1930     }
1931
1932     if (!pcm_devices || !file_infos) {
1933         pa_log_error("No information to load");
1934         return -1;
1935     }
1936
1937     PA_HASHMAP_FOREACH_KV(role, device_string, pcm_devices, state) {
1938         /* skip duplicate load */
1939         if (is_playback && _core_get_sink(dm->core, device_string, NULL)) {
1940             pa_log_debug("Already loaded %s", device_string);
1941             continue;
1942         }
1943         if (!is_playback && _core_get_source(dm->core, device_string, NULL)) {
1944             pa_log_debug("Already loaded %s", device_string);
1945             continue;
1946         }
1947
1948         params = _file_infos_get_param(file_infos, device_string, role);
1949         if (params == NULL) {
1950             pa_log_error("Failed to get param for %s", device_string);
1951             continue;
1952         }
1953         if (!(load_device(dm->core, is_playback, device_string, params))) {
1954             pa_log_warn("load device failed %s %s", device_string, params);
1955         }
1956     }
1957
1958     return 0;
1959 }
1960
1961 static pa_tz_device* _load_forwarding_device(pa_device_manager *dm) {
1962     pa_tz_device_new_data data;
1963     pa_tz_device *spk_device, *forwarding_device;
1964     pa_sink *spk_sink;
1965
1966     pa_assert(dm);
1967
1968     pa_log_info("Load forwarding device");
1969
1970     if ((forwarding_device = _device_list_get_device(dm, DEVICE_TYPE_FORWARDING, NULL))) {
1971         pa_log_info("Forwarding device already exists");
1972         return forwarding_device;
1973     }
1974
1975     if ((spk_device = _device_list_get_device(dm, DEVICE_TYPE_SPEAKER, NULL)) == NULL) {
1976         pa_log_error("Get speaker device failed");
1977         return NULL;
1978     }
1979
1980     if ((spk_sink = pa_tz_device_get_sink(spk_device, DEVICE_ROLE_NORMAL)) == NULL) {
1981         pa_log_error("Get speaker sink failed");
1982         return NULL;
1983     }
1984
1985     pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
1986     _fill_new_data_basic(&data, DEVICE_TYPE_FORWARDING, DM_DEVICE_DIRECTION_BOTH, true, dm);
1987     pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, spk_sink);
1988     pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, spk_sink->monitor_source);
1989
1990     if ((forwarding_device = pa_tz_device_new(&data)) == NULL)
1991         pa_log_error("Failed to create forwarding device");
1992
1993     pa_tz_device_new_data_done(&data);
1994
1995     return forwarding_device;
1996 }
1997
1998 /*
1999     Handle device connection detected through dbus.
2000     First, update device-status hashmap.
2001     And if correnspondent sink/sources for device_type exist, should make device and notify it.
2002     Use [device_type->roles] mappings in sink/source for find proper sink/source.
2003 */
2004 static void handle_device_connected(pa_device_manager *dm, const char *type,
2005         const char *name, const char *system_id, device_detected_type_t detected_type) {
2006     struct device_type_info *type_info;
2007     pa_tz_device_new_data data;
2008
2009     pa_assert(dm);
2010     pa_assert(dm->device_status);
2011     pa_assert(dm->device_list);
2012
2013     pa_log_info("Device connected, type(%s) name(%s) system_id(%s) detected_type(%d)",
2014             type, pa_strempty(name), pa_strempty(system_id), detected_type);
2015
2016     type_info = _device_manager_get_type_info(dm->type_infos, type);
2017
2018     if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2019         pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, dm->dbus_conn);
2020         _fill_new_data_basic(&data, DEVICE_TYPE_BT_SCO, DM_DEVICE_DIRECTION_BOTH, true, dm);
2021         _fill_new_data_sinks(&data, type_info, dm);
2022         _fill_new_data_sources(&data, type_info, dm);
2023         pa_tz_device_new_data_set_name(&data, name);
2024         pa_tz_device_new_data_set_system_id(&data, system_id);
2025         pa_tz_device_new(&data);
2026         pa_tz_device_new_data_done(&data);
2027     } else if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
2028         dm_device_direction_t direction;
2029
2030         if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P)
2031             direction = DM_DEVICE_DIRECTION_BOTH;
2032         else
2033             direction = DM_DEVICE_DIRECTION_OUT;
2034         pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
2035         _fill_new_data_basic(&data, DEVICE_TYPE_AUDIO_JACK, direction, true, dm);
2036         _fill_new_data_sinks(&data, type_info, dm);
2037         _fill_new_data_sources(&data, type_info, dm);
2038
2039         pa_tz_device_new(&data);
2040         pa_tz_device_new_data_done(&data);
2041     } else if (device_type_is_equal(type, DEVICE_TYPE_HDMI)) {
2042         pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
2043         _fill_new_data_basic(&data, DEVICE_TYPE_HDMI, DM_DEVICE_DIRECTION_OUT, true, dm);
2044         _fill_new_data_sinks(&data, type_info, dm);
2045
2046         pa_tz_device_new(&data);
2047         pa_tz_device_new_data_done(&data);
2048     } else if (device_type_is_equal(type, DEVICE_TYPE_FORWARDING)) {
2049         _load_forwarding_device(dm);
2050     } else {
2051         dm_device_direction_t direction;
2052
2053         direction = device_type_get_static_direction(type);
2054         if (direction != DM_DEVICE_DIRECTION_NONE) {
2055             pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
2056             _fill_new_data_basic(&data, type, direction, true, dm);
2057             if (direction & DM_DEVICE_DIRECTION_OUT)
2058                 _fill_new_data_sinks(&data, type_info, dm);
2059             if (direction & DM_DEVICE_DIRECTION_IN)
2060                 _fill_new_data_sources(&data, type_info, dm);
2061
2062             pa_tz_device_new(&data);
2063             pa_tz_device_new_data_done(&data);
2064         } else {
2065             pa_log_error("Invalid case : not static direction");
2066             return ;
2067         }
2068     }
2069
2070     return ;
2071 }
2072
2073 /*
2074     Handle device disconnection detected through dbus.
2075     First, update device-status hashmap.
2076     And if there is device which has the device_type, remove it.
2077 */
2078 static int handle_device_disconnected(pa_device_manager *dm, const char *type, const char *system_id) {
2079     pa_tz_device *device;
2080
2081     pa_assert(dm);
2082     pa_assert(dm->device_status);
2083
2084     pa_log_info("Device type(%s) system_id(%s) disconnected",
2085             type, pa_strempty(system_id));
2086
2087     device = _device_list_get_device(dm, type, system_id);
2088     if (!device) {
2089         pa_log_error("Disconnection detected but no device for that");
2090         return -1;
2091     }
2092
2093     pa_tz_device_free(device);
2094
2095     return 0;
2096 }
2097
2098 static int load_builtin_devices(pa_device_manager *dm) {
2099     struct device_type_info *type_info;
2100     uint32_t type_idx;
2101     device_detected_type_t detected_type = DEVICE_CONNECTED;
2102     const char *type;
2103
2104     pa_assert(dm);
2105
2106     pa_log_debug("\n==================== Load Builtin Devices ====================");
2107
2108     PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
2109
2110         type = type_info->type;
2111
2112         pa_log_info("type_info : %s", type);
2113         detected_type = _device_get_detected(dm, type, NULL);
2114         if (detected_type == DEVICE_DISCONNECTED) {
2115             pa_log_info("Not detected yet");
2116             continue;
2117         }
2118
2119         if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
2120             if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P) {
2121                 _load_type_devices(type_info, true, dm);
2122                 _load_type_devices(type_info, false, dm);
2123             } else {
2124                 _load_type_devices(type_info, true, dm);
2125             }
2126             handle_device_connected(dm, type, NULL, NULL, detected_type);
2127         } else if (device_type_is_use_external_card(type) == false) {
2128             dm_device_direction_t direction;
2129             direction = device_type_get_static_direction(type);
2130             if (direction == DM_DEVICE_DIRECTION_NONE) {
2131                 pa_log_warn("Wrong direction");
2132                 continue;
2133             }
2134             if (direction & DM_DEVICE_DIRECTION_OUT)
2135                 _load_type_devices(type_info, true, dm);
2136             if (direction & DM_DEVICE_DIRECTION_IN)
2137                 _load_type_devices(type_info, false, dm);
2138             handle_device_connected(dm, type, NULL, NULL, detected_type);
2139         } else {
2140             pa_log_warn("Invalid case");
2141         }
2142     }
2143
2144     return 0;
2145 }
2146
2147 /***************** Parse json file *******************/
2148 static pa_hashmap* parse_device_role_object(json_object *device_role_o) {
2149     pa_hashmap *roles = NULL;
2150     const char *params, *device_role;
2151     struct json_object_iterator it, it_end;
2152     json_object *params_o;
2153
2154     pa_assert(device_role_o);
2155     pa_assert(json_object_is_type(device_role_o, json_type_object));
2156
2157     roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2158     if (!roles) {
2159         pa_log_debug("hashmap new failed");
2160         goto fail;
2161     }
2162
2163     it = json_object_iter_begin(device_role_o);
2164     it_end = json_object_iter_end(device_role_o);
2165
2166     while (!json_object_iter_equal(&it, &it_end)) {
2167         device_role = json_object_iter_peek_name(&it);
2168         params_o = json_object_iter_peek_value(&it);
2169
2170         if (!(params = json_object_get_string(params_o))) {
2171             pa_log_debug("There is no device params for role '%s'", device_role);
2172         }
2173         pa_log_info("- Role '%s' -> '%s'", device_role, params);
2174         if (device_role_is_valid(device_role)) {
2175             if (pa_hashmap_put(roles, (void *)device_role, (void *)params)) {
2176                 pa_log_error("put new role to hashmap faild");
2177                 goto fail;
2178             }
2179         } else {
2180             pa_log_error("Invalid device role '%s'", device_role);
2181         }
2182
2183         json_object_iter_next(&it);
2184     }
2185
2186     if (pa_hashmap_size(roles) == 0) {
2187         pa_log_warn("There is no role for device.. free hashmap");
2188         pa_hashmap_free(roles);
2189         roles = NULL;
2190     }
2191
2192     return roles;
2193
2194 fail:
2195     if (roles)
2196         pa_hashmap_free(roles);
2197
2198     return NULL;
2199 }
2200
2201 static struct device_file_info* parse_device_file_object(json_object *device_file_o, const char **device_string_key) {
2202     pa_hashmap *roles = NULL;
2203     json_object *device_file_prop_o = NULL;
2204     const char *device_string = NULL;
2205     struct device_file_info *file_info = NULL;
2206
2207     pa_assert(device_file_o);
2208     pa_assert(device_string_key);
2209     pa_assert(json_object_is_type(device_file_o, json_type_object));
2210
2211     if (json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_DEVICE_STRING, &device_file_prop_o) && json_object_is_type(device_file_prop_o, json_type_string)) {
2212         if ((device_string = json_object_get_string(device_file_prop_o))) {
2213             pa_log_info("[ Device File - %s ]", device_string);
2214         } else {
2215             pa_log_error("Get device-string failed");
2216             return NULL;
2217         }
2218     } else {
2219         pa_log_error("Get device-string object failed");
2220         return NULL;
2221     }
2222
2223     if (json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_ROLE, &device_file_prop_o)) {
2224         if (!(roles = parse_device_role_object(device_file_prop_o))) {
2225             pa_log_error("Parse device role for '%s' failed", device_string);
2226             goto fail;
2227         }
2228     } else {
2229         pa_log_error("Get device role object failed");
2230     }
2231
2232     file_info = pa_xmalloc0(sizeof(struct device_file_info));
2233     file_info->device_string = device_string;
2234     file_info->device_types = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2235     file_info->roles = roles;
2236
2237 //    *device_string_key = device_string;
2238
2239     return file_info;
2240
2241 fail:
2242
2243     return NULL;
2244 }
2245
2246 static pa_idxset* parse_device_file_array_object(json_object *device_file_array_o) {
2247     int device_file_num, device_file_idx;
2248     struct device_file_info *file_info = NULL;
2249     json_object *device_file_o = NULL;
2250     pa_idxset *device_files = NULL;
2251     const char *device_string = NULL;
2252
2253     pa_assert(device_file_array_o);
2254     pa_assert(json_object_is_type(device_file_array_o, json_type_array));
2255
2256     device_files = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2257
2258     device_file_num = json_object_array_length(device_file_array_o);
2259     for (device_file_idx = 0; device_file_idx < device_file_num; device_file_idx++) {
2260         if ((device_file_o = json_object_array_get_idx(device_file_array_o, device_file_idx)) && json_object_is_type(device_file_o, json_type_object)) {
2261             if ((file_info = parse_device_file_object(device_file_o, &device_string))) {
2262                 pa_idxset_put(device_files, file_info, NULL);
2263             } else {
2264                 pa_log_error("parse device file object failed");
2265                 goto fail;
2266             }
2267         } else {
2268             pa_log_error("Get device file object failed");
2269             goto fail;
2270         }
2271     }
2272
2273     if (pa_idxset_size(device_files) == 0) {
2274         pa_idxset_free(device_files, NULL);
2275         device_files = NULL;
2276     }
2277
2278     return device_files;
2279
2280 fail:
2281     if (device_files)
2282         pa_xfree(device_files);
2283     return NULL;
2284 }
2285
2286 static struct device_file_map *parse_device_file_map() {
2287     struct device_file_map *file_map = NULL;
2288     json_object *o, *device_files_o;
2289     json_object *playback_devices_o = NULL, *capture_devices_o = NULL;
2290
2291     pa_log_info("\nParse device files");
2292
2293     o = json_object_from_file(DEVICE_MAP_FILE);
2294
2295     if (o == NULL) {
2296         pa_log_error("Read device-map file failed");
2297         return NULL;
2298     }
2299
2300     file_map = pa_xmalloc0(sizeof(struct device_file_map));
2301
2302     if (json_object_object_get_ex(o, DEVICE_FILE_OBJECT, &device_files_o) && json_object_is_type(device_files_o, json_type_object)) {
2303         if (json_object_object_get_ex(device_files_o, DEVICE_TYPE_PROP_PLAYBACK_DEVICES, &playback_devices_o)) {
2304             pa_log_info("Playback Device Files");
2305             file_map->playback = parse_device_file_array_object(playback_devices_o);
2306         }
2307         if (json_object_object_get_ex(device_files_o, DEVICE_TYPE_PROP_CAPTURE_DEVICES, &capture_devices_o)) {
2308             pa_log_info("Capture Device Files");
2309             file_map->capture = parse_device_file_array_object(capture_devices_o);
2310         }
2311     } else {
2312         pa_log_error("Get device files object failed");
2313         pa_xfree(file_map);
2314         return NULL;
2315     }
2316
2317     return file_map;
2318 }
2319
2320
2321 static pa_hashmap* parse_device_role_map(json_object *device_role_map_o) {
2322     pa_hashmap *roles = NULL;
2323     const char *device_string, *device_role;
2324     struct json_object_iterator it, it_end;
2325     json_object *device_string_o;
2326
2327     pa_assert(device_role_map_o);
2328     pa_assert(json_object_is_type(device_role_map_o, json_type_object));
2329
2330     roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2331
2332     it = json_object_iter_begin(device_role_map_o);
2333     it_end = json_object_iter_end(device_role_map_o);
2334
2335     while (!json_object_iter_equal(&it, &it_end)) {
2336         device_role = json_object_iter_peek_name(&it);
2337         device_string_o = json_object_iter_peek_value(&it);
2338
2339         if (!(device_string = json_object_get_string(device_string_o))) {
2340             pa_log_debug("There is no device string for role '%s'", device_role);
2341         }
2342         pa_log_info("- Role '%s' -> '%s'", device_role, device_string);
2343         if (device_role_is_valid(device_role)) {
2344             if (pa_hashmap_put(roles, (void *)device_role, (void *)device_string)) {
2345                 pa_log_error("put new role to hashmap faild");
2346                 goto fail;
2347             }
2348         } else {
2349             pa_log_error("Invalid device role '%s'", device_role);
2350             goto fail;
2351         }
2352
2353         json_object_iter_next(&it);
2354     }
2355
2356     return roles;
2357
2358 fail:
2359     if (roles)
2360         pa_xfree(roles);
2361
2362     return NULL;
2363 }
2364
2365
2366
2367 static pa_idxset* parse_device_type_infos() {
2368     json_object *o, *device_array_o = NULL;
2369     int device_type_num = 0;
2370     int device_type_idx = 0;
2371     struct device_type_info *type_info = NULL;
2372     //pa_hashmap *type_infos = NULL;
2373     pa_idxset *type_infos = NULL;
2374
2375     o = json_object_from_file(DEVICE_MAP_FILE);
2376     if (o == NULL) {
2377         pa_log_error("Read device-map file failed");
2378         return NULL;
2379     }
2380
2381     pa_log_info("\nParse device types");
2382     type_infos = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2383
2384     if (json_object_object_get_ex(o, DEVICE_TYPE_OBJECT, &device_array_o) && json_object_is_type(device_array_o, json_type_array)) {
2385         device_type_num = json_object_array_length(device_array_o);
2386         for (device_type_idx = 0; device_type_idx < device_type_num ; device_type_idx++) {
2387             json_object *device_o;
2388
2389             if ((device_o = json_object_array_get_idx(device_array_o, device_type_idx)) && json_object_is_type(device_o, json_type_object)) {
2390                 json_object *device_prop_o;
2391                 const char *type = NULL;
2392
2393                 if (!json_object_object_get_ex(device_o, DEVICE_TYPE_PROP_DEVICE_TYPE, &device_prop_o) && json_object_is_type(device_prop_o, json_type_string)) {
2394                     pa_log_error("Get device type failed");
2395                     goto fail;
2396                 }
2397                 type = json_object_get_string(device_prop_o);
2398                 pa_log_info("[ Device - %s ]", type);
2399
2400                 type_info = pa_xmalloc0(sizeof(struct device_type_info));
2401                 type_info->type = type;
2402
2403                 if (json_object_object_get_ex(device_o, DEVICE_TYPE_PROP_PLAYBACK_DEVICES, &device_prop_o) && json_object_is_type(device_prop_o, json_type_object)) {
2404                     pa_log_info("Playback Devices");
2405                     type_info->playback_devices = parse_device_role_map(device_prop_o);
2406                 }
2407
2408                 if (json_object_object_get_ex(device_o, DEVICE_TYPE_PROP_CAPTURE_DEVICES, &device_prop_o) && json_object_is_type(device_prop_o, json_type_object)) {
2409                     pa_log_info("Capture Devices");
2410                     type_info->capture_devices = parse_device_role_map(device_prop_o);
2411                 }
2412                 pa_idxset_put(type_infos, type_info, NULL);
2413
2414             } else {
2415                 pa_log_debug("Get device type object failed");
2416             }
2417         }
2418     } else {
2419         pa_log_debug("Get device type array object failed");
2420     }
2421     return type_infos;
2422
2423 fail:
2424     if (type_infos)
2425         pa_xfree(type_infos);
2426
2427     return NULL;
2428 }
2429
2430 /*
2431    look detected status which is external value, make conversion to internal consistent value, and handle it
2432    device_type, which type of device is detected
2433    system_id : system_id among same device types for support multi-device
2434 */
2435 static int handle_device_status_changed(pa_device_manager *dm, const char *type,
2436         const char *name, const char *system_id, device_detected_type_t detected) {
2437     pa_assert(dm);
2438     pa_assert(device_type_is_valid(type));
2439
2440     pa_log_info("Device Status Changed, type(%s) system_id(%s), detected_type(%d)",
2441             type, pa_strempty(system_id), detected);
2442
2443     if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2444         _device_set_detected(dm, type, name, system_id, detected);
2445         if (detected == DEVICE_DISCONNECTED)
2446             handle_device_disconnected(dm, type, system_id);
2447         else
2448             handle_device_connected(dm, type, name, system_id, detected);
2449     } else if (device_type_is_need_detect(type)) {
2450         _device_set_detected(dm, type, name, system_id, detected);
2451         if (detected == DEVICE_DISCONNECTED)
2452             handle_device_disconnected(dm, type, system_id);
2453         else
2454             handle_device_connected(dm, type, name, system_id, detected);
2455     } else {
2456         pa_log_debug("No need to detect type %s", type);
2457     }
2458
2459     return 0;
2460 }
2461
2462 /*
2463     Initialize device-status idxset.
2464     This is for device-status detected through dbus.
2465     So, if device_type is not detected through dbus, let's initialize them to detected. (ex. spk, rcv,...)
2466     If not, initialize to not detected.
2467 */
2468 static void device_type_status_init(pa_device_manager *manager) {
2469     struct device_type_info *type_info;
2470     uint32_t type_idx;
2471     const char *type;
2472
2473     pa_assert(manager);
2474     pa_assert(manager->type_infos);
2475
2476     pa_log_debug("\n==================== Init Device Status ====================");
2477
2478     PA_IDXSET_FOREACH(type_info, manager->type_infos, type_idx) {
2479         type = type_info->type;
2480         if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
2481             int earjack_status = 0;
2482             if (vconf_get_int(VCONFKEY_SYSMAN_EARJACK, &earjack_status) < 0) {
2483                 pa_log_error("Get earjack status failed");
2484                 continue;
2485             }
2486             if (earjack_status == EARJACK_TYPE_SPK_ONLY)
2487                 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_3P);
2488             else if (earjack_status == EARJACK_TYPE_SPK_WITH_MIC)
2489                 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_4P);
2490             else if (earjack_status == EARJACK_DISCONNECTED)
2491                 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2492             else
2493                 pa_log_warn("Unknown earjack status : %d", earjack_status);
2494         } else if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2495                 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2496         } else if (device_type_is_equal(type, DEVICE_TYPE_HDMI)) {
2497                 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2498         } else if (device_type_is_equal(type, DEVICE_TYPE_FORWARDING)) {
2499             int miracast_wfd_status = 0;
2500             if (vconf_get_bool(VCONFKEY_MIRACAST_WFD_SOURCE_STATUS, &miracast_wfd_status) < 0) {
2501                 pa_log_error("Get mirroring status failed");
2502                 continue;
2503             }
2504             if (miracast_wfd_status == FORWARDING_CONNECTED)
2505                 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
2506         } else {
2507             _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
2508         }
2509     }
2510     return ;
2511 }
2512
2513 #ifdef HAVE_DBUS
2514
2515 static int _translate_external_value(const char *type, int value, device_detected_type_t *detected) {
2516
2517     if (!type || !detected) {
2518         pa_log_error("Invalid Parameter for translate");
2519         return -1;
2520     }
2521
2522     if (device_type_is_equal(DEVICE_TYPE_AUDIO_JACK, type)) {
2523         if (value == EARJACK_DISCONNECTED)
2524             *detected = DEVICE_DISCONNECTED;
2525         else if (value == EARJACK_TYPE_SPK_ONLY)
2526             *detected = DEVICE_CONNECTED_AUDIO_JACK_3P;
2527         else if (value == EARJACK_TYPE_SPK_WITH_MIC)
2528             *detected = DEVICE_CONNECTED_AUDIO_JACK_4P;
2529         else
2530             return -1;
2531     } else if (device_type_is_equal(DEVICE_TYPE_HDMI, type)) {
2532         if (value == HDMI_AUDIO_DISCONNECTED)
2533             *detected = DEVICE_DISCONNECTED;
2534         else if (value == HDMI_AUDIO_AVAILABLE)
2535             *detected = DEVICE_CONNECTED;
2536         else
2537             return -1;
2538     } else if (device_type_is_equal(DEVICE_TYPE_FORWARDING, type)) {
2539         if (value == FORWARDING_DISCONNECTED)
2540             *detected = DEVICE_DISCONNECTED;
2541         else if (value == FORWARDING_CONNECTED)
2542             *detected = DEVICE_CONNECTED;
2543         else
2544             return -1;
2545     } else if (device_type_is_equal(DEVICE_TYPE_BT_SCO, type)) {
2546         if (value == BT_SCO_DISCONNECTED)
2547             *detected = DEVICE_DISCONNECTED;
2548         else if (value == BT_SCO_CONNECTED)
2549             *detected = DEVICE_CONNECTED_SCO;
2550         else
2551             return -1;
2552     }
2553
2554     return 0;
2555 }
2556
2557 static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
2558     DBusError error;
2559     int status = 0;
2560     pa_device_manager *dm = (pa_device_manager *) userdata;
2561     device_detected_type_t detected;
2562
2563     pa_assert(userdata);
2564
2565     if (dbus_message_get_type(s) != DBUS_MESSAGE_TYPE_SIGNAL)
2566         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2567
2568     pa_log_info("Device detect handler : Path(%s) Intf(%s) Member(%s) Signature(%s)",
2569             dbus_message_get_path(s), dbus_message_get_interface(s), dbus_message_get_member(s), dbus_message_get_signature(s));
2570
2571     dbus_error_init(&error);
2572
2573     if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedEarjack")) {
2574         if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2575             goto fail;
2576         } else {
2577             if (_translate_external_value(DEVICE_TYPE_AUDIO_JACK, status, &detected) < 0) {
2578                 pa_log_warn("failed to translate audio-jack detected value");
2579                 goto fail;
2580             }
2581             handle_device_status_changed(dm, DEVICE_TYPE_AUDIO_JACK, NULL, NULL, detected);
2582         }
2583     } else if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedHDMIAudio")) {
2584         if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2585             goto fail;
2586         } else {
2587             if (_translate_external_value(DEVICE_TYPE_HDMI, status, &detected) < 0) {
2588                 pa_log_warn("failed to translate HDMI detected value");
2589                 goto fail;
2590             }
2591             handle_device_status_changed(dm, DEVICE_TYPE_HDMI, NULL, NULL, detected);
2592         }
2593     } else if (dbus_message_is_signal(s, DBUS_INTERFACE_MIRRORING_SERVER, "miracast_wfd_source_status_changed")) {
2594         if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2595             goto fail;
2596         } else {
2597             if (_translate_external_value(DEVICE_TYPE_FORWARDING, status, &detected) < 0) {
2598                 pa_log_warn("failed to translate forwarding detected value");
2599                 goto fail;
2600             }
2601             handle_device_status_changed(dm, DEVICE_TYPE_FORWARDING, NULL, NULL, detected);
2602         }
2603     } else if (dbus_message_is_signal(s, DBUS_INTERFACE_BLUEZ_HEADSET, "PropertyChanged")) {
2604         DBusMessageIter msg_iter, variant_iter;
2605         char *property_name;
2606
2607         pa_log_debug("Got %s PropertyChanged signal", DBUS_INTERFACE_BLUEZ_HEADSET);
2608         dbus_message_iter_init(s, &msg_iter);
2609         if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_STRING) {
2610             pa_log_error("Property name not string");
2611             goto fail;
2612         }
2613         dbus_message_iter_get_basic(&msg_iter, &property_name);
2614         pa_log_info("Changed Property name : %s", property_name);
2615
2616         if (!dbus_message_iter_next(&msg_iter)) {
2617             pa_log_debug("Property value missing");
2618             goto fail;
2619         }
2620
2621         if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_VARIANT) {
2622             pa_log_debug("Property value not a variant.");
2623             goto fail;
2624         }
2625
2626         dbus_message_iter_recurse(&msg_iter, &variant_iter);
2627
2628         if (DBUS_TYPE_BOOLEAN == dbus_message_iter_get_arg_type(&variant_iter)) {
2629             dbus_bool_t value;
2630             char *name = NULL;
2631             dbus_message_iter_get_basic(&variant_iter, &value);
2632             if (pa_streq(property_name, "Connected")) {
2633                 pa_log_info("HFP Connection : %d", value);
2634                 if (value) {
2635                     method_call_bt_get_name(c, dbus_message_get_path(s), &name);
2636                     status = BT_SCO_CONNECTED;
2637                 } else {
2638                     status = BT_SCO_DISCONNECTED;
2639                 }
2640                 if (_translate_external_value(DEVICE_TYPE_BT_SCO, status, &detected) < 0) {
2641                     pa_log_warn("failed to translate bt-sco detected value");
2642                     goto fail;
2643                 }
2644                 handle_device_status_changed(dm, DEVICE_TYPE_BT_SCO,
2645                         name, dbus_message_get_path(s),  detected);
2646             } else if (pa_streq(property_name, "Playing")) {
2647                 pa_tz_device *device;
2648                 pa_log_info("SCO Playing : %d", value);
2649                 if ((device = _device_list_get_device(dm, DEVICE_TYPE_BT_SCO, NULL)) != NULL) {
2650                     device->sco_opened = value;
2651                     if (value) {
2652                         /* update BT band/nrec information */
2653                         bool is_wide_band = false;
2654                         bool nrec = false;
2655                         pa_tz_device_sco_get_property(device, &is_wide_band, &nrec);
2656                         pa_log_info("got new wideband:%d, nrec:%d", is_wide_band, nrec);
2657
2658                         UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-wideband", is_wide_band);
2659                         UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-nrec", nrec);
2660                     }
2661                 }
2662                 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-sco-ready", value);
2663             }
2664         }
2665     } else {
2666         pa_log_debug("Unknown message, not handle it");
2667         dbus_error_free(&error);
2668         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2669     }
2670
2671     pa_log_debug("Dbus Message handled");
2672
2673     dbus_error_free(&error);
2674     return DBUS_HANDLER_RESULT_HANDLED;
2675
2676 fail:
2677     pa_log_error("Fail to handle dbus signal");
2678     dbus_error_free(&error);
2679     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2680 }
2681
2682 static int watch_signals(pa_device_manager *dm) {
2683     DBusError error;
2684
2685     pa_assert(dm);
2686     pa_assert(dm->dbus_conn);
2687
2688     dbus_error_init(&error);
2689
2690     pa_log_info("Watch Dbus signals");
2691
2692     if (!dbus_connection_add_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm, NULL)) {
2693         pa_log_error("Unable to add D-Bus filter : %s: %s", error.name, error.message);
2694         goto fail;
2695     }
2696
2697     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) {
2698         pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
2699         goto fail;
2700     }
2701     return 0;
2702
2703 fail:
2704     dbus_error_free(&error);
2705     return -1;
2706 }
2707
2708 static void unwatch_signals(pa_device_manager *dm) {
2709     pa_log_info("Unwatch Dbus signals");
2710
2711     pa_assert(dm);
2712     pa_assert(dm->dbus_conn);
2713
2714     pa_dbus_remove_matches(pa_dbus_connection_get(dm->dbus_conn), FILTER_DEVICED_SYSNOTI, FILTER_SOUND_SERVER, FILTER_BLUEZ, FILTER_MIRRORING, NULL);
2715     dbus_connection_remove_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm);
2716 }
2717
2718 static void fill_signal_msg_with_device(const char *description, DBusMessageIter *msg_iter, uint32_t event_id, pa_tz_device *device) {
2719     DBusMessageIter array_iter, device_iter;
2720     char *type, *name;
2721     dbus_int32_t device_id, direction, state, stream_id;
2722     dbus_int32_t vendor_id, product_id;
2723     dbus_bool_t is_running;
2724     pa_intset *stream_id_set = NULL;
2725     int32_t stream_id_val;
2726     int ret;
2727
2728     pa_assert(msg_iter);
2729     pa_assert(device);
2730
2731     dbus_message_iter_append_basic(msg_iter, DBUS_TYPE_UINT32, &event_id);
2732     pa_assert_se(dbus_message_iter_open_container(msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2733
2734     direction = (dbus_int32_t) pa_tz_device_get_direction(device);
2735     type = pa_tz_device_get_type(device);
2736     name = pa_tz_device_get_name(device);
2737     device_id = (dbus_int32_t) pa_tz_device_get_id(device);
2738     state = pa_tz_device_get_state(device);
2739     vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
2740     product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
2741     is_running = (dbus_bool_t) pa_tz_device_is_running(device);
2742
2743     simple_device_dump(PA_LOG_INFO, description, device_id, type, name, direction, state);
2744
2745     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2746     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
2747     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
2748     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
2749     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
2750     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
2751     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
2752     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
2753     if (state == DM_DEVICE_STATE_ACTIVATED)
2754         stream_id_set = pa_tz_device_get_stream_list(device);
2755     pa_assert_se(dbus_message_iter_open_container(&device_iter, DBUS_TYPE_ARRAY, "i", &array_iter));
2756     if (state == DM_DEVICE_STATE_ACTIVATED) {
2757         PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
2758             stream_id = stream_id_val;
2759             dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_INT32, &stream_id);
2760         }
2761     }
2762     pa_assert_se(dbus_message_iter_close_container(&device_iter, &array_iter));
2763     if (stream_id_set)
2764         pa_intset_free(stream_id_set);
2765     pa_assert_se(dbus_message_iter_close_container(msg_iter, &device_iter));
2766     pa_log_info("end of fill signal msg");
2767 }
2768
2769 static void send_device_connection_changed_signal(uint32_t event_id, pa_tz_device *device, bool connected, pa_device_manager *dm) {
2770     DBusMessage *signal_msg;
2771     DBusMessageIter msg_iter;
2772     dbus_bool_t _connected = connected;
2773
2774     pa_assert(device);
2775     pa_assert(dm);
2776
2777     pa_log_info("Send device connection changed signal, event_id(%u)", event_id);
2778
2779     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceConnected"));
2780     dbus_message_iter_init_append(signal_msg, &msg_iter);
2781     fill_signal_msg_with_device(connected ? "[Connected]" : "[Disconnected]", &msg_iter, event_id, device);
2782
2783     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &_connected);
2784
2785     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2786
2787     dbus_message_unref(signal_msg);
2788     pa_log_info("end of send device connection changed signal");
2789 }
2790
2791 static void send_device_info_changed_signal(uint32_t event_id, pa_tz_device *device, int changed_type, pa_device_manager *dm) {
2792     DBusMessage *signal_msg;
2793     DBusMessageIter msg_iter;
2794     const char *changed_prefix[] = {"[State Changed]", "[Direction Changed]", "[Avail-Mode Changed]"};
2795
2796     pa_assert(device);
2797     pa_assert(dm);
2798
2799     pa_log_debug("Send device info changed signal, event_id(%u)", event_id);
2800
2801     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceInfoChanged"));
2802     dbus_message_iter_init_append(signal_msg, &msg_iter);
2803     fill_signal_msg_with_device(changed_prefix[changed_type], &msg_iter, event_id, device);
2804     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &changed_type);
2805
2806     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2807
2808     dbus_message_unref(signal_msg);
2809 }
2810
2811 static void send_device_state_changed_signal(uint32_t event_id, pa_tz_device *device, bool activated, pa_device_manager *dm) {
2812     DBusMessage *signal_msg;
2813     DBusMessageIter msg_iter;
2814
2815     pa_assert(device);
2816     pa_assert(dm);
2817
2818     pa_log_debug("Send device state changed signal, event_id(%u)", event_id);
2819
2820     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceStateChanged"));
2821     dbus_message_iter_init_append(signal_msg, &msg_iter);
2822     fill_signal_msg_with_device(activated ? "[Activated]" : "[Deactivated]", &msg_iter, event_id, device);
2823
2824     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2825
2826     dbus_message_unref(signal_msg);
2827 }
2828
2829 static void send_device_running_changed_signal(uint32_t event_id, pa_tz_device *device, bool is_running, pa_device_manager *dm) {
2830     DBusMessage *signal_msg;
2831     DBusMessageIter msg_iter;
2832
2833     pa_assert(device);
2834     pa_assert(dm);
2835
2836     pa_log_debug("Send device running changed signal, event_id(%u)", event_id);
2837
2838     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceRunningChanged"));
2839     dbus_message_iter_init_append(signal_msg, &msg_iter);
2840     fill_signal_msg_with_device(is_running ? "[Running]" : "[NotRunning]", &msg_iter, event_id, device);
2841
2842     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2843
2844     dbus_message_unref(signal_msg);
2845 }
2846
2847 static bool device_is_match_direction(pa_tz_device *device, int direction_mask) {
2848     dm_device_direction_t direction;
2849
2850     if (direction_mask == DEVICE_IO_DIRECTION_FLAGS || direction_mask == 0)
2851         return true;
2852
2853     direction = pa_tz_device_get_direction(device);
2854
2855     if ((direction_mask & DEVICE_IO_DIRECTION_IN_FLAG) && (direction & DM_DEVICE_DIRECTION_IN))
2856         return true;
2857     if ((direction_mask & DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & DM_DEVICE_DIRECTION_OUT))
2858         return true;
2859     if ((direction_mask & DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction == DM_DEVICE_DIRECTION_BOTH))
2860         return true;
2861
2862     return false;
2863 }
2864
2865 static bool device_is_match_state(pa_tz_device *device, int state_mask) {
2866     dm_device_state_t state;
2867
2868     if (state_mask == DEVICE_STATE_FLAGS || state_mask == 0)
2869         return true;
2870
2871     state = pa_tz_device_get_state(device);
2872
2873     if ((state_mask & DEVICE_STATE_DEACTIVATED_FLAG) && (state == DM_DEVICE_STATE_DEACTIVATED))
2874         return true;
2875     if ((state_mask & DEVICE_STATE_ACTIVATED_FLAG) && (state == DM_DEVICE_STATE_ACTIVATED))
2876         return true;
2877
2878     return false;
2879 }
2880
2881 static bool device_is_match_type(pa_tz_device *device, int type_mask) {
2882     char *type;
2883     bool is_builtin;
2884
2885     if (type_mask == DEVICE_TYPE_FLAGS || type_mask == 0)
2886         return true;
2887
2888     type = pa_tz_device_get_type(device);
2889     is_builtin = device_type_is_builtin(type);
2890
2891     if ((type_mask & DEVICE_TYPE_INTERNAL_FLAG) && is_builtin)
2892         return true;
2893     if ((type_mask & DEVICE_TYPE_EXTERNAL_FLAG) && !is_builtin)
2894         return true;
2895
2896     return false;
2897 }
2898
2899 static bool device_is_match_with_mask(pa_tz_device *device, int mask) {
2900     pa_assert(device);
2901
2902     if (mask == DEVICE_ALL_FLAG)
2903         return true;
2904
2905     return (device_is_match_direction(device, mask & DEVICE_IO_DIRECTION_FLAGS) &&
2906             device_is_match_state(device, mask & DEVICE_STATE_FLAGS) &&
2907             device_is_match_type(device, mask & DEVICE_TYPE_FLAGS));
2908 }
2909
2910 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name) {
2911     const char *intf = DBUS_INTERFACE_BLUEZ_DEVICE, *prop = "Alias";
2912     DBusMessage *msg, *reply;
2913     DBusMessageIter reply_iter, variant_iter;
2914     DBusError err;
2915
2916     pa_assert(conn);
2917     pa_assert(device_path);
2918     pa_assert(name);
2919
2920     if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_BLUEZ, device_path, "org.freedesktop.DBus.Properties", "Get"))) {
2921         pa_log_error("dbus method call failed");
2922         return -1;
2923     }
2924
2925     dbus_message_append_args(msg,
2926                 DBUS_TYPE_STRING, &intf,
2927                 DBUS_TYPE_STRING, &prop,
2928                 DBUS_TYPE_INVALID);
2929
2930     dbus_error_init(&err);
2931     if (!(reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err))) {
2932         pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_BLUEZ_DEVICE, "Get", err.message);
2933         dbus_error_free(&err);
2934         return -1;
2935     }
2936
2937     dbus_message_iter_init(reply,  &reply_iter);
2938
2939     if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_VARIANT) {
2940         pa_log_error("Cannot get reply argument");
2941         return -1;
2942     }
2943
2944     dbus_message_iter_recurse(&reply_iter,  &variant_iter);
2945
2946     if (dbus_message_iter_get_arg_type(&variant_iter) == DBUS_TYPE_STRING) {
2947         dbus_message_iter_get_basic(&variant_iter, name);
2948     }
2949
2950     dbus_message_unref(reply);
2951     return 0;
2952 }
2953
2954 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2955     pa_device_manager *dm;
2956     DBusMessage *reply = NULL;
2957     DBusMessageIter msg_iter, array_iter, device_iter;
2958     pa_tz_device *device;
2959     dm_device_state_t state;
2960     uint32_t device_idx;
2961     dbus_int32_t device_id, direction;
2962     int mask;
2963     char *type, *name;
2964     dbus_int32_t vendor_id, product_id;
2965     dbus_bool_t is_running;
2966
2967     pa_assert(conn);
2968     pa_assert(msg);
2969     pa_assert(userdata);
2970
2971
2972     dm = (pa_device_manager*) userdata;
2973
2974     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2975
2976     pa_assert_se(dbus_message_get_args(msg, NULL,
2977                                        DBUS_TYPE_INT32, &mask,
2978                                        DBUS_TYPE_INVALID));
2979
2980     pa_log_info("Get connected device list (mask : %d)", mask);
2981
2982     dbus_message_iter_init_append(reply, &msg_iter);
2983     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiisiib)", &array_iter));
2984
2985     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
2986         device_id = (dbus_int32_t)pa_tz_device_get_id(device);
2987         state = pa_tz_device_get_state(device);
2988         direction = pa_tz_device_get_direction(device);
2989         type = pa_tz_device_get_type(device);
2990         name = pa_tz_device_get_name(device);
2991         vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
2992         product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
2993         product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
2994         is_running = (dbus_bool_t) pa_tz_device_is_running(device);
2995         if (device_is_match_with_mask(device,  mask)) {
2996             simple_device_dump(PA_LOG_INFO, "[MATCH]", device_id, type, name, direction, state);
2997             pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2998             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2999             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
3000             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
3001             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
3002             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
3003             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
3004             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
3005             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
3006             pa_assert_se(dbus_message_iter_close_container(&array_iter, &device_iter));
3007         } else {
3008             simple_device_dump(PA_LOG_INFO, "[UNMATCH]", device_id, type, name, direction, state);
3009         }
3010     }
3011
3012     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
3013
3014     pa_assert_se(dbus_connection_send(conn, reply, NULL));
3015     dbus_message_unref(reply);
3016 }
3017
3018 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3019     pa_device_manager *manager;
3020     DBusMessage *reply;
3021     DBusMessageIter msg_iter;
3022     pa_tz_device *device;
3023     dbus_int32_t device_id;
3024     dbus_int32_t id, direction, state;
3025     dbus_int32_t vendor_id, product_id;
3026     char *type, *name;
3027
3028     pa_assert(conn);
3029     pa_assert(msg);
3030     pa_assert(userdata);
3031
3032     manager = (pa_device_manager*) userdata;
3033
3034     pa_assert_se(dbus_message_get_args(msg, NULL,
3035                                        DBUS_TYPE_INT32, &device_id,
3036                                        DBUS_TYPE_INVALID));
3037
3038     pa_log_info("Get device by id(%d)", device_id);
3039
3040     if ((device = _device_list_get_device_by_id(manager, device_id))) {
3041         pa_assert_se((reply = dbus_message_new_method_return(msg)));
3042         dbus_message_iter_init_append(reply, &msg_iter);
3043
3044         id = (dbus_int32_t)pa_tz_device_get_id(device);
3045         state = pa_tz_device_get_state(device);
3046         direction = pa_tz_device_get_direction(device);
3047         type = pa_tz_device_get_type(device);
3048         name = pa_tz_device_get_name(device);
3049         vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
3050         product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
3051
3052         simple_device_dump(PA_LOG_INFO, "[GET_BY_ID]", device_id, type, name, direction, state);
3053
3054         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &id);
3055         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &type);
3056         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &direction);
3057         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &state);
3058         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
3059         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &vendor_id);
3060         dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &product_id);
3061
3062         pa_assert_se(dbus_connection_send(conn, reply, NULL));
3063         dbus_message_unref(reply);
3064     } else {
3065         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3066     }
3067 }
3068
3069 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3070     pa_device_manager *manager;
3071     DBusMessage *reply;
3072     pa_tz_device *device;
3073     dbus_bool_t is_on = false;
3074     dbus_int32_t stream_id, device_id;
3075     pa_intset *stream_id_set;
3076     int32_t stream_id_val;
3077     int ret;
3078     dm_device_state_t state;
3079
3080     pa_assert(conn);
3081     pa_assert(msg);
3082     pa_assert(userdata);
3083
3084     pa_log_info("Is stream on device");
3085
3086     manager = (pa_device_manager*) userdata;
3087
3088
3089     pa_assert_se(dbus_message_get_args(msg, NULL,
3090                                        DBUS_TYPE_INT32, &stream_id,
3091                                        DBUS_TYPE_INT32, &device_id,
3092                                        DBUS_TYPE_INVALID));
3093
3094     if ((device = _device_list_get_device_by_id(manager, device_id))) {
3095         pa_assert_se((reply = dbus_message_new_method_return(msg)));
3096
3097         state = pa_tz_device_get_state(device);
3098         if (state == DM_DEVICE_STATE_ACTIVATED) {
3099             stream_id_set = pa_tz_device_get_stream_list(device);
3100             PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
3101                 if (stream_id_val == stream_id) {
3102                     is_on = true;
3103                     pa_log_info("stream(%d) is on device(%d)", stream_id, device_id);
3104                     break;
3105                 }
3106             }
3107             pa_intset_free(stream_id_set);
3108         } else {
3109             pa_log_info("device(%d) is not activated, regard as no stream on it", device_id);
3110             is_on = false;
3111         }
3112
3113         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_on,
3114                                                      DBUS_TYPE_INVALID));
3115
3116         pa_assert_se(dbus_connection_send(conn, reply, NULL));
3117         dbus_message_unref(reply);
3118     } else {
3119         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.Internal");
3120     }
3121 }
3122
3123 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3124     pa_device_manager *dm;
3125     DBusMessage *reply = NULL;
3126     pa_tz_device *device;
3127     dbus_bool_t is_bt_on = false;
3128     const char *bt_name = "none";
3129
3130     pa_assert(conn);
3131     pa_assert(msg);
3132     pa_assert(userdata);
3133
3134     pa_log_info("Get BT A2DP list");
3135
3136     dm = (pa_device_manager*) userdata;
3137
3138     pa_assert_se((reply = dbus_message_new_method_return(msg)));
3139
3140     /* FIXME : Give system_id for multi device */
3141     if ((device = _device_list_get_device(dm, DEVICE_TYPE_BT_A2DP, NULL)) != NULL) {
3142         is_bt_on = true;
3143         bt_name = pa_tz_device_get_name(device);
3144     }
3145
3146     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_bt_on,
3147                                                  DBUS_TYPE_STRING, &bt_name,
3148                                                  DBUS_TYPE_INVALID));
3149
3150     pa_assert_se(dbus_connection_send(conn, reply, NULL));
3151     dbus_message_unref(reply);
3152 }
3153
3154
3155
3156 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3157     pa_device_manager *dm;
3158     char *type, *role;
3159     DBusMessage *reply = NULL;
3160
3161     pa_assert_se((reply = dbus_message_new_method_return(msg)));
3162     dm = (pa_device_manager *) userdata;
3163     pa_assert_se(dbus_message_get_args(msg, NULL,
3164                                        DBUS_TYPE_STRING, &type,
3165                                        DBUS_TYPE_STRING, &role,
3166                                        DBUS_TYPE_INVALID));
3167
3168     pa_device_manager_load_sink(dm, type, role);
3169     pa_assert_se(dbus_connection_send(conn, reply, NULL));
3170     dbus_message_unref(reply);
3171 }
3172
3173 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3174     pa_device_manager *dm;
3175     char *type, *role;
3176     DBusMessage *reply = NULL;
3177
3178     pa_assert_se((reply = dbus_message_new_method_return(msg)));
3179     dm = (pa_device_manager *) userdata;
3180     pa_assert_se(dbus_message_get_args(msg, NULL,
3181                                        DBUS_TYPE_STRING, &type,
3182                                        DBUS_TYPE_STRING, &role,
3183                                        DBUS_TYPE_INVALID));
3184
3185     pa_device_manager_unload_sink(dm, type, role);
3186     pa_assert_se(dbus_connection_send(conn, reply, NULL));
3187     dbus_message_unref(reply);
3188 }
3189
3190 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3191     pa_device_manager *dm;
3192     char *device_string;
3193     DBusMessage *reply = NULL;
3194
3195     pa_assert_se((reply = dbus_message_new_method_return(msg)));
3196     dm = (pa_device_manager *) userdata;
3197     pa_assert_se(dbus_message_get_args(msg, NULL,
3198                                        DBUS_TYPE_STRING, &device_string,
3199                                        DBUS_TYPE_INVALID));
3200
3201     pa_device_manager_unload_sink_with_device_string(dm, device_string);
3202     pa_assert_se(dbus_connection_send(conn, reply, NULL));
3203     dbus_message_unref(reply);
3204 }
3205
3206 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3207     pa_device_manager *dm;
3208     char *type, *role;
3209     const char *device_string;
3210     dbus_bool_t is_playback;
3211     DBusMessage *reply;
3212
3213     dm = (pa_device_manager *) userdata;
3214     pa_assert_se(dbus_message_get_args(msg, NULL,
3215                                        DBUS_TYPE_BOOLEAN, &is_playback,
3216                                        DBUS_TYPE_STRING, &type,
3217                                        DBUS_TYPE_STRING, &role,
3218                                        DBUS_TYPE_INVALID));
3219
3220     device_string = pa_device_manager_get_device_string(dm, is_playback, type, role);
3221     if (device_string == NULL) {
3222         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3223         return;
3224     }
3225
3226     pa_log_info("device string : %s", device_string);
3227     pa_assert_se((reply = dbus_message_new_method_return(msg)));
3228     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &device_string,
3229                                                  DBUS_TYPE_INVALID));
3230     pa_assert_se(dbus_connection_send(conn, reply, NULL));
3231     dbus_message_unref(reply);
3232 }
3233
3234 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3235     pa_device_manager *dm;
3236     pa_tz_device *device;
3237     uint32_t device_idx;
3238     DBusMessage *reply = NULL;
3239
3240     pa_assert_se((reply = dbus_message_new_method_return(msg)));
3241     dm = (pa_device_manager *) userdata;
3242
3243     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3244         pa_tz_device_dump_info(device, PA_LOG_INFO);
3245     }
3246     pa_assert_se(dbus_connection_send(conn, reply, NULL));
3247     dbus_message_unref(reply);
3248 }
3249
3250 static bool is_usb_output_device(pa_tz_device *device) {
3251     char *type;
3252     dm_device_direction_t direction;
3253     pa_sink *sink;
3254
3255     pa_assert(device);
3256
3257     type = pa_tz_device_get_type(device);
3258     if (!pa_streq(type, DEVICE_TYPE_USB_AUDIO)) {
3259         pa_log_error("device(id:%d, %s) is not USB AUDIO type", pa_tz_device_get_id(device), type);
3260         return false;
3261     }
3262     direction = pa_tz_device_get_direction(device);
3263     if (direction & DM_DEVICE_DIRECTION_OUT) {
3264         if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
3265             pa_log_error("sink is null");
3266             return false;
3267         }
3268     } else {
3269         pa_log_error("this device is not for output");
3270         return false;
3271     }
3272
3273     return true;
3274 }
3275
3276 static bool is_supported_sample_rate(uint32_t *supported_sample_rates, uint32_t sample_rate) {
3277     int i;
3278
3279     pa_assert(supported_sample_rates);
3280
3281     /* use a supported sample rate selected by user */
3282     for (i = 0; supported_sample_rates[i]; i++) {
3283         if (supported_sample_rates[i] == sample_rate) {
3284             pa_log_info("%u is supported", sample_rate);
3285             return true;
3286         }
3287     }
3288     pa_log_error("%u is not supported", sample_rate);
3289     return false;
3290 }
3291
3292 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3293     pa_device_manager *dm;
3294     DBusMessage *reply = NULL;
3295     DBusMessageIter msg_iter, array_iter, item_iter;
3296     dbus_int32_t device_id;
3297     pa_tz_device *device;
3298     pa_sink *sink;
3299     int i;
3300
3301     pa_assert(conn);
3302     pa_assert(msg);
3303     pa_assert(userdata);
3304
3305     dm = (pa_device_manager *)userdata;
3306
3307     pa_assert_se((reply = dbus_message_new_method_return(msg)));
3308
3309     pa_assert_se(dbus_message_get_args(msg, NULL,
3310                                        DBUS_TYPE_INT32, &device_id,
3311                                        DBUS_TYPE_INVALID));
3312
3313     pa_log_info("Get supported sample rates of the device(id:%d)", device_id);
3314
3315     if (!(device = _device_list_get_device_by_id(dm, device_id))) {
3316         pa_log_error("could not find any device with id:%d", device_id);
3317         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3318         return;
3319     }
3320     if (!is_usb_output_device(device)) {
3321         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.PolicyInternal");
3322         return;
3323     }
3324     sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
3325
3326     dbus_message_iter_init_append(reply, &msg_iter);
3327     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(u)", &array_iter));
3328     for (i = 0; sink->supported_sample_rates[i]; i++) {
3329         pa_log_info("%u is supported", sink->supported_sample_rates[i]);
3330         pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &item_iter));
3331         dbus_message_iter_append_basic(&item_iter, DBUS_TYPE_UINT32, &sink->supported_sample_rates[i]);
3332         pa_assert_se(dbus_message_iter_close_container(&array_iter, &item_iter));
3333     }
3334     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
3335     pa_assert_se(dbus_connection_send(conn, reply, NULL));
3336     dbus_message_unref(reply);
3337 }
3338
3339 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3340     pa_device_manager *dm;
3341     DBusMessage *reply = NULL;
3342     dbus_int32_t device_id;
3343     dbus_uint32_t sample_rate;
3344     uint32_t prev_selected_sample_rate;
3345     pa_tz_device *device;
3346     pa_sink *sink;
3347     pa_sink_input *si;
3348     uint32_t idx;
3349
3350     pa_assert(conn);
3351     pa_assert(msg);
3352     pa_assert(userdata);
3353
3354     pa_assert_se((reply = dbus_message_new_method_return(msg)));
3355     dm = (pa_device_manager *)userdata;
3356     pa_assert_se(dbus_message_get_args(msg, NULL,
3357                                        DBUS_TYPE_INT32, &device_id,
3358                                        DBUS_TYPE_UINT32, &sample_rate,
3359                                        DBUS_TYPE_INVALID));
3360
3361     pa_log_info("Set sample rate(%u) of the device(id:%d)", sample_rate, device_id);
3362
3363     if (!(device = _device_list_get_device_by_id(dm, device_id))) {
3364         pa_log_error("could not find any device with id:%d", device_id);
3365         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3366         return;
3367     }
3368     if (!is_usb_output_device(device)) {
3369         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.PolicyInternal");
3370         return;
3371     }
3372     sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
3373
3374     /* use stream original sample rate if possible */
3375     if (sample_rate == 0) {
3376         sink->avoid_resampling = true;
3377         PA_IDXSET_FOREACH(si, sink->inputs, idx) {
3378             if (pa_sink_reconfigure(sink, &si->sample_spec, pa_sink_input_is_passthrough(si)) == -1) {
3379                 pa_log_error("failed to reconfigure");
3380                 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3381                 sink->avoid_resampling = sink->origin_avoid_resampling;
3382                 return;
3383             }
3384         }
3385         sink->selected_sample_rate = 0;
3386
3387         pa_log_info("Set sample rate to avoid resampling for the device(%u) successfully", device_id);
3388         pa_assert_se(dbus_connection_send(conn, reply, NULL));
3389         dbus_message_unref(reply);
3390         return;
3391     }
3392
3393     /* use a supported sample rate selected by user */
3394     if (!is_supported_sample_rate(sink->supported_sample_rates, sample_rate)) {
3395         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3396         return;
3397     }
3398     prev_selected_sample_rate = sink->selected_sample_rate;
3399     sink->selected_sample_rate = sample_rate;
3400
3401     PA_IDXSET_FOREACH(si, sink->inputs, idx) {
3402         if (pa_sink_reconfigure(sink, &si->sample_spec, pa_sink_input_is_passthrough(si)) == -1) {
3403             pa_log_error("failed to reconfigure");
3404             pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3405             sink->selected_sample_rate = prev_selected_sample_rate;
3406             return;
3407         }
3408         break;
3409     }
3410     sink->avoid_resampling = sink->origin_avoid_resampling;
3411
3412     pa_log_info("Set sample rate(%u) of the device(id:%d) successfully", sample_rate, device_id);
3413     pa_assert_se(dbus_connection_send(conn, reply, NULL));
3414     dbus_message_unref(reply);
3415 }
3416
3417 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3418     pa_device_manager *dm;
3419     DBusMessage *reply = NULL;
3420     dbus_int32_t device_id;
3421     pa_tz_device *device;
3422     pa_sink *sink;
3423
3424     pa_assert(conn);
3425     pa_assert(msg);
3426     pa_assert(userdata);
3427
3428     dm = (pa_device_manager *)userdata;
3429
3430     pa_assert_se((reply = dbus_message_new_method_return(msg)));
3431
3432     pa_assert_se(dbus_message_get_args(msg, NULL,
3433                                        DBUS_TYPE_INT32, &device_id,
3434                                        DBUS_TYPE_INVALID));
3435
3436     pa_log_info("Get sample rate of the device(id:%d)", device_id);
3437
3438     if (!(device = _device_list_get_device_by_id(dm, device_id))) {
3439         pa_log_error("could not find any device with id:%d", device_id);
3440         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3441         return;
3442     }
3443     if (!is_usb_output_device(device)) {
3444         pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.PolicyInternal");
3445         return;
3446     }
3447     sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
3448
3449     pa_log_info("Get sample rate(%u) of the device(id:%d) successfully", sink->selected_sample_rate, device_id);
3450     pa_assert_se((reply = dbus_message_new_method_return(msg)));
3451     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &sink->selected_sample_rate, DBUS_TYPE_INVALID));
3452     pa_assert_se(dbus_connection_send(conn, reply, NULL));
3453     dbus_message_unref(reply);
3454 }
3455
3456 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3457     pa_device_manager *dm = (pa_device_manager *)userdata;
3458     char *type;
3459     dbus_int32_t status;
3460     DBusMessage *reply = NULL;
3461     DBusError error;
3462
3463     pa_assert_se((reply = dbus_message_new_method_return(msg)));
3464
3465     dbus_error_init(&error);
3466     if (!dbus_message_get_args(msg, NULL,
3467                                        DBUS_TYPE_STRING, &type,
3468                                        DBUS_TYPE_INT32, &status,
3469                                        DBUS_TYPE_INVALID)) {
3470         pa_log_error("failed to get dbus args : %s", error.message);
3471         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
3472         dbus_error_free(&error);
3473     }
3474
3475     pa_log_debug("handle_test_device_status_change, type:%s, status:%d", type, status);
3476
3477     handle_device_status_changed(dm, type, NULL,  NULL, status);
3478     pa_assert_se(dbus_connection_send(conn, reply, NULL));
3479     dbus_message_unref(reply);
3480 }
3481
3482 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3483     const char *xml = DEVICE_MANAGER_INTROSPECT_XML;
3484     DBusMessage *r = NULL;
3485
3486     pa_assert(conn);
3487     pa_assert(msg);
3488     pa_assert(userdata);
3489
3490     pa_assert_se(r = dbus_message_new_method_return(msg));
3491     pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
3492
3493     if (r) {
3494         pa_assert_se(dbus_connection_send((conn), r, NULL));
3495         dbus_message_unref(r);
3496     }
3497
3498     return DBUS_HANDLER_RESULT_HANDLED;
3499 }
3500
3501 static DBusHandlerResult handle_device_manager_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3502     int method_idx = 0;
3503
3504     pa_assert(conn);
3505     pa_assert(msg);
3506     pa_assert(userdata);
3507
3508     for (method_idx = 0; method_idx < METHOD_HANDLER_MAX; method_idx++) {
3509         if (dbus_message_is_method_call(msg, DBUS_INTERFACE_DEVICE_MANAGER, method_handlers[method_idx].method_name)) {
3510             method_handlers[method_idx].receive_cb(conn, msg, userdata);
3511             return DBUS_HANDLER_RESULT_HANDLED;
3512         }
3513     }
3514
3515     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3516 }
3517
3518 static DBusHandlerResult method_call_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
3519     struct userdata *u = userdata;
3520     const char *path, *interface, *member;
3521
3522     pa_assert(c);
3523     pa_assert(m);
3524     pa_assert(u);
3525
3526     path = dbus_message_get_path(m);
3527     interface = dbus_message_get_interface(m);
3528     member = dbus_message_get_member(m);
3529
3530     pa_log_info("DeviceManager Method Call Handler : path=%s, interface=%s, member=%s", path, interface, member);
3531
3532     if (!pa_streq(path, DBUS_OBJECT_DEVICE_MANAGER))
3533         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3534
3535     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
3536         return handle_introspect(c, m, u);
3537         /*
3538     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get")) {
3539         return handle_get_property(c, m, u);
3540     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set")) {
3541         return  handle_set_property(c, m, u);
3542     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll")) {
3543         return handle_get_all_property(c, m, u);
3544         */
3545     } else {
3546         return handle_device_manager_methods(c, m, u);
3547     }
3548
3549     return DBUS_HANDLER_RESULT_HANDLED;
3550 }
3551
3552 static void endpoint_init(pa_device_manager *dm) {
3553     static const DBusObjectPathVTable vtable_endpoint = {
3554         .message_function = method_call_handler,
3555     };
3556
3557     pa_log_info("Device manager dbus endpoint init");
3558
3559     if (dm && dm->dbus_conn) {
3560         if (!dbus_connection_register_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER, &vtable_endpoint, dm))
3561             pa_log_error("Failed to register object path");
3562     } else {
3563         pa_log_error("Cannot get dbus connection to register object path");
3564     }
3565 }
3566
3567 static void endpoint_done(pa_device_manager *dm) {
3568     pa_log_info("Device manager dbus endpoint done");
3569     if (dm && dm->dbus_conn) {
3570         if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER))
3571             pa_log_error("Failed to unregister object path");
3572     } else {
3573         pa_log_error("Cannot get dbus connection to unregister object path");
3574     }
3575 }
3576
3577 static void dbus_init(pa_device_manager *dm) {
3578     DBusError error;
3579     pa_dbus_connection *connection = NULL;
3580
3581     pa_assert(dm);
3582     pa_log_info("Dbus init");
3583     dbus_error_init(&error);
3584
3585     if (!(connection = pa_dbus_bus_get(dm->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
3586         if (connection) {
3587             pa_dbus_connection_unref(connection);
3588         }
3589         pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
3590         goto fail;
3591     } else {
3592         pa_log_info("Got dbus connection");
3593     }
3594
3595     dm->dbus_conn = connection;
3596
3597     if (watch_signals(dm) < 0)
3598         pa_log_error("dbus watch signals failed");
3599     else
3600         pa_log_debug("dbus ready to get signals");
3601
3602     endpoint_init(dm);
3603
3604 fail:
3605     dbus_error_free(&error);
3606 }
3607
3608 static void dbus_deinit(pa_device_manager *dm) {
3609     pa_assert(dm);
3610
3611     pa_log_info("Dbus deinit");
3612
3613     endpoint_done(dm);
3614     unwatch_signals(dm);
3615
3616     if (dm->dbus_conn) {
3617         pa_dbus_connection_unref(dm->dbus_conn);
3618         dm->dbus_conn = NULL;
3619     }
3620 }
3621 #endif
3622
3623 pa_idxset* pa_device_manager_get_device_list(pa_device_manager *dm) {
3624     pa_assert(dm);
3625     pa_assert(dm->device_list);
3626
3627     return dm->device_list;
3628 }
3629
3630 pa_tz_device* pa_device_manager_get_device(pa_device_manager *dm, const char *type) {
3631     pa_assert(dm);
3632
3633     return _device_list_get_device(dm, type, NULL);
3634 }
3635
3636 pa_tz_device* pa_device_manager_get_device_by_id(pa_device_manager *dm, uint32_t id) {
3637     pa_assert(dm);
3638
3639     return _device_list_get_device_by_id(dm, id);
3640 }
3641
3642 pa_tz_device* pa_device_manager_get_device_with_sink(pa_sink *sink) {
3643     pa_assert(sink);
3644
3645     return sink->device_item;
3646 }
3647
3648 pa_tz_device* pa_device_manager_get_device_with_source(pa_source *source) {
3649     pa_assert(source);
3650
3651     return source->device_item;
3652 }
3653
3654 pa_tz_device* pa_device_manager_load_forwarding(pa_device_manager *dm) {
3655     return _load_forwarding_device(dm);
3656 }
3657
3658 void pa_device_manager_unload_forwarding(pa_device_manager *dm) {
3659     pa_tz_device *forwarding_device;
3660
3661     forwarding_device = _device_list_get_device(dm, DEVICE_TYPE_FORWARDING, NULL);
3662     if (forwarding_device)
3663         pa_tz_device_free(forwarding_device);
3664     else
3665         pa_log_warn("There is no forwarding device");
3666 }
3667
3668 pa_sink* pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const char *role) {
3669     const char *device_string, *params;
3670     struct device_type_info *type_info;
3671     struct device_file_info *file_info;
3672     pa_tz_device *device;
3673     pa_sink *sink;
3674     uint32_t device_idx;
3675
3676     pa_assert(dm);
3677     pa_assert(dm->device_list);
3678     pa_assert(type);
3679     pa_assert(role);
3680
3681     pa_log_info("Load Sink for '%s.%s'", type, role);
3682     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3683         if (pa_streq(type, pa_tz_device_get_type(device))) {
3684             if (pa_tz_device_get_sink(device, role)) {
3685                 pa_log_warn("Proper sink for '%s.%s' already loaded", type, role);
3686                 return NULL;
3687             }
3688         }
3689     }
3690
3691     if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3692         pa_log_error("No type map for %s", type);
3693         return NULL;
3694     }
3695
3696     if (type_info->playback_devices == NULL) {
3697         pa_log_error("No playback devices for %s", type_info->type);
3698         goto fail;
3699     }
3700
3701     if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
3702         pa_log_error("No device-string for '%s.%s'", type, role);
3703         goto fail;
3704     }
3705
3706     if (!(file_info = _device_manager_get_file_info(dm->file_map->playback, device_string))) {
3707         pa_log_error("No playback file-map for '%s'", device_string);
3708         goto fail;
3709     }
3710
3711     if (!(params = pa_hashmap_get(file_info->roles, role))) {
3712         pa_log_error("No params for '%s,%s'", device_string, role);
3713         goto fail;
3714     }
3715
3716     if ((sink = load_device(dm->core, true, device_string, params))) {
3717         pa_log_debug("loaded sink '%s' for '%s,%s' success", sink->name, type, role);
3718     } else {
3719         pa_log_warn("Cannot load playback device with '%s,%s'", device_string, params);
3720         goto fail;
3721     }
3722
3723     return sink;
3724
3725 fail:
3726     return NULL;
3727 }
3728
3729 void pa_device_manager_unload_sink(pa_device_manager *dm, const char *type, const char *role) {
3730     const char *device_string;
3731     struct device_type_info *type_info;
3732
3733     pa_assert(dm);
3734     pa_assert(dm->device_list);
3735     pa_assert(type);
3736     pa_assert(role);
3737
3738     pa_log_info("Unload Sink for '%s.%s'", type, role);
3739
3740     if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3741         pa_log_error("No type map for %s", type);
3742         return;
3743     }
3744
3745     if (type_info->playback_devices == NULL) {
3746         pa_log_error("No playback devices for %s", type_info->type);
3747         return;
3748     }
3749
3750     if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
3751         pa_log_error("No device-string for '%s.%s'", type, role);
3752         return;
3753     }
3754
3755     unload_device(dm->core, true, device_string);
3756 }
3757
3758 void pa_device_manager_unload_sink_with_device_string(pa_device_manager *dm, const char *device_string) {
3759     pa_assert(dm);
3760     pa_assert(device_string);
3761
3762     unload_device(dm->core, true, device_string);
3763 }
3764
3765 pa_source* pa_device_manager_load_source(pa_device_manager *dm, const char *type, const char *role) {
3766     const char *device_string, *params;
3767     struct device_type_info *type_info;
3768     struct device_file_info *file_info;
3769     pa_tz_device *device;
3770     pa_source *source;
3771     uint32_t device_idx;
3772
3773     pa_assert(dm);
3774     pa_assert(dm->device_list);
3775     pa_assert(type);
3776     pa_assert(role);
3777
3778     pa_log_info("Load Source for '%s.%s'", type, role);
3779
3780     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3781         if (pa_streq(type, pa_tz_device_get_type(device))) {
3782             if (pa_tz_device_get_source(device, role)) {
3783                 pa_log_warn("Proper source for '%s.%s' already loaded", type, role);
3784                 return NULL;
3785             }
3786         }
3787     }
3788
3789     if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3790         pa_log_error("No type map for %s", type);
3791         return NULL;
3792     }
3793
3794     if (type_info->capture_devices == NULL) {
3795         pa_log_error("No capture devices for %s", type_info->type);
3796         goto fail;
3797     }
3798
3799     if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
3800         pa_log_error("No device-string for '%s.%s'", type, role);
3801         goto fail;
3802     }
3803
3804     if (!(file_info = _device_manager_get_file_info(dm->file_map->capture, device_string))) {
3805         pa_log_error("No capture file-map for '%s'", device_string);
3806         goto fail;
3807     }
3808
3809     if (!(params = pa_hashmap_get(file_info->roles, role))) {
3810         pa_log_error("No params for '%s,%s'", device_string, role);
3811         goto fail;
3812     }
3813
3814     if ((source = load_device(dm->core, false, device_string, params))) {
3815         pa_log_debug("loaded source '%s' for '%s,%s' success", source->name, type, role);
3816     } else {
3817         pa_log_warn("Cannot load capture device with '%s,%s'", device_string, params);
3818         goto fail;
3819     }
3820
3821     return source;
3822
3823 fail:
3824     return NULL;
3825 }
3826
3827 void pa_device_manager_unload_source(pa_device_manager *dm, const char *type, const char *role) {
3828     const char *device_string;
3829     struct device_type_info *type_info;
3830
3831     pa_assert(dm);
3832     pa_assert(dm->device_list);
3833     pa_assert(type);
3834     pa_assert(role);
3835
3836     pa_log_info("Unload Source for '%s.%s'", type, role);
3837
3838     if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3839         pa_log_error("No type map for %s", type);
3840         return;
3841     }
3842
3843     if (type_info->capture_devices == NULL) {
3844         pa_log_error("No capture devices for %s", type_info->type);
3845         return;
3846     }
3847
3848     if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
3849         pa_log_error("No device-string for '%s.%s'", type, role);
3850         return;
3851     }
3852
3853     unload_device(dm->core, false, device_string);
3854 }
3855
3856 void pa_device_manager_unload_source_with_device_string(pa_device_manager *dm, const char *device_string) {
3857     pa_assert(dm);
3858     pa_assert(device_string);
3859
3860     unload_device(dm->core, false, device_string);
3861 }
3862
3863 const char* pa_device_manager_get_device_string(pa_device_manager *dm, bool is_playback, const char *type, const char *role) {
3864     struct device_type_info *type_info;
3865
3866     pa_assert(dm);
3867     pa_assert(type);
3868     pa_assert(role);
3869
3870     type_info = _device_manager_get_type_info(dm->type_infos, type);
3871     if (type_info == NULL) {
3872         pa_log_error("No type info for %s", type);
3873         return NULL;
3874     }
3875
3876     return device_type_info_get_device_string(type_info, is_playback, role);
3877 }
3878
3879 void pa_device_manager_update_device_running_state(pa_device_manager *dm, uint32_t num_of_devices, pa_device_info *device_infos, bool output_device) {
3880     int32_t i, j;
3881     uint32_t index;
3882
3883     pa_assert(dm);
3884
3885     index = (uint32_t)output_device; /* input:0, output:1 */
3886
3887     /* reset case */
3888     if (num_of_devices == 0) {
3889         for (i = 0; i < DEVICE_INDEX_MAX; i++) {
3890             if (!internal_codec_devices[i].is_running[index])
3891                 continue;
3892             internal_codec_devices[i].is_running[index] = false;
3893             /* change to NOT RUNNING */
3894             if (!internal_codec_devices[i].is_running[!index]) {
3895                 find_device_and_set_running(dm, internal_codec_devices[i].type, false);
3896                 internal_codec_devices_dump();
3897             }
3898         }
3899         return;
3900     }
3901
3902     for (i = 0; i < DEVICE_INDEX_MAX; i++) {
3903         bool skip = false;
3904         if (!internal_codec_devices[i].is_running[index])
3905             continue;
3906         for (j = 0; j < num_of_devices; j++) {
3907             if (pa_safe_streq(device_infos[j].type, internal_codec_devices[i].type))
3908                 skip = true;
3909         }
3910         if (!skip) {
3911             internal_codec_devices[i].is_running[index] = false;
3912             /* change to NOT RUNNING */
3913             if (!internal_codec_devices[i].is_running[!index]) {
3914                 find_device_and_set_running(dm, internal_codec_devices[i].type, false);
3915                 internal_codec_devices_dump();
3916             }
3917         }
3918     }
3919
3920     for (i = 0; i < num_of_devices; i++) {
3921         for (j = 0; j < DEVICE_INDEX_MAX; j++) {
3922             if (!pa_safe_streq(device_infos[i].type, internal_codec_devices[j].type))
3923                 continue;
3924             if (!internal_codec_devices[j].is_running[index]) {
3925                 internal_codec_devices[j].is_running[index] = true;
3926                 /* change to RUNNING */
3927                 find_device_and_set_running(dm, internal_codec_devices[j].type, true);
3928                 internal_codec_devices_dump();
3929             }
3930         }
3931     }
3932 }
3933
3934 static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_device_hook_data_for_conn_changed *data, pa_device_manager *dm) {
3935     send_device_connection_changed_signal(data->event_id, data->device, data->is_connected, dm);
3936     return PA_HOOK_OK;
3937 }
3938
3939 /* it will be replaced by running_changed_hook_cb() */
3940 static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_tz_device_hook_data_for_state_changed *data, pa_device_manager *dm) {
3941     send_device_info_changed_signal(data->event_id, data->device, DM_DEVICE_CHANGED_INFO_STATE, dm);
3942     send_device_state_changed_signal(data->event_id, data->device, data->activated, dm);
3943     return PA_HOOK_OK;
3944 }
3945
3946 static pa_hook_result_t device_running_changed_hook_cb(pa_core *c, pa_tz_device_hook_data_for_running_changed *data, pa_device_manager *dm) {
3947     send_device_running_changed_signal(data->event_id, data->device, data->is_running, dm);
3948     pa_log_info("RUNNING CHANGED!! device type[%s], is running[%d]", data->device->type, data->is_running);
3949     return PA_HOOK_OK;
3950 }
3951
3952 pa_device_manager* pa_device_manager_get(pa_core *c) {
3953     pa_device_manager *dm;
3954
3955     pa_assert(c);
3956
3957     pa_log_info("pa_device_manager_get");
3958
3959     if ((dm = pa_shared_get(c, SHARED_DEVICE_MANAGER)))
3960         return pa_device_manager_ref(dm);
3961
3962     dm = pa_xnew0(pa_device_manager, 1);
3963     PA_REFCNT_INIT(dm);
3964     dm->core = c;
3965     dm->device_list = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3966     dm->device_status = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3967
3968     dbus_init(dm);
3969
3970     dm->sink_put_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) sink_put_hook_callback, dm);
3971     dm->sink_unlink_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) sink_unlink_hook_callback, dm);
3972     dm->sink_state_changed_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_source_state_changed_hook_cb, dm);
3973     dm->source_put_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) source_put_hook_callback, dm);
3974     dm->source_unlink_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) source_unlink_hook_callback, dm);
3975     dm->source_state_changed_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_source_state_changed_hook_cb, dm);
3976     dm->comm = pa_communicator_get(dm->core);
3977     dm->comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
3978             PA_HOOK_EARLY, (pa_hook_cb_t)device_connection_changed_hook_cb, dm);
3979     dm->comm_hook_device_state_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_STATE_CHANGED),
3980             PA_HOOK_EARLY, (pa_hook_cb_t)device_state_changed_hook_cb, dm);
3981     dm->comm_hook_device_running_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_RUNNING_CHANGED),
3982         PA_HOOK_EARLY, (pa_hook_cb_t)device_running_changed_hook_cb, dm);
3983
3984     dm->hal_interface = pa_hal_interface_get(dm->core);
3985
3986     if (!(dm->type_infos = parse_device_type_infos())) {
3987         pa_log_error("Parse device-type-map failed");
3988         return NULL;
3989     }
3990
3991     if (!(dm->file_map = parse_device_file_map())) {
3992         pa_log_error("Parse device-file-map failed");
3993         return NULL;
3994     }
3995
3996     device_type_status_init(dm);
3997
3998     if (load_builtin_devices(dm) != 0) {
3999         pa_log_error("Load Builtin Devices faled");
4000         return NULL;
4001     }
4002
4003     /* Just for convenience when test*/
4004     if (!_device_manager_set_default_sink(dm,  DEVICE_TYPE_SPEAKER, "normal")) {
4005         pa_log_warn("Set default sink with speaker(normal) failed");
4006     }
4007     if (!_device_manager_set_default_source(dm,  DEVICE_TYPE_MIC, "normal")) {
4008         pa_log_warn("Set default source with mic(normal) failed");
4009     }
4010
4011     pa_shared_set(c, SHARED_DEVICE_MANAGER, dm);
4012
4013     return dm;
4014 }
4015
4016 pa_device_manager* pa_device_manager_ref(pa_device_manager *dm) {
4017     pa_assert(dm);
4018     pa_assert(PA_REFCNT_VALUE(dm) > 0);
4019
4020     pa_log_info("pa_device_manager_ref");
4021     PA_REFCNT_INC(dm);
4022
4023     return dm;
4024 }
4025
4026 void pa_device_manager_unref(pa_device_manager *dm) {
4027     pa_assert(dm);
4028     pa_assert(PA_REFCNT_VALUE(dm) > 0);
4029
4030     pa_log_info("pa_device_manager_unref");
4031     if (PA_REFCNT_DEC(dm) > 0)
4032         return;
4033
4034     if (dm->comm_hook_device_connection_changed_slot)
4035         pa_hook_slot_free(dm->comm_hook_device_connection_changed_slot);
4036     if (dm->comm_hook_device_state_changed_slot)
4037         pa_hook_slot_free(dm->comm_hook_device_state_changed_slot);
4038     if (dm->comm_hook_device_running_changed_slot)
4039         pa_hook_slot_free(dm->comm_hook_device_running_changed_slot);
4040     if (dm->sink_put_hook_slot)
4041         pa_hook_slot_free(dm->sink_put_hook_slot);
4042     if (dm->sink_unlink_hook_slot)
4043         pa_hook_slot_free(dm->sink_unlink_hook_slot);
4044     if (dm->sink_state_changed_slot)
4045         pa_hook_slot_free(dm->sink_state_changed_slot);
4046     if (dm->source_put_hook_slot)
4047         pa_hook_slot_free(dm->source_put_hook_slot);
4048     if (dm->source_unlink_hook_slot)
4049         pa_hook_slot_free(dm->source_unlink_hook_slot);
4050     if (dm->source_state_changed_slot)
4051         pa_hook_slot_free(dm->source_state_changed_slot);
4052
4053     if (dm->hal_interface)
4054         pa_hal_interface_unref(dm->hal_interface);
4055
4056     if (dm->comm)
4057         pa_communicator_unref(dm->comm);
4058
4059     if (dm->type_infos)
4060         pa_idxset_free(dm->type_infos, (pa_free_cb_t)type_info_free_func);
4061     if (dm->file_map) {
4062         if (dm->file_map->playback)
4063             pa_idxset_free(dm->file_map->playback, (pa_free_cb_t)file_info_free_func);
4064         if (dm->file_map->capture)
4065             pa_idxset_free(dm->file_map->capture, (pa_free_cb_t)file_info_free_func);
4066         pa_xfree(dm->file_map);
4067     }
4068     if (dm->device_list)
4069         pa_idxset_free(dm->device_list, (pa_free_cb_t)pa_tz_device_free);
4070     if (dm->device_status)
4071         pa_idxset_free(dm->device_status, NULL);
4072
4073     dbus_deinit(dm);
4074
4075     if (dm->core)
4076         pa_shared_remove(dm->core, SHARED_DEVICE_MANAGER);
4077
4078     pa_xfree(dm);
4079 }