daba72e554a7d2e4dec1a8fa56d4c9e82871cb2a
[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 "device-manager.h"
53
54 #define SHARED_DEVICE_MANAGER "tizen-device-manager"
55
56 #define DEVICE_MAP_FILE                    "/etc/pulse/device-map.json"
57 #define DEVICE_STR_MAX                      30
58 #define DEVICE_DIRECTION_MAX                3
59 #define DEVICE_PARAM_STRING_MAX             150
60 #define DEVICE_AVAIL_COND_NUM_MAX           2
61 #define DEVICE_AVAIL_COND_STR_MAX           6
62 #define DEVICE_FILE_PER_TYPE_MAX            4
63 #define DEVICE_FILE_STRING_MAX              4
64 #define DEVICE_TYPE_STR_MAX                 20
65 #define DEVICE_ROLE_STR_MAX                 15
66
67 #define DEVICE_TYPE_OBJECT                  "device-types"
68 #define DEVICE_FILE_OBJECT                  "device-files"
69 #define DEVICE_TYPE_PROP_DEVICE_TYPE        "device-type"
70 #define DEVICE_TYPE_PROP_PLAYBACK_DEVICES   "playback-devices"
71 #define DEVICE_TYPE_PROP_CAPTURE_DEVICES    "capture-devices"
72 #define DEVICE_TYPE_PROP_DEVICE_STRING      "device-string"
73 #define DEVICE_TYPE_PROP_ROLE               "role"
74
75 #define DEVICE_TYPE_STR_MAX                 20
76
77 /* Properties of sink/sources */
78 #define DEVICE_API_BLUEZ                    "bluez"
79 #define DEVICE_API_ALSA                     "alsa"
80 #define DEVICE_API_NULL                     "null"
81 #define DEVICE_BUS_USB                      "usb"
82 #define DEVICE_CLASS_SOUND                  "sound"
83 #define DEVICE_CLASS_MONITOR                "monitor"
84
85 /* Dbus defines */
86 #define DBUS_INTERFACE_DEVICE_MANAGER       "org.pulseaudio.DeviceManager"
87 #define DBUS_OBJECT_DEVICE_MANAGER          "/org/pulseaudio/DeviceManager"
88
89 #define DBUS_INTERFACE_DEVICED_SYSNOTI      "org.tizen.system.deviced.SysNoti"
90 #define DBUS_OBJECT_DEVICED_SYSNOTI         "/Org/Tizen/System/DeviceD/SysNoti"
91
92 #define DBUS_INTERFACE_SOUND_SERVER         "org.tizen.SoundServer1"
93 #define DBUS_OBJECT_SOUND_SERVER            "/org/tizen/SoundServer1"
94
95 #define DBUS_SERVICE_BLUEZ                  "org.bluez"
96 #define DBUS_INTERFACE_BLUEZ_HEADSET        "org.bluez.Headset"
97 #define DBUS_INTERFACE_BLUEZ_DEVICE         "org.bluez.Device1"
98 #define DBUS_OBJECT_BLUEZ                   "/org/bluez"
99
100 #define DBUS_INTERFACE_MIRRORING_SERVER     "org.tizen.scmirroring.server"
101 #define DBUS_OBJECT_MIRRORING_SERVER        "/org/tizen/scmirroring/server"
102
103 #define DBUS_SERVICE_HFP_AGENT "org.bluez.ag_agent"
104 #define DBUS_OBJECT_HFP_AGENT "/org/bluez/hfp_agent"
105 #define DBUS_INTERFACE_HFP_AGENT "Org.Hfp.App.Interface"
106
107 #define DEVICE_MANAGER_INTROSPECT_XML                                                       \
108     DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                                               \
109     "<node>\n"                                                                              \
110     " <interface name=\"" DBUS_INTERFACE_DEVICE_MANAGER "\">\n"                             \
111     "  <method name=\"GetConnectedDeviceList\">\n"                                          \
112     "   <arg name=\"mask_flags\" direction=\"in\" type=\"i\"/>\n"                           \
113     "   <arg name=\"ConnectedDeviceList\" direction=\"out\" type=\"a(isiis)\"/>\n"          \
114     "  </method>\n"                                                                         \
115     "  <method name='GetBTA2DPStatus'>"                                                     \
116     "    <arg type='b' name='is_bt_on' direction='out'/>"                                   \
117     "    <arg type='s' name='bt_name' direction='out'/>"                                    \
118     "  </method>"                                                                           \
119     "  <method name=\"LoadSink\">\n"                                                        \
120     "   <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n"                          \
121     "   <arg name=\"role\" direction=\"in\" type=\"s\"/>\n"                                 \
122     "  </method>\n"                                                                         \
123     "  <method name=\"TestStatusChange\">\n"                                                \
124     "   <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n"                          \
125     "   <arg name=\"status\" direction=\"in\" type=\"i\"/>\n"                               \
126     "  </method>\n"                                                                         \
127     "  <property name=\"PropertyTest1\" type=\"i\" access=\"readwrite\"/>\n"                \
128     "  <property name=\"PropertyTest2\" type=\"s\" access=\"read\"/>\n"                     \
129     "  <signal name=\"DeviceConnected\">\n"                                                 \
130     "   <arg name=\"arg1\" type=\"i\"/>\n"                                                  \
131     "  </signal>\n"                                                                         \
132     "  <signal name=\"DeviceInfoChanged\">\n"                                               \
133     "   <arg name=\"arg1\" type=\"s\"/>\n"                                                  \
134     "  </signal>\n"                                                                         \
135     " </interface>\n"                                                                       \
136     " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n"                             \
137     "  <method name=\"Introspect\">\n"                                                      \
138     "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"                                \
139     "  </method>\n"                                                                         \
140     " </interface>\n"                                                                       \
141     " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n"                                 \
142     "  <method name=\"Get\">\n"                                                             \
143     "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"                       \
144     "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"                        \
145     "   <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"                               \
146     "  </method>\n"                                                                         \
147     "  <method name=\"Set\">\n"                                                             \
148     "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"                       \
149     "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"                        \
150     "   <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"                                \
151     "  </method>\n"                                                                         \
152     "  <method name=\"GetAll\">\n"                                                          \
153     "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"                       \
154     "   <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n"                           \
155     "  </method>\n"                                                                         \
156     " </interface>\n"                                                                       \
157     "</node>\n"
158
159
160 #define FILTER_DEVICED_SYSNOTI                             \
161     "type='signal',"                                       \
162     " interface='" DBUS_INTERFACE_DEVICED_SYSNOTI "'"
163
164 #define FILTER_SOUND_SERVER                                \
165     "type='signal',"                                       \
166     " interface='" DBUS_INTERFACE_SOUND_SERVER "'"
167
168 #define FILTER_MIRRORING                                   \
169     "type='signal',"                                       \
170     " interface='" DBUS_INTERFACE_MIRRORING_SERVER "', member='miracast_wfd_source_status_changed'"
171
172 #define FILTER_BLUEZ                                       \
173     "type='signal',"                                       \
174     " interface='" DBUS_INTERFACE_BLUEZ_HEADSET "', member='PropertyChanged'"
175
176 static const char* const valid_alsa_device_modargs[] = {
177     "name",
178     "sink_name",
179     "sink_properties",
180     "source_name",
181     "source_properties",
182     "namereg_fail",
183     "device",
184     "device_id",
185     "format",
186     "rate",
187     "alternate_rate",
188     "channels",
189     "channel_map",
190     "fragments",
191     "fragment_size",
192     "mmap",
193     "tsched",
194     "tsched_buffer_size",
195     "tsched_buffer_watermark",
196     "ignore_dB",
197     "control",
198     "rewind_safeguard",
199     "deferred_volume",
200     "deferred_volume_safety_margin",
201     "deferred_volume_extra_delay",
202     "fixed_latency_range",
203     "need_audio_pm",
204     "start_threshold",
205     NULL
206 };
207
208 #define BT_CVSD_CODEC_ID 1 // narrow-band
209 #define BT_MSBC_CODEC_ID 2 // wide-band
210 /*
211     Enums for represent values which is defined on other module.
212     This is needed to identify values which are sent by dbus or vconf.
213 */
214 typedef enum external_value_earjack_type {
215     EARJACK_DISCONNECTED = 0,
216     EARJACK_TYPE_SPK_ONLY = 1,
217     EARJACK_TYPE_SPK_WITH_MIC = 3,
218 } external_value_earjack_t;
219
220 typedef enum external_value_bt_sco_type {
221     BT_SCO_DISCONNECTED = 0,
222     BT_SCO_CONNECTED = 1,
223 } external_value_bt_sco_t;
224
225 typedef enum external_value_forwarding_type {
226     FORWARDING_DISCONNECTED = 0,
227     FORWARDING_CONNECTED = 1,
228 } external_value_mirroring_t;
229
230 typedef enum external_value_hdmi_type {
231     HDMI_AUDIO_DISCONNECTED = -1,
232     HDMI_AUDIO_NOT_AVAILABLE = 0,
233     HDMI_AUDIO_AVAILABLE = 1,
234 } external_value_hdmi_t;
235
236
237 /*
238     Enums for represent device detected status (through dbus)
239     When some device is detected, one of these values should be saved in device_status hashmap.
240     device_detected_type_t is needed to distinguish detected device-types ( ex. earjack which can be out or both way)
241     So If you just want to know whether detected or not, can device_detected_t as mask.
242 */
243
244 typedef enum device_detected_type {
245     DEVICE_DISCONNECTED = 0x0,
246     DEVICE_CONNECTED = 0x1,
247     DEVICE_CONNECTED_AUDIO_JACK_4P = DEVICE_CONNECTED | 0x2,
248     DEVICE_CONNECTED_AUDIO_JACK_3P = DEVICE_CONNECTED | 0x4,
249     DEVICE_CONNECTED_SCO = DEVICE_CONNECTED | 0x8,
250     DEVICE_OPENED_SCO = DEVICE_CONNECTED | 0xF,
251 } device_detected_type_t;
252
253 typedef enum dm_device_class_type {
254     DM_DEVICE_CLASS_NONE,
255     DM_DEVICE_CLASS_ALSA,
256     DM_DEVICE_CLASS_TIZEN,
257     DM_DEVICE_CLASS_BT,
258     DM_DEVICE_CLASS_NULL,
259     DM_DEVICE_CLASS_MAX,
260 } dm_device_class_t;
261
262
263 typedef enum {
264     DEVICE_IO_DIRECTION_IN_FLAG      = 0x0001,  /**< Flag for input devices */
265     DEVICE_IO_DIRECTION_OUT_FLAG     = 0x0002,  /**< Flag for output devices */
266     DEVICE_IO_DIRECTION_BOTH_FLAG    = 0x0004,  /**< Flag for input/output devices (both directions are available) */
267     DEVICE_TYPE_INTERNAL_FLAG        = 0x0010,  /**< Flag for built-in devices */
268     DEVICE_TYPE_EXTERNAL_FLAG        = 0x0020,  /**< Flag for external devices */
269     DEVICE_STATE_DEACTIVATED_FLAG    = 0x1000,  /**< Flag for deactivated devices */
270     DEVICE_STATE_ACTIVATED_FLAG      = 0x2000,  /**< Flag for activated devices */
271     DEVICE_ALL_FLAG                  = 0xFFFF,  /**< Flag for all devices */
272 } device_flag_t;
273
274 typedef enum {
275     DEVICE_IO_DIRECTION_FLAGS        = 0x000F,  /**< Flag for io direction */
276     DEVICE_TYPE_FLAGS                = 0x00F0,  /**< Flag for device type */
277     DEVICE_STATE_FLAGS               = 0xF000,  /**< Flag for device state */
278 } device_flags_type_t;
279
280 typedef enum dm_device_bt_mode_type {
281     DM_DEVICE_BT_MODE_MEDIA = 0x1,
282     DM_DEVICE_BT_MODE_VOICE = 0x2
283 } dm_device_bt_mode_t;
284
285 typedef enum dm_device_changed_into_type {
286     DM_DEVICE_CHANGED_INFO_STATE,
287     DM_DEVICE_CHANGED_INFO_IO_DIRECTION,
288     DM_DEVICE_CHANGED_INFO_MAX
289 } dm_device_changed_info_t;
290
291
292 /*
293     Structure to save parsed information about device-file.
294 */
295 struct device_file_map {
296     /* { key:device_string -> value:device_file_prop } */
297     pa_idxset *playback;
298     pa_idxset *capture;
299 };
300
301 /***************** structures for static information get from json *********/
302
303 /*
304     Structure for informations related to some device-file(ex. 0:0)
305 */
306 struct device_file_info {
307     /*
308         String for identify target device.
309         ex) alsa:0,0  or null ..
310     */
311     const char *device_string;
312     /*
313         For save roles which are supported on device file, and parameters.
314         { key:device_role -> value:parameters for load sink/source }
315         ex) "normal"->"rate=44100 tsched=0", "uhqa"->"rate=192000 mmap=1"
316     */
317     pa_hashmap *roles;
318     /*
319         For save device-types related to device file.
320         { key:device_type-> value:pulse_device_prop }
321     */
322     pa_hashmap *device_types;
323 };
324
325 /* structure for represent device-types(ex. builtin-speaker) properties*/
326 struct device_type_info {
327     const char *type;
328     /*
329         For save supported roles and related device-file.
330         { key:role -> value:device_string ]
331     */
332     pa_hashmap *playback_devices;
333     pa_hashmap *capture_devices;
334 };
335
336 struct device_status_info {
337     char *type;
338     char *name;
339     /* Identify devices among same device-types (for multi-device), currently not works*/
340     char *system_id;
341     device_detected_type_t detected;
342 };
343
344 struct pulse_device_prop {
345     /* roles related to (device_type + device_file)*/
346     pa_idxset *roles;
347     /* For save that this devie_type is activated or not on sink/source */
348     int status;
349 };
350 /******************************************************************************/
351 struct pa_device_manager {
352     PA_REFCNT_DECLARE;
353
354     pa_core *core;
355     pa_hook_slot *sink_put_hook_slot, *sink_state_changed_slot, *sink_unlink_hook_slot;
356     pa_hook_slot *source_put_hook_slot, *source_state_changed_slot, *source_unlink_hook_slot;
357     pa_hook_slot *comm_hook_device_connection_changed_slot;
358     pa_hook_slot *comm_hook_device_state_changed_slot;
359     pa_communicator *comm;
360
361     /*
362        Idxset for save parsed information about device-type.
363        { device_type_info }
364     */
365     pa_idxset *type_infos;
366     /* For save Parsed information about device-file */
367     struct device_file_map *file_map;
368
369     /* device list */
370     pa_idxset *device_list;
371     /*
372        Hashmap for save statuses got through dbus.
373        { key:device_type -> value:(audio_detected_type_t or device_detected_t) }
374     */
375     pa_idxset *device_status;
376     pa_dbus_connection *dbus_conn;
377 };
378
379
380 struct composite_type {
381     const char *type;
382     const char *role;
383 };
384
385 #ifdef HAVE_DBUS
386
387 /*** Defines for method handle ***/
388 /* method handlers */
389 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
390 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
391 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
392 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata);
393
394 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name);
395
396 enum method_handler_index {
397     METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST,
398     METHOD_HANDLER_GET_BT_A2DP_STATUS,
399     METHOD_HANDLER_LOAD_SINK,
400     METHOD_HANDLER_STATUS_TEST,
401     METHOD_HANDLER_MAX
402 };
403
404 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
405     [METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST] = {
406         .method_name = "GetConnectedDeviceList",
407         .receive_cb = handle_get_connected_device_list },
408     [METHOD_HANDLER_GET_BT_A2DP_STATUS] = {
409         .method_name = "GetBTA2DPStatus",
410         .receive_cb = handle_get_bt_a2dp_status },
411     [METHOD_HANDLER_LOAD_SINK] = {
412         .method_name = "LoadSink",
413         .receive_cb = handle_load_sink},
414     [METHOD_HANDLER_STATUS_TEST] = {
415         .method_name = "TestStatusChange",
416         .receive_cb = handle_test_device_status_change},
417 };
418
419 #endif
420
421 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) {
422     pa_logl(level, "%s device id(%d) type(%s) name (%s) direction(%d) state(%d)",
423             pa_strempty(prefix), id, pa_strnull(type), pa_strnull(name), direction, state);
424 }
425
426 static void type_info_free_func(struct device_type_info *type_info) {
427     if (!type_info)
428         return;
429
430     if (type_info->playback_devices)
431         pa_hashmap_free(type_info->playback_devices);
432     if (type_info->capture_devices)
433         pa_hashmap_free(type_info->capture_devices);
434
435 }
436
437 static void file_info_free_func(struct device_file_info *file_info) {
438     if (!file_info)
439         return;
440
441     if (file_info->roles)
442         pa_hashmap_free(file_info->roles);
443 }
444
445 static dm_device_class_t device_string_get_class(const char *device_string) {
446     if (!device_string) {
447         return DM_DEVICE_CLASS_NONE;
448     }
449
450     if (device_string == strstr(device_string, "alsa")) {
451         return DM_DEVICE_CLASS_ALSA;
452     } else if (device_string == strstr(device_string, "null")) {
453         return DM_DEVICE_CLASS_NULL;
454     } else if (device_string == strstr(device_string, "tizen")) {
455         return DM_DEVICE_CLASS_TIZEN;
456     } else {
457         return DM_DEVICE_CLASS_NONE;
458     }
459 }
460
461 static const char* device_string_get_value(const char *device_string) {
462     int len;
463     const char *end_p, *value_p;
464
465     if (!device_string) {
466         return NULL;
467     }
468
469     len = strlen(device_string);
470     end_p = device_string + len -1;
471
472     if (!(value_p = strchr(device_string, ':'))) {
473         return NULL;
474     }
475     if (value_p < end_p) {
476         return value_p + 1;
477     } else {
478         return NULL;
479     }
480 }
481
482 static pa_proplist* pulse_device_get_proplist(pa_object *pdevice) {
483     if (pa_sink_isinstance(pdevice))
484         return PA_SINK(pdevice)->proplist;
485     else
486         return PA_SOURCE(pdevice)->proplist;
487 }
488
489 static bool pulse_device_is_alsa(pa_object *pdevice) {
490     const char *api_name = NULL;
491     pa_proplist *prop;
492
493     if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
494         return false;
495
496     if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
497         if (pa_streq(api_name, DEVICE_API_ALSA)) {
498             return true;
499         } else {
500             return false;
501         }
502     } else {
503         return false;
504     }
505 }
506
507
508 static bool pulse_device_is_bluez(pa_object *pdevice) {
509     const char *api_name = NULL;
510     pa_proplist *prop;
511
512     if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
513         return false;
514
515     if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
516         if (pa_streq(api_name, DEVICE_API_BLUEZ)) {
517             return true;
518         } else {
519             return false;
520         }
521     } else {
522         return false;
523     }
524 }
525
526 static bool pulse_device_is_tizenaudio(pa_object *pdevice) {
527     if (!pdevice)
528         return false;
529
530     if (pa_sink_isinstance(pdevice)) {
531         pa_sink *sink = PA_SINK(pdevice);
532         return pa_streq(sink->module->name, "module-tizenaudio-sink");
533     } else {
534         pa_source *source = PA_SOURCE(pdevice);
535         return pa_streq(source->module->name, "module-tizenaudio-source");
536     }
537 }
538
539 static bool pulse_device_is_usb(pa_object *pdevice) {
540     const char *bus_name = NULL;
541     pa_proplist *prop;
542
543     if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
544         return false;
545
546     if ((bus_name = pa_proplist_gets(prop, PA_PROP_DEVICE_BUS))) {
547         if (pa_streq(bus_name, DEVICE_BUS_USB)) {
548             return true;
549         } else {
550             return false;
551         }
552     } else {
553         pa_log_debug("This device doesn't have property '%s'", PA_PROP_DEVICE_BUS);
554         return false;
555     }
556 }
557
558 static bool pulse_device_is_null(pa_object *pdevice) {
559     pa_sink *sink;
560     pa_source *source;
561
562     if (!pdevice)
563         return false;
564
565     if (pa_sink_isinstance(pdevice)) {
566         sink = PA_SINK(pdevice);
567         return pa_streq(sink->module->name, "module-null-sink");
568     } else {
569         source = PA_SOURCE(pdevice);
570         return pa_streq(source->module->name, "module-null-source");
571     }
572 }
573
574 static const char* pulse_device_get_device_string_removed_argument(pa_object *pdevice) {
575     static char removed_param[DEVICE_PARAM_STRING_MAX] = {0,};
576     char *device_string_p = NULL;
577     char *next_p = NULL;
578     const char *params_p, *params;
579     char *end_p = NULL;
580     int len = 0, prev_len = 0;
581     pa_sink *sink;
582     pa_source *source;
583
584     if (pa_sink_isinstance(pdevice)) {
585         sink = PA_SINK(pdevice);
586         params = sink->module->argument;
587     } else {
588         source = PA_SOURCE(pdevice);
589         params = source->module->argument;
590     }
591
592     params_p = params;
593
594     if (!params) {
595         return NULL;
596     }
597     if (!(device_string_p = strstr(params, "device="))) {
598         return params;
599     }
600
601     next_p = device_string_p;
602     while (!isblank(*next_p)) {
603         next_p++;
604     }
605     while (isblank(*next_p)) {
606         next_p++;
607     }
608
609     strncpy(removed_param, next_p, DEVICE_PARAM_STRING_MAX);
610
611     if (device_string_p > params_p) {
612         prev_len = device_string_p - params_p;
613         len = strlen(removed_param);
614         end_p = removed_param + len;
615         *end_p = ' ';
616         end_p++;
617         strncpy(end_p, params_p, prev_len);
618     }
619
620     return removed_param;
621 }
622
623 static dm_device_class_t pulse_device_get_class(pa_object *pdevice) {
624
625     if (!pdevice) {
626         pa_log_error("pdevice null");
627         return DM_DEVICE_CLASS_NONE;
628     }
629
630     if (pulse_device_is_null(pdevice)) {
631         return DM_DEVICE_CLASS_NULL;
632     } else if (pulse_device_is_alsa(pdevice)) {
633         return DM_DEVICE_CLASS_ALSA;
634     } else if (pulse_device_is_tizenaudio(pdevice)) {
635         return DM_DEVICE_CLASS_TIZEN;
636     } else if (pulse_device_is_bluez(pdevice)) {
637         return DM_DEVICE_CLASS_BT;
638     } else {
639         return DM_DEVICE_CLASS_NONE;
640     }
641 }
642
643 static dm_device_direction_t pulse_device_get_direction(pa_object *pdevice) {
644     if (pa_sink_isinstance(pdevice))
645         return DM_DEVICE_DIRECTION_OUT;
646     else
647         return DM_DEVICE_DIRECTION_IN;
648 }
649
650 static bool pulse_device_is_monitor(pa_object *pdevice) {
651     const char *device_class = NULL;
652     pa_proplist *prop;
653
654     prop = pulse_device_get_proplist(pdevice);
655
656     if ((device_class = pa_proplist_gets(prop, PA_PROP_DEVICE_CLASS))) {
657         if (device_class && pa_streq(device_class, DEVICE_CLASS_MONITOR)) {
658             return true;
659         } else {
660             return false;
661         }
662     } else {
663         return false;
664     }
665 }
666
667 static int pulse_device_get_alsa_device_string(pa_proplist *prop, char **device_string) {
668     const char *device_string_prop = NULL;
669     char *device_string_tmp;
670
671     if (!prop || !device_string) {
672         pa_log_error("Invalid Parameter");
673         return -1;
674     }
675
676     if (!(device_string_prop = pa_proplist_gets(prop, "device.string"))) {
677         pa_log_error("failed to get property 'device.string'");
678         return -1;
679     }
680     if (!(device_string_tmp = strchr(device_string_prop, ':'))) {
681         pa_log_error("failed to parse device string");
682         return -1;
683     }
684
685     *device_string = device_string_tmp + 1;
686
687     return 0;
688 }
689
690 static const char* device_class_get_module_name(dm_device_class_t device_class, bool is_sink) {
691     if (device_class == DM_DEVICE_CLASS_NONE) {
692         return NULL;
693     } else if (device_class == DM_DEVICE_CLASS_ALSA) {
694         return is_sink ? "module-alsa-sink" : "module-alsa-source";
695     } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
696         return is_sink ? "module-tizenaudio-sink" : NULL;
697     } else if (device_class == DM_DEVICE_CLASS_BT) {
698         return is_sink ? "module-bluez5-device" : NULL;
699     } else if (device_class == DM_DEVICE_CLASS_NULL) {
700         return is_sink ? "module-null-sink" : "module-null-source";
701     } else {
702         return NULL;
703     }
704 }
705
706 static struct device_type_info* _device_manager_get_type_info(pa_idxset *type_infos, const char *type) {
707     struct device_type_info *type_info;
708     uint32_t type_idx;
709
710     PA_IDXSET_FOREACH(type_info, type_infos, type_idx) {
711         if (device_type_is_equal(type_info->type, type)) {
712             return type_info;
713         }
714     }
715
716     return NULL;
717 }
718
719 static struct device_file_info* _device_manager_get_file_info(pa_idxset *file_infos, const char *device_string) {
720     struct device_file_info *file_info;
721     uint32_t file_idx;
722
723     pa_assert(file_infos);
724
725     PA_IDXSET_FOREACH(file_info, file_infos, file_idx) {
726         if (file_info->device_string) {
727             if (pa_streq(file_info->device_string, device_string)) {
728                 return file_info;
729             }
730         }
731     }
732
733     return NULL;
734 }
735
736 static struct device_status_info* _device_status_new(const char *type,
737         const char *name, const char *system_id) {
738     struct device_status_info *status_info;
739
740     status_info = (struct device_status_info *) pa_xmalloc0(sizeof(struct device_status_info));
741     status_info->type = pa_xstrdup(type);
742     status_info->name = pa_xstrdup(name);
743     status_info->system_id = pa_xstrdup(system_id);
744     status_info->detected = DEVICE_DISCONNECTED;
745
746     return status_info;
747 }
748
749 static void _device_status_free(struct device_status_info *status_info) {
750     if (!status_info)
751         return ;
752
753     pa_xfree(status_info->type);
754     pa_xfree(status_info->name);
755     pa_xfree(status_info->system_id);
756     pa_xfree(status_info);
757 }
758
759 static struct device_status_info* _get_device_status(pa_device_manager *manager, const char *type,
760         const char *system_id) {
761     struct device_status_info *status_info = NULL;
762     uint32_t status_idx;
763
764     pa_assert(manager);
765     pa_assert(manager->device_status);
766
767     PA_IDXSET_FOREACH(status_info, manager->device_status, status_idx) {
768         if (device_type_is_equal(status_info->type, type)) {
769             if (device_type_is_avail_multi_device(type)) {
770                 /* if system_id is null, just compare type */
771                 if (system_id == NULL)
772                     return status_info;
773                 else if (status_info->system_id == NULL)
774                     continue;
775                 else if (pa_streq(status_info->system_id, system_id))
776                     return status_info;
777                 else
778                     continue;
779             } else {
780                 return status_info;
781             }
782         }
783     }
784
785     return NULL;
786 }
787
788 static const char* _file_infos_get_param(pa_idxset *file_infos, const char *device_string, const char *role) {
789     struct device_file_info *file_info;
790     const char *params;
791
792     if (!(file_info = _device_manager_get_file_info(file_infos, device_string))) {
793         pa_log_error("No file map for '%s'", device_string);
794         return NULL;
795     }
796
797     if (!(params = pa_hashmap_get(file_info->roles, role)))
798         pa_log_error("No params for '%s:%s'", device_string, role);
799
800     return params;
801 }
802
803 static device_detected_type_t _device_get_detected(pa_device_manager *manager, const char *type,
804         const char *system_id) {
805     struct device_status_info *status_info;
806
807     pa_assert(manager);
808     pa_assert(manager->device_status);
809     pa_assert(type);
810
811     if (!device_type_is_need_detect(type))
812         return DEVICE_CONNECTED;
813
814     status_info = _get_device_status(manager, type, system_id);
815     if (!status_info) {
816         pa_log_info("No status info for type(%s) system_id(%s)",
817                 type, pa_strempty(system_id));
818         return DEVICE_DISCONNECTED;
819     }
820
821     pa_log_debug("Get device detected, type(%s) system_id(%s) : %s(%d)",
822             type, pa_strempty(system_id),
823              (status_info->detected & DEVICE_CONNECTED) ? "Connected" : "Disconnected", status_info->detected);
824
825     return status_info->detected;
826 }
827
828 static void _device_set_detected(pa_device_manager *manager, const char *type,
829         const char *name, const char *system_id, device_detected_type_t detected_type) {
830     struct device_status_info *status_info;
831
832     pa_assert(manager);
833     pa_assert(manager->device_status);
834     pa_assert(type);
835
836     if (!device_type_is_need_detect(type))
837         return ;
838
839     pa_log_info("Set device detected, type(%s) system_id(%s) -> %s(%d)",
840             type, pa_strempty(system_id),
841             (detected_type & DEVICE_CONNECTED) ? "Connected" : "Disconnected", detected_type);
842
843     if (detected_type & DEVICE_CONNECTED) {
844         status_info = _get_device_status(manager, type, system_id);
845         if (!status_info) {
846             status_info = _device_status_new(type, name, system_id);
847             pa_idxset_put(manager->device_status, status_info, NULL);
848         }
849         status_info->detected = detected_type;
850     } else {
851         status_info = _get_device_status(manager, type, system_id);
852         if (status_info) {
853             pa_idxset_remove_by_data(manager->device_status, status_info, NULL);
854             _device_status_free(status_info);
855         }
856     }
857 }
858
859 static pa_tz_device* _device_list_get_device(pa_device_manager *manager, const char *type, const char *system_id) {
860     pa_tz_device *device;
861     uint32_t idx;
862     char *_type, *_system_id;
863
864     pa_assert(manager);
865     pa_assert(manager->device_list);
866     pa_assert(type);
867
868     PA_IDXSET_FOREACH(device, manager->device_list, idx) {
869         _type = pa_tz_device_get_type(device);
870         _system_id = pa_tz_device_get_system_id(device);
871         if (pa_streq(_type, type)) {
872             if (device_type_is_avail_multi_device(type)) {
873                 if (system_id == NULL)
874                     return device;
875                 else if (_system_id == NULL)
876                     continue;
877                 else if (pa_streq(_system_id, system_id))
878                     return device;
879                 else
880                     continue;
881             } else {
882                 return device;
883             }
884         }
885     }
886
887     return NULL;
888 }
889
890
891 static pa_tz_device* _device_list_get_device_with_id(pa_device_manager *manager, uint32_t id) {
892     pa_tz_device *device;
893     uint32_t idx;
894
895     pa_assert(manager);
896     pa_assert(manager->device_list);
897
898     PA_IDXSET_FOREACH(device, manager->device_list, idx) {
899         if (pa_tz_device_get_id(device) == id) {
900             return device;
901         }
902     }
903     return NULL;
904 }
905
906 static const char* build_params_to_load_device(const char *device_string, const char *params, dm_device_class_t device_class) {
907     pa_strbuf *args_buf;
908     static char args[DEVICE_PARAM_STRING_MAX] = {0,};
909
910     if (!device_string) {
911         pa_log_error("device string null");
912         return NULL;
913     }
914
915     if (device_class == DM_DEVICE_CLASS_NULL) {
916         return params;
917     } else if (device_class == DM_DEVICE_CLASS_ALSA) {
918         const char *alsa_device_name;
919         if (!(alsa_device_name = device_string_get_value(device_string))) {
920             pa_log_error("Invalid device string for alsa-device, '%s'", device_string);
921             return NULL;
922         }
923         args_buf = pa_strbuf_new();
924         pa_strbuf_printf(args_buf, "device=hw:%s \n", alsa_device_name);
925         if (params) {
926             pa_strbuf_printf(args_buf, "%s\n", params);
927         }
928         strncpy(args, pa_strbuf_tostring_free(args_buf), DEVICE_PARAM_STRING_MAX);
929     } else {
930         return params;
931     }
932
933     return (const char*) args;
934 }
935
936 static bool device_params_is_equal(const char *params1, const char *params2) {
937     const char *key = NULL;
938     const char *value1, *value2;
939     pa_modargs *modargs1, *modargs2;
940     void *state = NULL;
941     bool equal = true;
942
943     if (!params1 && !params2)
944         return true;
945     if (!params1 || !params2)
946         return false;
947
948     modargs1 = pa_modargs_new(params1, valid_alsa_device_modargs);
949     modargs2 = pa_modargs_new(params2, valid_alsa_device_modargs);
950
951     if (!modargs1 || !modargs2) {
952         equal = false;
953         goto finish;
954     }
955
956     for (state = NULL, key = pa_modargs_iterate(modargs1, &state); key; key = pa_modargs_iterate(modargs1, &state)) {
957         value1 = pa_modargs_get_value(modargs1, key, NULL);
958         value2 = pa_modargs_get_value(modargs2, key, NULL);
959         if (!value1 || !value2 || !pa_streq(value1, value2)) {
960             equal = false;
961             goto finish;
962         }
963     }
964
965     for (state = NULL, key = pa_modargs_iterate(modargs2, &state); key; key = pa_modargs_iterate(modargs2, &state)) {
966         value1 = pa_modargs_get_value(modargs1, key, NULL);
967         value2 = pa_modargs_get_value(modargs2, key, NULL);
968         if (!value1 || !value2 || !pa_streq(value1, value2)) {
969             equal = false;
970             goto finish;
971         }
972     }
973
974 finish:
975
976     if (modargs1)
977         pa_modargs_free(modargs1);
978     if (modargs2)
979         pa_modargs_free(modargs2);
980
981
982     return equal;
983 }
984
985 static bool pulse_device_params_is_equal(pa_object *pdevice, const char *params) {
986     const char *removed_module_args;
987     const char *module_args;
988     pa_sink *sink;
989     pa_source *source;
990
991     pa_assert(pdevice);
992
993     if (pa_sink_isinstance(pdevice)) {
994         sink = PA_SINK(pdevice);
995         module_args = sink->module->argument;
996     } else {
997         source = PA_SOURCE(pdevice);
998         module_args = source->module->argument;
999     }
1000
1001     if (!params && !module_args)
1002         return 0;
1003     if (!params || !module_args)
1004         return -1;
1005
1006     removed_module_args = pulse_device_get_device_string_removed_argument(pdevice);
1007     return device_params_is_equal(params, removed_module_args);
1008 }
1009
1010 static const char* pulse_device_get_device_string(pa_object *pdevice) {
1011     dm_device_class_t device_class;
1012     static char device_string[DEVICE_STR_MAX] = {0,};
1013     char *device_string_val = NULL;
1014     pa_proplist *prop;
1015
1016     pa_assert(pdevice);
1017
1018     device_class = pulse_device_get_class(pdevice);
1019     prop = pulse_device_get_proplist(pdevice);
1020
1021     if (device_class == DM_DEVICE_CLASS_ALSA) {
1022         if (pulse_device_get_alsa_device_string(prop, &device_string_val) < 0)
1023             return NULL;
1024         snprintf(device_string, DEVICE_STR_MAX, "alsa:%s", device_string_val);
1025         return device_string;
1026     } else if (device_class == DM_DEVICE_CLASS_NULL) {
1027         return "null";
1028     } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
1029         return "tizen";
1030     } else if (device_class == DM_DEVICE_CLASS_BT) {
1031         return "bt";
1032     } else {
1033         return device_string;
1034     }
1035 }
1036
1037 /*  pdevice is sink or source */
1038 static bool pulse_device_same_device_string(pa_object *pdevice, const char *device_string) {
1039     const char *_device_string;
1040
1041     pa_assert(pdevice);
1042     pa_assert(device_string);
1043
1044     if (!(_device_string = pulse_device_get_device_string(pdevice)))
1045         return false;
1046
1047     return pa_streq(_device_string, device_string);
1048 }
1049
1050 static const char* device_type_info_get_role(struct device_type_info *type_info, bool is_playback, const char *device_string) {
1051     pa_hashmap *pcm_devices;
1052     void *state;
1053     const char *role, *_device_string;
1054     dm_device_direction_t direction;
1055
1056     pa_assert(type_info);
1057     pa_assert(device_string);
1058
1059     direction = device_type_get_static_direction(type_info->type);
1060     if (direction == DM_DEVICE_DIRECTION_NONE) {
1061         pa_log_debug("Not static direction");
1062         return NULL;
1063     }
1064
1065     if (is_playback) {
1066         if (direction == DM_DEVICE_DIRECTION_IN) {
1067             pa_log_debug("Invalid direction");
1068             return NULL;
1069         }
1070         pcm_devices = type_info->playback_devices;
1071     } else {
1072         if (direction == DM_DEVICE_DIRECTION_OUT) {
1073             pa_log_debug("Invalid direction");
1074             return NULL;
1075         }
1076         pcm_devices = type_info->capture_devices;
1077     }
1078
1079     if (!pcm_devices) {
1080         pa_log_warn("No %s pcm devices for %s", is_playback ? "playback" : "capture", type_info->type);
1081         return NULL;
1082     }
1083
1084     PA_HASHMAP_FOREACH_KV(role, _device_string, pcm_devices, state) {
1085         if (pa_streq(_device_string, device_string)) {
1086             return role;
1087         }
1088     }
1089
1090     return NULL;
1091 }
1092
1093 pa_dynarray* pulse_device_get_belongs_type(pa_object *pdevice, pa_device_manager *dm) {
1094     pa_dynarray *ctypes;
1095     struct composite_type *ctype;
1096     struct device_type_info *type_info;
1097     const char *device_string, *role;
1098     uint32_t type_idx;
1099     pa_device_type_t pdt;
1100
1101     pa_assert(pdevice);
1102
1103     if (pulse_device_is_monitor(pdevice))
1104         return NULL;
1105     if (pulse_device_is_usb(pdevice))
1106         return NULL;
1107     if (pulse_device_is_bluez(pdevice))
1108         return NULL;
1109
1110     ctypes = pa_dynarray_new(pa_xfree);
1111
1112     if (pa_sink_isinstance(pdevice))
1113         pdt = PA_DEVICE_TYPE_SINK;
1114     else
1115         pdt = PA_DEVICE_TYPE_SOURCE;
1116
1117     PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
1118         device_string = pulse_device_get_device_string(pdevice);
1119         role = device_type_info_get_role(type_info, pdt, device_string);
1120         /* Found type_info which is matching with pulse_device */
1121         if (role) {
1122             ctype = pa_xmalloc0(sizeof(struct composite_type));
1123             ctype->type = type_info->type;
1124             ctype->role = role;
1125             pa_dynarray_append(ctypes, ctype);
1126         }
1127     }
1128
1129     if (pa_dynarray_size(ctypes) == 0) {
1130         pa_dynarray_free(ctypes);
1131         ctypes = NULL;
1132     }
1133
1134     return ctypes;
1135 }
1136
1137 static const char* pulse_device_get_device_name(pa_object *pdevice, const char *type) {
1138     pa_proplist *prop;
1139
1140     pa_assert(pdevice);
1141     pa_assert(device_type_is_valid(type));
1142
1143     prop = pulse_device_get_proplist(pdevice);
1144
1145     if (pa_streq(type, DEVICE_TYPE_USB_AUDIO))
1146         return pa_proplist_gets(prop, "udev.id");
1147     else if (pa_streq(type, DEVICE_TYPE_BT_A2DP))
1148         return pa_proplist_gets(prop, "bluez.alias");
1149     else
1150         return NULL;
1151 }
1152
1153 static void pulse_device_set_use_internal_codec(pa_object *pdevice, bool use_internal_codec) {
1154     pa_assert(pdevice);
1155
1156     if (pa_sink_isinstance(pdevice)) {
1157         pa_sink *sink = PA_SINK(pdevice);
1158         sink->use_internal_codec = use_internal_codec;
1159     } else {
1160         pa_source *source = PA_SOURCE(pdevice);
1161         source->use_internal_codec = use_internal_codec;
1162     }
1163 }
1164
1165 /* Get system_id of physical device, if external device */
1166 static const char* pulse_device_get_system_id(pa_object *pdevice) {
1167     pa_proplist *prop;
1168
1169     prop = pulse_device_get_proplist(pdevice);
1170     if (pulse_device_is_usb(pdevice))
1171         return pa_proplist_gets(prop, "sysfs.path");
1172     else if (pulse_device_is_bluez(pdevice))
1173         return pa_proplist_gets(prop, "bluez.path");
1174     else
1175         return NULL;
1176 }
1177
1178 static pa_sink* _core_get_sink(pa_core *core, const char *device_string, const char *params) {
1179     uint32_t device_idx;
1180     pa_sink *sink;
1181
1182     pa_assert(core);
1183     pa_assert(device_string);
1184
1185     PA_IDXSET_FOREACH(sink, core->sinks, device_idx) {
1186         if (pulse_device_is_monitor(PA_OBJECT(sink)))
1187             continue;
1188         if (pulse_device_same_device_string(PA_OBJECT(sink), device_string)) {
1189             if (params == NULL)
1190                 return sink;
1191             else if (pulse_device_params_is_equal(PA_OBJECT(sink), params))
1192                 return sink;
1193         }
1194     }
1195
1196     return NULL;
1197 }
1198
1199 static pa_source* _core_get_source(pa_core *core, const char *device_string, const char *params) {
1200     uint32_t device_idx;
1201     pa_source *source;
1202
1203     pa_assert(core);
1204     pa_assert(device_string);
1205
1206     PA_IDXSET_FOREACH(source, core->sources, device_idx) {
1207         if (pulse_device_is_monitor(PA_OBJECT(source)))
1208             continue;
1209         if (pulse_device_same_device_string(PA_OBJECT(source), device_string)) {
1210             if (params == NULL)
1211                 return source;
1212             else if (pulse_device_params_is_equal(PA_OBJECT(source), params))
1213                 return source;
1214         }
1215     }
1216
1217     return NULL;
1218 }
1219
1220
1221 static void _fill_new_data_basic(pa_tz_device_new_data *data, const char *type,
1222         dm_device_direction_t direction, bool use_internal_codec, pa_device_manager *dm) {
1223     pa_assert(data);
1224
1225     pa_tz_device_new_data_set_type(data, type);
1226     pa_tz_device_new_data_set_direction(data, direction);
1227     pa_tz_device_new_data_set_use_internal_codec(data, use_internal_codec);
1228 }
1229
1230 static int _fill_new_data_sinks(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
1231     pa_sink *sink;
1232     char *device_string, *role;
1233     void *state;
1234
1235     pa_assert(data);
1236     pa_assert(type_info);
1237
1238     if (type_info->playback_devices == NULL) {
1239         pa_log_error("No playback devices for %s", type_info->type);
1240         return -1;
1241     }
1242
1243     PA_HASHMAP_FOREACH_KV(role, device_string, type_info->playback_devices, state) {
1244         sink = _core_get_sink(dm->core, device_string, NULL);
1245         if (sink)
1246             pa_tz_device_new_data_add_sink(data, role, sink);
1247         else
1248             pa_log_error("Failed to get matching sink for %s %s", role, device_string);
1249     }
1250
1251     return 0;
1252 }
1253
1254 static int _fill_new_data_sources(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
1255     pa_source *source;
1256     char *device_string, *role;
1257     void *state;
1258
1259     pa_assert(data);
1260     pa_assert(type_info);
1261
1262     if (type_info->capture_devices == NULL) {
1263         pa_log_error("No capture devices for %s", type_info->type);
1264         return -1;
1265     }
1266
1267     PA_HASHMAP_FOREACH_KV(role, device_string, type_info->capture_devices, state) {
1268         source = _core_get_source(dm->core, device_string, NULL);
1269         if (source)
1270             pa_tz_device_new_data_add_source(data, role, source);
1271         else
1272             pa_log_error("Failed to get matching source for %s %s", role, device_string);
1273     }
1274
1275     return 0;
1276 }
1277
1278 static pa_sink* _device_manager_set_default_sink(pa_device_manager *dm,  const char *type, const char *role) {
1279     pa_tz_device *device;
1280     pa_sink *sink;
1281
1282     if (!type || !role) {
1283         pa_log_warn("Argument for set_default_sink invalid");
1284         return NULL;
1285     }
1286
1287     if (!(device = _device_list_get_device(dm, type, NULL))) {
1288         pa_log_warn("cannot get device item for %s", type);
1289         return NULL;
1290     }
1291
1292     if (!(sink = pa_tz_device_get_sink(device, role))) {
1293         pa_log_warn("cannot get sink for %s", role);
1294         return NULL;
1295     }
1296
1297     sink = pa_namereg_set_default_sink(dm->core, sink);
1298     return sink;
1299 }
1300
1301 static pa_source* _device_manager_set_default_source(pa_device_manager *dm,  const char *type, const char *role) {
1302     pa_tz_device *device;
1303     pa_source *source;
1304
1305     if (!type || !role) {
1306         pa_log_warn("Argument for set_default_source invalid");
1307         return NULL;
1308     }
1309
1310     if (!(device = _device_list_get_device(dm, type, NULL))) {
1311         pa_log_warn("cannot get device item for %s", type);
1312         return NULL;
1313     }
1314
1315     if (!(source = pa_tz_device_get_source(device, role))) {
1316         pa_log_warn("cannot get source for %s", role);
1317         return NULL;
1318     }
1319
1320     source = pa_namereg_set_default_source(dm->core, source);
1321     return source;
1322 }
1323
1324 static void handle_usb_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1325     const char *name, *system_id;
1326     dm_device_direction_t direction;
1327     pa_tz_device *device;
1328
1329     pa_assert(pdevice);
1330     pa_assert(manager);
1331
1332     pa_log_info("Handle usb pulse device");
1333
1334     system_id = pulse_device_get_system_id(pdevice);
1335     direction = pulse_device_get_direction(pdevice);
1336
1337     if (is_loaded) {
1338         pa_tz_device_new_data data;
1339
1340         name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_USB_AUDIO);
1341
1342         pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, NULL);
1343         pa_tz_device_new_data_set_type(&data, DEVICE_TYPE_USB_AUDIO);
1344         pa_tz_device_new_data_set_name(&data, name);
1345         pa_tz_device_new_data_set_direction(&data, direction);
1346         pa_tz_device_new_data_set_system_id(&data, system_id);
1347         pa_tz_device_new_data_set_use_internal_codec(&data, false);
1348         if (direction == DM_DEVICE_DIRECTION_OUT)
1349             pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
1350         else
1351             pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1352
1353         pa_tz_device_new(&data);
1354         pa_tz_device_new_data_done(&data);
1355     } else {
1356         if (!(device = _device_list_get_device(manager, DEVICE_TYPE_USB_AUDIO, system_id)))
1357             pa_log_warn("Can't get usb device for %s", system_id);
1358         else
1359             pa_tz_device_free(device);
1360     }
1361 }
1362
1363 static void handle_bt_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1364     dm_device_direction_t direction;
1365     pa_tz_device *device;
1366     const char *system_id;
1367
1368     pa_assert(pdevice);
1369     pa_assert(manager);
1370
1371     pa_log_info("Handle bt pulse device");
1372
1373     direction = pulse_device_get_direction(pdevice);
1374     system_id = pulse_device_get_system_id(pdevice);
1375
1376     if (is_loaded) {
1377         pa_tz_device_new_data data;
1378
1379         const char *name;
1380         name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_BT_A2DP);
1381
1382         pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, manager->dbus_conn);
1383         _fill_new_data_basic(&data, DEVICE_TYPE_BT_A2DP, direction, false, manager);
1384         pa_tz_device_new_data_set_name(&data, name);
1385         pa_tz_device_new_data_set_system_id(&data, system_id);
1386         if (direction == DM_DEVICE_DIRECTION_OUT)
1387             pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
1388         else
1389             pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1390
1391         pa_tz_device_new(&data);
1392         pa_tz_device_new_data_done(&data);
1393     } else {
1394
1395         if (!(device = _device_list_get_device(manager, DEVICE_TYPE_BT_A2DP, system_id)))
1396             pa_log_warn("Can't get bt device for %s", system_id);
1397         else
1398             pa_tz_device_free(device);
1399     }
1400 }
1401
1402 static void handle_internal_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1403     pa_tz_device *device;
1404     struct composite_type *ctype;
1405     pa_dynarray *ctypes;
1406     dm_device_direction_t direction;
1407
1408     pa_assert(pdevice);
1409     pa_assert(manager);
1410
1411     pa_log_info("Handle internal pulse device");
1412     direction = pulse_device_get_direction(pdevice);
1413
1414     /* Get types which this pulse_device belongs to */
1415     if ((ctypes = pulse_device_get_belongs_type(pdevice, manager)) == NULL) {
1416         pa_log_debug("Failed to get device type. Skip this");
1417         return ;
1418     }
1419
1420     if (is_loaded) {
1421         /* Put this pulse_device to already loaded devices */
1422         for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
1423             ctype = pa_dynarray_get(ctypes, i);
1424             pa_log_info("Found belongs type %s %s", ctype->type, ctype->role);
1425             if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
1426                 pa_log_info("Add this pulse_device to device(%u)", pa_tz_device_get_id(device));
1427                 if (direction == DM_DEVICE_DIRECTION_OUT)
1428                     pa_tz_device_add_sink(device, ctype->role, PA_SINK(pdevice));
1429                 else
1430                     pa_tz_device_add_source(device, ctype->role, PA_SOURCE(pdevice));
1431             } else {
1432                 pa_log_info("No device for %s", ctype->type);
1433             }
1434         }
1435     } else {
1436         /* Remove this pulse_device from already loaded devices */
1437         for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
1438             ctype = pa_dynarray_get(ctypes, i);
1439             pa_log_info("Found belongs type %s %s", ctype->type, ctype->role);
1440             if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
1441                 pa_log_info("Remove this pulse_device from device(%u)", pa_tz_device_get_id(device));
1442                 if (direction == DM_DEVICE_DIRECTION_OUT)
1443                     pa_tz_device_remove_sink(device, PA_SINK(pdevice));
1444                 else
1445                     pa_tz_device_remove_source(device, PA_SOURCE(pdevice));
1446             } else {
1447                 pa_log_info("No device for %s", ctype->type);
1448             }
1449         }
1450     }
1451
1452     pa_dynarray_free(ctypes);
1453 }
1454
1455 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1456     pa_assert(c);
1457     pa_assert(sink);
1458     pa_assert(dm);
1459
1460     pa_log_info("========== Sink Put Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1461
1462     if (pulse_device_is_monitor(PA_OBJECT(sink)))
1463         return PA_HOOK_OK;
1464
1465     if (pulse_device_is_usb(PA_OBJECT(sink))) {
1466         pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
1467         handle_usb_pulse_device(PA_OBJECT(sink), true, dm);
1468         return PA_HOOK_OK;
1469     } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
1470         pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
1471         handle_bt_pulse_device(PA_OBJECT(sink), true, dm);
1472         return PA_HOOK_OK;
1473     } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
1474         pulse_device_set_use_internal_codec(PA_OBJECT(sink), true);
1475         handle_internal_pulse_device(PA_OBJECT(sink), true, dm);
1476         return PA_HOOK_OK;
1477     } else {
1478         pa_log_debug("Don't care this sink");
1479     }
1480
1481     return PA_HOOK_OK;
1482 }
1483
1484 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1485     pa_assert(c);
1486     pa_assert(sink);
1487     pa_assert(dm);
1488
1489     pa_log_info("=========== Sink unlink Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1490
1491     if (pulse_device_is_monitor(PA_OBJECT(sink)))
1492         return PA_HOOK_OK;
1493
1494     if (pulse_device_is_usb(PA_OBJECT(sink))) {
1495         handle_usb_pulse_device(PA_OBJECT(sink), false, dm);
1496         return PA_HOOK_OK;
1497     } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
1498         handle_bt_pulse_device(PA_OBJECT(sink), false, dm);
1499         return PA_HOOK_OK;
1500     } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
1501         handle_internal_pulse_device(PA_OBJECT(sink), false, dm);
1502         return PA_HOOK_OK;
1503     } else {
1504         pa_log_debug("Don't care this sink");
1505     }
1506
1507     return PA_HOOK_OK;
1508 }
1509
1510 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1511     pa_assert(c);
1512     pa_assert(source);
1513     pa_assert(dm);
1514
1515     pa_log_info("========== source Put Hook Callback '%s'(%d) ==========", source->name, source->index);
1516
1517     if (pulse_device_is_monitor(PA_OBJECT(source)))
1518         return PA_HOOK_OK;
1519
1520     if (pulse_device_is_usb(PA_OBJECT(source))) {
1521         pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
1522         handle_usb_pulse_device(PA_OBJECT(source), true, dm);
1523         return PA_HOOK_OK;
1524     } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
1525         pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
1526         handle_bt_pulse_device(PA_OBJECT(source), true, dm);
1527         return PA_HOOK_OK;
1528     } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
1529         pulse_device_set_use_internal_codec(PA_OBJECT(source), true);
1530         handle_internal_pulse_device(PA_OBJECT(source), true, dm);
1531         return PA_HOOK_OK;
1532     } else {
1533         pa_log_debug("Don't care this source");
1534     }
1535
1536     return PA_HOOK_OK;
1537 }
1538
1539 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1540     pa_assert(c);
1541     pa_assert(source);
1542     pa_assert(dm);
1543
1544     pa_log_info("=========== source unlink Hook Callback '%s'(%d) ==========", source->name, source->index);
1545
1546     if (pulse_device_is_monitor(PA_OBJECT(source)))
1547         return PA_HOOK_OK;
1548
1549     if (pulse_device_is_usb(PA_OBJECT(source))) {
1550         handle_usb_pulse_device(PA_OBJECT(source), false, dm);
1551         return PA_HOOK_OK;
1552     } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
1553         handle_bt_pulse_device(PA_OBJECT(source), false, dm);
1554         return PA_HOOK_OK;
1555     } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
1556         handle_internal_pulse_device(PA_OBJECT(source), false, dm);
1557         return PA_HOOK_OK;
1558     } else {
1559         pa_log_debug("Don't care this source");
1560     }
1561
1562     return PA_HOOK_OK;
1563 }
1564
1565
1566
1567 static pa_hook_result_t sink_source_state_changed_hook_cb(pa_core *c, pa_object *pdevice, pa_device_manager *dm) {
1568     pa_tz_device *device;
1569     uint32_t idx = 0;
1570
1571     pa_assert(c);
1572     pa_object_assert_ref(pdevice);
1573     pa_assert(dm);
1574
1575     if (pa_sink_isinstance(pdevice)) {
1576         pa_sink *s = PA_SINK(pdevice);
1577         pa_sink_state_t state = pa_sink_get_state(s);
1578         pa_log_debug("=========== Sink(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
1579         if (s->use_internal_codec && state == PA_SINK_SUSPENDED) {
1580             PA_IDXSET_FOREACH(device, dm->device_list, idx) {
1581                 if (pa_tz_device_is_use_internal_codec(device) && pa_tz_device_is_all_suspended(device))
1582                     pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_DEACTIVATED);
1583             }
1584         } else {
1585             if ((device = pa_device_manager_get_device_with_sink(s))) {
1586                 if (state == PA_SINK_RUNNING)
1587                     pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_ACTIVATED);
1588                 else if (state == PA_SINK_SUSPENDED)
1589                     pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_DEACTIVATED);
1590             }
1591         }
1592     } else if (pa_source_isinstance(pdevice)) {
1593         pa_source *s = PA_SOURCE(pdevice);
1594         pa_source_state_t state = pa_source_get_state(s);
1595         pa_log_debug("=========== Source(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
1596         if (s->use_internal_codec && state == PA_SOURCE_SUSPENDED) {
1597             PA_IDXSET_FOREACH(device, dm->device_list, idx) {
1598                 if (pa_tz_device_is_use_internal_codec(device) && pa_tz_device_is_all_suspended(device))
1599                     pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_DEACTIVATED);
1600             }
1601         } else {
1602             if ((device = pa_device_manager_get_device_with_source(s))) {
1603                 if (state == PA_SOURCE_RUNNING)
1604                     pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_ACTIVATED);
1605                 else if (state == PA_SOURCE_SUSPENDED)
1606                     pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_DEACTIVATED);
1607             }
1608         }
1609     }
1610     pa_log_debug("========= sink_source_state_changed_hook_cb END =====");
1611
1612     return PA_HOOK_OK;
1613 }
1614
1615 /*
1616     Build params for load sink or source, and load it.
1617 */
1618
1619 static void* load_device(pa_core *c, bool is_sink, const char *device_string, const char *device_params) {
1620     const char *args = NULL;
1621     const char *module_name;
1622     pa_module *module;
1623     pa_sink *sink;
1624     pa_source *source;
1625     uint32_t device_idx;
1626     dm_device_class_t device_class;
1627
1628     pa_assert(c);
1629     pa_assert(device_string);
1630     pa_assert(device_params);
1631
1632     pa_log_info("Load %s Device : String'%s' Param'%s'", is_sink ? "Playback" : "Capture", device_string, device_params);
1633
1634     device_class = device_string_get_class(device_string);
1635     if (device_class <= DM_DEVICE_CLASS_NONE || device_class >= DM_DEVICE_CLASS_MAX) {
1636         pa_log_warn("Invalid device_string '%s'", device_string);
1637         return NULL;
1638     }
1639
1640     if (!(module_name = device_class_get_module_name(device_class, is_sink))) {
1641         pa_log_error("Get proper module name to load failed");
1642         return NULL;
1643     }
1644     if (!(args = build_params_to_load_device(device_string, device_params, device_class))) {
1645         pa_log_error("Get proper module name to load failed");
1646         return NULL;
1647     }
1648     if (!(module = pa_module_load(c, module_name, args))) {
1649         pa_log_error("Load module with name '%s' argu '%s' failed", module_name, args);
1650         return NULL;
1651     }
1652
1653
1654     if (is_sink) {
1655         PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
1656             if (sink->module == module) {
1657                 return sink;
1658             }
1659         }
1660     } else {
1661         PA_IDXSET_FOREACH(source, c->sources, device_idx) {
1662             if (source->module == module) {
1663                 return source;
1664             }
1665         }
1666     }
1667
1668     return NULL;
1669 }
1670
1671 static int _load_type_devices(struct device_type_info *type_info, bool is_playback, pa_device_manager *dm) {
1672     pa_hashmap *pcm_devices;
1673     pa_idxset *file_infos;
1674     void *state;
1675     char *role;
1676     const char *device_string, *params;
1677
1678     pa_assert(dm);
1679     pa_assert(type_info);
1680
1681     pa_log_info("Load type devices : %s %s", type_info->type, is_playback ? "playback" : "capture");
1682
1683     if (is_playback) {
1684         pcm_devices = type_info->playback_devices;
1685         file_infos = dm->file_map->playback;
1686     } else {
1687         pcm_devices = type_info->capture_devices;
1688         file_infos = dm->file_map->capture;
1689     }
1690
1691     if (!pcm_devices || !file_infos) {
1692         pa_log_error("No information to load");
1693         return -1;
1694     }
1695
1696     PA_HASHMAP_FOREACH_KV(role, device_string, pcm_devices, state) {
1697         params = _file_infos_get_param(file_infos, device_string, role);
1698         if (params == NULL) {
1699             pa_log_error("Failed to get param for %s", device_string);
1700             continue;
1701         }
1702         /* Check duplicate load */
1703         if (is_playback && _core_get_sink(dm->core, device_string, params)) {
1704             pa_log_debug("Already loaded %s %s", device_string, params);
1705             continue;
1706         }
1707         if (!is_playback && _core_get_source(dm->core, device_string, params)) {
1708             pa_log_debug("Already loaded %s %s", device_string, params);
1709             continue;
1710         }
1711         if (!(load_device(dm->core, is_playback, device_string, params))) {
1712             pa_log_warn("load device failed %s %s", device_string, params);
1713         }
1714     }
1715
1716     return 0;
1717 }
1718
1719 static pa_tz_device* _load_forwarding_device(pa_device_manager *dm) {
1720     pa_tz_device_new_data data;
1721     pa_tz_device *spk_device, *forwarding_device;
1722     pa_sink *spk_sink;
1723
1724     pa_assert(dm);
1725
1726     pa_log_info("Load forwarding device");
1727
1728     if ((forwarding_device = _device_list_get_device(dm, DEVICE_TYPE_FORWARDING, NULL))) {
1729         pa_log_info("Forwarding device already exists");
1730         return forwarding_device;
1731     }
1732
1733     if ((spk_device = _device_list_get_device(dm, DEVICE_TYPE_SPEAKER, NULL)) == NULL) {
1734         pa_log_error("Get speaker device failed");
1735         return NULL;
1736     }
1737
1738     if ((spk_sink = pa_tz_device_get_sink(spk_device, DEVICE_ROLE_NORMAL)) == NULL) {
1739         pa_log_error("Get speaker sink failed");
1740         return NULL;
1741     }
1742
1743     pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
1744     _fill_new_data_basic(&data, DEVICE_TYPE_FORWARDING, DM_DEVICE_DIRECTION_BOTH, true, dm);
1745     pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, spk_sink);
1746     pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, spk_sink->monitor_source);
1747
1748     if ((forwarding_device = pa_tz_device_new(&data)) == NULL)
1749         pa_log_error("Failed to create forwarding device");
1750
1751     pa_tz_device_new_data_done(&data);
1752
1753     return forwarding_device;
1754 }
1755
1756 /*
1757     Handle device connection detected through dbus.
1758     First, update device-status hashmap.
1759     And if correnspondent sink/sources for device_type exist, should make device and notify it.
1760     Use [device_type->roles] mappings in sink/source for find proper sink/source.
1761 */
1762 static void handle_device_connected(pa_device_manager *dm, const char *type,
1763         const char *name, const char *system_id, device_detected_type_t detected_type) {
1764     struct device_type_info *type_info;
1765     pa_tz_device_new_data data;
1766
1767     pa_assert(dm);
1768     pa_assert(dm->device_status);
1769     pa_assert(dm->device_list);
1770
1771     pa_log_info("Device connected, type(%s) name(%s) system_id(%s) detected_type(%d)",
1772             type, pa_strempty(name), pa_strempty(system_id), detected_type);
1773
1774     type_info = _device_manager_get_type_info(dm->type_infos, type);
1775
1776     if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
1777         pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, dm->dbus_conn);
1778         _fill_new_data_basic(&data, DEVICE_TYPE_BT_SCO, DM_DEVICE_DIRECTION_BOTH, true, dm);
1779         _fill_new_data_sinks(&data, type_info, dm);
1780         _fill_new_data_sources(&data, type_info, dm);
1781         pa_tz_device_new_data_set_name(&data, name);
1782         pa_tz_device_new_data_set_system_id(&data, system_id);
1783         pa_tz_device_new(&data);
1784         pa_tz_device_new_data_done(&data);
1785     } else if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
1786         dm_device_direction_t direction;
1787
1788         if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P)
1789             direction = DM_DEVICE_DIRECTION_BOTH;
1790         else
1791             direction = DM_DEVICE_DIRECTION_OUT;
1792         pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
1793         _fill_new_data_basic(&data, DEVICE_TYPE_AUDIO_JACK, direction, true, dm);
1794         _fill_new_data_sinks(&data, type_info, dm);
1795         _fill_new_data_sources(&data, type_info, dm);
1796
1797         pa_tz_device_new(&data);
1798         pa_tz_device_new_data_done(&data);
1799     } else if (device_type_is_equal(type, DEVICE_TYPE_HDMI)) {
1800         pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
1801         _fill_new_data_basic(&data, DEVICE_TYPE_HDMI, DM_DEVICE_DIRECTION_OUT, true, dm);
1802         _fill_new_data_sinks(&data, type_info, dm);
1803
1804         pa_tz_device_new(&data);
1805         pa_tz_device_new_data_done(&data);
1806     } else if (device_type_is_equal(type, DEVICE_TYPE_FORWARDING)) {
1807         _load_forwarding_device(dm);
1808     } else {
1809         dm_device_direction_t direction;
1810
1811         direction = device_type_get_static_direction(type);
1812         if (direction != DM_DEVICE_DIRECTION_NONE) {
1813             pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
1814             _fill_new_data_basic(&data, type, direction, true, dm);
1815             if (direction & DM_DEVICE_DIRECTION_OUT)
1816                 _fill_new_data_sinks(&data, type_info, dm);
1817             if (direction & DM_DEVICE_DIRECTION_IN)
1818                 _fill_new_data_sources(&data, type_info, dm);
1819
1820             pa_tz_device_new(&data);
1821             pa_tz_device_new_data_done(&data);
1822         } else {
1823             pa_log_error("Invalid case : not static direction");
1824             return ;
1825         }
1826     }
1827
1828     return ;
1829 }
1830
1831 /*
1832     Handle device disconnection detected through dbus.
1833     First, update device-status hashmap.
1834     And if there is device which has the device_type, remove it.
1835 */
1836 static int handle_device_disconnected(pa_device_manager *dm, const char *type, const char *system_id) {
1837     pa_tz_device *device;
1838
1839     pa_assert(dm);
1840     pa_assert(dm->device_status);
1841
1842     pa_log_info("Device type(%s) system_id(%s) disconnected",
1843             type, pa_strempty(system_id));
1844
1845     device = _device_list_get_device(dm, type, system_id);
1846     if (!device) {
1847         pa_log_error("Disconnection detected but no device for that");
1848         return -1;
1849     }
1850
1851     pa_tz_device_free(device);
1852
1853     return 0;
1854 }
1855
1856 static int load_builtin_devices(pa_device_manager *dm) {
1857     struct device_type_info *type_info;
1858     uint32_t type_idx;
1859     device_detected_type_t detected_type = DEVICE_CONNECTED;
1860     const char *type;
1861
1862     pa_assert(dm);
1863
1864     pa_log_debug("\n==================== Load Builtin Devices ====================");
1865
1866     PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
1867
1868         type = type_info->type;
1869
1870         pa_log_info("type_info : %s", type);
1871         detected_type = _device_get_detected(dm, type, NULL);
1872         if (detected_type == DEVICE_DISCONNECTED) {
1873             pa_log_info("Not detected yet");
1874             continue;
1875         }
1876
1877         if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
1878             if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P) {
1879                 _load_type_devices(type_info, true, dm);
1880                 _load_type_devices(type_info, false, dm);
1881             } else {
1882                 _load_type_devices(type_info, true, dm);
1883             }
1884             handle_device_connected(dm, type, NULL, NULL, detected_type);
1885         } else if (device_type_is_use_external_card(type) == false) {
1886             dm_device_direction_t direction;
1887             direction = device_type_get_static_direction(type);
1888             if (direction == DM_DEVICE_DIRECTION_NONE) {
1889                 pa_log_warn("Wrong direction");
1890                 continue;
1891             }
1892             if (direction & DM_DEVICE_DIRECTION_OUT)
1893                 _load_type_devices(type_info, true, dm);
1894             if (direction & DM_DEVICE_DIRECTION_IN)
1895                 _load_type_devices(type_info, false, dm);
1896             handle_device_connected(dm, type, NULL, NULL, detected_type);
1897         } else {
1898             pa_log_warn("Invalid case");
1899         }
1900     }
1901
1902     return 0;
1903 }
1904
1905 /***************** Parse json file *******************/
1906 static pa_hashmap* parse_device_role_object(json_object *device_role_o) {
1907     pa_hashmap *roles = NULL;
1908     const char *params, *device_role;
1909     struct json_object_iterator it, it_end;
1910     json_object *params_o;
1911
1912     pa_assert(device_role_o);
1913     pa_assert(json_object_is_type(device_role_o, json_type_object));
1914
1915     roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1916     if (!roles) {
1917         pa_log_debug("hashmap new failed");
1918         goto fail;
1919     }
1920
1921     it = json_object_iter_begin(device_role_o);
1922     it_end = json_object_iter_end(device_role_o);
1923
1924     while (!json_object_iter_equal(&it, &it_end)) {
1925         device_role = json_object_iter_peek_name(&it);
1926         params_o = json_object_iter_peek_value(&it);
1927
1928         if (!(params = json_object_get_string(params_o))) {
1929             pa_log_debug("There is no device params for role '%s'", device_role);
1930         }
1931         pa_log_info("- Role '%s' -> '%s'", device_role, params);
1932         if (device_role_is_valid(device_role)) {
1933             if (pa_hashmap_put(roles, (void *)device_role, (void *)params)) {
1934                 pa_log_error("put new role to hashmap faild");
1935                 goto fail;
1936             }
1937         } else {
1938             pa_log_error("Invalid device role '%s'", device_role);
1939         }
1940
1941         json_object_iter_next(&it);
1942     }
1943
1944     if (pa_hashmap_size(roles) == 0) {
1945         pa_log_warn("There is no role for device.. free hashmap");
1946         pa_hashmap_free(roles);
1947         roles = NULL;
1948     }
1949
1950     return roles;
1951
1952 fail:
1953     if (roles)
1954         pa_hashmap_free(roles);
1955
1956     return NULL;
1957 }
1958
1959 static struct device_file_info* parse_device_file_object(json_object *device_file_o, const char **device_string_key) {
1960     pa_hashmap *roles = NULL;
1961     json_object *device_file_prop_o = NULL;
1962     const char *device_string = NULL;
1963     struct device_file_info *file_info = NULL;
1964
1965     pa_assert(device_file_o);
1966     pa_assert(device_string_key);
1967     pa_assert(json_object_is_type(device_file_o, json_type_object));
1968
1969     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)) {
1970         if ((device_string = json_object_get_string(device_file_prop_o))) {
1971             pa_log_info("[ Device File - %s ]", device_string);
1972         } else {
1973             pa_log_error("Get device-string failed");
1974             return NULL;
1975         }
1976     } else {
1977         pa_log_error("Get device-string object failed");
1978         return NULL;
1979     }
1980
1981     if (json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_ROLE, &device_file_prop_o)) {
1982         if (!(roles = parse_device_role_object(device_file_prop_o))) {
1983             pa_log_error("Parse device role for '%s' failed", device_string);
1984             goto fail;
1985         }
1986     } else {
1987         pa_log_error("Get device role object failed");
1988     }
1989
1990     file_info = pa_xmalloc0(sizeof(struct device_file_info));
1991     file_info->device_string = device_string;
1992     file_info->device_types = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1993     file_info->roles = roles;
1994
1995 //    *device_string_key = device_string;
1996
1997     return file_info;
1998
1999 fail:
2000
2001     return NULL;
2002 }
2003
2004 static pa_idxset* parse_device_file_array_object(json_object *device_file_array_o) {
2005     int device_file_num, device_file_idx;
2006     struct device_file_info *file_info = NULL;
2007     json_object *device_file_o = NULL;
2008     pa_idxset *device_files = NULL;
2009     const char *device_string = NULL;
2010
2011     pa_assert(device_file_array_o);
2012     pa_assert(json_object_is_type(device_file_array_o, json_type_array));
2013
2014     device_files = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2015
2016     device_file_num = json_object_array_length(device_file_array_o);
2017     for (device_file_idx = 0; device_file_idx < device_file_num; device_file_idx++) {
2018         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)) {
2019             if ((file_info = parse_device_file_object(device_file_o, &device_string))) {
2020                 pa_idxset_put(device_files, file_info, NULL);
2021             } else {
2022                 pa_log_error("parse device file object failed");
2023                 goto fail;
2024             }
2025         } else {
2026             pa_log_error("Get device file object failed");
2027             goto fail;
2028         }
2029     }
2030
2031     if (pa_idxset_size(device_files) == 0) {
2032         pa_idxset_free(device_files, NULL);
2033         device_files = NULL;
2034     }
2035
2036     return device_files;
2037
2038 fail:
2039     if (device_files)
2040         pa_xfree(device_files);
2041     return NULL;
2042 }
2043
2044 static struct device_file_map *parse_device_file_map() {
2045     struct device_file_map *file_map = NULL;
2046     json_object *o, *device_files_o;
2047     json_object *playback_devices_o = NULL, *capture_devices_o = NULL;
2048
2049     pa_log_info("\nParse device files");
2050
2051     o = json_object_from_file(DEVICE_MAP_FILE);
2052
2053     if (is_error(o)) {
2054         pa_log_error("Read device-map file failed");
2055         return NULL;
2056     }
2057
2058     file_map = pa_xmalloc0(sizeof(struct device_file_map));
2059
2060     if (json_object_object_get_ex(o, DEVICE_FILE_OBJECT, &device_files_o) && json_object_is_type(device_files_o, json_type_object)) {
2061         if (json_object_object_get_ex(device_files_o, DEVICE_TYPE_PROP_PLAYBACK_DEVICES, &playback_devices_o)) {
2062             pa_log_info("Playback Device Files");
2063             file_map->playback = parse_device_file_array_object(playback_devices_o);
2064         }
2065         if (json_object_object_get_ex(device_files_o, DEVICE_TYPE_PROP_CAPTURE_DEVICES, &capture_devices_o)) {
2066             pa_log_info("Capture Device Files");
2067             file_map->capture = parse_device_file_array_object(capture_devices_o);
2068         }
2069     } else {
2070         pa_log_error("Get device files object failed");
2071         return NULL;
2072     }
2073
2074     return file_map;
2075 }
2076
2077
2078 static pa_hashmap* parse_device_role_map(json_object *device_role_map_o) {
2079     pa_hashmap *roles = NULL;
2080     const char *device_string, *device_role;
2081     struct json_object_iterator it, it_end;
2082     json_object *device_string_o;
2083
2084     pa_assert(device_role_map_o);
2085     pa_assert(json_object_is_type(device_role_map_o, json_type_object));
2086
2087     roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2088
2089     it = json_object_iter_begin(device_role_map_o);
2090     it_end = json_object_iter_end(device_role_map_o);
2091
2092     while (!json_object_iter_equal(&it, &it_end)) {
2093         device_role = json_object_iter_peek_name(&it);
2094         device_string_o = json_object_iter_peek_value(&it);
2095
2096         if (!(device_string = json_object_get_string(device_string_o))) {
2097             pa_log_debug("There is no device string for role '%s'", device_role);
2098         }
2099         pa_log_info("- Role '%s' -> '%s'", device_role, device_string);
2100         if (device_role_is_valid(device_role)) {
2101             if (pa_hashmap_put(roles, (void *)device_role, (void *)device_string)) {
2102                 pa_log_error("put new role to hashmap faild");
2103                 goto fail;
2104             }
2105         } else {
2106             pa_log_error("Invalid device role '%s'", device_role);
2107             goto fail;
2108         }
2109
2110         json_object_iter_next(&it);
2111     }
2112
2113     return roles;
2114
2115 fail:
2116     if (roles)
2117         pa_xfree(roles);
2118
2119     return NULL;
2120 }
2121
2122
2123
2124 static pa_idxset* parse_device_type_infos() {
2125     json_object *o, *device_array_o = NULL;
2126     int device_type_num = 0;
2127     int device_type_idx = 0;
2128     struct device_type_info *type_info = NULL;
2129     //pa_hashmap *type_infos = NULL;
2130     pa_idxset *type_infos = NULL;
2131
2132     o = json_object_from_file(DEVICE_MAP_FILE);
2133     if (is_error(o)) {
2134         pa_log_error("Read device-map file failed");
2135         return NULL;
2136     }
2137
2138     pa_log_info("\nParse device types");
2139     type_infos = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2140
2141     if (json_object_object_get_ex(o, DEVICE_TYPE_OBJECT, &device_array_o) && json_object_is_type(device_array_o, json_type_array)) {
2142         device_type_num = json_object_array_length(device_array_o);
2143         for (device_type_idx = 0; device_type_idx < device_type_num ; device_type_idx++) {
2144             json_object *device_o;
2145
2146             if ((device_o = json_object_array_get_idx(device_array_o, device_type_idx)) && json_object_is_type(device_o, json_type_object)) {
2147                 json_object *device_prop_o;
2148                 const char *type = NULL;
2149                 type_info = pa_xmalloc0(sizeof(struct device_type_info));
2150
2151                 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)) {
2152                     type = json_object_get_string(device_prop_o);
2153                     pa_log_info("[ Device - %s ]", type);
2154                     type_info->type = type;
2155                 } else {
2156                     pa_log_error("Get device type failed");
2157                     goto fail;
2158                 }
2159
2160                 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)) {
2161                     pa_log_info("Playback Devices");
2162                     type_info->playback_devices = parse_device_role_map(device_prop_o);
2163                 }
2164
2165                 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)) {
2166                     pa_log_info("Capture Devices");
2167                     type_info->capture_devices = parse_device_role_map(device_prop_o);
2168                 }
2169                 pa_idxset_put(type_infos, type_info, NULL);
2170
2171             } else {
2172                 pa_log_debug("Get device type object failed");
2173             }
2174         }
2175     } else {
2176         pa_log_debug("Get device type array object failed");
2177     }
2178     return type_infos;
2179
2180 fail:
2181     if (type_infos)
2182         pa_xfree(type_infos);
2183
2184     return NULL;
2185 }
2186
2187 /*
2188    look detected status which is external value, make conversion to internal consistent value, and handle it
2189    device_type, which type of device is detected
2190    system_id : system_id among same device types for support multi-device
2191 */
2192 static int handle_device_status_changed(pa_device_manager *dm, const char *type,
2193         const char *name, const char *system_id, device_detected_type_t detected) {
2194     pa_assert(dm);
2195     pa_assert(device_type_is_valid(type));
2196
2197     pa_log_info("Device Status Changed, type(%s) system_id(%s), detected_type(%d)",
2198             type, pa_strempty(system_id), detected);
2199
2200     if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2201         _device_set_detected(dm, type, name, system_id, detected);
2202         if (detected == DEVICE_DISCONNECTED)
2203             handle_device_disconnected(dm, type, system_id);
2204         else
2205             handle_device_connected(dm, type, name, system_id, detected);
2206     } else if (device_type_is_need_detect(type)) {
2207         _device_set_detected(dm, type, name, system_id, detected);
2208         if (detected == DEVICE_DISCONNECTED)
2209             handle_device_disconnected(dm, type, system_id);
2210         else
2211             handle_device_connected(dm, type, name, system_id, detected);
2212     } else {
2213         pa_log_debug("No need to detect type %s", type);
2214     }
2215
2216     return 0;
2217 }
2218
2219 /*
2220     Initialize device-status idxset.
2221     This is for device-status detected through dbus.
2222     So, if device_type is not detected through dbus, let's initialize them to detected. (ex. spk, rcv,...)
2223     If not, initialize to not detected.
2224 */
2225 static void device_type_status_init(pa_device_manager *manager) {
2226     struct device_type_info *type_info;
2227     uint32_t type_idx;
2228     const char *type;
2229
2230     pa_assert(manager);
2231     pa_assert(manager->type_infos);
2232
2233     pa_log_debug("\n==================== Init Device Status ====================");
2234
2235     PA_IDXSET_FOREACH(type_info, manager->type_infos, type_idx) {
2236         type = type_info->type;
2237         if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
2238             int earjack_status = 0;
2239             if (vconf_get_int(VCONFKEY_SYSMAN_EARJACK, &earjack_status) < 0) {
2240                 pa_log_error("Get earjack status failed");
2241                 continue;
2242             }
2243             if (earjack_status == EARJACK_TYPE_SPK_ONLY)
2244                 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_3P);
2245             else if (earjack_status == EARJACK_TYPE_SPK_WITH_MIC)
2246                 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_4P);
2247             else if (earjack_status == EARJACK_DISCONNECTED)
2248                 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2249             else
2250                 pa_log_warn("Unknown earjack status : %d", earjack_status);
2251         } else if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2252                 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2253         } else if (device_type_is_equal(type, DEVICE_TYPE_HDMI)) {
2254                 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2255         } else if (device_type_is_equal(type, DEVICE_TYPE_FORWARDING)) {
2256             int miracast_wfd_status = 0;
2257             if (vconf_get_bool(VCONFKEY_MIRACAST_WFD_SOURCE_STATUS, &miracast_wfd_status) < 0) {
2258                 pa_log_error("Get mirroring status failed");
2259                 continue;
2260             }
2261             if (miracast_wfd_status == FORWARDING_CONNECTED)
2262                 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
2263         } else {
2264             _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
2265         }
2266     }
2267     return ;
2268 }
2269
2270 #ifdef HAVE_DBUS
2271
2272 static int _translate_external_value(const char *type, int value, device_detected_type_t *detected) {
2273
2274     if (!type || !detected) {
2275         pa_log_error("Invalid Parameter for translate");
2276         return -1;
2277     }
2278
2279     if (device_type_is_equal(DEVICE_TYPE_AUDIO_JACK, type)) {
2280         if (value == EARJACK_DISCONNECTED)
2281             *detected = DEVICE_DISCONNECTED;
2282         else if (value == EARJACK_TYPE_SPK_ONLY)
2283             *detected = DEVICE_CONNECTED_AUDIO_JACK_3P;
2284         else if (value == EARJACK_TYPE_SPK_WITH_MIC)
2285             *detected = DEVICE_CONNECTED_AUDIO_JACK_4P;
2286         else
2287             return -1;
2288     } else if (device_type_is_equal(DEVICE_TYPE_HDMI, type)) {
2289         if (value == HDMI_AUDIO_DISCONNECTED)
2290             *detected = DEVICE_DISCONNECTED;
2291         else if (value == HDMI_AUDIO_AVAILABLE)
2292             *detected = DEVICE_CONNECTED;
2293         else
2294             return -1;
2295     } else if (device_type_is_equal(DEVICE_TYPE_FORWARDING, type)) {
2296         if (value == FORWARDING_DISCONNECTED)
2297             *detected = DEVICE_DISCONNECTED;
2298         else if (value == FORWARDING_CONNECTED)
2299             *detected = DEVICE_CONNECTED;
2300         else
2301             return -1;
2302     } else if (device_type_is_equal(DEVICE_TYPE_BT_SCO, type)) {
2303         if (value == BT_SCO_DISCONNECTED)
2304             *detected = DEVICE_DISCONNECTED;
2305         else if (value == BT_SCO_CONNECTED)
2306             *detected = DEVICE_CONNECTED_SCO;
2307         else
2308             return -1;
2309     }
2310
2311     return 0;
2312 }
2313
2314 static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
2315     DBusError error;
2316     int status = 0;
2317     pa_device_manager *dm = (pa_device_manager *) userdata;
2318     device_detected_type_t detected;
2319
2320     pa_assert(userdata);
2321
2322     if (dbus_message_get_type(s) != DBUS_MESSAGE_TYPE_SIGNAL)
2323         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2324
2325     pa_log_info("Device detect handler : Path(%s) Intf(%s) Member(%s) Signature(%s)",
2326             dbus_message_get_path(s), dbus_message_get_interface(s), dbus_message_get_member(s), dbus_message_get_signature(s));
2327
2328     dbus_error_init(&error);
2329
2330     if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedEarjack")) {
2331         if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2332             goto fail;
2333         } else {
2334             if (_translate_external_value(DEVICE_TYPE_AUDIO_JACK, status, &detected) < 0) {
2335                 pa_log_warn("failed to translate audio-jack detected value");
2336                 goto fail;
2337             }
2338             handle_device_status_changed(dm, DEVICE_TYPE_AUDIO_JACK, NULL, NULL, detected);
2339         }
2340     } else if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedHDMIAudio")) {
2341         if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2342             goto fail;
2343         } else {
2344             if (_translate_external_value(DEVICE_TYPE_HDMI, status, &detected) < 0) {
2345                 pa_log_warn("failed to translate HDMI detected value");
2346                 goto fail;
2347             }
2348             handle_device_status_changed(dm, DEVICE_TYPE_HDMI, NULL, NULL, detected);
2349         }
2350     } else if (dbus_message_is_signal(s, DBUS_INTERFACE_MIRRORING_SERVER, "miracast_wfd_source_status_changed")) {
2351         if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2352             goto fail;
2353         } else {
2354             if (_translate_external_value(DEVICE_TYPE_FORWARDING, status, &detected) < 0) {
2355                 pa_log_warn("failed to translate forwarding detected value");
2356                 goto fail;
2357             }
2358             handle_device_status_changed(dm, DEVICE_TYPE_FORWARDING, NULL, NULL, detected);
2359         }
2360     } else if (dbus_message_is_signal(s, DBUS_INTERFACE_BLUEZ_HEADSET, "PropertyChanged")) {
2361         DBusMessageIter msg_iter, variant_iter;
2362         char *property_name;
2363
2364         pa_log_debug("Got %s PropertyChanged signal", DBUS_INTERFACE_BLUEZ_HEADSET);
2365         dbus_message_iter_init(s, &msg_iter);
2366         if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_STRING) {
2367             pa_log_error("Property name not string");
2368             goto fail;
2369         }
2370         dbus_message_iter_get_basic(&msg_iter, &property_name);
2371         pa_log_info("Changed Property name : %s", property_name);
2372
2373         if (!dbus_message_iter_next(&msg_iter)) {
2374             pa_log_debug("Property value missing");
2375             goto fail;
2376         }
2377
2378         if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_VARIANT) {
2379             pa_log_debug("Property value not a variant.");
2380             goto fail;
2381         }
2382
2383         dbus_message_iter_recurse(&msg_iter, &variant_iter);
2384
2385         if (DBUS_TYPE_BOOLEAN == dbus_message_iter_get_arg_type(&variant_iter)) {
2386             dbus_bool_t value;
2387             char *name;
2388             dbus_message_iter_get_basic(&variant_iter, &value);
2389             if (pa_streq(property_name, "Connected")) {
2390                 pa_log_info("HFP Connection : %d", value);
2391                 if (value) {
2392                     method_call_bt_get_name(c, dbus_message_get_path(s), &name);
2393                     status = BT_SCO_CONNECTED;
2394                 } else {
2395                     status = BT_SCO_DISCONNECTED;
2396                 }
2397                 if (_translate_external_value(DEVICE_TYPE_BT_SCO, status, &detected) < 0) {
2398                     pa_log_warn("failed to translate bt-sco detected value");
2399                     goto fail;
2400                 }
2401                 handle_device_status_changed(dm, DEVICE_TYPE_BT_SCO,
2402                         name, dbus_message_get_path(s),  detected);
2403             }
2404         }
2405     } else {
2406         pa_log_debug("Unknown message, not handle it");
2407         dbus_error_free(&error);
2408         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2409     }
2410
2411     pa_log_debug("Dbus Message handled");
2412
2413     dbus_error_free(&error);
2414     return DBUS_HANDLER_RESULT_HANDLED;
2415
2416 fail:
2417     pa_log_error("Fail to handle dbus signal");
2418     dbus_error_free(&error);
2419     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2420 }
2421
2422 static int watch_signals(pa_device_manager *dm) {
2423     DBusError error;
2424
2425     pa_assert(dm);
2426     pa_assert(dm->dbus_conn);
2427
2428     dbus_error_init(&error);
2429
2430     pa_log_info("Watch Dbus signals");
2431
2432     if (!dbus_connection_add_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm, NULL)) {
2433         pa_log_error("Unable to add D-Bus filter : %s: %s", error.name, error.message);
2434         goto fail;
2435     }
2436
2437     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) {
2438         pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
2439         goto fail;
2440     }
2441     return 0;
2442
2443 fail:
2444     dbus_error_free(&error);
2445     return -1;
2446 }
2447
2448 static void unwatch_signals(pa_device_manager *dm) {
2449     pa_log_info("Unwatch Dbus signals");
2450
2451     pa_assert(dm);
2452     pa_assert(dm->dbus_conn);
2453
2454     pa_dbus_remove_matches(pa_dbus_connection_get(dm->dbus_conn), FILTER_DEVICED_SYSNOTI, FILTER_SOUND_SERVER, FILTER_BLUEZ, FILTER_MIRRORING, NULL);
2455     dbus_connection_remove_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm);
2456 }
2457
2458 static void send_device_connection_changed_signal(uint32_t event_id, pa_tz_device *device, bool connected, pa_device_manager *dm) {
2459     DBusMessage *signal_msg;
2460     DBusMessageIter msg_iter, device_iter;
2461     dbus_bool_t _connected = connected;
2462     dm_device_state_t compound_state;
2463     dbus_int32_t device_id, direction;
2464     char *type, *name;
2465
2466     pa_assert(device);
2467     pa_assert(dm);
2468
2469     pa_log_info("Send device connection changed signal, event_id(%u)", event_id);
2470
2471     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceConnected"));
2472     dbus_message_iter_init_append(signal_msg, &msg_iter);
2473     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &event_id);
2474     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2475
2476     direction = (dbus_int32_t) pa_tz_device_get_direction(device);
2477     type = pa_tz_device_get_type(device);
2478     name = pa_tz_device_get_name(device);
2479     device_id = (dbus_int32_t) pa_tz_device_get_id(device);
2480     compound_state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
2481
2482     simple_device_dump(PA_LOG_INFO, connected ? "[Connected]" : "[Disconnected]", device_id, type, name, direction, compound_state);
2483
2484     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2485     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
2486     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
2487     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
2488     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
2489     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &device_iter));
2490     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &_connected);
2491
2492     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2493
2494     dbus_message_unref(signal_msg);
2495 }
2496
2497 static void send_device_info_changed_signal(uint32_t event_id, pa_tz_device *device, int changed_type, pa_device_manager *dm) {
2498     DBusMessage *signal_msg;
2499     DBusMessageIter msg_iter, device_iter;
2500     dm_device_state_t compound_state;
2501     dbus_int32_t device_id, direction;
2502     char *type, *name;
2503     const char *changed_prefix[] = {"[State Changed]", "[Direction Changed]", "[Avail-Mode Changed]"};
2504
2505     pa_assert(device);
2506     pa_assert(dm);
2507
2508     pa_log_debug("Send device info changed signal, event_id(%u)", event_id);
2509
2510     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceInfoChanged"));
2511     dbus_message_iter_init_append(signal_msg, &msg_iter);
2512     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &event_id);
2513     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2514
2515     direction = (dbus_int32_t) pa_tz_device_get_direction(device);
2516     type = pa_tz_device_get_type(device);
2517     name = pa_tz_device_get_name(device);
2518     device_id = (dbus_int32_t) pa_tz_device_get_id(device);
2519     compound_state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
2520
2521     simple_device_dump(PA_LOG_DEBUG, changed_prefix[changed_type], device_id, type, name, direction, compound_state);
2522
2523     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2524     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
2525     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
2526     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
2527     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
2528     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &device_iter));
2529     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &changed_type);
2530
2531     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2532
2533     dbus_message_unref(signal_msg);
2534 }
2535
2536 static void send_device_state_changed_signal(uint32_t event_id, pa_tz_device *device, bool activated, pa_device_manager *dm) {
2537     DBusMessage *signal_msg;
2538     DBusMessageIter msg_iter, device_iter;
2539     dm_device_state_t compound_state;
2540     dbus_int32_t device_id, direction;
2541     char *type, *name;
2542
2543     pa_assert(device);
2544     pa_assert(dm);
2545
2546     pa_log_debug("Send device state changed signal, event_id(%u)", event_id);
2547
2548     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceStateChanged"));
2549     dbus_message_iter_init_append(signal_msg, &msg_iter);
2550     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &event_id);
2551     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2552
2553     direction = (dbus_int32_t) pa_tz_device_get_direction(device);
2554     type = pa_tz_device_get_type(device);
2555     name = pa_tz_device_get_name(device);
2556     device_id = (dbus_int32_t) pa_tz_device_get_id(device);
2557     compound_state = activated ? DM_DEVICE_STATE_ACTIVATED : DM_DEVICE_STATE_DEACTIVATED;
2558
2559     simple_device_dump(PA_LOG_DEBUG, "[State Changed]", device_id, type, name, direction, compound_state);
2560
2561     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2562     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
2563     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
2564     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
2565     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
2566     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &device_iter));
2567
2568     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2569
2570     dbus_message_unref(signal_msg);
2571 }
2572
2573 static bool device_is_match_direction(pa_tz_device *device, int direction_mask) {
2574     dm_device_direction_t direction;
2575
2576     if (direction_mask == DEVICE_IO_DIRECTION_FLAGS || direction_mask == 0)
2577         return true;
2578
2579     direction = pa_tz_device_get_direction(device);
2580
2581     if ((direction_mask & DEVICE_IO_DIRECTION_IN_FLAG) && (direction & DM_DEVICE_DIRECTION_IN))
2582         return true;
2583     if ((direction_mask & DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & DM_DEVICE_DIRECTION_OUT))
2584         return true;
2585     if ((direction_mask & DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction & DM_DEVICE_DIRECTION_BOTH))
2586         return true;
2587
2588     return false;
2589 }
2590
2591 static bool device_is_match_state(pa_tz_device *device, int state_mask) {
2592     dm_device_state_t state;
2593
2594     if (state_mask == DEVICE_STATE_FLAGS || state_mask == 0)
2595         return true;
2596
2597     state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
2598
2599     if ((state_mask & DEVICE_STATE_DEACTIVATED_FLAG) && (state == DM_DEVICE_STATE_DEACTIVATED))
2600         return true;
2601     if ((state_mask & DEVICE_STATE_ACTIVATED_FLAG) && (state == DM_DEVICE_STATE_ACTIVATED))
2602         return true;
2603
2604     return false;
2605 }
2606
2607 static bool device_is_match_type(pa_tz_device *device, int type_mask) {
2608     char *type;
2609     bool is_builtin;
2610
2611     if (type_mask == DEVICE_TYPE_FLAGS || type_mask == 0)
2612         return true;
2613
2614     type = pa_tz_device_get_type(device);
2615     is_builtin = device_type_is_builtin(type);
2616
2617     if ((type_mask & DEVICE_TYPE_INTERNAL_FLAG) && is_builtin)
2618         return true;
2619     if ((type_mask & DEVICE_TYPE_EXTERNAL_FLAG) && !is_builtin)
2620         return true;
2621
2622     return false;
2623 }
2624
2625 static bool device_is_match_with_mask(pa_tz_device *device, int mask) {
2626     pa_assert(device);
2627
2628     if (mask == DEVICE_ALL_FLAG)
2629         return true;
2630
2631     return (device_is_match_direction(device, mask & DEVICE_IO_DIRECTION_FLAGS) &&
2632             device_is_match_state(device, mask & DEVICE_STATE_FLAGS) &&
2633             device_is_match_type(device, mask & DEVICE_TYPE_FLAGS));
2634 }
2635
2636 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name) {
2637     const char *intf = DBUS_INTERFACE_BLUEZ_DEVICE, *prop = "Alias";
2638     DBusMessage *msg, *reply;
2639     DBusMessageIter reply_iter, variant_iter;
2640     DBusError err;
2641
2642     pa_assert(conn);
2643     pa_assert(device_path);
2644     pa_assert(name);
2645
2646     if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_BLUEZ, device_path, "org.freedesktop.DBus.Properties", "Get"))) {
2647         pa_log_error("dbus method call failed");
2648         return -1;
2649     }
2650
2651     dbus_message_append_args(msg,
2652                 DBUS_TYPE_STRING, &intf,
2653                 DBUS_TYPE_STRING, &prop,
2654                 DBUS_TYPE_INVALID);
2655
2656     dbus_error_init(&err);
2657     if (!(reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err))) {
2658         pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_BLUEZ_DEVICE, "Get", err.message);
2659         dbus_error_free(&err);
2660         return -1;
2661     }
2662
2663     dbus_message_iter_init(reply,  &reply_iter);
2664
2665     if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_VARIANT) {
2666         pa_log_error("Cannot get reply argument");
2667         return -1;
2668     }
2669
2670     dbus_message_iter_recurse(&reply_iter,  &variant_iter);
2671
2672     if (dbus_message_iter_get_arg_type(&variant_iter) == DBUS_TYPE_STRING) {
2673         dbus_message_iter_get_basic(&variant_iter, name);
2674     }
2675
2676     dbus_message_unref(reply);
2677     return 0;
2678 }
2679
2680
2681 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2682     pa_device_manager *dm;
2683     DBusMessage *reply = NULL;
2684     DBusMessageIter msg_iter, array_iter, device_iter;
2685     pa_tz_device *device;
2686     dm_device_state_t compound_state;
2687     uint32_t device_idx;
2688     dbus_int32_t device_id, direction;
2689     int mask;
2690     char *type, *name;
2691
2692     pa_assert(conn);
2693     pa_assert(msg);
2694     pa_assert(userdata);
2695
2696
2697     dm = (pa_device_manager*) userdata;
2698
2699     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2700
2701     pa_assert_se(dbus_message_get_args(msg, NULL,
2702                                        DBUS_TYPE_INT32, &mask,
2703                                        DBUS_TYPE_INVALID));
2704
2705     pa_log_info("Get connected device list (mask : %d)", mask);
2706
2707     dbus_message_iter_init_append(reply, &msg_iter);
2708     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiis)", &array_iter));
2709
2710     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
2711         compound_state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
2712         direction = pa_tz_device_get_direction(device);
2713         type = pa_tz_device_get_type(device);
2714         name = pa_tz_device_get_name(device);
2715         if (device_is_match_with_mask(device,  mask)) {
2716             device_id = (dbus_int32_t)pa_tz_device_get_id(device);
2717
2718             simple_device_dump(PA_LOG_INFO, "[MATCH]", device_id, type, name, direction, compound_state);
2719             pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2720             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2721             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
2722             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
2723             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
2724             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
2725             pa_assert_se(dbus_message_iter_close_container(&array_iter, &device_iter));
2726         } else {
2727             simple_device_dump(PA_LOG_INFO, "[UNMATCH]", device_id, type, name, direction, compound_state);
2728         }
2729     }
2730
2731     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
2732
2733     pa_assert_se(dbus_connection_send(conn, reply, NULL));
2734     dbus_message_unref(reply);
2735 }
2736
2737
2738 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2739     pa_device_manager *dm;
2740     DBusMessage *reply = NULL;
2741     pa_tz_device *device;
2742     dbus_bool_t is_bt_on = false;
2743     const char *bt_name = "none";
2744
2745     pa_assert(conn);
2746     pa_assert(msg);
2747     pa_assert(userdata);
2748
2749     pa_log_info("Get BT A2DP list");
2750
2751     dm = (pa_device_manager*) userdata;
2752
2753     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2754
2755     /* FIXME : Give system_id for multi device */
2756     if ((device = _device_list_get_device(dm, DEVICE_TYPE_BT_A2DP, NULL)) != NULL) {
2757         is_bt_on = true;
2758         bt_name = pa_tz_device_get_name(device);
2759     }
2760
2761     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_bt_on,
2762                                                  DBUS_TYPE_STRING, &bt_name,
2763                                                  DBUS_TYPE_INVALID));
2764
2765     pa_assert_se(dbus_connection_send(conn, reply, NULL));
2766     dbus_message_unref(reply);
2767 }
2768
2769
2770
2771 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2772     pa_device_manager *dm;
2773     char *type, *role;
2774     DBusMessage *reply = NULL;
2775
2776     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2777     dm = (pa_device_manager *) userdata;
2778     pa_assert_se(dbus_message_get_args(msg, NULL,
2779                                        DBUS_TYPE_STRING, &type,
2780                                        DBUS_TYPE_STRING, &role,
2781                                        DBUS_TYPE_INVALID));
2782
2783     pa_device_manager_load_sink(dm, type, role);
2784     pa_assert_se(dbus_connection_send(conn, reply, NULL));
2785     dbus_message_unref(reply);
2786 }
2787
2788 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2789     pa_device_manager *dm = (pa_device_manager *)userdata;
2790     char *type;
2791     dbus_int32_t status;
2792     DBusMessage *reply = NULL;
2793     DBusError error;
2794
2795     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2796
2797     dbus_error_init(&error);
2798     if (!dbus_message_get_args(msg, NULL,
2799                                        DBUS_TYPE_STRING, &type,
2800                                        DBUS_TYPE_INT32, &status,
2801                                        DBUS_TYPE_INVALID)) {
2802         pa_log_error("failed to get dbus args : %s", error.message);
2803         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
2804         dbus_error_free(&error);
2805     }
2806
2807     pa_log_debug("handle_test_device_status_change, type:%s, status:%d", type, status);
2808
2809     handle_device_status_changed(dm, type, NULL,  NULL, status);
2810     pa_assert_se(dbus_connection_send(conn, reply, NULL));
2811     dbus_message_unref(reply);
2812 }
2813
2814 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2815     const char *xml = DEVICE_MANAGER_INTROSPECT_XML;
2816     DBusMessage *r = NULL;
2817
2818     pa_assert(conn);
2819     pa_assert(msg);
2820     pa_assert(userdata);
2821
2822     pa_assert_se(r = dbus_message_new_method_return(msg));
2823     pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
2824
2825     if (r) {
2826         pa_assert_se(dbus_connection_send((conn), r, NULL));
2827         dbus_message_unref(r);
2828     }
2829
2830     return DBUS_HANDLER_RESULT_HANDLED;
2831 }
2832
2833 static DBusHandlerResult handle_device_manager_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2834     int method_idx = 0;
2835
2836     pa_assert(conn);
2837     pa_assert(msg);
2838     pa_assert(userdata);
2839
2840     for (method_idx = 0; method_idx < METHOD_HANDLER_MAX; method_idx++) {
2841         if (dbus_message_is_method_call(msg, DBUS_INTERFACE_DEVICE_MANAGER, method_handlers[method_idx].method_name)) {
2842             method_handlers[method_idx].receive_cb(conn, msg, userdata);
2843             return DBUS_HANDLER_RESULT_HANDLED;
2844         }
2845     }
2846
2847     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2848 }
2849
2850 static DBusHandlerResult method_call_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
2851     struct userdata *u = userdata;
2852     const char *path, *interface, *member;
2853
2854     pa_assert(c);
2855     pa_assert(m);
2856     pa_assert(u);
2857
2858     path = dbus_message_get_path(m);
2859     interface = dbus_message_get_interface(m);
2860     member = dbus_message_get_member(m);
2861
2862     pa_log_info("DeviceManager Method Call Handler : path=%s, interface=%s, member=%s", path, interface, member);
2863
2864     if (!pa_streq(path, DBUS_OBJECT_DEVICE_MANAGER))
2865         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2866
2867     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2868         return handle_introspect(c, m, u);
2869         /*
2870     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get")) {
2871         return handle_get_property(c, m, u);
2872     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set")) {
2873         return  handle_set_property(c, m, u);
2874     } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll")) {
2875         return handle_get_all_property(c, m, u);
2876         */
2877     } else {
2878         return handle_device_manager_methods(c, m, u);
2879     }
2880
2881     return DBUS_HANDLER_RESULT_HANDLED;
2882 }
2883
2884 static void endpoint_init(pa_device_manager *dm) {
2885     static const DBusObjectPathVTable vtable_endpoint = {
2886         .message_function = method_call_handler,
2887     };
2888
2889     pa_log_info("Device manager dbus endpoint init");
2890
2891     if (dm && dm->dbus_conn) {
2892         if (!dbus_connection_register_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER, &vtable_endpoint, dm))
2893             pa_log_error("Failed to register object path");
2894     } else {
2895         pa_log_error("Cannot get dbus connection to register object path");
2896     }
2897 }
2898
2899 static void endpoint_done(pa_device_manager *dm) {
2900     pa_log_info("Device manager dbus endpoint done");
2901     if (dm && dm->dbus_conn) {
2902         if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER))
2903             pa_log_error("Failed to unregister object path");
2904     } else {
2905         pa_log_error("Cannot get dbus connection to unregister object path");
2906     }
2907 }
2908
2909 static void dbus_init(pa_device_manager *dm) {
2910     DBusError error;
2911     pa_dbus_connection *connection = NULL;
2912
2913     pa_assert(dm);
2914     pa_log_info("Dbus init");
2915     dbus_error_init(&error);
2916
2917     if (!(connection = pa_dbus_bus_get(dm->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
2918         if (connection) {
2919             pa_dbus_connection_unref(connection);
2920         }
2921         pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
2922         goto fail;
2923     } else {
2924         pa_log_info("Got dbus connection");
2925     }
2926
2927     dm->dbus_conn = connection;
2928
2929     if (watch_signals(dm) < 0)
2930         pa_log_error("dbus watch signals failed");
2931     else
2932         pa_log_debug("dbus ready to get signals");
2933
2934     endpoint_init(dm);
2935
2936 fail:
2937     dbus_error_free(&error);
2938 }
2939
2940 static void dbus_deinit(pa_device_manager *dm) {
2941     pa_assert(dm);
2942
2943     pa_log_info("Dbus deinit");
2944
2945     endpoint_done(dm);
2946     unwatch_signals(dm);
2947
2948     if (dm->dbus_conn) {
2949         pa_dbus_connection_unref(dm->dbus_conn);
2950         dm->dbus_conn = NULL;
2951     }
2952 }
2953 #endif
2954
2955 pa_idxset* pa_device_manager_get_device_list(pa_device_manager *dm) {
2956     pa_assert(dm);
2957     pa_assert(dm->device_list);
2958
2959     return dm->device_list;
2960 }
2961
2962 pa_tz_device* pa_device_manager_get_device(pa_device_manager *dm, const char *type) {
2963     pa_assert(dm);
2964
2965     return _device_list_get_device(dm, type, NULL);
2966 }
2967
2968 pa_tz_device* pa_device_manager_get_device_by_id(pa_device_manager *dm, uint32_t id) {
2969     pa_assert(dm);
2970
2971     return _device_list_get_device_with_id(dm, id);
2972 }
2973
2974 pa_tz_device* pa_device_manager_get_device_with_sink(pa_sink *sink) {
2975     pa_assert(sink);
2976
2977     return sink->device_item;
2978 }
2979
2980 pa_tz_device* pa_device_manager_get_device_with_source(pa_source *source) {
2981     pa_assert(source);
2982
2983     return source->device_item;
2984 }
2985
2986 pa_tz_device* pa_device_manager_load_forwarding(pa_device_manager *dm) {
2987     return _load_forwarding_device(dm);
2988 }
2989
2990 void pa_device_manager_unload_forwarding(pa_device_manager *dm) {
2991     pa_tz_device *forwarding_device;
2992
2993     forwarding_device = _device_list_get_device(dm, DEVICE_TYPE_FORWARDING, NULL);
2994     if (forwarding_device)
2995         pa_tz_device_free(forwarding_device);
2996     else
2997         pa_log_warn("There is no forwarding device");
2998 }
2999
3000 int pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const char *role) {
3001     const char *device_string, *params;
3002     struct device_type_info *type_info;
3003     struct device_file_info *file_info;
3004     pa_tz_device *device;
3005     pa_sink *sink;
3006     uint32_t device_idx;
3007
3008     pa_assert(dm);
3009     pa_assert(dm->device_list);
3010
3011     pa_log_info("Load Sink for '%s.%s'", type, role);
3012     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3013         if (pa_streq(type, pa_tz_device_get_type(device))) {
3014             if (pa_tz_device_get_sink(device, role) == NULL) {
3015                 pa_log_warn("Proper sink for '%s.%s' already loaded", type, role);
3016                 return -1;
3017             }
3018         }
3019     }
3020
3021     if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3022         pa_log_error("No type map for %s", type);
3023         return -1;
3024     }
3025
3026     if (type_info->playback_devices == NULL) {
3027         pa_log_error("No playback devices for %s", type_info->type);
3028         goto fail;
3029     }
3030
3031     if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
3032         pa_log_error("No device-string for '%s.%s'", type, role);
3033         goto fail;
3034     }
3035
3036     if (!(file_info = _device_manager_get_file_info(dm->file_map->playback, device_string))) {
3037         pa_log_error("No playback file-map for '%s'", device_string);
3038         goto fail;
3039     }
3040
3041     if (!(params = pa_hashmap_get(file_info->roles, role))) {
3042         pa_log_error("No params for '%s,%s'", device_string, role);
3043         goto fail;
3044     }
3045
3046     if ((sink = load_device(dm->core, PA_DEVICE_TYPE_SINK, device_string, params))) {
3047         pa_log_debug("loaded sink '%s' for '%s,%s' success", sink->name, type, role);
3048     } else {
3049         pa_log_warn("Cannot load playback device with '%s,%s'", device_string, params);
3050         goto fail;
3051     }
3052
3053     return 0;
3054
3055 fail:
3056     return -1;
3057 }
3058
3059 int pa_device_manager_load_source(pa_device_manager *dm, const char *type, const char *role) {
3060     const char *device_string, *params;
3061     struct device_type_info *type_info;
3062     struct device_file_info *file_info;
3063     pa_tz_device *device;
3064     pa_source *source;
3065     uint32_t device_idx;
3066
3067     pa_assert(dm);
3068
3069     pa_log_info("Load Source for '%s.%s'", type, role);
3070
3071     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3072         if (pa_streq(type, pa_tz_device_get_type(device))) {
3073             if (pa_tz_device_get_source(device, role) == NULL) {
3074                 pa_log_warn("Proper source for '%s.%s' already loaded", type, role);
3075                 return -1;
3076             }
3077         }
3078     }
3079
3080     if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3081         pa_log_error("No type map for %s", type);
3082         return -1;
3083     }
3084
3085     if (type_info->capture_devices == NULL) {
3086         pa_log_error("No capture devices for %s", type_info->type);
3087         goto fail;
3088     }
3089
3090     if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
3091         pa_log_error("No device-string for '%s.%s'", type, role);
3092         goto fail;
3093     }
3094
3095     if (!(file_info = _device_manager_get_file_info(dm->file_map->capture, device_string))) {
3096         pa_log_error("No capture file-map for '%s'", device_string);
3097         goto fail;
3098     }
3099
3100     if (!(params = pa_hashmap_get(file_info->roles, role))) {
3101         pa_log_error("No params for '%s,%s'", device_string, role);
3102         goto fail;
3103     }
3104
3105     if ((source = load_device(dm->core, PA_DEVICE_TYPE_SOURCE, device_string, params))) {
3106         pa_log_debug("loaded source '%s' for '%s,%s' success", source->name, type, role);
3107     } else {
3108         pa_log_warn("Cannot load capture device with '%s,%s'", device_string, params);
3109         goto fail;
3110     }
3111
3112     return 0;
3113
3114 fail:
3115     return -1;
3116 }
3117
3118 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) {
3119     send_device_connection_changed_signal(data->event_id, data->device, data->is_connected, dm);
3120     return PA_HOOK_OK;
3121 }
3122
3123 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) {
3124     send_device_info_changed_signal(data->event_id, data->device, DM_DEVICE_CHANGED_INFO_STATE, dm);
3125     send_device_state_changed_signal(data->event_id, data->device, data->activated, dm);
3126     return PA_HOOK_OK;
3127 }
3128
3129 pa_device_manager* pa_device_manager_get(pa_core *c) {
3130     pa_device_manager *dm;
3131
3132     pa_assert(c);
3133
3134     pa_log_info("pa_device_manager_get");
3135
3136     if ((dm = pa_shared_get(c, SHARED_DEVICE_MANAGER)))
3137         return pa_device_manager_ref(dm);
3138
3139     dm = pa_xnew0(pa_device_manager, 1);
3140     PA_REFCNT_INIT(dm);
3141     dm->core = c;
3142     dm->device_list = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3143     dm->device_status = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3144
3145     dbus_init(dm);
3146
3147     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);
3148     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);
3149     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);
3150     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);
3151     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);
3152     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);
3153     dm->comm = pa_communicator_get(dm->core);
3154     dm->comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
3155             PA_HOOK_EARLY, (pa_hook_cb_t)device_connection_changed_hook_cb, dm);
3156     dm->comm_hook_device_state_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_STATE_CHANGED),
3157             PA_HOOK_EARLY, (pa_hook_cb_t)device_state_changed_hook_cb, dm);
3158     if (!(dm->type_infos = parse_device_type_infos())) {
3159         pa_log_error("Parse device-type-map failed");
3160         return NULL;
3161     }
3162
3163     if (!(dm->file_map = parse_device_file_map())) {
3164         pa_log_error("Parse device-file-map failed");
3165         return NULL;
3166     }
3167
3168     device_type_status_init(dm);
3169
3170     if (load_builtin_devices(dm) != 0) {
3171         pa_log_error("Load Builtin Devices faled");
3172         return NULL;
3173     }
3174
3175     /* Just for convenience when test*/
3176     if (!_device_manager_set_default_sink(dm,  DEVICE_TYPE_SPEAKER, "normal")) {
3177         pa_log_warn("Set default sink with speaker(normal) failed");
3178     }
3179     if (!_device_manager_set_default_source(dm,  DEVICE_TYPE_MIC, "normal")) {
3180         pa_log_warn("Set default source with mic(normal) failed");
3181     }
3182
3183     pa_shared_set(c, SHARED_DEVICE_MANAGER, dm);
3184
3185     return dm;
3186 }
3187
3188 pa_device_manager* pa_device_manager_ref(pa_device_manager *dm) {
3189     pa_assert(dm);
3190     pa_assert(PA_REFCNT_VALUE(dm) > 0);
3191
3192     pa_log_info("pa_device_manager_ref");
3193     PA_REFCNT_INC(dm);
3194
3195     return dm;
3196 }
3197
3198 void pa_device_manager_unref(pa_device_manager *dm) {
3199     pa_assert(dm);
3200     pa_assert(PA_REFCNT_VALUE(dm) > 0);
3201
3202     pa_log_info("pa_device_manager_unref");
3203     if (PA_REFCNT_DEC(dm) > 0)
3204         return;
3205
3206     if (dm->comm_hook_device_connection_changed_slot)
3207         pa_hook_slot_free(dm->comm_hook_device_connection_changed_slot);
3208     if (dm->comm_hook_device_state_changed_slot)
3209         pa_hook_slot_free(dm->comm_hook_device_state_changed_slot);
3210     if (dm->sink_put_hook_slot)
3211         pa_hook_slot_free(dm->sink_put_hook_slot);
3212     if (dm->sink_state_changed_slot)
3213         pa_hook_slot_free(dm->sink_state_changed_slot);
3214     if (dm->sink_unlink_hook_slot)
3215         pa_hook_slot_free(dm->sink_unlink_hook_slot);
3216     if (dm->source_put_hook_slot)
3217         pa_hook_slot_free(dm->source_put_hook_slot);
3218     if (dm->source_state_changed_slot)
3219         pa_hook_slot_free(dm->source_state_changed_slot);
3220     if (dm->source_unlink_hook_slot)
3221         pa_hook_slot_free(dm->source_unlink_hook_slot);
3222
3223     if (dm->comm)
3224         pa_communicator_unref(dm->comm);
3225
3226     if (dm->type_infos)
3227         pa_idxset_free(dm->type_infos, (pa_free_cb_t)type_info_free_func);
3228     if (dm->file_map) {
3229         if (dm->file_map->playback)
3230             pa_idxset_free(dm->file_map->playback, (pa_free_cb_t)file_info_free_func);
3231         if (dm->file_map->capture)
3232             pa_idxset_free(dm->file_map->capture, (pa_free_cb_t)file_info_free_func);
3233         pa_xfree(dm->file_map);
3234     }
3235     if (dm->device_list)
3236         pa_idxset_free(dm->device_list, (pa_free_cb_t)pa_tz_device_free);
3237     if (dm->device_status)
3238         pa_idxset_free(dm->device_status, NULL);
3239
3240     dbus_deinit(dm);
3241
3242
3243     if (dm->core)
3244         pa_shared_remove(dm->core, SHARED_DEVICE_MANAGER);
3245
3246     pa_xfree(dm);
3247 }