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