2 This file is part of PulseAudio.
4 Copyright 2015-2016 Jeonho Mok <jho.mok@samsung.com>
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.
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.
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
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>
44 #include <vconf-keys.h>
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"
52 #define SHARED_DEVICE_MANAGER "tizen-device-manager"
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
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"
76 #define DEVICE_TYPE_STR_MAX 20
77 #define DEVICE_NAME_MAX 30
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"
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"
96 typedef enum dm_device_class_type {
99 DM_DEVICE_CLASS_TIZEN,
101 DM_DEVICE_CLASS_NULL,
103 #ifdef __TIZEN_TV_BUILTIN_MIC__
104 DM_DEVICE_CLASS_TVMIC,
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;
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;
120 /***************** structures for static information get from json *********/
123 Structure for informations related to some device-file(ex. 0:0)
125 struct device_file_info {
127 String for identify target device.
128 ex) alsa:0,0 or null ..
130 const char *device_string;
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"
138 For save device-types related to device file.
139 { key:device_type-> value:pulse_device_prop }
141 pa_hashmap *device_types;
144 struct device_status_info {
147 /* Identify devices among same device-types (for multi-device), currently not works*/
149 device_detected_type_t detected;
152 struct pulse_device_prop {
153 /* roles related to (device_type + device_file)*/
155 /* For save that this devie_type is activated or not on sink/source */
159 /******************************************************************************/
161 struct composite_type {
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,
175 typedef struct _internal_codec_device {
177 bool is_running[2]; /* index[in:0, out:1] */
178 } internal_codec_device;
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 },
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 *);
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);
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
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
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
228 [DM_DEVICE_CLASS_BT] = {
229 .module_name = { NULL, "module-bluez5-device" },
230 .device_string = "bt",
231 .custom_device_get_func = NULL
233 [DM_DEVICE_CLASS_NULL] = {
234 .module_name = { "module-null-source", "module-null-sink" },
235 .device_string = "null",
236 .custom_device_get_func = NULL
238 [DM_DEVICE_CLASS_ACM] = {
239 .module_name = { NULL, "module-acm-sink" },
240 .device_string = "acm",
241 .custom_device_get_func = NULL
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
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);
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,};
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);
271 snprintf(key, DEVICE_KEY_STR_MAX, "%s.%s", vendor_id, product_id);
276 static inline void internal_codec_devices_dump() {
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("==================================================");
285 static void find_device_and_set_running(pa_device_manager *dm, const char *type, bool is_running) {
286 pa_tz_device* device;
293 pa_log_info("find device [%s]", type);
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);
299 pa_log_warn("this device [%s] does not use internal codec, skip it", type);
301 pa_log_warn("cound not find a device of [%s]", type);
305 static void type_info_free_func(device_type_info *type_info) {
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);
316 static void file_info_free_func(struct device_file_info *file_info) {
320 if (file_info->roles)
321 pa_hashmap_free(file_info->roles);
324 static dm_device_class_t device_string_get_class(const char *device_string) {
326 return DM_DEVICE_CLASS_NONE;
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;
341 return DM_DEVICE_CLASS_NONE;
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) {
349 if (!(colon_p = strchr(device_string, ':'))) {
350 pa_log_error("No Colon in device string");
355 if (*colon_p == '\0' || !strchr(colon_p, ',')) {
356 pa_log_error("No Comma or empty device name");
360 if (strlen(colon_p) >= DEVICE_NAME_MAX) {
361 pa_log_error("device name too long : %s", colon_p);
365 strncpy(name, colon_p, DEVICE_NAME_MAX);
370 static pa_proplist* pulse_device_get_proplist(pa_object *pdevice) {
374 return pa_sink_isinstance(pdevice) ? PA_SINK(pdevice)->proplist :
375 PA_SOURCE(pdevice)->proplist;
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);
385 if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API)))
386 return pa_safe_streq(api_name, DEVICE_API_ALSA);
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);
398 if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API)))
399 return pa_safe_streq(api_name, DEVICE_API_BLUEZ);
404 static bool pulse_device_is_acm(pa_object *pdevice) {
405 pa_proplist *prop = pulse_device_get_proplist(pdevice);
410 return pa_safe_streq(pa_proplist_gets(prop, PA_PROP_DEVICE_API), DEVICE_API_ACM);
413 static bool pulse_device_is_raop(pa_object *pdevice) {
414 pa_proplist *prop = pulse_device_get_proplist(pdevice);
419 return pa_safe_streq(pa_proplist_gets(prop, PA_PROP_DEVICE_API), DEVICE_API_RAOP);
422 static bool pulse_device_is_tunnel(pa_object *pdevice) {
423 pa_proplist *prop = pulse_device_get_proplist(pdevice);
428 return pa_safe_streq(pa_proplist_gets(prop, PA_PROP_DEVICE_API), DEVICE_API_TUNNEL);
431 static bool pulse_device_is_tizenaudio(pa_object *pdevice) {
432 char name[DEVICE_NAME_MAX];
437 if (!module_table[DM_DEVICE_CLASS_TIZEN].custom_device_get_func)
440 if (module_table[DM_DEVICE_CLASS_TIZEN].custom_device_get_func(pdevice, name))
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);
453 if ((bus_name = pa_proplist_gets(prop, PA_PROP_DEVICE_BUS)))
454 return pa_safe_streq(bus_name, DEVICE_BUS_USB);
456 pa_log_debug("This device doesn't have property '%s'", PA_PROP_DEVICE_BUS);
460 static bool pulse_device_is_null(pa_object *pdevice) {
464 if (pa_sink_isinstance(pdevice))
465 return pa_safe_streq(PA_SINK(pdevice)->module->name, "module-null-sink");
467 return pa_safe_streq(PA_SOURCE(pdevice)->module->name, "module-null-source");
470 static bool pulse_device_is_rtsp(pa_object *pdevice) {
471 pa_proplist *prop = pulse_device_get_proplist(pdevice);
476 return pa_safe_streq(pa_proplist_gets(prop, PA_PROP_DEVICE_API), DEVICE_API_RTSP);
479 #ifdef __TIZEN_TV_BUILTIN_MIC__
480 static bool pulse_device_is_tvmic(pa_object *pdevice) {
484 if (pa_sink_isinstance(pdevice))
487 return pa_safe_streq(PA_SOURCE(pdevice)->module->name, module_table[DM_DEVICE_CLASS_TVMIC].module_name[0]);
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);
498 return pa_safe_streq(pa_proplist_gets(prop, PA_PROP_DEVICE_API), DEVICE_API_BTSCO);
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);
506 if (pa_sink_isinstance(pdevice))
509 return pa_safe_streq(pa_proplist_gets(prop, "device.type"), DEVICE_TYPE_FORWARDING);
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);
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);
524 pa_log_debug("This device doesn't have property '%s'", PA_PROP_DEVICE_BUS_PATH);
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;
532 const char *params_p, *params;
534 int len = 0, prev_len = 0;
536 params = pa_sink_isinstance(pdevice) ? PA_SINK(pdevice)->module->argument :
537 PA_SOURCE(pdevice)->module->argument;
544 if (!(device_string_p = strstr(params, "device=")))
547 next_p = device_string_p;
548 while (!isblank(*next_p))
551 while (isblank(*next_p))
554 pa_strlcpy(removed_param, next_p, DEVICE_PARAM_STRING_MAX);
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;
562 strncpy(end_p, params_p, prev_len);
565 return removed_param;
568 static dm_device_class_t pulse_device_get_class(pa_object *pdevice) {
571 pa_log_error("pdevice null");
572 return DM_DEVICE_CLASS_NONE;
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;
590 return DM_DEVICE_CLASS_NONE;
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;
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);
604 if ((device_class = pa_proplist_gets(prop, PA_PROP_DEVICE_CLASS)))
605 return pa_safe_streq(device_class, DEVICE_CLASS_MONITOR);
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;
615 if (device_class >= DM_DEVICE_CLASS_MAX)
621 _module_name = module_table[device_class].module_name[is_sink];
623 /* supports tizen[2-9] keyword in device-map */
624 if (device_class == DM_DEVICE_CLASS_TIZEN) {
627 const char *state = NULL, *prefix = "tizen";
629 class = pa_split(device_string, ":", &state);
631 pa_log_error("Failed to parse device_string %s", device_string);
635 if (!pa_safe_streq(class, prefix)) {
636 if (!pa_atoi(class + strlen(prefix), &v))
637 snprintf(version, sizeof(version), "%d", v);
639 pa_log_warn("failed to get a version from class(%s)", class);
645 snprintf(module_name, DEVICE_MODULE_STRING_MAX, "%s%s", _module_name, version);
647 return pa_xstrdup(module_name);
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;
653 const char *device_string;
657 pa_assert(type_infos);
660 PA_IDXSET_FOREACH(type_info, type_infos, type_idx) {
661 if (device_type_is_equal(type_info->type, type)) {
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))
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))
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;
688 pa_assert(file_infos);
690 PA_IDXSET_FOREACH(file_info, file_infos, file_idx) {
691 if (pa_safe_streq(file_info->device_string, device_string))
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;
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;
711 static void _device_status_free(struct device_status_info *status_info) {
715 pa_xfree(status_info->type);
716 pa_xfree(status_info->name);
717 pa_xfree(status_info->system_id);
718 pa_xfree(status_info);
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;
727 pa_assert(manager->device_status);
729 PA_IDXSET_FOREACH(status_info, manager->device_status, status_idx) {
730 if (!device_type_is_equal(status_info->type, type))
736 if (pa_safe_streq(status_info->system_id, system_id))
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;
747 if (!(file_info = _device_manager_get_file_info(file_infos, device_string))) {
748 pa_log_error("No file map for '%s'", device_string);
752 if (!(params = pa_hashmap_get(file_info->roles, role)))
753 pa_log_error("No params for '%s:%s'", device_string, role);
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;
763 pa_assert(manager->device_status);
766 if (!device_type_is_need_detect(type))
767 return DEVICE_CONNECTED;
769 status_info = _get_device_status(manager, type, system_id);
771 pa_log_info("No status info for type(%s) system_id(%s)",
772 type, pa_strempty(system_id));
773 return DEVICE_DISCONNECTED;
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);
780 return status_info->detected;
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;
788 pa_assert(manager->device_status);
791 if (!device_type_is_need_detect(type))
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);
798 if (detected_type & DEVICE_CONNECTED) {
799 status_info = _get_device_status(manager, type, system_id);
801 status_info = _device_status_new(type, name, system_id);
802 pa_idxset_put(manager->device_status, status_info, NULL);
804 status_info->detected = detected_type;
806 status_info = _get_device_status(manager, type, system_id);
808 pa_idxset_remove_by_data(manager->device_status, status_info, NULL);
809 _device_status_free(status_info);
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;
819 pa_assert(manager->device_list);
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 */
826 if (pa_safe_streq(pa_tz_device_get_system_id(device), system_id))
832 if (pa_tz_device_get_role(device, role))
843 pa_tz_device* device_list_get_device_by_id(pa_device_manager *manager, uint32_t id) {
844 pa_tz_device *device;
848 pa_assert(manager->device_list);
850 PA_IDXSET_FOREACH(device, manager->device_list, idx) {
851 if (pa_tz_device_get_id(device) == id)
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];
861 pa_assert(device_string);
865 switch (device_class) {
866 case DM_DEVICE_CLASS_ACM:
867 #ifdef __TIZEN_TV_BUILTIN_MIC__
869 case DM_DEVICE_CLASS_TVMIC:
871 snprintf(target, DEVICE_PARAM_STRING_MAX, "%s ", params);
874 case DM_DEVICE_CLASS_ALSA:
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);
882 snprintf(target, DEVICE_PARAM_STRING_MAX, "device=%s%s %s",
883 (device_class == DM_DEVICE_CLASS_ALSA) ? "hw:" : "", device_name, params);
887 pa_log_error("unexpected device_class(%d)", device_class);
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;
901 if (!params1 && !params2)
903 if (!params1 || !params2)
906 modargs1 = pa_modargs_new(params1, NULL);
907 modargs2 = pa_modargs_new(params2, NULL);
909 if (!modargs1 || !modargs2) {
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)) {
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)) {
935 pa_modargs_free(modargs1);
937 pa_modargs_free(modargs2);
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;
949 module_args = pa_sink_isinstance(pdevice) ? PA_SINK(pdevice)->module->argument :
950 PA_SOURCE(pdevice)->module->argument;
952 if (!params && !module_args)
954 if (!params || !module_args)
957 removed_module_args = pulse_device_get_device_string_removed_argument(pdevice);
959 return device_params_is_equal(params, removed_module_args);
962 static int pulse_device_get_alsa_device_name(pa_object *pdevice, char *device_name) {
964 const char *device_string_prop;
967 prop = pulse_device_get_proplist(pdevice);
969 if (!(device_string_prop = pa_proplist_gets(prop, PA_PROP_DEVICE_STRING))) {
970 pa_log_error("failed to get property 'device.string'");
973 if (!(name_p = strchr(device_string_prop, ':'))) {
974 pa_log_error("failed to parse device string");
978 snprintf(device_name, DEVICE_NAME_MAX, "alsa:%s", name_p + 1);
982 static int pulse_device_get_tizen_device_name(pa_object *pdevice, char *device_name) {
984 const char *card, *device, *version;
985 char class[8] = "tizen";
987 prop = pulse_device_get_proplist(pdevice);
989 if (!(card = pa_proplist_gets(prop, "tizen.card"))) {
990 pa_log_error("failed to get property 'tizen.card'");
994 if (!(device = pa_proplist_gets(prop, "tizen.device"))) {
995 pa_log_error("failed to get property 'tizen.device'");
999 if ((version = pa_proplist_gets(prop, "tizen.version")))
1000 snprintf(class, sizeof(class), "tizen%s", version);
1002 snprintf(device_name, DEVICE_NAME_MAX, "%s:%s,%s", class, card, device);
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];
1012 pa_assert(device_string);
1014 device_class = pulse_device_get_class(pdevice);
1015 if (device_class <= DM_DEVICE_CLASS_NONE ||
1016 device_class >= DM_DEVICE_CLASS_MAX)
1019 if (module_table[device_class].custom_device_get_func &&
1020 module_table[device_class].custom_device_get_func(pdevice, device_name) < 0)
1023 snprintf(device_string, DEVICE_STR_MAX, "%s",
1024 module_table[device_class].device_string ?
1025 module_table[device_class].device_string : device_name);
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];
1035 pa_assert(device_string);
1037 if (pulse_device_get_device_string(pdevice, _device_string) < 0)
1040 return pa_safe_streq(_device_string, device_string);
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;
1046 pa_hashmap *pcm_devices;
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);
1054 PA_HASHMAP_FOREACH_KV(_role, device_string, pcm_devices, state) {
1055 if (pa_safe_streq(role, _role))
1056 return device_string;
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;
1068 pa_device_type_t pdt;
1069 pa_idxset *file_infos;
1070 pa_hashmap *pcm_devices;
1076 pa_log_info("pulse device get belongs type");
1078 if (pulse_device_is_monitor(pdevice))
1080 if (pulse_device_is_usb(pdevice))
1082 if (pulse_device_is_hdmi(pdevice))
1084 if (pulse_device_is_bluez(pdevice))
1087 ctypes = pa_dynarray_new(pa_xfree);
1089 if (pa_sink_isinstance(pdevice)) {
1090 pdt = PA_DEVICE_TYPE_SINK;
1091 file_infos = dm->file_map->playback;
1093 pdt = PA_DEVICE_TYPE_SOURCE;
1094 file_infos = dm->file_map->capture;
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;
1102 pcm_devices = type_info->capture_devices;
1103 if (pcm_devices == NULL)
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)
1109 param = _file_infos_get_param(file_infos, device_string, role);
1110 if (pulse_device_params_is_equal(pdevice, param) == false)
1112 /* Found type.role which is matching with pulse_device */
1113 ctype = pa_xmalloc0(sizeof(struct composite_type));
1114 ctype->type = type_info->type;
1116 pa_dynarray_append(ctypes, ctype);
1120 if (pa_dynarray_size(ctypes) == 0) {
1121 pa_dynarray_free(ctypes);
1128 /* If fails return -1 */
1129 static int atoi_base16(const char *s) {
1136 l = strtol(s, &x, 16);
1138 if (!x || *x || errno) {
1139 pa_log_error("Convert Failed");
1144 pa_log_error("Range error, does not fit into int");
1151 static int pulse_device_get_vendor_id(pa_object *pdevice) {
1153 const char *vendor_id_s;
1158 if (pulse_device_is_usb(pdevice) == false) {
1159 pa_log_warn("Not USB device");
1163 prop = pulse_device_get_proplist(pdevice);
1165 if ((vendor_id_s = pa_proplist_gets(prop, PA_PROP_DEVICE_VENDOR_ID)) == NULL) {
1166 pa_log_error("No vendor id");
1170 if ((vendor_id = atoi_base16(vendor_id_s)) == -1) {
1171 pa_log_error("Failed to convert to int");
1178 static int pulse_device_get_product_id(pa_object *pdevice) {
1180 const char *product_id_s;
1185 if (pulse_device_is_usb(pdevice) == false) {
1186 pa_log_warn("Not USB device");
1190 prop = pulse_device_get_proplist(pdevice);
1192 if ((product_id_s = pa_proplist_gets(prop, PA_PROP_DEVICE_PRODUCT_ID)) == NULL) {
1193 pa_log_error("No product id");
1197 if ((product_id = atoi_base16(product_id_s)) == -1) {
1198 pa_log_error("Failed to convert to int");
1205 static void pulse_device_set_use_internal_codec(pa_object *pdevice, bool use_internal_codec) {
1208 if (pa_sink_isinstance(pdevice))
1209 PA_SINK(pdevice)->use_internal_codec = use_internal_codec;
1211 PA_SOURCE(pdevice)->use_internal_codec = use_internal_codec;
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) {
1218 prop = pulse_device_get_proplist(pdevice);
1220 #ifdef __TIZEN_TV_EXTERNAL_TV_SOURCE__
1221 if (pulse_device_is_tvsource(pdevice))
1222 return pa_proplist_gets(prop, PA_PROP_DEVICE_DESCRIPTION);
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);
1243 static pa_sink* _core_get_sink(pa_core *core, const char *device_string, const char *params) {
1244 uint32_t device_idx;
1248 pa_assert(device_string);
1250 PA_IDXSET_FOREACH(sink, core->sinks, device_idx) {
1251 if (pulse_device_is_monitor(PA_OBJECT(sink)))
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))
1262 static pa_source* _core_get_source(pa_core *core, const char *device_string, const char *params) {
1263 uint32_t device_idx;
1267 pa_assert(device_string);
1269 PA_IDXSET_FOREACH(source, core->sources, device_idx) {
1270 if (pulse_device_is_monitor(PA_OBJECT(source)))
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))
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) {
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);
1291 static int _fill_new_data_sinks(pa_tz_device_new_data *data, device_type_info *type_info, pa_device_manager *dm) {
1293 const char *device_string, *role, *param;
1295 pa_idxset *file_infos;
1298 pa_assert(type_info);
1300 if (type_info->playback_devices == NULL) {
1301 pa_log_error("No playback devices for %s", type_info->type);
1305 file_infos = dm->file_map->playback;
1306 if (file_infos == NULL) {
1307 pa_log_error("No playback pcm device config");
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);
1315 pa_tz_device_new_data_add_sink(data, role, sink);
1317 pa_log_warn("No matching sink for %s %s", device_string, role);
1323 static int _fill_new_data_sources(pa_tz_device_new_data *data, device_type_info *type_info, pa_device_manager *dm) {
1325 const char *device_string, *role, *param;
1327 pa_idxset *file_infos;
1330 pa_assert(type_info);
1332 if (type_info->capture_devices == NULL) {
1333 pa_log_error("No capture devices for %s", type_info->type);
1337 file_infos = dm->file_map->capture;
1338 if (file_infos == NULL) {
1339 pa_log_error("No capture pcm device config");
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);
1347 pa_tz_device_new_data_add_source(data, role, source);
1349 pa_log_warn("No matching source for %s %s", device_string, role);
1355 static pa_sink* _device_manager_set_default_sink(pa_device_manager *dm, const char *type, const char *role) {
1356 pa_tz_device *device;
1359 if (!type || !role) {
1360 pa_log_warn("Argument for set_default_sink invalid");
1364 if (!(device = device_list_get_device(dm, type, NULL, NULL))) {
1365 pa_log_warn("cannot get device item for %s", type);
1369 if (!(sink = pa_tz_device_get_sink(device, role))) {
1370 pa_log_warn("cannot get sink for %s", role);
1374 // sink = pa_namereg_set_default_sink(dm->core, sink);
1378 static pa_source* _device_manager_set_default_source(pa_device_manager *dm, const char *type, const char *role) {
1379 pa_tz_device *device;
1382 if (!type || !role) {
1383 pa_log_warn("Argument for set_default_source invalid");
1387 if (!(device = device_list_get_device(dm, type, NULL, NULL))) {
1388 pa_log_warn("cannot get device item for %s", type);
1392 if (!(source = pa_tz_device_get_source(device, role))) {
1393 pa_log_warn("cannot get source for %s", role);
1397 // source = pa_namereg_set_default_source(dm->core, source);
1401 static void apply_preference(pa_device_manager *dm, pa_sink *sink) {
1404 bool do_reconfigure = false;
1409 if (!(key = build_key_from_proplist(sink->proplist)))
1412 if (!(e = read_prefer_entry(dm, key)))
1415 if (sink->avoid_resampling != e->avoid_resampling) {
1416 sink->avoid_resampling = e->avoid_resampling;
1417 do_reconfigure = true;
1419 if (sink->selected_sample_format != e->format) {
1420 sink->selected_sample_format = e->format;
1421 do_reconfigure = true;
1423 if (sink->selected_sample_rate != e->rate) {
1424 sink->selected_sample_rate = e->rate;
1425 do_reconfigure = true;
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);
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;
1447 pa_log_info("Handle usb pulse device");
1449 system_id = pulse_device_get_system_id(pdevice);
1450 direction = pulse_device_get_direction(pdevice);
1453 pa_tz_device_new_data data;
1454 int product_id, vendor_id;
1456 prop = pulse_device_get_proplist(pdevice);
1457 name = pa_proplist_gets(prop, "udev.id");
1459 vendor_id = pulse_device_get_vendor_id(pdevice);
1460 product_id = pulse_device_get_product_id(pdevice);
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);
1468 pa_tz_device_new_data_set_vendor_id(&data, vendor_id);
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));
1476 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1479 pa_tz_device_new(&data);
1480 pa_tz_device_new_data_done(&data);
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);
1485 pa_tz_device_free(device);
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;
1497 pa_log_info("Handle hdmi pulse device");
1499 system_id = pulse_device_get_system_id(pdevice);
1500 direction = pulse_device_get_direction(pdevice);
1503 pa_tz_device_new_data data;
1506 prop = pulse_device_get_proplist(pdevice);
1507 name = pa_proplist_gets(prop, "alsa.card_name");
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));
1519 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1522 pa_tz_device_new(&data);
1523 pa_tz_device_new_data_done(&data);
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);
1528 pa_tz_device_free(device);
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;
1540 pa_log_info("Handle bt pulse device");
1542 direction = pulse_device_get_direction(pdevice);
1543 system_id = pulse_device_get_system_id(pdevice);
1546 pa_tz_device_new_data data;
1551 prop = pulse_device_get_proplist(pdevice);
1552 name = pa_proplist_gets(prop, "bluez.alias");
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));
1561 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1563 pa_tz_device_new(&data);
1564 pa_tz_device_new_data_done(&data);
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);
1570 pa_tz_device_free(device);
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;
1581 pa_log_info("Handle RAOP pulse device");
1583 system_id = pulse_device_get_system_id(pdevice);
1586 pa_tz_device_new_data data;
1588 pa_proplist *prop = pulse_device_get_proplist(pdevice);
1589 const char *name = pa_proplist_gets(prop, PA_PROP_DEVICE_DESCRIPTION);
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);
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);
1602 pa_tz_device_free(device);
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;
1614 pa_log_info("Handle TUNNEL pulse device");
1616 direction = pulse_device_get_direction(pdevice);
1617 system_id = pulse_device_get_system_id(pdevice);
1620 pa_tz_device_new_data data;
1622 pa_proplist *prop = pulse_device_get_proplist(pdevice);
1623 const char *name = pa_proplist_gets(prop, PA_PROP_DEVICE_DESCRIPTION);
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));
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);
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);
1639 pa_tz_device_free(device);
1643 static void handle_acm_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *dm) {
1644 pa_tz_device *device;
1649 pa_log_info("Handle ACM pulse device");
1652 pa_tz_device_new_data data;
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);
1660 if (!(device = device_list_get_device(dm, DEVICE_TYPE_NETWORK, DEVICE_ROLE_ACM, NULL)))
1661 pa_log_warn("Can't get ACM device");
1663 pa_tz_device_free(device);
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;
1674 pa_log_info("Handle RTSP pulse device");
1676 system_id = pulse_device_get_system_id(pdevice);
1679 pa_tz_device_new_data data;
1681 pa_proplist *prop = pulse_device_get_proplist(pdevice);
1682 const char *name = pa_proplist_gets(prop, PA_PROP_DEVICE_DESCRIPTION);
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);
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);
1695 pa_tz_device_free(device);
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;
1708 pa_log_info("Handle btsco pulse device");
1710 system_id = pulse_device_get_system_id(pdevice);
1711 direction = pulse_device_get_direction(pdevice);
1714 pa_tz_device_new_data data;
1717 prop = pulse_device_get_proplist(pdevice);
1718 name = pa_proplist_gets(prop, PA_PROP_DEVICE_DESCRIPTION);
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));
1729 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1732 pa_tz_device_new(&data);
1733 pa_tz_device_new_data_done(&data);
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);
1738 pa_tz_device_free(device);
1741 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
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;
1752 pa_log_info("Handle tvsource pulse device");
1754 system_id = pulse_device_get_system_id(pdevice);
1755 direction = pulse_device_get_direction(pdevice);
1758 pa_tz_device_new_data data;
1761 prop = pulse_device_get_proplist(pdevice);
1762 name = pa_proplist_gets(prop, PA_PROP_DEVICE_DESCRIPTION);
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));
1772 pa_tz_device_new(&data);
1773 pa_tz_device_new_data_done(&data);
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);
1778 pa_tz_device_free(device);
1781 #endif /* __TIZEN_TV_EXTERNAL_TV_SOURCE__ */
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;
1794 pa_log_info("Handle internal pulse device");
1795 direction = pulse_device_get_direction(pdevice);
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");
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));
1809 if (direction == DM_DEVICE_DIRECTION_OUT)
1810 pa_tz_device_add_sink(device, ctype->role, PA_SINK(pdevice));
1812 pa_tz_device_add_source(device, ctype->role, PA_SOURCE(pdevice));
1814 if (direction == DM_DEVICE_DIRECTION_OUT)
1815 pa_tz_device_remove_sink(device, PA_SINK(pdevice));
1817 pa_tz_device_remove_source(device, PA_SOURCE(pdevice));
1820 pa_log_info("No device for %s.%s", ctype->type, ctype->role);
1824 pa_dynarray_free(ctypes);
1827 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1832 pa_log_info("========== Sink Put Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1834 if (pulse_device_is_monitor(PA_OBJECT(sink)))
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);
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);
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);
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);
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);
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);
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);
1869 pa_log_debug("Don't care this sink");
1874 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1879 pa_log_info("=========== Sink unlink Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1881 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1884 if (pulse_device_is_usb(PA_OBJECT(sink))) {
1885 handle_usb_pulse_device(PA_OBJECT(sink), false, dm);
1887 } else if (pulse_device_is_hdmi(PA_OBJECT(sink))) {
1888 handle_hdmi_pulse_device(PA_OBJECT(sink), false, dm);
1890 } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
1891 handle_bt_pulse_device(PA_OBJECT(sink), false, dm);
1893 } else if (pulse_device_is_raop(PA_OBJECT(sink))) {
1894 handle_raop_pulse_device(PA_OBJECT(sink), false, dm);
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);
1902 pa_log_info("denied sink is unlinked, nothing to do");
1905 pa_log_warn("tunnel but not remote....ignore this");
1908 } else if (pulse_device_is_acm(PA_OBJECT(sink))) {
1909 handle_acm_pulse_device(PA_OBJECT(sink), false, dm);
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);
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);
1921 pa_log_debug("Don't care this sink");
1926 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1931 pa_log_info("========== source Put Hook Callback '%s'(%d) ==========", source->name, source->index);
1933 if (pulse_device_is_monitor(PA_OBJECT(source)))
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);
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);
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);
1952 } else if (pulse_device_is_alsa(PA_OBJECT(source)) ||
1953 #ifdef __TIZEN_TV_BUILTIN_MIC__
1954 pulse_device_is_tvmic(PA_OBJECT(source)) ||
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);
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);
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);
1972 pa_log_debug("Don't care this source");
1977 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1982 pa_log_info("=========== source unlink Hook Callback '%s'(%d) ==========", source->name, source->index);
1984 if (pulse_device_is_monitor(PA_OBJECT(source)))
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);
1994 if (pulse_device_is_usb(PA_OBJECT(source))) {
1995 handle_usb_pulse_device(PA_OBJECT(source), false, dm);
1997 } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
1998 handle_bt_pulse_device(PA_OBJECT(source), false, dm);
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);
2006 pa_log_info("denied source is unlinked, nothing to do");
2009 pa_log_warn("tunnel but not remote....ignore this");
2012 } else if (pulse_device_is_alsa(PA_OBJECT(source)) ||
2013 #ifdef __TIZEN_TV_BUILTIN_MIC__
2014 pulse_device_is_tvmic(PA_OBJECT(source)) ||
2016 pulse_device_is_tizenaudio(PA_OBJECT(source))) {
2017 handle_internal_pulse_device(PA_OBJECT(source), false, dm);
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);
2028 pa_log_debug("Don't care this source");
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;
2039 pa_object_assert_ref(pdevice);
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));
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));
2056 pa_log_debug("========= sink_source_state_changed_hook_cb END =====");
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);
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);
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);
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);
2089 Build params for load sink or source, and load it.
2091 static void* load_module(pa_core *c, bool is_sink, const char *device_string, const char *device_params, const char *device_role) {
2096 uint32_t device_idx;
2097 dm_device_class_t device_class;
2098 char full_params[DEVICE_PARAM_STRING_MAX];
2101 pa_assert(device_string);
2102 pa_assert(device_params);
2104 pa_log_info("Load %s Device : String'%s' Param'%s'", is_sink ? "Playback" : "Capture", device_string, device_params);
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);
2111 pa_log_info("device class : %d", device_class);
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");
2117 pa_log_info("module name : %s", module_name);
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");
2123 pa_log_info("argument : %s", full_params);
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);
2129 pa_log_info("module loaded : %s %u with '%s'", module->name, module->index, module->argument);
2131 pa_xfree(module_name);
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));
2139 pa_proplist_sets(sink->proplist, PA_PROP_DEVICE_ROLE, device_role);
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));
2148 pa_proplist_sets(source->proplist, PA_PROP_DEVICE_ROLE, device_role);
2154 pa_log_warn("Failed to find matching %s after load module", is_sink ? "sink" : "source");
2158 pa_xfree(module_name);
2163 static void unload_module(pa_core *c, bool is_sink, const char *device_string) {
2164 uint32_t device_idx;
2167 pa_assert(device_string);
2169 pa_log_info("Unload %s Device : String'%s'", is_sink ? "Playback" : "Capture", device_string);
2174 PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
2175 if (pulse_device_is_monitor(PA_OBJECT(sink)))
2177 if (pulse_device_same_device_string(PA_OBJECT(sink), device_string))
2178 pa_module_unload(sink->module, true);
2183 PA_IDXSET_FOREACH(source, c->sources, device_idx) {
2184 if (pulse_device_is_monitor(PA_OBJECT(source)))
2186 if (pulse_device_same_device_string(PA_OBJECT(source), device_string))
2187 pa_module_unload(source->module, true);
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;
2197 const char *device_string, *params;
2198 bool first_one = true;
2200 bool loaded = false;
2203 pa_assert(type_info);
2205 pa_log_info("Load type devices : %s %s", type_info->type, is_playback ? "playback" : "capture");
2208 pcm_devices = type_info->playback_devices;
2209 file_infos = dm->file_map->playback;
2211 pcm_devices = type_info->capture_devices;
2212 file_infos = dm->file_map->capture;
2215 if (!pcm_devices || !file_infos) {
2216 pa_log_error("No information to load");
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);
2227 if (!is_playback && _core_get_source(dm->core, device_string, NULL)) {
2228 pa_log_debug("Already loaded %s", device_string);
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);
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);
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. */
2246 PA_SINK(device)->use_internal_codec = false;
2248 PA_SOURCE(device)->use_internal_codec = false;
2251 pa_log_info("load device success %s %s %s", device_string, params, role);
2256 pa_log_error("Returning error due to no device loaded in success");
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;
2271 pa_log_info("Load forwarding device");
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;
2278 if ((spk_device = device_list_get_device(dm, DEVICE_TYPE_SPEAKER, NULL, NULL)) == NULL) {
2279 pa_log_error("Get speaker device failed");
2283 if ((spk_sink = pa_tz_device_get_sink(spk_device, NULL)) == NULL) {
2284 pa_log_error("Get speaker sink failed");
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);
2293 if ((forwarding_device = pa_tz_device_new(&data)) == NULL)
2294 pa_log_error("Failed to create forwarding device");
2296 pa_tz_device_new_data_done(&data);
2298 return forwarding_device;
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.
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;
2313 pa_assert(dm->device_status);
2314 pa_assert(dm->device_list);
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);
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");
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;
2336 if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P)
2337 direction = DM_DEVICE_DIRECTION_BOTH;
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);
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);
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);
2359 dm_device_direction_t direction;
2360 bool use_internal_codec = true;
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);
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;
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;
2376 _fill_new_data_basic(&data, type, direction, use_internal_codec, dm);
2378 pa_tz_device_new(&data);
2379 pa_tz_device_new_data_done(&data);
2381 pa_log_error("Invalid case : not static direction");
2387 static int load_builtin_devices(pa_device_manager *dm) {
2388 device_type_info *type_info;
2390 device_detected_type_t detected_type = DEVICE_CONNECTED;
2395 pa_log_debug("\n==================== Load Builtin Devices ====================");
2397 PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
2399 type = type_info->type;
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");
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);
2413 _load_type_devices(type_info, true, dm);
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");
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);
2426 pa_log_warn("type %s failed....", type);
2429 pa_log_warn("Invalid case");
2433 pa_log_debug("Load Builtin Devices Done");
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;
2445 pa_assert(device_role_o);
2446 pa_assert(json_object_is_type(device_role_o, json_type_object));
2448 roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2450 pa_log_debug("hashmap new failed");
2454 it = json_object_iter_begin(device_role_o);
2455 it_end = json_object_iter_end(device_role_o);
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);
2461 if (!(params = json_object_get_string(params_o))) {
2462 pa_log_debug("There is no device params for role '%s'", device_role);
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");
2471 pa_log_error("Invalid device role '%s'", device_role);
2474 json_object_iter_next(&it);
2477 if (pa_hashmap_size(roles) == 0) {
2478 pa_log_warn("There is no role for device.. free hashmap");
2479 pa_hashmap_free(roles);
2487 pa_hashmap_free(roles);
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;
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));
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);
2506 pa_log_error("Get device-string failed");
2510 pa_log_error("Get device-string object failed");
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);
2520 pa_log_error("Get device role object failed");
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;
2528 // *device_string_key = device_string;
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;
2544 pa_assert(device_file_array_o);
2545 pa_assert(json_object_is_type(device_file_array_o, json_type_array));
2547 device_files = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
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);
2555 pa_log_error("parse device file object failed");
2559 pa_log_error("Get device file object failed");
2564 if (pa_idxset_size(device_files) == 0) {
2565 pa_idxset_free(device_files, NULL);
2566 device_files = NULL;
2569 return device_files;
2573 pa_xfree(device_files);
2577 static const char * get_device_map_json()
2579 return (access("/run/systemd/container", F_OK) == 0) ? DEVICE_MAP_FILE_CONTAINER : DEVICE_MAP_FILE;
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();
2588 pa_log_info("\nParse device files");
2590 o = json_object_from_file(device_map_file);
2592 pa_log_error("Read %s file failed", device_map_file);
2596 file_map = pa_xmalloc0(sizeof(struct device_file_map));
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);
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);
2608 pa_log_error("Get device files object failed");
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;
2622 pa_assert(device_role_map_o);
2623 pa_assert(json_object_is_type(device_role_map_o, json_type_object));
2625 roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2627 it = json_object_iter_begin(device_role_map_o);
2628 it_end = json_object_iter_end(device_role_map_o);
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);
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);
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");
2644 pa_log_error("Invalid device role '%s'", device_role);
2648 json_object_iter_next(&it);
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();
2668 o = json_object_from_file(device_map_file);
2670 pa_log_error("Read %s file failed", device_map_file);
2674 pa_log_info("\nParse device types");
2675 type_infos = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
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;
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;
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");
2690 type = json_object_get_string(device_prop_o);
2691 pa_log_info("[ Device - %s ]", type);
2693 type_info = pa_xmalloc0(sizeof(device_type_info));
2694 type_info->type = type;
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);
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);
2705 pa_idxset_put(type_infos, type_info, NULL);
2708 pa_log_debug("Get device type object failed");
2712 pa_log_debug("Get device type array object failed");
2718 pa_xfree(type_infos);
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.
2729 static void device_type_status_init(pa_device_manager *manager) {
2730 device_type_info *type_info;
2735 pa_assert(manager->type_infos);
2737 pa_log_debug("\n==================== Init Device Status ====================");
2739 PA_IDXSET_FOREACH(type_info, manager->type_infos, type_idx) {
2740 type = type_info->type;
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");
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);
2755 pa_log_warn("Unknown earjack status : %d", earjack_status);
2757 } else if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2758 device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
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");
2769 if (miracast_wfd_status == FORWARDING_CONNECTED)
2770 device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
2773 device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
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;
2784 uint32_t device_idx;
2787 pa_assert(dm->device_list);
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);
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);
2806 if (type_info->playback_devices == NULL) {
2807 pa_log_error("No playback devices for %s", type_info->type);
2811 if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
2812 pa_log_error("No device-string for '%s.%s'", type, role);
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);
2821 if (!(params = pa_hashmap_get(file_info->roles, role))) {
2822 pa_log_error("No params for '%s,%s'", device_string, role);
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);
2829 pa_log_warn("Cannot load playback device with '%s,%s'", device_string, params);
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;
2844 pa_assert(dm->device_list);
2848 pa_log_info("Unload Sink for '%s.%s'", type, role);
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);
2855 if (type_info->playback_devices == NULL) {
2856 pa_log_error("No playback devices for %s", type_info->type);
2860 if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
2861 pa_log_error("No device-string for '%s.%s'", type, role);
2865 unload_module(dm->core, true, device_string);
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;
2874 uint32_t device_idx;
2877 pa_assert(dm->device_list);
2881 pa_log_info("Load Source for '%s.%s'", type, role);
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);
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);
2897 if (type_info->capture_devices == NULL) {
2898 pa_log_error("No capture devices for %s", type_info->type);
2902 if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
2903 pa_log_error("No device-string for '%s.%s'", type, role);
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);
2912 if (!(params = pa_hashmap_get(file_info->roles, role))) {
2913 pa_log_error("No params for '%s,%s'", device_string, role);
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);
2920 pa_log_warn("Cannot load capture device with '%s,%s'", device_string, params);
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;
2935 pa_assert(dm->device_list);
2939 pa_log_info("Unload Source for '%s.%s'", type, role);
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);
2946 if (type_info->capture_devices == NULL) {
2947 pa_log_error("No capture devices for %s", type_info->type);
2951 if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
2952 pa_log_error("No device-string for '%s.%s'", type, role);
2956 unload_module(dm->core, false, device_string);
2959 pa_sink* load_acm_sink(pa_device_manager *dm) {
2960 pa_tz_device *acm_device;
2964 pa_log_info("Load ACM sink");
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);
2971 return load_sink(dm, DEVICE_TYPE_NETWORK, DEVICE_ROLE_ACM);
2974 void unload_acm_sink(pa_device_manager *dm) {
2977 pa_log_info("Unload ACM sink");
2979 if (!device_list_get_device(dm, DEVICE_TYPE_NETWORK, DEVICE_ROLE_ACM, NULL)) {
2980 pa_log_info("ACM device does not exist");
2984 unload_sink(dm, DEVICE_TYPE_NETWORK, DEVICE_ROLE_ACM);
2987 pa_idxset* pa_device_manager_get_device_list(pa_device_manager *dm) {
2989 pa_assert(dm->device_list);
2991 return dm->device_list;
2994 pa_tz_device* pa_device_manager_get_device(pa_device_manager *dm, const char *type, const char *role) {
2997 return device_list_get_device(dm, type, role, NULL);
3000 pa_tz_device* pa_device_manager_get_device_by_id(pa_device_manager *dm, uint32_t id) {
3003 return device_list_get_device_by_id(dm, id);
3006 pa_tz_device* pa_device_manager_get_device_with_sink(pa_sink *sink) {
3009 return sink->device_item;
3012 pa_tz_device* pa_device_manager_get_device_with_source(pa_source *source) {
3015 return source->device_item;
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);
3023 void pa_device_manager_unload_forwarding(pa_device_manager *dm) {
3024 pa_tz_device *forwarding_device;
3026 forwarding_device = device_list_get_device(dm, DEVICE_TYPE_FORWARDING, NULL, NULL);
3027 if (forwarding_device)
3028 pa_tz_device_free(forwarding_device);
3030 pa_log_warn("There is no forwarding device");
3033 pa_sink* pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const char *role) {
3038 return load_sink(dm, type, role);
3041 void pa_device_manager_unload_sink(pa_device_manager *dm, const char *type, const char *role) {
3046 unload_sink(dm, type, role);
3049 void pa_device_manager_unload_sink_with_device_string(pa_device_manager *dm, const char *device_string) {
3051 pa_assert(device_string);
3053 unload_module(dm->core, true, device_string);
3056 pa_source* pa_device_manager_load_source(pa_device_manager *dm, const char *type, const char *role) {
3061 return load_source(dm, type, role);
3064 void pa_device_manager_unload_source(pa_device_manager *dm, const char *type, const char *role) {
3069 unload_source(dm, type, role);
3072 void pa_device_manager_unload_source_with_device_string(pa_device_manager *dm, const char *device_string) {
3074 pa_assert(device_string);
3076 unload_module(dm->core, false, device_string);
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;
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);
3091 return device_type_info_get_device_string(type_info, is_playback, role);
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) {
3100 index = (uint32_t)output_device; /* input:0, output:1 */
3103 if (num_of_devices == 0) {
3104 for (i = 0; i < DEVICE_INDEX_MAX; i++) {
3105 if (!internal_codec_devices[i].is_running[index])
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();
3117 for (i = 0; i < DEVICE_INDEX_MAX; i++) {
3119 if (!internal_codec_devices[i].is_running[index])
3121 for (j = 0; j < num_of_devices; j++) {
3122 if (pa_safe_streq(device_infos[j].type, internal_codec_devices[i].type))
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();
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))
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();
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);
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);
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);
3167 pa_device_manager* pa_device_manager_get(pa_core *c) {
3168 pa_device_manager *dm;
3172 pa_log_debug("pa_device_manager_get");
3174 if ((dm = pa_shared_get(c, SHARED_DEVICE_MANAGER)))
3175 return pa_device_manager_ref(dm);
3177 dm = pa_xnew0(pa_device_manager, 1);
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);
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);
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);
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);
3205 dm->hal_interface = pa_hal_interface_get(dm->core);
3207 if (!(dm->type_infos = parse_device_type_infos())) {
3208 pa_log_error("Parse device-type-map failed");
3212 if (!(dm->file_map = parse_device_file_map())) {
3213 pa_log_error("Parse device-file-map failed");
3217 device_type_status_init(dm);
3219 if (load_builtin_devices(dm) != 0) {
3220 pa_log_error("Load Builtin Devices faled");
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");
3228 if (!_device_manager_set_default_source(dm, DEVICE_TYPE_MIC, "normal")) {
3229 pa_log_warn("Set default source with mic(normal) failed");
3232 pa_shared_set(c, SHARED_DEVICE_MANAGER, dm);
3237 pa_device_manager* pa_device_manager_ref(pa_device_manager *dm) {
3239 pa_assert(PA_REFCNT_VALUE(dm) > 0);
3242 pa_log_debug("pa_device_manager_ref to %d", PA_REFCNT_VALUE(dm));
3247 void pa_device_manager_unref(pa_device_manager *dm) {
3249 pa_assert(PA_REFCNT_VALUE(dm) > 0);
3251 pa_log_debug("pa_device_manager_unref to %d", PA_REFCNT_VALUE(dm) - 1);
3252 if (PA_REFCNT_DEC(dm) > 0)
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);
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);
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);
3280 if (dm->hal_interface)
3281 pa_hal_interface_unref(dm->hal_interface);
3284 pa_communicator_unref(dm->comm);
3287 pa_idxset_free(dm->type_infos, (pa_free_cb_t)type_info_free_func);
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);
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);
3302 deinit_database(dm);
3305 pa_shared_remove(dm->core, SHARED_DEVICE_MANAGER);