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/hashmap.h>
44 #include <vconf-keys.h>
46 #include <pulsecore/dbus-shared.h>
47 #include <pulsecore/dbus-util.h>
48 #include <pulsecore/protocol-dbus.h>
51 #include "communicator.h"
52 #include "device-manager.h"
54 #define SHARED_DEVICE_MANAGER "tizen-device-manager"
56 #define DEVICE_MAP_FILE "/etc/pulse/device-map.json"
57 #define DEVICE_STR_MAX 30
58 #define DEVICE_DIRECTION_MAX 3
59 #define DEVICE_PARAM_STRING_MAX 150
60 #define DEVICE_AVAIL_COND_NUM_MAX 2
61 #define DEVICE_AVAIL_COND_STR_MAX 6
62 #define DEVICE_FILE_PER_TYPE_MAX 4
63 #define DEVICE_FILE_STRING_MAX 4
64 #define DEVICE_TYPE_STR_MAX 20
65 #define DEVICE_ROLE_STR_MAX 15
67 #define DEVICE_TYPE_OBJECT "device-types"
68 #define DEVICE_FILE_OBJECT "device-files"
69 #define DEVICE_TYPE_PROP_DEVICE_TYPE "device-type"
70 #define DEVICE_TYPE_PROP_PLAYBACK_DEVICES "playback-devices"
71 #define DEVICE_TYPE_PROP_CAPTURE_DEVICES "capture-devices"
72 #define DEVICE_TYPE_PROP_DEVICE_STRING "device-string"
73 #define DEVICE_TYPE_PROP_ROLE "role"
75 #define DEVICE_TYPE_STR_MAX 20
77 /* Properties of sink/sources */
78 #define DEVICE_API_BLUEZ "bluez"
79 #define DEVICE_API_ALSA "alsa"
80 #define DEVICE_API_NULL "null"
81 #define DEVICE_BUS_USB "usb"
82 #define DEVICE_CLASS_SOUND "sound"
83 #define DEVICE_CLASS_MONITOR "monitor"
86 #define DBUS_INTERFACE_DEVICE_MANAGER "org.pulseaudio.DeviceManager"
87 #define DBUS_OBJECT_DEVICE_MANAGER "/org/pulseaudio/DeviceManager"
89 #define DBUS_INTERFACE_DEVICED_SYSNOTI "org.tizen.system.deviced.SysNoti"
90 #define DBUS_OBJECT_DEVICED_SYSNOTI "/Org/Tizen/System/DeviceD/SysNoti"
92 #define DBUS_INTERFACE_SOUND_SERVER "org.tizen.SoundServer1"
93 #define DBUS_OBJECT_SOUND_SERVER "/org/tizen/SoundServer1"
95 #define DBUS_SERVICE_BLUEZ "org.bluez"
96 #define DBUS_INTERFACE_BLUEZ_HEADSET "org.bluez.Headset"
97 #define DBUS_INTERFACE_BLUEZ_DEVICE "org.bluez.Device1"
98 #define DBUS_OBJECT_BLUEZ "/org/bluez"
100 #define DBUS_INTERFACE_MIRRORING_SERVER "org.tizen.scmirroring.server"
101 #define DBUS_OBJECT_MIRRORING_SERVER "/org/tizen/scmirroring/server"
103 #define DBUS_SERVICE_HFP_AGENT "org.bluez.ag_agent"
104 #define DBUS_OBJECT_HFP_AGENT "/org/bluez/hfp_agent"
105 #define DBUS_INTERFACE_HFP_AGENT "Org.Hfp.App.Interface"
107 #define DEVICE_MANAGER_INTROSPECT_XML \
108 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
110 " <interface name=\"" DBUS_INTERFACE_DEVICE_MANAGER "\">\n" \
111 " <method name=\"GetConnectedDeviceList\">\n" \
112 " <arg name=\"mask_flags\" direction=\"in\" type=\"i\"/>\n" \
113 " <arg name=\"ConnectedDeviceList\" direction=\"out\" type=\"a(isiis)\"/>\n" \
115 " <method name='GetBTA2DPStatus'>" \
116 " <arg type='b' name='is_bt_on' direction='out'/>" \
117 " <arg type='s' name='bt_name' direction='out'/>" \
119 " <method name=\"LoadSink\">\n" \
120 " <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n" \
121 " <arg name=\"role\" direction=\"in\" type=\"s\"/>\n" \
123 " <method name=\"TestStatusChange\">\n" \
124 " <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n" \
125 " <arg name=\"status\" direction=\"in\" type=\"i\"/>\n" \
127 " <property name=\"PropertyTest1\" type=\"i\" access=\"readwrite\"/>\n" \
128 " <property name=\"PropertyTest2\" type=\"s\" access=\"read\"/>\n" \
129 " <signal name=\"DeviceConnected\">\n" \
130 " <arg name=\"arg1\" type=\"i\"/>\n" \
132 " <signal name=\"DeviceInfoChanged\">\n" \
133 " <arg name=\"arg1\" type=\"s\"/>\n" \
136 " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n" \
137 " <method name=\"Introspect\">\n" \
138 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \
141 " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n" \
142 " <method name=\"Get\">\n" \
143 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
144 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" \
145 " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n" \
147 " <method name=\"Set\">\n" \
148 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
149 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" \
150 " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n" \
152 " <method name=\"GetAll\">\n" \
153 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
154 " <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n" \
160 #define FILTER_DEVICED_SYSNOTI \
162 " interface='" DBUS_INTERFACE_DEVICED_SYSNOTI "'"
164 #define FILTER_SOUND_SERVER \
166 " interface='" DBUS_INTERFACE_SOUND_SERVER "'"
168 #define FILTER_MIRRORING \
170 " interface='" DBUS_INTERFACE_MIRRORING_SERVER "', member='miracast_wfd_source_status_changed'"
172 #define FILTER_BLUEZ \
174 " interface='" DBUS_INTERFACE_BLUEZ_HEADSET "', member='PropertyChanged'"
176 static const char* const valid_alsa_device_modargs[] = {
194 "tsched_buffer_size",
195 "tsched_buffer_watermark",
200 "deferred_volume_safety_margin",
201 "deferred_volume_extra_delay",
202 "fixed_latency_range",
208 #define BT_CVSD_CODEC_ID 1 // narrow-band
209 #define BT_MSBC_CODEC_ID 2 // wide-band
211 Enums for represent values which is defined on other module.
212 This is needed to identify values which are sent by dbus or vconf.
214 typedef enum external_value_earjack_type {
215 EARJACK_DISCONNECTED = 0,
216 EARJACK_TYPE_SPK_ONLY = 1,
217 EARJACK_TYPE_SPK_WITH_MIC = 3,
218 } external_value_earjack_t;
220 typedef enum external_value_bt_sco_type {
221 BT_SCO_DISCONNECTED = 0,
222 BT_SCO_CONNECTED = 1,
223 } external_value_bt_sco_t;
225 typedef enum external_value_forwarding_type {
226 FORWARDING_DISCONNECTED = 0,
227 FORWARDING_CONNECTED = 1,
228 } external_value_mirroring_t;
230 typedef enum external_value_hdmi_type {
231 HDMI_AUDIO_DISCONNECTED = -1,
232 HDMI_AUDIO_NOT_AVAILABLE = 0,
233 HDMI_AUDIO_AVAILABLE = 1,
234 } external_value_hdmi_t;
238 Enums for represent device detected status (through dbus)
239 When some device is detected, one of these values should be saved in device_status hashmap.
240 device_detected_type_t is needed to distinguish detected device-types ( ex. earjack which can be out or both way)
241 So If you just want to know whether detected or not, can device_detected_t as mask.
244 typedef enum device_detected_type {
245 DEVICE_DISCONNECTED = 0x0,
246 DEVICE_CONNECTED = 0x1,
247 DEVICE_CONNECTED_AUDIO_JACK_4P = DEVICE_CONNECTED | 0x2,
248 DEVICE_CONNECTED_AUDIO_JACK_3P = DEVICE_CONNECTED | 0x4,
249 DEVICE_CONNECTED_SCO = DEVICE_CONNECTED | 0x8,
250 DEVICE_OPENED_SCO = DEVICE_CONNECTED | 0xF,
251 } device_detected_type_t;
253 typedef enum dm_device_class_type {
254 DM_DEVICE_CLASS_NONE,
255 DM_DEVICE_CLASS_ALSA,
256 DM_DEVICE_CLASS_TIZEN,
258 DM_DEVICE_CLASS_NULL,
264 DEVICE_IO_DIRECTION_IN_FLAG = 0x0001, /**< Flag for input devices */
265 DEVICE_IO_DIRECTION_OUT_FLAG = 0x0002, /**< Flag for output devices */
266 DEVICE_IO_DIRECTION_BOTH_FLAG = 0x0004, /**< Flag for input/output devices (both directions are available) */
267 DEVICE_TYPE_INTERNAL_FLAG = 0x0010, /**< Flag for built-in devices */
268 DEVICE_TYPE_EXTERNAL_FLAG = 0x0020, /**< Flag for external devices */
269 DEVICE_STATE_DEACTIVATED_FLAG = 0x1000, /**< Flag for deactivated devices */
270 DEVICE_STATE_ACTIVATED_FLAG = 0x2000, /**< Flag for activated devices */
271 DEVICE_ALL_FLAG = 0xFFFF, /**< Flag for all devices */
275 DEVICE_IO_DIRECTION_FLAGS = 0x000F, /**< Flag for io direction */
276 DEVICE_TYPE_FLAGS = 0x00F0, /**< Flag for device type */
277 DEVICE_STATE_FLAGS = 0xF000, /**< Flag for device state */
278 } device_flags_type_t;
280 typedef enum dm_device_bt_mode_type {
281 DM_DEVICE_BT_MODE_MEDIA = 0x1,
282 DM_DEVICE_BT_MODE_VOICE = 0x2
283 } dm_device_bt_mode_t;
285 typedef enum dm_device_changed_into_type {
286 DM_DEVICE_CHANGED_INFO_STATE,
287 DM_DEVICE_CHANGED_INFO_IO_DIRECTION,
288 DM_DEVICE_CHANGED_INFO_MAX
289 } dm_device_changed_info_t;
293 Structure to save parsed information about device-file.
295 struct device_file_map {
296 /* { key:device_string -> value:device_file_prop } */
301 /***************** structures for static information get from json *********/
304 Structure for informations related to some device-file(ex. 0:0)
306 struct device_file_info {
308 String for identify target device.
309 ex) alsa:0,0 or null ..
311 const char *device_string;
313 For save roles which are supported on device file, and parameters.
314 { key:device_role -> value:parameters for load sink/source }
315 ex) "normal"->"rate=44100 tsched=0", "uhqa"->"rate=192000 mmap=1"
319 For save device-types related to device file.
320 { key:device_type-> value:pulse_device_prop }
322 pa_hashmap *device_types;
325 /* structure for represent device-types(ex. builtin-speaker) properties*/
326 struct device_type_info {
329 For save supported roles and related device-file.
330 { key:role -> value:device_string ]
332 pa_hashmap *playback_devices;
333 pa_hashmap *capture_devices;
336 struct device_status_info {
339 /* Identify devices among same device-types (for multi-device), currently not works*/
341 device_detected_type_t detected;
344 struct pulse_device_prop {
345 /* roles related to (device_type + device_file)*/
347 /* For save that this devie_type is activated or not on sink/source */
350 /******************************************************************************/
351 struct pa_device_manager {
355 pa_hook_slot *sink_put_hook_slot, *sink_state_changed_slot, *sink_unlink_hook_slot;
356 pa_hook_slot *source_put_hook_slot, *source_state_changed_slot, *source_unlink_hook_slot;
357 pa_hook_slot *comm_hook_device_connection_changed_slot;
358 pa_hook_slot *comm_hook_device_state_changed_slot;
359 pa_communicator *comm;
362 Idxset for save parsed information about device-type.
365 pa_idxset *type_infos;
366 /* For save Parsed information about device-file */
367 struct device_file_map *file_map;
370 pa_idxset *device_list;
372 Hashmap for save statuses got through dbus.
373 { key:device_type -> value:(audio_detected_type_t or device_detected_t) }
375 pa_idxset *device_status;
376 pa_dbus_connection *dbus_conn;
380 struct composite_type {
387 /*** Defines for method handle ***/
388 /* method handlers */
389 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
390 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
391 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
392 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata);
394 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name);
396 enum method_handler_index {
397 METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST,
398 METHOD_HANDLER_GET_BT_A2DP_STATUS,
399 METHOD_HANDLER_LOAD_SINK,
400 METHOD_HANDLER_STATUS_TEST,
404 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
405 [METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST] = {
406 .method_name = "GetConnectedDeviceList",
407 .receive_cb = handle_get_connected_device_list },
408 [METHOD_HANDLER_GET_BT_A2DP_STATUS] = {
409 .method_name = "GetBTA2DPStatus",
410 .receive_cb = handle_get_bt_a2dp_status },
411 [METHOD_HANDLER_LOAD_SINK] = {
412 .method_name = "LoadSink",
413 .receive_cb = handle_load_sink},
414 [METHOD_HANDLER_STATUS_TEST] = {
415 .method_name = "TestStatusChange",
416 .receive_cb = handle_test_device_status_change},
421 static inline void simple_device_dump(pa_log_level_t level, const char *prefix, int id, const char *type, const char *name, int direction, int state) {
422 pa_logl(level, "%s device id(%d) type(%s) name (%s) direction(%d) state(%d)",
423 pa_strempty(prefix), id, pa_strnull(type), pa_strnull(name), direction, state);
426 static void type_info_free_func(struct device_type_info *type_info) {
430 if (type_info->playback_devices)
431 pa_hashmap_free(type_info->playback_devices);
432 if (type_info->capture_devices)
433 pa_hashmap_free(type_info->capture_devices);
437 static void file_info_free_func(struct device_file_info *file_info) {
441 if (file_info->roles)
442 pa_hashmap_free(file_info->roles);
445 static dm_device_class_t device_string_get_class(const char *device_string) {
446 if (!device_string) {
447 return DM_DEVICE_CLASS_NONE;
450 if (device_string == strstr(device_string, "alsa")) {
451 return DM_DEVICE_CLASS_ALSA;
452 } else if (device_string == strstr(device_string, "null")) {
453 return DM_DEVICE_CLASS_NULL;
454 } else if (device_string == strstr(device_string, "tizen")) {
455 return DM_DEVICE_CLASS_TIZEN;
457 return DM_DEVICE_CLASS_NONE;
461 static const char* device_string_get_value(const char *device_string) {
463 const char *end_p, *value_p;
465 if (!device_string) {
469 len = strlen(device_string);
470 end_p = device_string + len -1;
472 if (!(value_p = strchr(device_string, ':'))) {
475 if (value_p < end_p) {
482 static pa_proplist* pulse_device_get_proplist(pa_object *pdevice) {
483 if (pa_sink_isinstance(pdevice))
484 return PA_SINK(pdevice)->proplist;
486 return PA_SOURCE(pdevice)->proplist;
489 static bool pulse_device_is_alsa(pa_object *pdevice) {
490 const char *api_name = NULL;
493 if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
496 if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
497 if (pa_streq(api_name, DEVICE_API_ALSA)) {
508 static bool pulse_device_is_bluez(pa_object *pdevice) {
509 const char *api_name = NULL;
512 if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
515 if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
516 if (pa_streq(api_name, DEVICE_API_BLUEZ)) {
526 static bool pulse_device_is_tizenaudio(pa_object *pdevice) {
530 if (pa_sink_isinstance(pdevice)) {
531 pa_sink *sink = PA_SINK(pdevice);
532 return pa_streq(sink->module->name, "module-tizenaudio-sink");
534 pa_source *source = PA_SOURCE(pdevice);
535 return pa_streq(source->module->name, "module-tizenaudio-source");
539 static bool pulse_device_is_usb(pa_object *pdevice) {
540 const char *bus_name = NULL;
543 if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
546 if ((bus_name = pa_proplist_gets(prop, PA_PROP_DEVICE_BUS))) {
547 if (pa_streq(bus_name, DEVICE_BUS_USB)) {
553 pa_log_debug("This device doesn't have property '%s'", PA_PROP_DEVICE_BUS);
558 static bool pulse_device_is_null(pa_object *pdevice) {
565 if (pa_sink_isinstance(pdevice)) {
566 sink = PA_SINK(pdevice);
567 return pa_streq(sink->module->name, "module-null-sink");
569 source = PA_SOURCE(pdevice);
570 return pa_streq(source->module->name, "module-null-source");
574 static const char* pulse_device_get_device_string_removed_argument(pa_object *pdevice) {
575 static char removed_param[DEVICE_PARAM_STRING_MAX] = {0,};
576 char *device_string_p = NULL;
578 const char *params_p, *params;
580 int len = 0, prev_len = 0;
584 if (pa_sink_isinstance(pdevice)) {
585 sink = PA_SINK(pdevice);
586 params = sink->module->argument;
588 source = PA_SOURCE(pdevice);
589 params = source->module->argument;
597 if (!(device_string_p = strstr(params, "device="))) {
601 next_p = device_string_p;
602 while (!isblank(*next_p)) {
605 while (isblank(*next_p)) {
609 strncpy(removed_param, next_p, DEVICE_PARAM_STRING_MAX);
611 if (device_string_p > params_p) {
612 prev_len = device_string_p - params_p;
613 len = strlen(removed_param);
614 end_p = removed_param + len;
617 strncpy(end_p, params_p, prev_len);
620 return removed_param;
623 static dm_device_class_t pulse_device_get_class(pa_object *pdevice) {
626 pa_log_error("pdevice null");
627 return DM_DEVICE_CLASS_NONE;
630 if (pulse_device_is_null(pdevice)) {
631 return DM_DEVICE_CLASS_NULL;
632 } else if (pulse_device_is_alsa(pdevice)) {
633 return DM_DEVICE_CLASS_ALSA;
634 } else if (pulse_device_is_tizenaudio(pdevice)) {
635 return DM_DEVICE_CLASS_TIZEN;
636 } else if (pulse_device_is_bluez(pdevice)) {
637 return DM_DEVICE_CLASS_BT;
639 return DM_DEVICE_CLASS_NONE;
643 static dm_device_direction_t pulse_device_get_direction(pa_object *pdevice) {
644 if (pa_sink_isinstance(pdevice))
645 return DM_DEVICE_DIRECTION_OUT;
647 return DM_DEVICE_DIRECTION_IN;
650 static bool pulse_device_is_monitor(pa_object *pdevice) {
651 const char *device_class = NULL;
654 prop = pulse_device_get_proplist(pdevice);
656 if ((device_class = pa_proplist_gets(prop, PA_PROP_DEVICE_CLASS))) {
657 if (device_class && pa_streq(device_class, DEVICE_CLASS_MONITOR)) {
667 static int pulse_device_get_alsa_device_string(pa_proplist *prop, char **device_string) {
668 const char *device_string_prop = NULL;
669 char *device_string_tmp;
671 if (!prop || !device_string) {
672 pa_log_error("Invalid Parameter");
676 if (!(device_string_prop = pa_proplist_gets(prop, "device.string"))) {
677 pa_log_error("failed to get property 'device.string'");
680 if (!(device_string_tmp = strchr(device_string_prop, ':'))) {
681 pa_log_error("failed to parse device string");
685 *device_string = device_string_tmp + 1;
690 static const char* device_class_get_module_name(dm_device_class_t device_class, bool is_sink) {
691 if (device_class == DM_DEVICE_CLASS_NONE) {
693 } else if (device_class == DM_DEVICE_CLASS_ALSA) {
694 return is_sink ? "module-alsa-sink" : "module-alsa-source";
695 } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
696 return is_sink ? "module-tizenaudio-sink" : NULL;
697 } else if (device_class == DM_DEVICE_CLASS_BT) {
698 return is_sink ? "module-bluez5-device" : NULL;
699 } else if (device_class == DM_DEVICE_CLASS_NULL) {
700 return is_sink ? "module-null-sink" : "module-null-source";
706 static struct device_type_info* _device_manager_get_type_info(pa_idxset *type_infos, const char *type) {
707 struct device_type_info *type_info;
710 PA_IDXSET_FOREACH(type_info, type_infos, type_idx) {
711 if (device_type_is_equal(type_info->type, type)) {
719 static struct device_file_info* _device_manager_get_file_info(pa_idxset *file_infos, const char *device_string) {
720 struct device_file_info *file_info;
723 pa_assert(file_infos);
725 PA_IDXSET_FOREACH(file_info, file_infos, file_idx) {
726 if (file_info->device_string) {
727 if (pa_streq(file_info->device_string, device_string)) {
736 static struct device_status_info* _device_status_new(const char *type,
737 const char *name, const char *system_id) {
738 struct device_status_info *status_info;
740 status_info = (struct device_status_info *) pa_xmalloc0(sizeof(struct device_status_info));
741 status_info->type = pa_xstrdup(type);
742 status_info->name = pa_xstrdup(name);
743 status_info->system_id = pa_xstrdup(system_id);
744 status_info->detected = DEVICE_DISCONNECTED;
749 static void _device_status_free(struct device_status_info *status_info) {
753 pa_xfree(status_info->type);
754 pa_xfree(status_info->name);
755 pa_xfree(status_info->system_id);
756 pa_xfree(status_info);
759 static struct device_status_info* _get_device_status(pa_device_manager *manager, const char *type,
760 const char *system_id) {
761 struct device_status_info *status_info = NULL;
765 pa_assert(manager->device_status);
767 PA_IDXSET_FOREACH(status_info, manager->device_status, status_idx) {
768 if (device_type_is_equal(status_info->type, type)) {
769 if (device_type_is_avail_multi_device(type)) {
770 /* if system_id is null, just compare type */
771 if (system_id == NULL)
773 else if (status_info->system_id == NULL)
775 else if (pa_streq(status_info->system_id, system_id))
788 static const char* _file_infos_get_param(pa_idxset *file_infos, const char *device_string, const char *role) {
789 struct device_file_info *file_info;
792 if (!(file_info = _device_manager_get_file_info(file_infos, device_string))) {
793 pa_log_error("No file map for '%s'", device_string);
797 if (!(params = pa_hashmap_get(file_info->roles, role)))
798 pa_log_error("No params for '%s:%s'", device_string, role);
803 static device_detected_type_t _device_get_detected(pa_device_manager *manager, const char *type,
804 const char *system_id) {
805 struct device_status_info *status_info;
808 pa_assert(manager->device_status);
811 if (!device_type_is_need_detect(type))
812 return DEVICE_CONNECTED;
814 status_info = _get_device_status(manager, type, system_id);
816 pa_log_info("No status info for type(%s) system_id(%s)",
817 type, pa_strempty(system_id));
818 return DEVICE_DISCONNECTED;
821 pa_log_debug("Get device detected, type(%s) system_id(%s) : %s(%d)",
822 type, pa_strempty(system_id),
823 (status_info->detected & DEVICE_CONNECTED) ? "Connected" : "Disconnected", status_info->detected);
825 return status_info->detected;
828 static void _device_set_detected(pa_device_manager *manager, const char *type,
829 const char *name, const char *system_id, device_detected_type_t detected_type) {
830 struct device_status_info *status_info;
833 pa_assert(manager->device_status);
836 if (!device_type_is_need_detect(type))
839 pa_log_info("Set device detected, type(%s) system_id(%s) -> %s(%d)",
840 type, pa_strempty(system_id),
841 (detected_type & DEVICE_CONNECTED) ? "Connected" : "Disconnected", detected_type);
843 if (detected_type & DEVICE_CONNECTED) {
844 status_info = _get_device_status(manager, type, system_id);
846 status_info = _device_status_new(type, name, system_id);
847 pa_idxset_put(manager->device_status, status_info, NULL);
849 status_info->detected = detected_type;
851 status_info = _get_device_status(manager, type, system_id);
853 pa_idxset_remove_by_data(manager->device_status, status_info, NULL);
854 _device_status_free(status_info);
859 static pa_tz_device* _device_list_get_device(pa_device_manager *manager, const char *type, const char *system_id) {
860 pa_tz_device *device;
862 char *_type, *_system_id;
865 pa_assert(manager->device_list);
868 PA_IDXSET_FOREACH(device, manager->device_list, idx) {
869 _type = pa_tz_device_get_type(device);
870 _system_id = pa_tz_device_get_system_id(device);
871 if (pa_streq(_type, type)) {
872 if (device_type_is_avail_multi_device(type)) {
873 if (system_id == NULL)
875 else if (_system_id == NULL)
877 else if (pa_streq(_system_id, system_id))
891 static pa_tz_device* _device_list_get_device_with_id(pa_device_manager *manager, uint32_t id) {
892 pa_tz_device *device;
896 pa_assert(manager->device_list);
898 PA_IDXSET_FOREACH(device, manager->device_list, idx) {
899 if (pa_tz_device_get_id(device) == id) {
906 static const char* build_params_to_load_device(const char *device_string, const char *params, dm_device_class_t device_class) {
908 static char args[DEVICE_PARAM_STRING_MAX] = {0,};
910 if (!device_string) {
911 pa_log_error("device string null");
915 if (device_class == DM_DEVICE_CLASS_NULL) {
917 } else if (device_class == DM_DEVICE_CLASS_ALSA) {
918 const char *alsa_device_name;
919 if (!(alsa_device_name = device_string_get_value(device_string))) {
920 pa_log_error("Invalid device string for alsa-device, '%s'", device_string);
923 args_buf = pa_strbuf_new();
924 pa_strbuf_printf(args_buf, "device=hw:%s \n", alsa_device_name);
926 pa_strbuf_printf(args_buf, "%s\n", params);
928 strncpy(args, pa_strbuf_tostring_free(args_buf), DEVICE_PARAM_STRING_MAX);
933 return (const char*) args;
936 static bool device_params_is_equal(const char *params1, const char *params2) {
937 const char *key = NULL;
938 const char *value1, *value2;
939 pa_modargs *modargs1, *modargs2;
943 if (!params1 && !params2)
945 if (!params1 || !params2)
948 modargs1 = pa_modargs_new(params1, valid_alsa_device_modargs);
949 modargs2 = pa_modargs_new(params2, valid_alsa_device_modargs);
951 if (!modargs1 || !modargs2) {
956 for (state = NULL, key = pa_modargs_iterate(modargs1, &state); key; key = pa_modargs_iterate(modargs1, &state)) {
957 value1 = pa_modargs_get_value(modargs1, key, NULL);
958 value2 = pa_modargs_get_value(modargs2, key, NULL);
959 if (!value1 || !value2 || !pa_streq(value1, value2)) {
965 for (state = NULL, key = pa_modargs_iterate(modargs2, &state); key; key = pa_modargs_iterate(modargs2, &state)) {
966 value1 = pa_modargs_get_value(modargs1, key, NULL);
967 value2 = pa_modargs_get_value(modargs2, key, NULL);
968 if (!value1 || !value2 || !pa_streq(value1, value2)) {
977 pa_modargs_free(modargs1);
979 pa_modargs_free(modargs2);
985 static bool pulse_device_params_is_equal(pa_object *pdevice, const char *params) {
986 const char *removed_module_args;
987 const char *module_args;
993 if (pa_sink_isinstance(pdevice)) {
994 sink = PA_SINK(pdevice);
995 module_args = sink->module->argument;
997 source = PA_SOURCE(pdevice);
998 module_args = source->module->argument;
1001 if (!params && !module_args)
1003 if (!params || !module_args)
1006 removed_module_args = pulse_device_get_device_string_removed_argument(pdevice);
1007 return device_params_is_equal(params, removed_module_args);
1010 static const char* pulse_device_get_device_string(pa_object *pdevice) {
1011 dm_device_class_t device_class;
1012 static char device_string[DEVICE_STR_MAX] = {0,};
1013 char *device_string_val = NULL;
1018 device_class = pulse_device_get_class(pdevice);
1019 prop = pulse_device_get_proplist(pdevice);
1021 if (device_class == DM_DEVICE_CLASS_ALSA) {
1022 if (pulse_device_get_alsa_device_string(prop, &device_string_val) < 0)
1024 snprintf(device_string, DEVICE_STR_MAX, "alsa:%s", device_string_val);
1025 return device_string;
1026 } else if (device_class == DM_DEVICE_CLASS_NULL) {
1028 } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
1030 } else if (device_class == DM_DEVICE_CLASS_BT) {
1033 return device_string;
1037 /* pdevice is sink or source */
1038 static bool pulse_device_same_device_string(pa_object *pdevice, const char *device_string) {
1039 const char *_device_string;
1042 pa_assert(device_string);
1044 if (!(_device_string = pulse_device_get_device_string(pdevice)))
1047 return pa_streq(_device_string, device_string);
1050 static const char* device_type_info_get_role(struct device_type_info *type_info, bool is_playback, const char *device_string) {
1051 pa_hashmap *pcm_devices;
1053 const char *role, *_device_string;
1054 dm_device_direction_t direction;
1056 pa_assert(type_info);
1057 pa_assert(device_string);
1059 direction = device_type_get_static_direction(type_info->type);
1060 if (direction == DM_DEVICE_DIRECTION_NONE) {
1061 pa_log_debug("Not static direction");
1066 if (direction == DM_DEVICE_DIRECTION_IN) {
1067 pa_log_debug("Invalid direction");
1070 pcm_devices = type_info->playback_devices;
1072 if (direction == DM_DEVICE_DIRECTION_OUT) {
1073 pa_log_debug("Invalid direction");
1076 pcm_devices = type_info->capture_devices;
1080 pa_log_warn("No %s pcm devices for %s", is_playback ? "playback" : "capture", type_info->type);
1084 PA_HASHMAP_FOREACH_KV(role, _device_string, pcm_devices, state) {
1085 if (pa_streq(_device_string, device_string)) {
1093 pa_dynarray* pulse_device_get_belongs_type(pa_object *pdevice, pa_device_manager *dm) {
1094 pa_dynarray *ctypes;
1095 struct composite_type *ctype;
1096 struct device_type_info *type_info;
1097 const char *device_string, *role;
1099 pa_device_type_t pdt;
1103 if (pulse_device_is_monitor(pdevice))
1105 if (pulse_device_is_usb(pdevice))
1107 if (pulse_device_is_bluez(pdevice))
1110 ctypes = pa_dynarray_new(pa_xfree);
1112 if (pa_sink_isinstance(pdevice))
1113 pdt = PA_DEVICE_TYPE_SINK;
1115 pdt = PA_DEVICE_TYPE_SOURCE;
1117 PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
1118 device_string = pulse_device_get_device_string(pdevice);
1119 role = device_type_info_get_role(type_info, pdt, device_string);
1120 /* Found type_info which is matching with pulse_device */
1122 ctype = pa_xmalloc0(sizeof(struct composite_type));
1123 ctype->type = type_info->type;
1125 pa_dynarray_append(ctypes, ctype);
1129 if (pa_dynarray_size(ctypes) == 0) {
1130 pa_dynarray_free(ctypes);
1137 static const char* pulse_device_get_device_name(pa_object *pdevice, const char *type) {
1141 pa_assert(device_type_is_valid(type));
1143 prop = pulse_device_get_proplist(pdevice);
1145 if (pa_streq(type, DEVICE_TYPE_USB_AUDIO))
1146 return pa_proplist_gets(prop, "udev.id");
1147 else if (pa_streq(type, DEVICE_TYPE_BT_A2DP))
1148 return pa_proplist_gets(prop, "bluez.alias");
1153 static void pulse_device_set_use_internal_codec(pa_object *pdevice, bool use_internal_codec) {
1156 if (pa_sink_isinstance(pdevice)) {
1157 pa_sink *sink = PA_SINK(pdevice);
1158 sink->use_internal_codec = use_internal_codec;
1160 pa_source *source = PA_SOURCE(pdevice);
1161 source->use_internal_codec = use_internal_codec;
1165 /* Get system_id of physical device, if external device */
1166 static const char* pulse_device_get_system_id(pa_object *pdevice) {
1169 prop = pulse_device_get_proplist(pdevice);
1170 if (pulse_device_is_usb(pdevice))
1171 return pa_proplist_gets(prop, "sysfs.path");
1172 else if (pulse_device_is_bluez(pdevice))
1173 return pa_proplist_gets(prop, "bluez.path");
1178 static pa_sink* _core_get_sink(pa_core *core, const char *device_string, const char *params) {
1179 uint32_t device_idx;
1183 pa_assert(device_string);
1185 PA_IDXSET_FOREACH(sink, core->sinks, device_idx) {
1186 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1188 if (pulse_device_same_device_string(PA_OBJECT(sink), device_string)) {
1191 else if (pulse_device_params_is_equal(PA_OBJECT(sink), params))
1199 static pa_source* _core_get_source(pa_core *core, const char *device_string, const char *params) {
1200 uint32_t device_idx;
1204 pa_assert(device_string);
1206 PA_IDXSET_FOREACH(source, core->sources, device_idx) {
1207 if (pulse_device_is_monitor(PA_OBJECT(source)))
1209 if (pulse_device_same_device_string(PA_OBJECT(source), device_string)) {
1212 else if (pulse_device_params_is_equal(PA_OBJECT(source), params))
1221 static void _fill_new_data_basic(pa_tz_device_new_data *data, const char *type,
1222 dm_device_direction_t direction, bool use_internal_codec, pa_device_manager *dm) {
1225 pa_tz_device_new_data_set_type(data, type);
1226 pa_tz_device_new_data_set_direction(data, direction);
1227 pa_tz_device_new_data_set_use_internal_codec(data, use_internal_codec);
1230 static int _fill_new_data_sinks(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
1232 char *device_string, *role;
1236 pa_assert(type_info);
1238 if (type_info->playback_devices == NULL) {
1239 pa_log_error("No playback devices for %s", type_info->type);
1243 PA_HASHMAP_FOREACH_KV(role, device_string, type_info->playback_devices, state) {
1244 sink = _core_get_sink(dm->core, device_string, NULL);
1246 pa_tz_device_new_data_add_sink(data, role, sink);
1248 pa_log_error("Failed to get matching sink for %s %s", role, device_string);
1254 static int _fill_new_data_sources(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
1256 char *device_string, *role;
1260 pa_assert(type_info);
1262 if (type_info->capture_devices == NULL) {
1263 pa_log_error("No capture devices for %s", type_info->type);
1267 PA_HASHMAP_FOREACH_KV(role, device_string, type_info->capture_devices, state) {
1268 source = _core_get_source(dm->core, device_string, NULL);
1270 pa_tz_device_new_data_add_source(data, role, source);
1272 pa_log_error("Failed to get matching source for %s %s", role, device_string);
1278 static pa_sink* _device_manager_set_default_sink(pa_device_manager *dm, const char *type, const char *role) {
1279 pa_tz_device *device;
1282 if (!type || !role) {
1283 pa_log_warn("Argument for set_default_sink invalid");
1287 if (!(device = _device_list_get_device(dm, type, NULL))) {
1288 pa_log_warn("cannot get device item for %s", type);
1292 if (!(sink = pa_tz_device_get_sink(device, role))) {
1293 pa_log_warn("cannot get sink for %s", role);
1297 sink = pa_namereg_set_default_sink(dm->core, sink);
1301 static pa_source* _device_manager_set_default_source(pa_device_manager *dm, const char *type, const char *role) {
1302 pa_tz_device *device;
1305 if (!type || !role) {
1306 pa_log_warn("Argument for set_default_source invalid");
1310 if (!(device = _device_list_get_device(dm, type, NULL))) {
1311 pa_log_warn("cannot get device item for %s", type);
1315 if (!(source = pa_tz_device_get_source(device, role))) {
1316 pa_log_warn("cannot get source for %s", role);
1320 source = pa_namereg_set_default_source(dm->core, source);
1324 static void handle_usb_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1325 const char *name, *system_id;
1326 dm_device_direction_t direction;
1327 pa_tz_device *device;
1332 pa_log_info("Handle usb pulse device");
1334 system_id = pulse_device_get_system_id(pdevice);
1335 direction = pulse_device_get_direction(pdevice);
1338 pa_tz_device_new_data data;
1340 name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_USB_AUDIO);
1342 pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, NULL);
1343 pa_tz_device_new_data_set_type(&data, DEVICE_TYPE_USB_AUDIO);
1344 pa_tz_device_new_data_set_name(&data, name);
1345 pa_tz_device_new_data_set_direction(&data, direction);
1346 pa_tz_device_new_data_set_system_id(&data, system_id);
1347 pa_tz_device_new_data_set_use_internal_codec(&data, false);
1348 if (direction == DM_DEVICE_DIRECTION_OUT)
1349 pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
1351 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1353 pa_tz_device_new(&data);
1354 pa_tz_device_new_data_done(&data);
1356 if (!(device = _device_list_get_device(manager, DEVICE_TYPE_USB_AUDIO, system_id)))
1357 pa_log_warn("Can't get usb device for %s", system_id);
1359 pa_tz_device_free(device);
1363 static void handle_bt_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1364 dm_device_direction_t direction;
1365 pa_tz_device *device;
1366 const char *system_id;
1371 pa_log_info("Handle bt pulse device");
1373 direction = pulse_device_get_direction(pdevice);
1374 system_id = pulse_device_get_system_id(pdevice);
1377 pa_tz_device_new_data data;
1380 name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_BT_A2DP);
1382 pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, manager->dbus_conn);
1383 _fill_new_data_basic(&data, DEVICE_TYPE_BT_A2DP, direction, false, manager);
1384 pa_tz_device_new_data_set_name(&data, name);
1385 pa_tz_device_new_data_set_system_id(&data, system_id);
1386 if (direction == DM_DEVICE_DIRECTION_OUT)
1387 pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
1389 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1391 pa_tz_device_new(&data);
1392 pa_tz_device_new_data_done(&data);
1395 if (!(device = _device_list_get_device(manager, DEVICE_TYPE_BT_A2DP, system_id)))
1396 pa_log_warn("Can't get bt device for %s", system_id);
1398 pa_tz_device_free(device);
1402 static void handle_internal_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1403 pa_tz_device *device;
1404 struct composite_type *ctype;
1405 pa_dynarray *ctypes;
1406 dm_device_direction_t direction;
1411 pa_log_info("Handle internal pulse device");
1412 direction = pulse_device_get_direction(pdevice);
1414 /* Get types which this pulse_device belongs to */
1415 if ((ctypes = pulse_device_get_belongs_type(pdevice, manager)) == NULL) {
1416 pa_log_debug("Failed to get device type. Skip this");
1421 /* Put this pulse_device to already loaded devices */
1422 for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
1423 ctype = pa_dynarray_get(ctypes, i);
1424 pa_log_info("Found belongs type %s %s", ctype->type, ctype->role);
1425 if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
1426 pa_log_info("Add this pulse_device to device(%u)", pa_tz_device_get_id(device));
1427 if (direction == DM_DEVICE_DIRECTION_OUT)
1428 pa_tz_device_add_sink(device, ctype->role, PA_SINK(pdevice));
1430 pa_tz_device_add_source(device, ctype->role, PA_SOURCE(pdevice));
1432 pa_log_info("No device for %s", ctype->type);
1436 /* Remove this pulse_device from already loaded devices */
1437 for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
1438 ctype = pa_dynarray_get(ctypes, i);
1439 pa_log_info("Found belongs type %s %s", ctype->type, ctype->role);
1440 if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
1441 pa_log_info("Remove this pulse_device from device(%u)", pa_tz_device_get_id(device));
1442 if (direction == DM_DEVICE_DIRECTION_OUT)
1443 pa_tz_device_remove_sink(device, PA_SINK(pdevice));
1445 pa_tz_device_remove_source(device, PA_SOURCE(pdevice));
1447 pa_log_info("No device for %s", ctype->type);
1452 pa_dynarray_free(ctypes);
1455 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1460 pa_log_info("========== Sink Put Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1462 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1465 if (pulse_device_is_usb(PA_OBJECT(sink))) {
1466 pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
1467 handle_usb_pulse_device(PA_OBJECT(sink), true, dm);
1469 } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
1470 pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
1471 handle_bt_pulse_device(PA_OBJECT(sink), true, dm);
1473 } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
1474 pulse_device_set_use_internal_codec(PA_OBJECT(sink), true);
1475 handle_internal_pulse_device(PA_OBJECT(sink), true, dm);
1478 pa_log_debug("Don't care this sink");
1484 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1489 pa_log_info("=========== Sink unlink Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1491 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1494 if (pulse_device_is_usb(PA_OBJECT(sink))) {
1495 handle_usb_pulse_device(PA_OBJECT(sink), false, dm);
1497 } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
1498 handle_bt_pulse_device(PA_OBJECT(sink), false, dm);
1500 } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
1501 handle_internal_pulse_device(PA_OBJECT(sink), false, dm);
1504 pa_log_debug("Don't care this sink");
1510 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1515 pa_log_info("========== source Put Hook Callback '%s'(%d) ==========", source->name, source->index);
1517 if (pulse_device_is_monitor(PA_OBJECT(source)))
1520 if (pulse_device_is_usb(PA_OBJECT(source))) {
1521 pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
1522 handle_usb_pulse_device(PA_OBJECT(source), true, dm);
1524 } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
1525 pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
1526 handle_bt_pulse_device(PA_OBJECT(source), true, dm);
1528 } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
1529 pulse_device_set_use_internal_codec(PA_OBJECT(source), true);
1530 handle_internal_pulse_device(PA_OBJECT(source), true, dm);
1533 pa_log_debug("Don't care this source");
1539 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1544 pa_log_info("=========== source unlink Hook Callback '%s'(%d) ==========", source->name, source->index);
1546 if (pulse_device_is_monitor(PA_OBJECT(source)))
1549 if (pulse_device_is_usb(PA_OBJECT(source))) {
1550 handle_usb_pulse_device(PA_OBJECT(source), false, dm);
1552 } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
1553 handle_bt_pulse_device(PA_OBJECT(source), false, dm);
1555 } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
1556 handle_internal_pulse_device(PA_OBJECT(source), false, dm);
1559 pa_log_debug("Don't care this source");
1567 static pa_hook_result_t sink_source_state_changed_hook_cb(pa_core *c, pa_object *pdevice, pa_device_manager *dm) {
1568 pa_tz_device *device;
1572 pa_object_assert_ref(pdevice);
1575 if (pa_sink_isinstance(pdevice)) {
1576 pa_sink *s = PA_SINK(pdevice);
1577 pa_sink_state_t state = pa_sink_get_state(s);
1578 pa_log_debug("=========== Sink(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
1579 if (s->use_internal_codec && state == PA_SINK_SUSPENDED) {
1580 PA_IDXSET_FOREACH(device, dm->device_list, idx) {
1581 if (pa_tz_device_is_use_internal_codec(device) && pa_tz_device_is_all_suspended(device))
1582 pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_DEACTIVATED);
1585 if ((device = pa_device_manager_get_device_with_sink(s))) {
1586 if (state == PA_SINK_RUNNING)
1587 pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_ACTIVATED);
1588 else if (state == PA_SINK_SUSPENDED)
1589 pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_DEACTIVATED);
1592 } else if (pa_source_isinstance(pdevice)) {
1593 pa_source *s = PA_SOURCE(pdevice);
1594 pa_source_state_t state = pa_source_get_state(s);
1595 pa_log_debug("=========== Source(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
1596 if (s->use_internal_codec && state == PA_SOURCE_SUSPENDED) {
1597 PA_IDXSET_FOREACH(device, dm->device_list, idx) {
1598 if (pa_tz_device_is_use_internal_codec(device) && pa_tz_device_is_all_suspended(device))
1599 pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_DEACTIVATED);
1602 if ((device = pa_device_manager_get_device_with_source(s))) {
1603 if (state == PA_SOURCE_RUNNING)
1604 pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_ACTIVATED);
1605 else if (state == PA_SOURCE_SUSPENDED)
1606 pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_DEACTIVATED);
1610 pa_log_debug("========= sink_source_state_changed_hook_cb END =====");
1616 Build params for load sink or source, and load it.
1619 static void* load_device(pa_core *c, bool is_sink, const char *device_string, const char *device_params) {
1620 const char *args = NULL;
1621 const char *module_name;
1625 uint32_t device_idx;
1626 dm_device_class_t device_class;
1629 pa_assert(device_string);
1630 pa_assert(device_params);
1632 pa_log_info("Load %s Device : String'%s' Param'%s'", is_sink ? "Playback" : "Capture", device_string, device_params);
1634 device_class = device_string_get_class(device_string);
1635 if (device_class <= DM_DEVICE_CLASS_NONE || device_class >= DM_DEVICE_CLASS_MAX) {
1636 pa_log_warn("Invalid device_string '%s'", device_string);
1640 if (!(module_name = device_class_get_module_name(device_class, is_sink))) {
1641 pa_log_error("Get proper module name to load failed");
1644 if (!(args = build_params_to_load_device(device_string, device_params, device_class))) {
1645 pa_log_error("Get proper module name to load failed");
1648 if (!(module = pa_module_load(c, module_name, args))) {
1649 pa_log_error("Load module with name '%s' argu '%s' failed", module_name, args);
1655 PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
1656 if (sink->module == module) {
1661 PA_IDXSET_FOREACH(source, c->sources, device_idx) {
1662 if (source->module == module) {
1671 static int _load_type_devices(struct device_type_info *type_info, bool is_playback, pa_device_manager *dm) {
1672 pa_hashmap *pcm_devices;
1673 pa_idxset *file_infos;
1676 const char *device_string, *params;
1679 pa_assert(type_info);
1681 pa_log_info("Load type devices : %s %s", type_info->type, is_playback ? "playback" : "capture");
1684 pcm_devices = type_info->playback_devices;
1685 file_infos = dm->file_map->playback;
1687 pcm_devices = type_info->capture_devices;
1688 file_infos = dm->file_map->capture;
1691 if (!pcm_devices || !file_infos) {
1692 pa_log_error("No information to load");
1696 PA_HASHMAP_FOREACH_KV(role, device_string, pcm_devices, state) {
1697 params = _file_infos_get_param(file_infos, device_string, role);
1698 if (params == NULL) {
1699 pa_log_error("Failed to get param for %s", device_string);
1702 /* Check duplicate load */
1703 if (is_playback && _core_get_sink(dm->core, device_string, params)) {
1704 pa_log_debug("Already loaded %s %s", device_string, params);
1707 if (!is_playback && _core_get_source(dm->core, device_string, params)) {
1708 pa_log_debug("Already loaded %s %s", device_string, params);
1711 if (!(load_device(dm->core, is_playback, device_string, params))) {
1712 pa_log_warn("load device failed %s %s", device_string, params);
1719 static pa_tz_device* _load_forwarding_device(pa_device_manager *dm) {
1720 pa_tz_device_new_data data;
1721 pa_tz_device *spk_device, *forwarding_device;
1726 pa_log_info("Load forwarding device");
1728 if ((forwarding_device = _device_list_get_device(dm, DEVICE_TYPE_FORWARDING, NULL))) {
1729 pa_log_info("Forwarding device already exists");
1730 return forwarding_device;
1733 if ((spk_device = _device_list_get_device(dm, DEVICE_TYPE_SPEAKER, NULL)) == NULL) {
1734 pa_log_error("Get speaker device failed");
1738 if ((spk_sink = pa_tz_device_get_sink(spk_device, DEVICE_ROLE_NORMAL)) == NULL) {
1739 pa_log_error("Get speaker sink failed");
1743 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
1744 _fill_new_data_basic(&data, DEVICE_TYPE_FORWARDING, DM_DEVICE_DIRECTION_BOTH, true, dm);
1745 pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, spk_sink);
1746 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, spk_sink->monitor_source);
1748 if ((forwarding_device = pa_tz_device_new(&data)) == NULL)
1749 pa_log_error("Failed to create forwarding device");
1751 pa_tz_device_new_data_done(&data);
1753 return forwarding_device;
1757 Handle device connection detected through dbus.
1758 First, update device-status hashmap.
1759 And if correnspondent sink/sources for device_type exist, should make device and notify it.
1760 Use [device_type->roles] mappings in sink/source for find proper sink/source.
1762 static void handle_device_connected(pa_device_manager *dm, const char *type,
1763 const char *name, const char *system_id, device_detected_type_t detected_type) {
1764 struct device_type_info *type_info;
1765 pa_tz_device_new_data data;
1768 pa_assert(dm->device_status);
1769 pa_assert(dm->device_list);
1771 pa_log_info("Device connected, type(%s) name(%s) system_id(%s) detected_type(%d)",
1772 type, pa_strempty(name), pa_strempty(system_id), detected_type);
1774 type_info = _device_manager_get_type_info(dm->type_infos, type);
1776 if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
1777 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, dm->dbus_conn);
1778 _fill_new_data_basic(&data, DEVICE_TYPE_BT_SCO, DM_DEVICE_DIRECTION_BOTH, true, dm);
1779 _fill_new_data_sinks(&data, type_info, dm);
1780 _fill_new_data_sources(&data, type_info, dm);
1781 pa_tz_device_new_data_set_name(&data, name);
1782 pa_tz_device_new_data_set_system_id(&data, system_id);
1783 pa_tz_device_new(&data);
1784 pa_tz_device_new_data_done(&data);
1785 } else if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
1786 dm_device_direction_t direction;
1788 if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P)
1789 direction = DM_DEVICE_DIRECTION_BOTH;
1791 direction = DM_DEVICE_DIRECTION_OUT;
1792 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
1793 _fill_new_data_basic(&data, DEVICE_TYPE_AUDIO_JACK, direction, true, dm);
1794 _fill_new_data_sinks(&data, type_info, dm);
1795 _fill_new_data_sources(&data, type_info, dm);
1797 pa_tz_device_new(&data);
1798 pa_tz_device_new_data_done(&data);
1799 } else if (device_type_is_equal(type, DEVICE_TYPE_HDMI)) {
1800 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
1801 _fill_new_data_basic(&data, DEVICE_TYPE_HDMI, DM_DEVICE_DIRECTION_OUT, true, dm);
1802 _fill_new_data_sinks(&data, type_info, dm);
1804 pa_tz_device_new(&data);
1805 pa_tz_device_new_data_done(&data);
1806 } else if (device_type_is_equal(type, DEVICE_TYPE_FORWARDING)) {
1807 _load_forwarding_device(dm);
1809 dm_device_direction_t direction;
1811 direction = device_type_get_static_direction(type);
1812 if (direction != DM_DEVICE_DIRECTION_NONE) {
1813 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
1814 _fill_new_data_basic(&data, type, direction, true, dm);
1815 if (direction & DM_DEVICE_DIRECTION_OUT)
1816 _fill_new_data_sinks(&data, type_info, dm);
1817 if (direction & DM_DEVICE_DIRECTION_IN)
1818 _fill_new_data_sources(&data, type_info, dm);
1820 pa_tz_device_new(&data);
1821 pa_tz_device_new_data_done(&data);
1823 pa_log_error("Invalid case : not static direction");
1832 Handle device disconnection detected through dbus.
1833 First, update device-status hashmap.
1834 And if there is device which has the device_type, remove it.
1836 static int handle_device_disconnected(pa_device_manager *dm, const char *type, const char *system_id) {
1837 pa_tz_device *device;
1840 pa_assert(dm->device_status);
1842 pa_log_info("Device type(%s) system_id(%s) disconnected",
1843 type, pa_strempty(system_id));
1845 device = _device_list_get_device(dm, type, system_id);
1847 pa_log_error("Disconnection detected but no device for that");
1851 pa_tz_device_free(device);
1856 static int load_builtin_devices(pa_device_manager *dm) {
1857 struct device_type_info *type_info;
1859 device_detected_type_t detected_type = DEVICE_CONNECTED;
1864 pa_log_debug("\n==================== Load Builtin Devices ====================");
1866 PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
1868 type = type_info->type;
1870 pa_log_info("type_info : %s", type);
1871 detected_type = _device_get_detected(dm, type, NULL);
1872 if (detected_type == DEVICE_DISCONNECTED) {
1873 pa_log_info("Not detected yet");
1877 if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
1878 if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P) {
1879 _load_type_devices(type_info, true, dm);
1880 _load_type_devices(type_info, false, dm);
1882 _load_type_devices(type_info, true, dm);
1884 handle_device_connected(dm, type, NULL, NULL, detected_type);
1885 } else if (device_type_is_use_external_card(type) == false) {
1886 dm_device_direction_t direction;
1887 direction = device_type_get_static_direction(type);
1888 if (direction == DM_DEVICE_DIRECTION_NONE) {
1889 pa_log_warn("Wrong direction");
1892 if (direction & DM_DEVICE_DIRECTION_OUT)
1893 _load_type_devices(type_info, true, dm);
1894 if (direction & DM_DEVICE_DIRECTION_IN)
1895 _load_type_devices(type_info, false, dm);
1896 handle_device_connected(dm, type, NULL, NULL, detected_type);
1898 pa_log_warn("Invalid case");
1905 /***************** Parse json file *******************/
1906 static pa_hashmap* parse_device_role_object(json_object *device_role_o) {
1907 pa_hashmap *roles = NULL;
1908 const char *params, *device_role;
1909 struct json_object_iterator it, it_end;
1910 json_object *params_o;
1912 pa_assert(device_role_o);
1913 pa_assert(json_object_is_type(device_role_o, json_type_object));
1915 roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1917 pa_log_debug("hashmap new failed");
1921 it = json_object_iter_begin(device_role_o);
1922 it_end = json_object_iter_end(device_role_o);
1924 while (!json_object_iter_equal(&it, &it_end)) {
1925 device_role = json_object_iter_peek_name(&it);
1926 params_o = json_object_iter_peek_value(&it);
1928 if (!(params = json_object_get_string(params_o))) {
1929 pa_log_debug("There is no device params for role '%s'", device_role);
1931 pa_log_info("- Role '%s' -> '%s'", device_role, params);
1932 if (device_role_is_valid(device_role)) {
1933 if (pa_hashmap_put(roles, (void *)device_role, (void *)params)) {
1934 pa_log_error("put new role to hashmap faild");
1938 pa_log_error("Invalid device role '%s'", device_role);
1941 json_object_iter_next(&it);
1944 if (pa_hashmap_size(roles) == 0) {
1945 pa_log_warn("There is no role for device.. free hashmap");
1946 pa_hashmap_free(roles);
1954 pa_hashmap_free(roles);
1959 static struct device_file_info* parse_device_file_object(json_object *device_file_o, const char **device_string_key) {
1960 pa_hashmap *roles = NULL;
1961 json_object *device_file_prop_o = NULL;
1962 const char *device_string = NULL;
1963 struct device_file_info *file_info = NULL;
1965 pa_assert(device_file_o);
1966 pa_assert(device_string_key);
1967 pa_assert(json_object_is_type(device_file_o, json_type_object));
1969 if (json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_DEVICE_STRING, &device_file_prop_o) && json_object_is_type(device_file_prop_o, json_type_string)) {
1970 if ((device_string = json_object_get_string(device_file_prop_o))) {
1971 pa_log_info("[ Device File - %s ]", device_string);
1973 pa_log_error("Get device-string failed");
1977 pa_log_error("Get device-string object failed");
1981 if (json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_ROLE, &device_file_prop_o)) {
1982 if (!(roles = parse_device_role_object(device_file_prop_o))) {
1983 pa_log_error("Parse device role for '%s' failed", device_string);
1987 pa_log_error("Get device role object failed");
1990 file_info = pa_xmalloc0(sizeof(struct device_file_info));
1991 file_info->device_string = device_string;
1992 file_info->device_types = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1993 file_info->roles = roles;
1995 // *device_string_key = device_string;
2004 static pa_idxset* parse_device_file_array_object(json_object *device_file_array_o) {
2005 int device_file_num, device_file_idx;
2006 struct device_file_info *file_info = NULL;
2007 json_object *device_file_o = NULL;
2008 pa_idxset *device_files = NULL;
2009 const char *device_string = NULL;
2011 pa_assert(device_file_array_o);
2012 pa_assert(json_object_is_type(device_file_array_o, json_type_array));
2014 device_files = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2016 device_file_num = json_object_array_length(device_file_array_o);
2017 for (device_file_idx = 0; device_file_idx < device_file_num; device_file_idx++) {
2018 if ((device_file_o = json_object_array_get_idx(device_file_array_o, device_file_idx)) && json_object_is_type(device_file_o, json_type_object)) {
2019 if ((file_info = parse_device_file_object(device_file_o, &device_string))) {
2020 pa_idxset_put(device_files, file_info, NULL);
2022 pa_log_error("parse device file object failed");
2026 pa_log_error("Get device file object failed");
2031 if (pa_idxset_size(device_files) == 0) {
2032 pa_idxset_free(device_files, NULL);
2033 device_files = NULL;
2036 return device_files;
2040 pa_xfree(device_files);
2044 static struct device_file_map *parse_device_file_map() {
2045 struct device_file_map *file_map = NULL;
2046 json_object *o, *device_files_o;
2047 json_object *playback_devices_o = NULL, *capture_devices_o = NULL;
2049 pa_log_info("\nParse device files");
2051 o = json_object_from_file(DEVICE_MAP_FILE);
2054 pa_log_error("Read device-map file failed");
2058 file_map = pa_xmalloc0(sizeof(struct device_file_map));
2060 if (json_object_object_get_ex(o, DEVICE_FILE_OBJECT, &device_files_o) && json_object_is_type(device_files_o, json_type_object)) {
2061 if (json_object_object_get_ex(device_files_o, DEVICE_TYPE_PROP_PLAYBACK_DEVICES, &playback_devices_o)) {
2062 pa_log_info("Playback Device Files");
2063 file_map->playback = parse_device_file_array_object(playback_devices_o);
2065 if (json_object_object_get_ex(device_files_o, DEVICE_TYPE_PROP_CAPTURE_DEVICES, &capture_devices_o)) {
2066 pa_log_info("Capture Device Files");
2067 file_map->capture = parse_device_file_array_object(capture_devices_o);
2070 pa_log_error("Get device files object failed");
2078 static pa_hashmap* parse_device_role_map(json_object *device_role_map_o) {
2079 pa_hashmap *roles = NULL;
2080 const char *device_string, *device_role;
2081 struct json_object_iterator it, it_end;
2082 json_object *device_string_o;
2084 pa_assert(device_role_map_o);
2085 pa_assert(json_object_is_type(device_role_map_o, json_type_object));
2087 roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2089 it = json_object_iter_begin(device_role_map_o);
2090 it_end = json_object_iter_end(device_role_map_o);
2092 while (!json_object_iter_equal(&it, &it_end)) {
2093 device_role = json_object_iter_peek_name(&it);
2094 device_string_o = json_object_iter_peek_value(&it);
2096 if (!(device_string = json_object_get_string(device_string_o))) {
2097 pa_log_debug("There is no device string for role '%s'", device_role);
2099 pa_log_info("- Role '%s' -> '%s'", device_role, device_string);
2100 if (device_role_is_valid(device_role)) {
2101 if (pa_hashmap_put(roles, (void *)device_role, (void *)device_string)) {
2102 pa_log_error("put new role to hashmap faild");
2106 pa_log_error("Invalid device role '%s'", device_role);
2110 json_object_iter_next(&it);
2124 static pa_idxset* parse_device_type_infos() {
2125 json_object *o, *device_array_o = NULL;
2126 int device_type_num = 0;
2127 int device_type_idx = 0;
2128 struct device_type_info *type_info = NULL;
2129 //pa_hashmap *type_infos = NULL;
2130 pa_idxset *type_infos = NULL;
2132 o = json_object_from_file(DEVICE_MAP_FILE);
2134 pa_log_error("Read device-map file failed");
2138 pa_log_info("\nParse device types");
2139 type_infos = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2141 if (json_object_object_get_ex(o, DEVICE_TYPE_OBJECT, &device_array_o) && json_object_is_type(device_array_o, json_type_array)) {
2142 device_type_num = json_object_array_length(device_array_o);
2143 for (device_type_idx = 0; device_type_idx < device_type_num ; device_type_idx++) {
2144 json_object *device_o;
2146 if ((device_o = json_object_array_get_idx(device_array_o, device_type_idx)) && json_object_is_type(device_o, json_type_object)) {
2147 json_object *device_prop_o;
2148 const char *type = NULL;
2149 type_info = pa_xmalloc0(sizeof(struct device_type_info));
2151 if (json_object_object_get_ex(device_o, DEVICE_TYPE_PROP_DEVICE_TYPE, &device_prop_o) && json_object_is_type(device_prop_o, json_type_string)) {
2152 type = json_object_get_string(device_prop_o);
2153 pa_log_info("[ Device - %s ]", type);
2154 type_info->type = type;
2156 pa_log_error("Get device type failed");
2160 if (json_object_object_get_ex(device_o, DEVICE_TYPE_PROP_PLAYBACK_DEVICES, &device_prop_o) && json_object_is_type(device_prop_o, json_type_object)) {
2161 pa_log_info("Playback Devices");
2162 type_info->playback_devices = parse_device_role_map(device_prop_o);
2165 if (json_object_object_get_ex(device_o, DEVICE_TYPE_PROP_CAPTURE_DEVICES, &device_prop_o) && json_object_is_type(device_prop_o, json_type_object)) {
2166 pa_log_info("Capture Devices");
2167 type_info->capture_devices = parse_device_role_map(device_prop_o);
2169 pa_idxset_put(type_infos, type_info, NULL);
2172 pa_log_debug("Get device type object failed");
2176 pa_log_debug("Get device type array object failed");
2182 pa_xfree(type_infos);
2188 look detected status which is external value, make conversion to internal consistent value, and handle it
2189 device_type, which type of device is detected
2190 system_id : system_id among same device types for support multi-device
2192 static int handle_device_status_changed(pa_device_manager *dm, const char *type,
2193 const char *name, const char *system_id, device_detected_type_t detected) {
2195 pa_assert(device_type_is_valid(type));
2197 pa_log_info("Device Status Changed, type(%s) system_id(%s), detected_type(%d)",
2198 type, pa_strempty(system_id), detected);
2200 if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2201 _device_set_detected(dm, type, name, system_id, detected);
2202 if (detected == DEVICE_DISCONNECTED)
2203 handle_device_disconnected(dm, type, system_id);
2205 handle_device_connected(dm, type, name, system_id, detected);
2206 } else if (device_type_is_need_detect(type)) {
2207 _device_set_detected(dm, type, name, system_id, detected);
2208 if (detected == DEVICE_DISCONNECTED)
2209 handle_device_disconnected(dm, type, system_id);
2211 handle_device_connected(dm, type, name, system_id, detected);
2213 pa_log_debug("No need to detect type %s", type);
2220 Initialize device-status idxset.
2221 This is for device-status detected through dbus.
2222 So, if device_type is not detected through dbus, let's initialize them to detected. (ex. spk, rcv,...)
2223 If not, initialize to not detected.
2225 static void device_type_status_init(pa_device_manager *manager) {
2226 struct device_type_info *type_info;
2231 pa_assert(manager->type_infos);
2233 pa_log_debug("\n==================== Init Device Status ====================");
2235 PA_IDXSET_FOREACH(type_info, manager->type_infos, type_idx) {
2236 type = type_info->type;
2237 if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
2238 int earjack_status = 0;
2239 if (vconf_get_int(VCONFKEY_SYSMAN_EARJACK, &earjack_status) < 0) {
2240 pa_log_error("Get earjack status failed");
2243 if (earjack_status == EARJACK_TYPE_SPK_ONLY)
2244 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_3P);
2245 else if (earjack_status == EARJACK_TYPE_SPK_WITH_MIC)
2246 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_4P);
2247 else if (earjack_status == EARJACK_DISCONNECTED)
2248 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2250 pa_log_warn("Unknown earjack status : %d", earjack_status);
2251 } else if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2252 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2253 } else if (device_type_is_equal(type, DEVICE_TYPE_HDMI)) {
2254 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2255 } else if (device_type_is_equal(type, DEVICE_TYPE_FORWARDING)) {
2256 int miracast_wfd_status = 0;
2257 if (vconf_get_bool(VCONFKEY_MIRACAST_WFD_SOURCE_STATUS, &miracast_wfd_status) < 0) {
2258 pa_log_error("Get mirroring status failed");
2261 if (miracast_wfd_status == FORWARDING_CONNECTED)
2262 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
2264 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
2272 static int _translate_external_value(const char *type, int value, device_detected_type_t *detected) {
2274 if (!type || !detected) {
2275 pa_log_error("Invalid Parameter for translate");
2279 if (device_type_is_equal(DEVICE_TYPE_AUDIO_JACK, type)) {
2280 if (value == EARJACK_DISCONNECTED)
2281 *detected = DEVICE_DISCONNECTED;
2282 else if (value == EARJACK_TYPE_SPK_ONLY)
2283 *detected = DEVICE_CONNECTED_AUDIO_JACK_3P;
2284 else if (value == EARJACK_TYPE_SPK_WITH_MIC)
2285 *detected = DEVICE_CONNECTED_AUDIO_JACK_4P;
2288 } else if (device_type_is_equal(DEVICE_TYPE_HDMI, type)) {
2289 if (value == HDMI_AUDIO_DISCONNECTED)
2290 *detected = DEVICE_DISCONNECTED;
2291 else if (value == HDMI_AUDIO_AVAILABLE)
2292 *detected = DEVICE_CONNECTED;
2295 } else if (device_type_is_equal(DEVICE_TYPE_FORWARDING, type)) {
2296 if (value == FORWARDING_DISCONNECTED)
2297 *detected = DEVICE_DISCONNECTED;
2298 else if (value == FORWARDING_CONNECTED)
2299 *detected = DEVICE_CONNECTED;
2302 } else if (device_type_is_equal(DEVICE_TYPE_BT_SCO, type)) {
2303 if (value == BT_SCO_DISCONNECTED)
2304 *detected = DEVICE_DISCONNECTED;
2305 else if (value == BT_SCO_CONNECTED)
2306 *detected = DEVICE_CONNECTED_SCO;
2314 static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
2317 pa_device_manager *dm = (pa_device_manager *) userdata;
2318 device_detected_type_t detected;
2320 pa_assert(userdata);
2322 if (dbus_message_get_type(s) != DBUS_MESSAGE_TYPE_SIGNAL)
2323 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2325 pa_log_info("Device detect handler : Path(%s) Intf(%s) Member(%s) Signature(%s)",
2326 dbus_message_get_path(s), dbus_message_get_interface(s), dbus_message_get_member(s), dbus_message_get_signature(s));
2328 dbus_error_init(&error);
2330 if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedEarjack")) {
2331 if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2334 if (_translate_external_value(DEVICE_TYPE_AUDIO_JACK, status, &detected) < 0) {
2335 pa_log_warn("failed to translate audio-jack detected value");
2338 handle_device_status_changed(dm, DEVICE_TYPE_AUDIO_JACK, NULL, NULL, detected);
2340 } else if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedHDMIAudio")) {
2341 if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2344 if (_translate_external_value(DEVICE_TYPE_HDMI, status, &detected) < 0) {
2345 pa_log_warn("failed to translate HDMI detected value");
2348 handle_device_status_changed(dm, DEVICE_TYPE_HDMI, NULL, NULL, detected);
2350 } else if (dbus_message_is_signal(s, DBUS_INTERFACE_MIRRORING_SERVER, "miracast_wfd_source_status_changed")) {
2351 if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2354 if (_translate_external_value(DEVICE_TYPE_FORWARDING, status, &detected) < 0) {
2355 pa_log_warn("failed to translate forwarding detected value");
2358 handle_device_status_changed(dm, DEVICE_TYPE_FORWARDING, NULL, NULL, detected);
2360 } else if (dbus_message_is_signal(s, DBUS_INTERFACE_BLUEZ_HEADSET, "PropertyChanged")) {
2361 DBusMessageIter msg_iter, variant_iter;
2362 char *property_name;
2364 pa_log_debug("Got %s PropertyChanged signal", DBUS_INTERFACE_BLUEZ_HEADSET);
2365 dbus_message_iter_init(s, &msg_iter);
2366 if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_STRING) {
2367 pa_log_error("Property name not string");
2370 dbus_message_iter_get_basic(&msg_iter, &property_name);
2371 pa_log_info("Changed Property name : %s", property_name);
2373 if (!dbus_message_iter_next(&msg_iter)) {
2374 pa_log_debug("Property value missing");
2378 if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_VARIANT) {
2379 pa_log_debug("Property value not a variant.");
2383 dbus_message_iter_recurse(&msg_iter, &variant_iter);
2385 if (DBUS_TYPE_BOOLEAN == dbus_message_iter_get_arg_type(&variant_iter)) {
2388 dbus_message_iter_get_basic(&variant_iter, &value);
2389 if (pa_streq(property_name, "Connected")) {
2390 pa_log_info("HFP Connection : %d", value);
2392 method_call_bt_get_name(c, dbus_message_get_path(s), &name);
2393 status = BT_SCO_CONNECTED;
2395 status = BT_SCO_DISCONNECTED;
2397 if (_translate_external_value(DEVICE_TYPE_BT_SCO, status, &detected) < 0) {
2398 pa_log_warn("failed to translate bt-sco detected value");
2401 handle_device_status_changed(dm, DEVICE_TYPE_BT_SCO,
2402 name, dbus_message_get_path(s), detected);
2406 pa_log_debug("Unknown message, not handle it");
2407 dbus_error_free(&error);
2408 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2411 pa_log_debug("Dbus Message handled");
2413 dbus_error_free(&error);
2414 return DBUS_HANDLER_RESULT_HANDLED;
2417 pa_log_error("Fail to handle dbus signal");
2418 dbus_error_free(&error);
2419 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2422 static int watch_signals(pa_device_manager *dm) {
2426 pa_assert(dm->dbus_conn);
2428 dbus_error_init(&error);
2430 pa_log_info("Watch Dbus signals");
2432 if (!dbus_connection_add_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm, NULL)) {
2433 pa_log_error("Unable to add D-Bus filter : %s: %s", error.name, error.message);
2437 if (pa_dbus_add_matches(pa_dbus_connection_get(dm->dbus_conn), &error, FILTER_DEVICED_SYSNOTI, FILTER_SOUND_SERVER, FILTER_BLUEZ, FILTER_MIRRORING, NULL) < 0) {
2438 pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
2444 dbus_error_free(&error);
2448 static void unwatch_signals(pa_device_manager *dm) {
2449 pa_log_info("Unwatch Dbus signals");
2452 pa_assert(dm->dbus_conn);
2454 pa_dbus_remove_matches(pa_dbus_connection_get(dm->dbus_conn), FILTER_DEVICED_SYSNOTI, FILTER_SOUND_SERVER, FILTER_BLUEZ, FILTER_MIRRORING, NULL);
2455 dbus_connection_remove_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm);
2458 static void send_device_connection_changed_signal(uint32_t event_id, pa_tz_device *device, bool connected, pa_device_manager *dm) {
2459 DBusMessage *signal_msg;
2460 DBusMessageIter msg_iter, device_iter;
2461 dbus_bool_t _connected = connected;
2462 dm_device_state_t compound_state;
2463 dbus_int32_t device_id, direction;
2469 pa_log_info("Send device connection changed signal, event_id(%u)", event_id);
2471 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceConnected"));
2472 dbus_message_iter_init_append(signal_msg, &msg_iter);
2473 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &event_id);
2474 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2476 direction = (dbus_int32_t) pa_tz_device_get_direction(device);
2477 type = pa_tz_device_get_type(device);
2478 name = pa_tz_device_get_name(device);
2479 device_id = (dbus_int32_t) pa_tz_device_get_id(device);
2480 compound_state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
2482 simple_device_dump(PA_LOG_INFO, connected ? "[Connected]" : "[Disconnected]", device_id, type, name, direction, compound_state);
2484 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2485 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
2486 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
2487 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
2488 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
2489 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &device_iter));
2490 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &_connected);
2492 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2494 dbus_message_unref(signal_msg);
2497 static void send_device_info_changed_signal(uint32_t event_id, pa_tz_device *device, int changed_type, pa_device_manager *dm) {
2498 DBusMessage *signal_msg;
2499 DBusMessageIter msg_iter, device_iter;
2500 dm_device_state_t compound_state;
2501 dbus_int32_t device_id, direction;
2503 const char *changed_prefix[] = {"[State Changed]", "[Direction Changed]", "[Avail-Mode Changed]"};
2508 pa_log_debug("Send device info changed signal, event_id(%u)", event_id);
2510 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceInfoChanged"));
2511 dbus_message_iter_init_append(signal_msg, &msg_iter);
2512 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &event_id);
2513 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2515 direction = (dbus_int32_t) pa_tz_device_get_direction(device);
2516 type = pa_tz_device_get_type(device);
2517 name = pa_tz_device_get_name(device);
2518 device_id = (dbus_int32_t) pa_tz_device_get_id(device);
2519 compound_state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
2521 simple_device_dump(PA_LOG_DEBUG, changed_prefix[changed_type], device_id, type, name, direction, compound_state);
2523 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2524 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
2525 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
2526 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
2527 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
2528 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &device_iter));
2529 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &changed_type);
2531 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2533 dbus_message_unref(signal_msg);
2536 static void send_device_state_changed_signal(uint32_t event_id, pa_tz_device *device, bool activated, pa_device_manager *dm) {
2537 DBusMessage *signal_msg;
2538 DBusMessageIter msg_iter, device_iter;
2539 dm_device_state_t compound_state;
2540 dbus_int32_t device_id, direction;
2546 pa_log_debug("Send device state changed signal, event_id(%u)", event_id);
2548 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceStateChanged"));
2549 dbus_message_iter_init_append(signal_msg, &msg_iter);
2550 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &event_id);
2551 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2553 direction = (dbus_int32_t) pa_tz_device_get_direction(device);
2554 type = pa_tz_device_get_type(device);
2555 name = pa_tz_device_get_name(device);
2556 device_id = (dbus_int32_t) pa_tz_device_get_id(device);
2557 compound_state = activated ? DM_DEVICE_STATE_ACTIVATED : DM_DEVICE_STATE_DEACTIVATED;
2559 simple_device_dump(PA_LOG_DEBUG, "[State Changed]", device_id, type, name, direction, compound_state);
2561 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2562 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
2563 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
2564 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
2565 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
2566 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &device_iter));
2568 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2570 dbus_message_unref(signal_msg);
2573 static bool device_is_match_direction(pa_tz_device *device, int direction_mask) {
2574 dm_device_direction_t direction;
2576 if (direction_mask == DEVICE_IO_DIRECTION_FLAGS || direction_mask == 0)
2579 direction = pa_tz_device_get_direction(device);
2581 if ((direction_mask & DEVICE_IO_DIRECTION_IN_FLAG) && (direction & DM_DEVICE_DIRECTION_IN))
2583 if ((direction_mask & DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & DM_DEVICE_DIRECTION_OUT))
2585 if ((direction_mask & DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction & DM_DEVICE_DIRECTION_BOTH))
2591 static bool device_is_match_state(pa_tz_device *device, int state_mask) {
2592 dm_device_state_t state;
2594 if (state_mask == DEVICE_STATE_FLAGS || state_mask == 0)
2597 state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
2599 if ((state_mask & DEVICE_STATE_DEACTIVATED_FLAG) && (state == DM_DEVICE_STATE_DEACTIVATED))
2601 if ((state_mask & DEVICE_STATE_ACTIVATED_FLAG) && (state == DM_DEVICE_STATE_ACTIVATED))
2607 static bool device_is_match_type(pa_tz_device *device, int type_mask) {
2611 if (type_mask == DEVICE_TYPE_FLAGS || type_mask == 0)
2614 type = pa_tz_device_get_type(device);
2615 is_builtin = device_type_is_builtin(type);
2617 if ((type_mask & DEVICE_TYPE_INTERNAL_FLAG) && is_builtin)
2619 if ((type_mask & DEVICE_TYPE_EXTERNAL_FLAG) && !is_builtin)
2625 static bool device_is_match_with_mask(pa_tz_device *device, int mask) {
2628 if (mask == DEVICE_ALL_FLAG)
2631 return (device_is_match_direction(device, mask & DEVICE_IO_DIRECTION_FLAGS) &&
2632 device_is_match_state(device, mask & DEVICE_STATE_FLAGS) &&
2633 device_is_match_type(device, mask & DEVICE_TYPE_FLAGS));
2636 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name) {
2637 const char *intf = DBUS_INTERFACE_BLUEZ_DEVICE, *prop = "Alias";
2638 DBusMessage *msg, *reply;
2639 DBusMessageIter reply_iter, variant_iter;
2643 pa_assert(device_path);
2646 if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_BLUEZ, device_path, "org.freedesktop.DBus.Properties", "Get"))) {
2647 pa_log_error("dbus method call failed");
2651 dbus_message_append_args(msg,
2652 DBUS_TYPE_STRING, &intf,
2653 DBUS_TYPE_STRING, &prop,
2656 dbus_error_init(&err);
2657 if (!(reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err))) {
2658 pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_BLUEZ_DEVICE, "Get", err.message);
2659 dbus_error_free(&err);
2663 dbus_message_iter_init(reply, &reply_iter);
2665 if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_VARIANT) {
2666 pa_log_error("Cannot get reply argument");
2670 dbus_message_iter_recurse(&reply_iter, &variant_iter);
2672 if (dbus_message_iter_get_arg_type(&variant_iter) == DBUS_TYPE_STRING) {
2673 dbus_message_iter_get_basic(&variant_iter, name);
2676 dbus_message_unref(reply);
2681 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2682 pa_device_manager *dm;
2683 DBusMessage *reply = NULL;
2684 DBusMessageIter msg_iter, array_iter, device_iter;
2685 pa_tz_device *device;
2686 dm_device_state_t compound_state;
2687 uint32_t device_idx;
2688 dbus_int32_t device_id, direction;
2694 pa_assert(userdata);
2697 dm = (pa_device_manager*) userdata;
2699 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2701 pa_assert_se(dbus_message_get_args(msg, NULL,
2702 DBUS_TYPE_INT32, &mask,
2703 DBUS_TYPE_INVALID));
2705 pa_log_info("Get connected device list (mask : %d)", mask);
2707 dbus_message_iter_init_append(reply, &msg_iter);
2708 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiis)", &array_iter));
2710 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
2711 compound_state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
2712 direction = pa_tz_device_get_direction(device);
2713 type = pa_tz_device_get_type(device);
2714 name = pa_tz_device_get_name(device);
2715 if (device_is_match_with_mask(device, mask)) {
2716 device_id = (dbus_int32_t)pa_tz_device_get_id(device);
2718 simple_device_dump(PA_LOG_INFO, "[MATCH]", device_id, type, name, direction, compound_state);
2719 pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2720 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2721 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
2722 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
2723 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
2724 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
2725 pa_assert_se(dbus_message_iter_close_container(&array_iter, &device_iter));
2727 simple_device_dump(PA_LOG_INFO, "[UNMATCH]", device_id, type, name, direction, compound_state);
2731 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
2733 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2734 dbus_message_unref(reply);
2738 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2739 pa_device_manager *dm;
2740 DBusMessage *reply = NULL;
2741 pa_tz_device *device;
2742 dbus_bool_t is_bt_on = false;
2743 const char *bt_name = "none";
2747 pa_assert(userdata);
2749 pa_log_info("Get BT A2DP list");
2751 dm = (pa_device_manager*) userdata;
2753 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2755 /* FIXME : Give system_id for multi device */
2756 if ((device = _device_list_get_device(dm, DEVICE_TYPE_BT_A2DP, NULL)) != NULL) {
2758 bt_name = pa_tz_device_get_name(device);
2761 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_bt_on,
2762 DBUS_TYPE_STRING, &bt_name,
2763 DBUS_TYPE_INVALID));
2765 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2766 dbus_message_unref(reply);
2771 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2772 pa_device_manager *dm;
2774 DBusMessage *reply = NULL;
2776 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2777 dm = (pa_device_manager *) userdata;
2778 pa_assert_se(dbus_message_get_args(msg, NULL,
2779 DBUS_TYPE_STRING, &type,
2780 DBUS_TYPE_STRING, &role,
2781 DBUS_TYPE_INVALID));
2783 pa_device_manager_load_sink(dm, type, role);
2784 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2785 dbus_message_unref(reply);
2788 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2789 pa_device_manager *dm = (pa_device_manager *)userdata;
2791 dbus_int32_t status;
2792 DBusMessage *reply = NULL;
2795 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2797 dbus_error_init(&error);
2798 if (!dbus_message_get_args(msg, NULL,
2799 DBUS_TYPE_STRING, &type,
2800 DBUS_TYPE_INT32, &status,
2801 DBUS_TYPE_INVALID)) {
2802 pa_log_error("failed to get dbus args : %s", error.message);
2803 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
2804 dbus_error_free(&error);
2807 pa_log_debug("handle_test_device_status_change, type:%s, status:%d", type, status);
2809 handle_device_status_changed(dm, type, NULL, NULL, status);
2810 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2811 dbus_message_unref(reply);
2814 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2815 const char *xml = DEVICE_MANAGER_INTROSPECT_XML;
2816 DBusMessage *r = NULL;
2820 pa_assert(userdata);
2822 pa_assert_se(r = dbus_message_new_method_return(msg));
2823 pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
2826 pa_assert_se(dbus_connection_send((conn), r, NULL));
2827 dbus_message_unref(r);
2830 return DBUS_HANDLER_RESULT_HANDLED;
2833 static DBusHandlerResult handle_device_manager_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2838 pa_assert(userdata);
2840 for (method_idx = 0; method_idx < METHOD_HANDLER_MAX; method_idx++) {
2841 if (dbus_message_is_method_call(msg, DBUS_INTERFACE_DEVICE_MANAGER, method_handlers[method_idx].method_name)) {
2842 method_handlers[method_idx].receive_cb(conn, msg, userdata);
2843 return DBUS_HANDLER_RESULT_HANDLED;
2847 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2850 static DBusHandlerResult method_call_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
2851 struct userdata *u = userdata;
2852 const char *path, *interface, *member;
2858 path = dbus_message_get_path(m);
2859 interface = dbus_message_get_interface(m);
2860 member = dbus_message_get_member(m);
2862 pa_log_info("DeviceManager Method Call Handler : path=%s, interface=%s, member=%s", path, interface, member);
2864 if (!pa_streq(path, DBUS_OBJECT_DEVICE_MANAGER))
2865 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2867 if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2868 return handle_introspect(c, m, u);
2870 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get")) {
2871 return handle_get_property(c, m, u);
2872 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set")) {
2873 return handle_set_property(c, m, u);
2874 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll")) {
2875 return handle_get_all_property(c, m, u);
2878 return handle_device_manager_methods(c, m, u);
2881 return DBUS_HANDLER_RESULT_HANDLED;
2884 static void endpoint_init(pa_device_manager *dm) {
2885 static const DBusObjectPathVTable vtable_endpoint = {
2886 .message_function = method_call_handler,
2889 pa_log_info("Device manager dbus endpoint init");
2891 if (dm && dm->dbus_conn) {
2892 if (!dbus_connection_register_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER, &vtable_endpoint, dm))
2893 pa_log_error("Failed to register object path");
2895 pa_log_error("Cannot get dbus connection to register object path");
2899 static void endpoint_done(pa_device_manager *dm) {
2900 pa_log_info("Device manager dbus endpoint done");
2901 if (dm && dm->dbus_conn) {
2902 if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER))
2903 pa_log_error("Failed to unregister object path");
2905 pa_log_error("Cannot get dbus connection to unregister object path");
2909 static void dbus_init(pa_device_manager *dm) {
2911 pa_dbus_connection *connection = NULL;
2914 pa_log_info("Dbus init");
2915 dbus_error_init(&error);
2917 if (!(connection = pa_dbus_bus_get(dm->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
2919 pa_dbus_connection_unref(connection);
2921 pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
2924 pa_log_info("Got dbus connection");
2927 dm->dbus_conn = connection;
2929 if (watch_signals(dm) < 0)
2930 pa_log_error("dbus watch signals failed");
2932 pa_log_debug("dbus ready to get signals");
2937 dbus_error_free(&error);
2940 static void dbus_deinit(pa_device_manager *dm) {
2943 pa_log_info("Dbus deinit");
2946 unwatch_signals(dm);
2948 if (dm->dbus_conn) {
2949 pa_dbus_connection_unref(dm->dbus_conn);
2950 dm->dbus_conn = NULL;
2955 pa_idxset* pa_device_manager_get_device_list(pa_device_manager *dm) {
2957 pa_assert(dm->device_list);
2959 return dm->device_list;
2962 pa_tz_device* pa_device_manager_get_device(pa_device_manager *dm, const char *type) {
2965 return _device_list_get_device(dm, type, NULL);
2968 pa_tz_device* pa_device_manager_get_device_by_id(pa_device_manager *dm, uint32_t id) {
2971 return _device_list_get_device_with_id(dm, id);
2974 pa_tz_device* pa_device_manager_get_device_with_sink(pa_sink *sink) {
2977 return sink->device_item;
2980 pa_tz_device* pa_device_manager_get_device_with_source(pa_source *source) {
2983 return source->device_item;
2986 pa_tz_device* pa_device_manager_load_forwarding(pa_device_manager *dm) {
2987 return _load_forwarding_device(dm);
2990 void pa_device_manager_unload_forwarding(pa_device_manager *dm) {
2991 pa_tz_device *forwarding_device;
2993 forwarding_device = _device_list_get_device(dm, DEVICE_TYPE_FORWARDING, NULL);
2994 if (forwarding_device)
2995 pa_tz_device_free(forwarding_device);
2997 pa_log_warn("There is no forwarding device");
3000 int pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const char *role) {
3001 const char *device_string, *params;
3002 struct device_type_info *type_info;
3003 struct device_file_info *file_info;
3004 pa_tz_device *device;
3006 uint32_t device_idx;
3009 pa_assert(dm->device_list);
3011 pa_log_info("Load Sink for '%s.%s'", type, role);
3012 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3013 if (pa_streq(type, pa_tz_device_get_type(device))) {
3014 if (pa_tz_device_get_sink(device, role) == NULL) {
3015 pa_log_warn("Proper sink for '%s.%s' already loaded", type, role);
3021 if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3022 pa_log_error("No type map for %s", type);
3026 if (type_info->playback_devices == NULL) {
3027 pa_log_error("No playback devices for %s", type_info->type);
3031 if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
3032 pa_log_error("No device-string for '%s.%s'", type, role);
3036 if (!(file_info = _device_manager_get_file_info(dm->file_map->playback, device_string))) {
3037 pa_log_error("No playback file-map for '%s'", device_string);
3041 if (!(params = pa_hashmap_get(file_info->roles, role))) {
3042 pa_log_error("No params for '%s,%s'", device_string, role);
3046 if ((sink = load_device(dm->core, PA_DEVICE_TYPE_SINK, device_string, params))) {
3047 pa_log_debug("loaded sink '%s' for '%s,%s' success", sink->name, type, role);
3049 pa_log_warn("Cannot load playback device with '%s,%s'", device_string, params);
3059 int pa_device_manager_load_source(pa_device_manager *dm, const char *type, const char *role) {
3060 const char *device_string, *params;
3061 struct device_type_info *type_info;
3062 struct device_file_info *file_info;
3063 pa_tz_device *device;
3065 uint32_t device_idx;
3069 pa_log_info("Load Source for '%s.%s'", type, role);
3071 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3072 if (pa_streq(type, pa_tz_device_get_type(device))) {
3073 if (pa_tz_device_get_source(device, role) == NULL) {
3074 pa_log_warn("Proper source for '%s.%s' already loaded", type, role);
3080 if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3081 pa_log_error("No type map for %s", type);
3085 if (type_info->capture_devices == NULL) {
3086 pa_log_error("No capture devices for %s", type_info->type);
3090 if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
3091 pa_log_error("No device-string for '%s.%s'", type, role);
3095 if (!(file_info = _device_manager_get_file_info(dm->file_map->capture, device_string))) {
3096 pa_log_error("No capture file-map for '%s'", device_string);
3100 if (!(params = pa_hashmap_get(file_info->roles, role))) {
3101 pa_log_error("No params for '%s,%s'", device_string, role);
3105 if ((source = load_device(dm->core, PA_DEVICE_TYPE_SOURCE, device_string, params))) {
3106 pa_log_debug("loaded source '%s' for '%s,%s' success", source->name, type, role);
3108 pa_log_warn("Cannot load capture device with '%s,%s'", device_string, params);
3118 static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_device_hook_data_for_conn_changed *data, pa_device_manager *dm) {
3119 send_device_connection_changed_signal(data->event_id, data->device, data->is_connected, dm);
3123 static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_tz_device_hook_data_for_state_changed *data, pa_device_manager *dm) {
3124 send_device_info_changed_signal(data->event_id, data->device, DM_DEVICE_CHANGED_INFO_STATE, dm);
3125 send_device_state_changed_signal(data->event_id, data->device, data->activated, dm);
3129 pa_device_manager* pa_device_manager_get(pa_core *c) {
3130 pa_device_manager *dm;
3134 pa_log_info("pa_device_manager_get");
3136 if ((dm = pa_shared_get(c, SHARED_DEVICE_MANAGER)))
3137 return pa_device_manager_ref(dm);
3139 dm = pa_xnew0(pa_device_manager, 1);
3142 dm->device_list = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3143 dm->device_status = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3147 dm->sink_put_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) sink_put_hook_callback, dm);
3148 dm->sink_state_changed_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_source_state_changed_hook_cb, dm);
3149 dm->sink_unlink_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) sink_unlink_hook_callback, dm);
3150 dm->source_put_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) source_put_hook_callback, dm);
3151 dm->source_state_changed_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_source_state_changed_hook_cb, dm);
3152 dm->source_unlink_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) source_unlink_hook_callback, dm);
3153 dm->comm = pa_communicator_get(dm->core);
3154 dm->comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
3155 PA_HOOK_EARLY, (pa_hook_cb_t)device_connection_changed_hook_cb, dm);
3156 dm->comm_hook_device_state_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_STATE_CHANGED),
3157 PA_HOOK_EARLY, (pa_hook_cb_t)device_state_changed_hook_cb, dm);
3158 if (!(dm->type_infos = parse_device_type_infos())) {
3159 pa_log_error("Parse device-type-map failed");
3163 if (!(dm->file_map = parse_device_file_map())) {
3164 pa_log_error("Parse device-file-map failed");
3168 device_type_status_init(dm);
3170 if (load_builtin_devices(dm) != 0) {
3171 pa_log_error("Load Builtin Devices faled");
3175 /* Just for convenience when test*/
3176 if (!_device_manager_set_default_sink(dm, DEVICE_TYPE_SPEAKER, "normal")) {
3177 pa_log_warn("Set default sink with speaker(normal) failed");
3179 if (!_device_manager_set_default_source(dm, DEVICE_TYPE_MIC, "normal")) {
3180 pa_log_warn("Set default source with mic(normal) failed");
3183 pa_shared_set(c, SHARED_DEVICE_MANAGER, dm);
3188 pa_device_manager* pa_device_manager_ref(pa_device_manager *dm) {
3190 pa_assert(PA_REFCNT_VALUE(dm) > 0);
3192 pa_log_info("pa_device_manager_ref");
3198 void pa_device_manager_unref(pa_device_manager *dm) {
3200 pa_assert(PA_REFCNT_VALUE(dm) > 0);
3202 pa_log_info("pa_device_manager_unref");
3203 if (PA_REFCNT_DEC(dm) > 0)
3206 if (dm->comm_hook_device_connection_changed_slot)
3207 pa_hook_slot_free(dm->comm_hook_device_connection_changed_slot);
3208 if (dm->comm_hook_device_state_changed_slot)
3209 pa_hook_slot_free(dm->comm_hook_device_state_changed_slot);
3210 if (dm->sink_put_hook_slot)
3211 pa_hook_slot_free(dm->sink_put_hook_slot);
3212 if (dm->sink_state_changed_slot)
3213 pa_hook_slot_free(dm->sink_state_changed_slot);
3214 if (dm->sink_unlink_hook_slot)
3215 pa_hook_slot_free(dm->sink_unlink_hook_slot);
3216 if (dm->source_put_hook_slot)
3217 pa_hook_slot_free(dm->source_put_hook_slot);
3218 if (dm->source_state_changed_slot)
3219 pa_hook_slot_free(dm->source_state_changed_slot);
3220 if (dm->source_unlink_hook_slot)
3221 pa_hook_slot_free(dm->source_unlink_hook_slot);
3224 pa_communicator_unref(dm->comm);
3227 pa_idxset_free(dm->type_infos, (pa_free_cb_t)type_info_free_func);
3229 if (dm->file_map->playback)
3230 pa_idxset_free(dm->file_map->playback, (pa_free_cb_t)file_info_free_func);
3231 if (dm->file_map->capture)
3232 pa_idxset_free(dm->file_map->capture, (pa_free_cb_t)file_info_free_func);
3233 pa_xfree(dm->file_map);
3235 if (dm->device_list)
3236 pa_idxset_free(dm->device_list, (pa_free_cb_t)pa_tz_device_free);
3237 if (dm->device_status)
3238 pa_idxset_free(dm->device_status, NULL);
3244 pa_shared_remove(dm->core, SHARED_DEVICE_MANAGER);