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 "hal-interface.h"
53 #include "stream-manager.h"
54 #include "device-manager.h"
56 #define SHARED_DEVICE_MANAGER "tizen-device-manager"
58 #define DEVICE_MAP_FILE "/etc/pulse/device-map.json"
59 #define DEVICE_STR_MAX 30
60 #define DEVICE_DIRECTION_MAX 3
61 #define DEVICE_PARAM_STRING_MAX 150
62 #define DEVICE_AVAIL_COND_NUM_MAX 2
63 #define DEVICE_AVAIL_COND_STR_MAX 6
64 #define DEVICE_FILE_PER_TYPE_MAX 4
65 #define DEVICE_FILE_STRING_MAX 4
66 #define DEVICE_TYPE_STR_MAX 20
67 #define DEVICE_ROLE_STR_MAX 15
69 #define DEVICE_TYPE_OBJECT "device-types"
70 #define DEVICE_FILE_OBJECT "device-files"
71 #define DEVICE_TYPE_PROP_DEVICE_TYPE "device-type"
72 #define DEVICE_TYPE_PROP_PLAYBACK_DEVICES "playback-devices"
73 #define DEVICE_TYPE_PROP_CAPTURE_DEVICES "capture-devices"
74 #define DEVICE_TYPE_PROP_DEVICE_STRING "device-string"
75 #define DEVICE_TYPE_PROP_ROLE "role"
77 #define DEVICE_TYPE_STR_MAX 20
79 /* Properties of sink/sources */
80 #define DEVICE_API_BLUEZ "bluez"
81 #define DEVICE_API_ALSA "alsa"
82 #define DEVICE_API_NULL "null"
83 #define DEVICE_BUS_USB "usb"
84 #define DEVICE_CLASS_SOUND "sound"
85 #define DEVICE_CLASS_MONITOR "monitor"
88 #define DBUS_INTERFACE_DEVICE_MANAGER "org.pulseaudio.DeviceManager"
89 #define DBUS_OBJECT_DEVICE_MANAGER "/org/pulseaudio/DeviceManager"
91 #define DBUS_INTERFACE_DEVICED_SYSNOTI "org.tizen.system.deviced.SysNoti"
92 #define DBUS_OBJECT_DEVICED_SYSNOTI "/Org/Tizen/System/DeviceD/SysNoti"
94 #define DBUS_INTERFACE_SOUND_SERVER "org.tizen.SoundServer1"
95 #define DBUS_OBJECT_SOUND_SERVER "/org/tizen/SoundServer1"
97 #define DBUS_SERVICE_BLUEZ "org.bluez"
98 #define DBUS_INTERFACE_BLUEZ_HEADSET "org.bluez.Headset"
99 #define DBUS_INTERFACE_BLUEZ_DEVICE "org.bluez.Device1"
100 #define DBUS_OBJECT_BLUEZ "/org/bluez"
102 #define DBUS_INTERFACE_MIRRORING_SERVER "org.tizen.scmirroring.server"
103 #define DBUS_OBJECT_MIRRORING_SERVER "/org/tizen/scmirroring/server"
105 #define DBUS_SERVICE_HFP_AGENT "org.bluez.ag_agent"
106 #define DBUS_OBJECT_HFP_AGENT "/org/bluez/hfp_agent"
107 #define DBUS_INTERFACE_HFP_AGENT "Org.Hfp.App.Interface"
109 #define DEVICE_MANAGER_INTROSPECT_XML \
110 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
112 " <interface name=\"" DBUS_INTERFACE_DEVICE_MANAGER "\">\n" \
113 " <method name=\"GetConnectedDeviceList\">\n" \
114 " <arg name=\"mask_flags\" direction=\"in\" type=\"i\"/>\n" \
115 " <arg name=\"ConnectedDeviceList\" direction=\"out\" type=\"a(isiisii)\"/>\n" \
117 " <method name=\"GetDeviceById\">\n" \
118 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
119 " <arg name=\"device\" direction=\"out\" type=\"(isiisii)\"/>\n" \
121 " <method name=\"IsStreamOnDevice\">\n" \
122 " <arg name=\"stream_id\" direction=\"in\" type=\"i\"/>\n" \
123 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
124 " <arg name=\"is_on\" direction=\"out\" type=\"b\"/>\n" \
126 " <method name='GetBTA2DPStatus'>" \
127 " <arg type='b' name='is_bt_on' direction='out'/>" \
128 " <arg type='s' name='bt_name' direction='out'/>" \
130 " <method name=\"LoadSink\">\n" \
131 " <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n" \
132 " <arg name=\"role\" direction=\"in\" type=\"s\"/>\n" \
134 " <method name=\"UnloadSink\">\n" \
135 " <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n" \
136 " <arg name=\"role\" direction=\"in\" type=\"s\"/>\n" \
138 " <method name=\"GetSupportedSampleRates\">\n" \
139 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
140 " <arg name=\"sample_rates\" direction=\"out\" type=\"a(u)\"/>\n" \
142 " <method name=\"SetSampleRate\">\n" \
143 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
144 " <arg name=\"sample_rate\" direction=\"in\" type=\"u\"/>\n" \
146 " <method name=\"GetSampleRate\">\n" \
147 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
148 " <arg name=\"sample_rate\" direction=\"out\" type=\"u\"/>\n" \
150 " <method name=\"SetSpecificStreamOnly\">\n" \
151 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
152 " <arg name=\"stream_role\" direction=\"in\" type=\"s\"/>\n" \
154 " <method name=\"GetSpecifiedStream\">\n" \
155 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
156 " <arg name=\"stream_role\" direction=\"out\" type=\"s\"/>\n" \
158 " <method name=\"DumpDeviceList\">\n" \
160 " <method name=\"TestStatusChange\">\n" \
161 " <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n" \
162 " <arg name=\"status\" direction=\"in\" type=\"i\"/>\n" \
164 " <property name=\"PropertyTest1\" type=\"i\" access=\"readwrite\"/>\n" \
165 " <property name=\"PropertyTest2\" type=\"s\" access=\"read\"/>\n" \
166 " <signal name=\"DeviceConnected\">\n" \
167 " <arg name=\"arg1\" type=\"i\"/>\n" \
169 " <signal name=\"DeviceInfoChanged\">\n" \
170 " <arg name=\"arg1\" type=\"s\"/>\n" \
173 " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n" \
174 " <method name=\"Introspect\">\n" \
175 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \
178 " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n" \
179 " <method name=\"Get\">\n" \
180 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
181 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" \
182 " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n" \
184 " <method name=\"Set\">\n" \
185 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
186 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" \
187 " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n" \
189 " <method name=\"GetAll\">\n" \
190 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
191 " <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n" \
196 #define FILTER_DEVICED_SYSNOTI \
198 " interface='" DBUS_INTERFACE_DEVICED_SYSNOTI "'"
200 #define FILTER_SOUND_SERVER \
202 " interface='" DBUS_INTERFACE_SOUND_SERVER "'"
204 #define FILTER_MIRRORING \
206 " interface='" DBUS_INTERFACE_MIRRORING_SERVER "', member='miracast_wfd_source_status_changed'"
208 #define FILTER_BLUEZ \
210 " interface='" DBUS_INTERFACE_BLUEZ_HEADSET "', member='PropertyChanged'"
212 static const char* const valid_alsa_device_modargs[] = {
230 "tsched_buffer_size",
231 "tsched_buffer_watermark",
236 "deferred_volume_safety_margin",
237 "deferred_volume_extra_delay",
238 "fixed_latency_range",
244 #define BT_CVSD_CODEC_ID 1 // narrow-band
245 #define BT_MSBC_CODEC_ID 2 // wide-band
247 Enums for represent values which is defined on other module.
248 This is needed to identify values which are sent by dbus or vconf.
250 typedef enum external_value_earjack_type {
251 EARJACK_DISCONNECTED = 0,
252 EARJACK_TYPE_SPK_ONLY = 1,
253 EARJACK_TYPE_SPK_WITH_MIC = 3,
254 } external_value_earjack_t;
256 typedef enum external_value_bt_sco_type {
257 BT_SCO_DISCONNECTED = 0,
258 BT_SCO_CONNECTED = 1,
259 } external_value_bt_sco_t;
261 typedef enum external_value_forwarding_type {
262 FORWARDING_DISCONNECTED = 0,
263 FORWARDING_CONNECTED = 1,
264 } external_value_mirroring_t;
266 typedef enum external_value_hdmi_type {
267 HDMI_AUDIO_DISCONNECTED = -1,
268 HDMI_AUDIO_NOT_AVAILABLE = 0,
269 HDMI_AUDIO_AVAILABLE = 1,
270 } external_value_hdmi_t;
274 Enums for represent device detected status (through dbus)
275 When some device is detected, one of these values should be saved in device_status hashmap.
276 device_detected_type_t is needed to distinguish detected device-types ( ex. earjack which can be out or both way)
277 So If you just want to know whether detected or not, can device_detected_t as mask.
280 typedef enum device_detected_type {
281 DEVICE_DISCONNECTED = 0x0,
282 DEVICE_CONNECTED = 0x1,
283 DEVICE_CONNECTED_AUDIO_JACK_4P = DEVICE_CONNECTED | 0x2,
284 DEVICE_CONNECTED_AUDIO_JACK_3P = DEVICE_CONNECTED | 0x4,
285 DEVICE_CONNECTED_SCO = DEVICE_CONNECTED | 0x8,
286 DEVICE_OPENED_SCO = DEVICE_CONNECTED | 0xF,
287 } device_detected_type_t;
289 typedef enum dm_device_class_type {
290 DM_DEVICE_CLASS_NONE,
291 DM_DEVICE_CLASS_ALSA,
292 DM_DEVICE_CLASS_TIZEN,
294 DM_DEVICE_CLASS_NULL,
299 DEVICE_IO_DIRECTION_IN_FLAG = 0x0001, /**< Flag for input devices */
300 DEVICE_IO_DIRECTION_OUT_FLAG = 0x0002, /**< Flag for output devices */
301 DEVICE_IO_DIRECTION_BOTH_FLAG = 0x0004, /**< Flag for input/output devices (both directions are available) */
302 DEVICE_TYPE_INTERNAL_FLAG = 0x0010, /**< Flag for built-in devices */
303 DEVICE_TYPE_EXTERNAL_FLAG = 0x0020, /**< Flag for external devices */
304 DEVICE_STATE_DEACTIVATED_FLAG = 0x1000, /**< Flag for deactivated devices */
305 DEVICE_STATE_ACTIVATED_FLAG = 0x2000, /**< Flag for activated devices */
306 DEVICE_ALL_FLAG = 0xFFFF, /**< Flag for all devices */
310 DEVICE_IO_DIRECTION_FLAGS = 0x000F, /**< Flag for io direction */
311 DEVICE_TYPE_FLAGS = 0x00F0, /**< Flag for device type */
312 DEVICE_STATE_FLAGS = 0xF000, /**< Flag for device state */
313 } device_flags_type_t;
315 typedef enum dm_device_bt_mode_type {
316 DM_DEVICE_BT_MODE_MEDIA = 0x1,
317 DM_DEVICE_BT_MODE_VOICE = 0x2
318 } dm_device_bt_mode_t;
320 typedef enum dm_device_changed_into_type {
321 DM_DEVICE_CHANGED_INFO_STATE,
322 DM_DEVICE_CHANGED_INFO_IO_DIRECTION,
323 DM_DEVICE_CHANGED_INFO_MAX
324 } dm_device_changed_info_t;
328 Structure to save parsed information about device-file.
330 struct device_file_map {
331 /* { key:device_string -> value:device_file_prop } */
336 /***************** structures for static information get from json *********/
339 Structure for informations related to some device-file(ex. 0:0)
341 struct device_file_info {
343 String for identify target device.
344 ex) alsa:0,0 or null ..
346 const char *device_string;
348 For save roles which are supported on device file, and parameters.
349 { key:device_role -> value:parameters for load sink/source }
350 ex) "normal"->"rate=44100 tsched=0", "uhqa"->"rate=192000 mmap=1"
354 For save device-types related to device file.
355 { key:device_type-> value:pulse_device_prop }
357 pa_hashmap *device_types;
360 /* structure for represent device-types(ex. builtin-speaker) properties*/
361 struct device_type_info {
364 For save supported roles and related device-file.
365 { key:role -> value:device_string ]
367 pa_hashmap *playback_devices;
368 pa_hashmap *capture_devices;
371 struct device_status_info {
374 /* Identify devices among same device-types (for multi-device), currently not works*/
376 device_detected_type_t detected;
379 struct pulse_device_prop {
380 /* roles related to (device_type + device_file)*/
382 /* For save that this devie_type is activated or not on sink/source */
385 /******************************************************************************/
386 struct pa_device_manager {
390 pa_hook_slot *sink_put_hook_slot, *sink_unlink_hook_slot, *sink_state_changed_slot;
391 pa_hook_slot *source_put_hook_slot, *source_unlink_hook_slot, *source_state_changed_slot;
392 pa_hook_slot *comm_hook_device_connection_changed_slot;
393 pa_hook_slot *comm_hook_device_state_changed_slot;
394 pa_hook_slot *comm_hook_device_running_changed_slot;
395 pa_communicator *comm;
396 pa_hal_interface *hal_interface;
399 Idxset for save parsed information about device-type.
402 pa_idxset *type_infos;
403 /* For save Parsed information about device-file */
404 struct device_file_map *file_map;
407 pa_idxset *device_list;
409 Hashmap for save statuses got through dbus.
410 { key:device_type -> value:(audio_detected_type_t or device_detected_t) }
412 pa_idxset *device_status;
413 pa_dbus_connection *dbus_conn;
416 struct composite_type {
423 /*** Defines for method handle ***/
424 /* method handlers */
425 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
426 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata);
427 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
428 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
429 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata);
430 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
431 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
432 static void handle_set_specific_stream_only(DBusConnection *conn, DBusMessage *msg, void *userdata);
433 static void handle_get_specified_stream(DBusConnection *conn, DBusMessage *msg, void *userdata);
434 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
435 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
436 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata);
437 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata);
438 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
439 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata);
441 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name);
443 enum method_handler_index {
444 METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST,
445 METHOD_HANDLER_GET_DEVICE_BY_ID,
446 METHOD_HANDLER_IS_STREAM_ON_DEVICE,
447 METHOD_HANDLER_GET_BT_A2DP_STATUS,
448 METHOD_HANDLER_LOAD_SINK,
449 METHOD_HANDLER_UNLOAD_SINK,
450 METHOD_HANDLER_UNLOAD_SINK_WITH_DEVICE_STRING,
451 METHOD_HANDLER_GET_DEVICE_STRING,
452 METHOD_HANDLER_GET_SUPPORTED_SAMPLE_RATES,
453 METHOD_HANDLER_SET_SAMPLE_RATE,
454 METHOD_HANDLER_GET_SAMPLE_RATE,
455 METHOD_HANDLER_SET_SPECIFIC_STREAM_ONLY,
456 METHOD_HANDLER_GET_SPECIFIED_STREAM,
457 METHOD_HANDLER_DUMP_DEVICE_LIST,
458 METHOD_HANDLER_STATUS_TEST,
462 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
463 [METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST] = {
464 .method_name = "GetConnectedDeviceList",
465 .receive_cb = handle_get_connected_device_list },
466 [METHOD_HANDLER_GET_DEVICE_BY_ID] = {
467 .method_name = "GetDeviceById",
468 .receive_cb = handle_get_device_by_id },
469 [METHOD_HANDLER_IS_STREAM_ON_DEVICE] = {
470 .method_name = "IsStreamOnDevice",
471 .receive_cb = handle_is_stream_on_device },
472 [METHOD_HANDLER_GET_BT_A2DP_STATUS] = {
473 .method_name = "GetBTA2DPStatus",
474 .receive_cb = handle_get_bt_a2dp_status },
475 [METHOD_HANDLER_LOAD_SINK] = {
476 .method_name = "LoadSink",
477 .receive_cb = handle_load_sink },
478 [METHOD_HANDLER_UNLOAD_SINK] = {
479 .method_name = "UnloadSink",
480 .receive_cb = handle_unload_sink },
481 [METHOD_HANDLER_UNLOAD_SINK_WITH_DEVICE_STRING] = {
482 .method_name = "UnloadSinkWithDeviceString",
483 .receive_cb = handle_unload_sink_with_device_string },
484 [METHOD_HANDLER_GET_DEVICE_STRING] = {
485 .method_name = "GetDeviceString",
486 .receive_cb = handle_get_device_string },
487 [METHOD_HANDLER_GET_SUPPORTED_SAMPLE_RATES] = {
488 .method_name = "GetSupportedSampleRates",
489 .receive_cb = handle_get_supported_sample_rates },
490 [METHOD_HANDLER_SET_SAMPLE_RATE] = {
491 .method_name = "SetSampleRate",
492 .receive_cb = handle_set_sample_rate },
493 [METHOD_HANDLER_GET_SAMPLE_RATE] = {
494 .method_name = "GetSampleRate",
495 .receive_cb = handle_get_sample_rate },
496 [METHOD_HANDLER_SET_SPECIFIC_STREAM_ONLY] = {
497 .method_name = "SetSpecificStreamOnly",
498 .receive_cb = handle_set_specific_stream_only },
499 [METHOD_HANDLER_GET_SPECIFIED_STREAM] = {
500 .method_name = "GetSpecifiedStream",
501 .receive_cb = handle_get_specified_stream },
502 [METHOD_HANDLER_DUMP_DEVICE_LIST] = {
503 .method_name = "DumpDeviceList",
504 .receive_cb = handle_dump_device_list },
505 [METHOD_HANDLER_STATUS_TEST] = {
506 .method_name = "TestStatusChange",
507 .receive_cb = handle_test_device_status_change },
512 enum internal_codec_device_index {
513 DEVICE_INDEX_BUILTIN_SPEAKER,
514 DEVICE_INDEX_BUILTIN_RECEIVER,
515 DEVICE_INDEX_BUILTIN_MIC,
516 DEVICE_INDEX_AUDIO_JACK,
521 typedef struct _internal_codec_device {
523 bool is_running[2]; /* index[in:0, out:1] */
524 } internal_codec_device;
526 static internal_codec_device internal_codec_devices[DEVICE_INDEX_MAX] = {
527 [DEVICE_INDEX_BUILTIN_SPEAKER] = {
528 .type = DEVICE_TYPE_SPEAKER,
529 .is_running[0] = false,
530 .is_running[1] = false },
531 [DEVICE_INDEX_BUILTIN_RECEIVER] = {
532 .type = DEVICE_TYPE_RECEIVER,
533 .is_running[0] = false,
534 .is_running[1] = false },
535 [DEVICE_INDEX_BUILTIN_MIC] = {
536 .type = DEVICE_TYPE_MIC,
537 .is_running[0] = false,
538 .is_running[1] = false },
539 [DEVICE_INDEX_AUDIO_JACK] = {
540 .type = DEVICE_TYPE_AUDIO_JACK,
541 .is_running[0] = false,
542 .is_running[1] = false },
543 [DEVICE_INDEX_BT_SCO] = {
544 .type = DEVICE_TYPE_BT_SCO,
545 .is_running[0] = false,
546 .is_running[1] = false },
549 static inline void internal_codec_devices_dump() {
551 pa_log_info("========== devices using internal codec ==========");
552 for (i = 0; i < DEVICE_INDEX_MAX; i++)
553 pa_log_info(" type[%18s], is_running[in:%d,out:%d]", internal_codec_devices[i].type,
554 internal_codec_devices[i].is_running[0], internal_codec_devices[i].is_running[1]);
555 pa_log_info("==================================================");
558 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) {
559 pa_logl(level, "%s device id(%d) type(%s) name (%s) direction(%d) state(%d)",
560 pa_strempty(prefix), id, pa_strnull(type), pa_strnull(name), direction, state);
563 static void find_device_and_set_running(pa_device_manager *dm, const char *type, bool is_running) {
564 pa_tz_device* device;
571 pa_log_info("find device [%s]", type);
573 if ((device = pa_device_manager_get_device(dm, type))) {
574 if (pa_tz_device_is_use_internal_codec(device))
575 pa_tz_device_set_running_and_notify(device, is_running);
577 pa_log_warn("this device [%s] does not use internal codec, skip it", type);
579 pa_log_warn("cound not find a device of [%s]", type);
583 static void type_info_free_func(struct device_type_info *type_info) {
587 if (type_info->playback_devices)
588 pa_hashmap_free(type_info->playback_devices);
589 if (type_info->capture_devices)
590 pa_hashmap_free(type_info->capture_devices);
594 static void file_info_free_func(struct device_file_info *file_info) {
598 if (file_info->roles)
599 pa_hashmap_free(file_info->roles);
602 static dm_device_class_t device_string_get_class(const char *device_string) {
603 if (!device_string) {
604 return DM_DEVICE_CLASS_NONE;
607 if (device_string == strstr(device_string, "alsa")) {
608 return DM_DEVICE_CLASS_ALSA;
609 } else if (device_string == strstr(device_string, "null")) {
610 return DM_DEVICE_CLASS_NULL;
611 } else if (device_string == strstr(device_string, "tizen")) {
612 return DM_DEVICE_CLASS_TIZEN;
614 return DM_DEVICE_CLASS_NONE;
618 static const char* device_string_get_value(const char *device_string) {
620 const char *end_p, *value_p;
622 if (!device_string) {
626 len = strlen(device_string);
627 end_p = device_string + len -1;
629 if (!(value_p = strchr(device_string, ':'))) {
632 if (value_p < end_p) {
639 static pa_proplist* pulse_device_get_proplist(pa_object *pdevice) {
640 if (pa_sink_isinstance(pdevice))
641 return PA_SINK(pdevice)->proplist;
643 return PA_SOURCE(pdevice)->proplist;
646 static bool pulse_device_is_alsa(pa_object *pdevice) {
647 const char *api_name = NULL;
650 if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
653 if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
654 if (pa_streq(api_name, DEVICE_API_ALSA)) {
664 static bool pulse_device_is_bluez(pa_object *pdevice) {
665 const char *api_name = NULL;
668 if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
671 if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
672 if (pa_streq(api_name, DEVICE_API_BLUEZ)) {
682 static bool pulse_device_is_tizenaudio(pa_object *pdevice) {
686 if (pa_sink_isinstance(pdevice)) {
687 pa_sink *sink = PA_SINK(pdevice);
688 return pa_streq(sink->module->name, "module-tizenaudio-sink");
690 pa_source *source = PA_SOURCE(pdevice);
691 return pa_streq(source->module->name, "module-tizenaudio-source");
695 static bool pulse_device_is_usb(pa_object *pdevice) {
696 const char *bus_name = NULL;
699 if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
702 if ((bus_name = pa_proplist_gets(prop, PA_PROP_DEVICE_BUS))) {
703 if (pa_streq(bus_name, DEVICE_BUS_USB)) {
709 pa_log_debug("This device doesn't have property '%s'", PA_PROP_DEVICE_BUS);
714 static bool pulse_device_is_null(pa_object *pdevice) {
721 if (pa_sink_isinstance(pdevice)) {
722 sink = PA_SINK(pdevice);
723 return pa_streq(sink->module->name, "module-null-sink");
725 source = PA_SOURCE(pdevice);
726 return pa_streq(source->module->name, "module-null-source");
730 static const char* pulse_device_get_device_string_removed_argument(pa_object *pdevice) {
731 static char removed_param[DEVICE_PARAM_STRING_MAX] = {0,};
732 char *device_string_p = NULL;
734 const char *params_p, *params;
736 int len = 0, prev_len = 0;
740 if (pa_sink_isinstance(pdevice)) {
741 sink = PA_SINK(pdevice);
742 params = sink->module->argument;
744 source = PA_SOURCE(pdevice);
745 params = source->module->argument;
753 if (!(device_string_p = strstr(params, "device="))) {
757 next_p = device_string_p;
758 while (!isblank(*next_p)) {
761 while (isblank(*next_p)) {
765 pa_strlcpy(removed_param, next_p, DEVICE_PARAM_STRING_MAX);
767 if (device_string_p > params_p) {
768 prev_len = device_string_p - params_p;
769 len = strlen(removed_param);
770 end_p = removed_param + len;
773 strncpy(end_p, params_p, prev_len);
776 return removed_param;
779 static dm_device_class_t pulse_device_get_class(pa_object *pdevice) {
782 pa_log_error("pdevice null");
783 return DM_DEVICE_CLASS_NONE;
786 if (pulse_device_is_null(pdevice)) {
787 return DM_DEVICE_CLASS_NULL;
788 } else if (pulse_device_is_alsa(pdevice)) {
789 return DM_DEVICE_CLASS_ALSA;
790 } else if (pulse_device_is_tizenaudio(pdevice)) {
791 return DM_DEVICE_CLASS_TIZEN;
792 } else if (pulse_device_is_bluez(pdevice)) {
793 return DM_DEVICE_CLASS_BT;
795 return DM_DEVICE_CLASS_NONE;
799 static dm_device_direction_t pulse_device_get_direction(pa_object *pdevice) {
800 if (pa_sink_isinstance(pdevice))
801 return DM_DEVICE_DIRECTION_OUT;
803 return DM_DEVICE_DIRECTION_IN;
806 static bool pulse_device_is_monitor(pa_object *pdevice) {
807 const char *device_class = NULL;
810 prop = pulse_device_get_proplist(pdevice);
812 if ((device_class = pa_proplist_gets(prop, PA_PROP_DEVICE_CLASS))) {
813 if (device_class && pa_streq(device_class, DEVICE_CLASS_MONITOR)) {
823 static int pulse_device_get_alsa_device_string(pa_proplist *prop, char **device_string) {
824 const char *device_string_prop = NULL;
825 char *device_string_tmp;
827 if (!prop || !device_string) {
828 pa_log_error("Invalid Parameter");
832 if (!(device_string_prop = pa_proplist_gets(prop, "device.string"))) {
833 pa_log_error("failed to get property 'device.string'");
836 if (!(device_string_tmp = strchr(device_string_prop, ':'))) {
837 pa_log_error("failed to parse device string");
841 *device_string = device_string_tmp + 1;
846 static const char* device_class_get_module_name(dm_device_class_t device_class, bool is_sink) {
847 if (device_class == DM_DEVICE_CLASS_NONE) {
849 } else if (device_class == DM_DEVICE_CLASS_ALSA) {
850 return is_sink ? "module-alsa-sink" : "module-alsa-source";
851 } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
852 return is_sink ? "module-tizenaudio-sink" : NULL;
853 } else if (device_class == DM_DEVICE_CLASS_BT) {
854 return is_sink ? "module-bluez5-device" : NULL;
855 } else if (device_class == DM_DEVICE_CLASS_NULL) {
856 return is_sink ? "module-null-sink" : "module-null-source";
862 static struct device_type_info* _device_manager_get_type_info(pa_idxset *type_infos, const char *type) {
863 struct device_type_info *type_info;
866 PA_IDXSET_FOREACH(type_info, type_infos, type_idx) {
867 if (device_type_is_equal(type_info->type, type)) {
875 static struct device_file_info* _device_manager_get_file_info(pa_idxset *file_infos, const char *device_string) {
876 struct device_file_info *file_info;
879 pa_assert(file_infos);
881 PA_IDXSET_FOREACH(file_info, file_infos, file_idx) {
882 if (file_info->device_string) {
883 if (pa_streq(file_info->device_string, device_string)) {
892 static struct device_status_info* _device_status_new(const char *type,
893 const char *name, const char *system_id) {
894 struct device_status_info *status_info;
896 status_info = (struct device_status_info *) pa_xmalloc0(sizeof(struct device_status_info));
897 status_info->type = pa_xstrdup(type);
898 status_info->name = pa_xstrdup(name);
899 status_info->system_id = pa_xstrdup(system_id);
900 status_info->detected = DEVICE_DISCONNECTED;
905 static void _device_status_free(struct device_status_info *status_info) {
909 pa_xfree(status_info->type);
910 pa_xfree(status_info->name);
911 pa_xfree(status_info->system_id);
912 pa_xfree(status_info);
915 static struct device_status_info* _get_device_status(pa_device_manager *manager, const char *type,
916 const char *system_id) {
917 struct device_status_info *status_info = NULL;
921 pa_assert(manager->device_status);
923 PA_IDXSET_FOREACH(status_info, manager->device_status, status_idx) {
924 if (device_type_is_equal(status_info->type, type)) {
925 if (device_type_is_avail_multi_device(type)) {
926 /* if system_id is null, just compare type */
927 if (system_id == NULL)
929 else if (status_info->system_id == NULL)
931 else if (pa_streq(status_info->system_id, system_id))
944 static const char* _file_infos_get_param(pa_idxset *file_infos, const char *device_string, const char *role) {
945 struct device_file_info *file_info;
948 if (!(file_info = _device_manager_get_file_info(file_infos, device_string))) {
949 pa_log_error("No file map for '%s'", device_string);
953 if (!(params = pa_hashmap_get(file_info->roles, role)))
954 pa_log_error("No params for '%s:%s'", device_string, role);
959 static device_detected_type_t _device_get_detected(pa_device_manager *manager, const char *type,
960 const char *system_id) {
961 struct device_status_info *status_info;
964 pa_assert(manager->device_status);
967 if (!device_type_is_need_detect(type))
968 return DEVICE_CONNECTED;
970 status_info = _get_device_status(manager, type, system_id);
972 pa_log_info("No status info for type(%s) system_id(%s)",
973 type, pa_strempty(system_id));
974 return DEVICE_DISCONNECTED;
977 pa_log_debug("Get device detected, type(%s) system_id(%s) : %s(%d)",
978 type, pa_strempty(system_id),
979 (status_info->detected & DEVICE_CONNECTED) ? "Connected" : "Disconnected", status_info->detected);
981 return status_info->detected;
984 static void _device_set_detected(pa_device_manager *manager, const char *type,
985 const char *name, const char *system_id, device_detected_type_t detected_type) {
986 struct device_status_info *status_info;
989 pa_assert(manager->device_status);
992 if (!device_type_is_need_detect(type))
995 pa_log_info("Set device detected, type(%s) system_id(%s) -> %s(%d)",
996 type, pa_strempty(system_id),
997 (detected_type & DEVICE_CONNECTED) ? "Connected" : "Disconnected", detected_type);
999 if (detected_type & DEVICE_CONNECTED) {
1000 status_info = _get_device_status(manager, type, system_id);
1002 status_info = _device_status_new(type, name, system_id);
1003 pa_idxset_put(manager->device_status, status_info, NULL);
1005 status_info->detected = detected_type;
1007 status_info = _get_device_status(manager, type, system_id);
1009 pa_idxset_remove_by_data(manager->device_status, status_info, NULL);
1010 _device_status_free(status_info);
1015 static pa_tz_device* _device_list_get_device(pa_device_manager *manager, const char *type, const char *system_id) {
1016 pa_tz_device *device;
1018 char *_type, *_system_id;
1021 pa_assert(manager->device_list);
1024 PA_IDXSET_FOREACH(device, manager->device_list, idx) {
1025 _type = pa_tz_device_get_type(device);
1026 _system_id = pa_tz_device_get_system_id(device);
1027 if (pa_streq(_type, type)) {
1028 if (device_type_is_avail_multi_device(type)) {
1029 if (system_id == NULL)
1031 else if (_system_id == NULL)
1033 else if (pa_streq(_system_id, system_id))
1047 static pa_tz_device* _device_list_get_device_by_id(pa_device_manager *manager, uint32_t id) {
1048 pa_tz_device *device;
1052 pa_assert(manager->device_list);
1054 PA_IDXSET_FOREACH(device, manager->device_list, idx) {
1055 if (pa_tz_device_get_id(device) == id) {
1062 static const char* build_params_to_load_device(const char *device_string, const char *params, dm_device_class_t device_class) {
1063 pa_strbuf *args_buf;
1064 static char args[DEVICE_PARAM_STRING_MAX] = {0,};
1066 if (!device_string) {
1067 pa_log_error("device string null");
1071 if (device_class == DM_DEVICE_CLASS_NULL) {
1073 } else if (device_class == DM_DEVICE_CLASS_ALSA) {
1074 const char *alsa_device_name;
1075 if (!(alsa_device_name = device_string_get_value(device_string))) {
1076 pa_log_error("Invalid device string for alsa-device, '%s'", device_string);
1079 args_buf = pa_strbuf_new();
1080 pa_strbuf_printf(args_buf, "device=hw:%s ", alsa_device_name);
1082 pa_strbuf_printf(args_buf, "%s", params);
1084 pa_strlcpy(args, pa_strbuf_to_string_free(args_buf), DEVICE_PARAM_STRING_MAX);
1089 return (const char*) args;
1092 static bool device_params_is_equal(const char *params1, const char *params2) {
1093 const char *key = NULL;
1094 const char *value1, *value2;
1095 pa_modargs *modargs1, *modargs2;
1099 if (!params1 && !params2)
1101 if (!params1 || !params2)
1104 modargs1 = pa_modargs_new(params1, valid_alsa_device_modargs);
1105 modargs2 = pa_modargs_new(params2, valid_alsa_device_modargs);
1107 if (!modargs1 || !modargs2) {
1112 for (state = NULL, key = pa_modargs_iterate(modargs1, &state); key; key = pa_modargs_iterate(modargs1, &state)) {
1113 value1 = pa_modargs_get_value(modargs1, key, NULL);
1114 value2 = pa_modargs_get_value(modargs2, key, NULL);
1115 if (!value1 || !value2 || !pa_streq(value1, value2)) {
1121 for (state = NULL, key = pa_modargs_iterate(modargs2, &state); key; key = pa_modargs_iterate(modargs2, &state)) {
1122 value1 = pa_modargs_get_value(modargs1, key, NULL);
1123 value2 = pa_modargs_get_value(modargs2, key, NULL);
1124 if (!value1 || !value2 || !pa_streq(value1, value2)) {
1133 pa_modargs_free(modargs1);
1135 pa_modargs_free(modargs2);
1141 static bool pulse_device_params_is_equal(pa_object *pdevice, const char *params) {
1142 const char *removed_module_args;
1143 const char *module_args;
1149 if (pa_sink_isinstance(pdevice)) {
1150 sink = PA_SINK(pdevice);
1151 module_args = sink->module->argument;
1153 source = PA_SOURCE(pdevice);
1154 module_args = source->module->argument;
1157 if (!params && !module_args)
1159 if (!params || !module_args)
1162 removed_module_args = pulse_device_get_device_string_removed_argument(pdevice);
1163 return device_params_is_equal(params, removed_module_args);
1166 static const char* pulse_device_get_device_string(pa_object *pdevice) {
1167 dm_device_class_t device_class;
1168 static char device_string[DEVICE_STR_MAX] = {0,};
1169 char *device_string_val = NULL;
1174 device_class = pulse_device_get_class(pdevice);
1175 prop = pulse_device_get_proplist(pdevice);
1177 if (device_class == DM_DEVICE_CLASS_ALSA) {
1178 if (pulse_device_get_alsa_device_string(prop, &device_string_val) < 0)
1180 snprintf(device_string, DEVICE_STR_MAX, "alsa:%s", device_string_val);
1181 return device_string;
1182 } else if (device_class == DM_DEVICE_CLASS_NULL) {
1184 } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
1186 } else if (device_class == DM_DEVICE_CLASS_BT) {
1189 return device_string;
1193 /* pdevice is sink or source */
1194 static bool pulse_device_same_device_string(pa_object *pdevice, const char *device_string) {
1195 const char *_device_string;
1198 pa_assert(device_string);
1200 if (!(_device_string = pulse_device_get_device_string(pdevice)))
1203 return pa_streq(_device_string, device_string);
1206 static const char* device_type_info_get_device_string(struct device_type_info *type_info, bool is_playback, const char *role) {
1207 const char *_role, *device_string;
1209 pa_hashmap *pcm_devices;
1211 pcm_devices = is_playback ? type_info->playback_devices : type_info->capture_devices;
1212 if (pcm_devices == NULL) {
1213 pa_log_error("No pcm device config for %s %s %s", is_playback ? "Playback" : "Capture", type_info->type, role);
1217 PA_HASHMAP_FOREACH_KV(_role, device_string, pcm_devices, state) {
1218 if (pa_safe_streq(role, _role))
1219 return device_string;
1225 pa_dynarray* pulse_device_get_belongs_type(pa_object *pdevice, pa_device_manager *dm) {
1226 pa_dynarray *ctypes;
1227 struct composite_type *ctype;
1228 struct device_type_info *type_info;
1229 const char *device_string, *role, *param;
1231 pa_device_type_t pdt;
1232 pa_idxset *file_infos;
1233 pa_hashmap *pcm_devices;
1239 pa_log_info("pulse device get belongs type");
1241 if (pulse_device_is_monitor(pdevice))
1243 if (pulse_device_is_usb(pdevice))
1245 if (pulse_device_is_bluez(pdevice))
1248 ctypes = pa_dynarray_new(pa_xfree);
1250 if (pa_sink_isinstance(pdevice)) {
1251 pdt = PA_DEVICE_TYPE_SINK;
1252 file_infos = dm->file_map->playback;
1254 pdt = PA_DEVICE_TYPE_SOURCE;
1255 file_infos = dm->file_map->capture;
1258 /* iterate "device-types" in device-map.json */
1259 PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
1260 if (pdt == PA_DEVICE_TYPE_SINK)
1261 pcm_devices = type_info->playback_devices;
1263 pcm_devices = type_info->capture_devices;
1264 if (pcm_devices == NULL)
1266 /* iterate "{playback,capture}-devices" in specific device-type */
1267 PA_HASHMAP_FOREACH_KV(role, device_string, pcm_devices, state) {
1268 if (pulse_device_same_device_string(pdevice, device_string) == false)
1270 param = _file_infos_get_param(file_infos, device_string, role);
1271 if (pulse_device_params_is_equal(pdevice, param) == false)
1273 /* Found type.role which is matching with pulse_device */
1274 ctype = pa_xmalloc0(sizeof(struct composite_type));
1275 ctype->type = type_info->type;
1277 pa_dynarray_append(ctypes, ctype);
1281 if (pa_dynarray_size(ctypes) == 0) {
1282 pa_dynarray_free(ctypes);
1289 static const char* pulse_device_get_device_name(pa_object *pdevice, const char *type) {
1293 pa_assert(device_type_is_valid(type));
1295 prop = pulse_device_get_proplist(pdevice);
1297 if (pa_streq(type, DEVICE_TYPE_USB_AUDIO))
1298 return pa_proplist_gets(prop, "udev.id");
1299 else if (pa_streq(type, DEVICE_TYPE_BT_A2DP))
1300 return pa_proplist_gets(prop, "bluez.alias");
1305 /* If fails return -1 */
1306 static int atoi_base16(const char *s) {
1313 l = strtol(s, &x, 16);
1315 if (!x || *x || errno) {
1316 pa_log_error("Convert Failed");
1321 pa_log_error("Range error, does not fit into int");
1328 static int pulse_device_get_vendor_id(pa_object *pdevice) {
1330 const char *vendor_id_s;
1335 if (pulse_device_is_usb(pdevice) == false) {
1336 pa_log_warn("Not USB device");
1340 prop = pulse_device_get_proplist(pdevice);
1342 if ((vendor_id_s = pa_proplist_gets(prop, PA_PROP_DEVICE_VENDOR_ID)) == NULL) {
1343 pa_log_error("No vendor id");
1347 if ((vendor_id = atoi_base16(vendor_id_s)) == -1) {
1348 pa_log_error("Failed to convert to int");
1355 static int pulse_device_get_product_id(pa_object *pdevice) {
1357 const char *product_id_s;
1362 if (pulse_device_is_usb(pdevice) == false) {
1363 pa_log_warn("Not USB device");
1367 prop = pulse_device_get_proplist(pdevice);
1369 if ((product_id_s = pa_proplist_gets(prop, PA_PROP_DEVICE_PRODUCT_ID)) == NULL) {
1370 pa_log_error("No product id");
1374 if ((product_id = atoi_base16(product_id_s)) == -1) {
1375 pa_log_error("Failed to convert to int");
1382 static void pulse_device_set_use_internal_codec(pa_object *pdevice, bool use_internal_codec) {
1385 if (pa_sink_isinstance(pdevice)) {
1386 pa_sink *sink = PA_SINK(pdevice);
1387 sink->use_internal_codec = use_internal_codec;
1389 pa_source *source = PA_SOURCE(pdevice);
1390 source->use_internal_codec = use_internal_codec;
1394 /* Get system_id of physical device, if external device */
1395 static const char* pulse_device_get_system_id(pa_object *pdevice) {
1398 prop = pulse_device_get_proplist(pdevice);
1399 if (pulse_device_is_usb(pdevice))
1400 return pa_proplist_gets(prop, "sysfs.path");
1401 else if (pulse_device_is_bluez(pdevice))
1402 return pa_proplist_gets(prop, "bluez.path");
1407 static pa_sink* _core_get_sink(pa_core *core, const char *device_string, const char *params) {
1408 uint32_t device_idx;
1412 pa_assert(device_string);
1414 PA_IDXSET_FOREACH(sink, core->sinks, device_idx) {
1415 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1417 if (pulse_device_same_device_string(PA_OBJECT(sink), device_string)) {
1420 else if (pulse_device_params_is_equal(PA_OBJECT(sink), params))
1428 static pa_source* _core_get_source(pa_core *core, const char *device_string, const char *params) {
1429 uint32_t device_idx;
1433 pa_assert(device_string);
1435 PA_IDXSET_FOREACH(source, core->sources, device_idx) {
1436 if (pulse_device_is_monitor(PA_OBJECT(source)))
1438 if (pulse_device_same_device_string(PA_OBJECT(source), device_string)) {
1441 else if (pulse_device_params_is_equal(PA_OBJECT(source), params))
1450 static void _fill_new_data_basic(pa_tz_device_new_data *data, const char *type,
1451 dm_device_direction_t direction, bool use_internal_codec, pa_device_manager *dm) {
1454 pa_tz_device_new_data_set_type(data, type);
1455 pa_tz_device_new_data_set_direction(data, direction);
1456 pa_tz_device_new_data_set_use_internal_codec(data, use_internal_codec);
1459 static int _fill_new_data_sinks(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
1461 const char *device_string, *role, *param;
1463 pa_idxset *file_infos;
1466 pa_assert(type_info);
1468 if (type_info->playback_devices == NULL) {
1469 pa_log_error("No playback devices for %s", type_info->type);
1473 file_infos = dm->file_map->playback;
1474 if (file_infos == NULL) {
1475 pa_log_error("No playback pcm device config");
1479 PA_HASHMAP_FOREACH_KV(role, device_string, type_info->playback_devices, state) {
1480 param = _file_infos_get_param(file_infos, device_string, role);
1481 sink = _core_get_sink(dm->core, device_string, param);
1483 pa_tz_device_new_data_add_sink(data, role, sink);
1485 pa_log_warn("No matching sink for %s %s", device_string, role);
1491 static int _fill_new_data_sources(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
1493 const char *device_string, *role, *param;
1495 pa_idxset *file_infos;
1498 pa_assert(type_info);
1500 if (type_info->capture_devices == NULL) {
1501 pa_log_error("No capture devices for %s", type_info->type);
1505 file_infos = dm->file_map->capture;
1506 if (file_infos == NULL) {
1507 pa_log_error("No capture pcm device config");
1511 PA_HASHMAP_FOREACH_KV(role, device_string, type_info->capture_devices, state) {
1512 param = _file_infos_get_param(file_infos, device_string, role);
1513 source = _core_get_source(dm->core, device_string, param);
1515 pa_tz_device_new_data_add_source(data, role, source);
1517 pa_log_warn("No matching source for %s %s", device_string, role);
1523 static pa_sink* _device_manager_set_default_sink(pa_device_manager *dm, const char *type, const char *role) {
1524 pa_tz_device *device;
1527 if (!type || !role) {
1528 pa_log_warn("Argument for set_default_sink invalid");
1532 if (!(device = _device_list_get_device(dm, type, NULL))) {
1533 pa_log_warn("cannot get device item for %s", type);
1537 if (!(sink = pa_tz_device_get_sink(device, role))) {
1538 pa_log_warn("cannot get sink for %s", role);
1542 // sink = pa_namereg_set_default_sink(dm->core, sink);
1546 static pa_source* _device_manager_set_default_source(pa_device_manager *dm, const char *type, const char *role) {
1547 pa_tz_device *device;
1550 if (!type || !role) {
1551 pa_log_warn("Argument for set_default_source invalid");
1555 if (!(device = _device_list_get_device(dm, type, NULL))) {
1556 pa_log_warn("cannot get device item for %s", type);
1560 if (!(source = pa_tz_device_get_source(device, role))) {
1561 pa_log_warn("cannot get source for %s", role);
1565 // source = pa_namereg_set_default_source(dm->core, source);
1569 static void handle_usb_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1570 const char *name, *system_id;
1571 dm_device_direction_t direction;
1572 pa_tz_device *device;
1577 pa_log_info("Handle usb pulse device");
1579 system_id = pulse_device_get_system_id(pdevice);
1580 direction = pulse_device_get_direction(pdevice);
1583 pa_tz_device_new_data data;
1584 int product_id, vendor_id;
1586 name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_USB_AUDIO);
1587 vendor_id = pulse_device_get_vendor_id(pdevice);
1588 product_id = pulse_device_get_product_id(pdevice);
1590 pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, NULL);
1591 pa_tz_device_new_data_set_type(&data, DEVICE_TYPE_USB_AUDIO);
1592 pa_tz_device_new_data_set_name(&data, name);
1593 pa_tz_device_new_data_set_direction(&data, direction);
1594 pa_tz_device_new_data_set_system_id(&data, system_id);
1596 pa_tz_device_new_data_set_vendor_id(&data, vendor_id);
1598 pa_tz_device_new_data_set_product_id(&data, product_id);
1599 pa_tz_device_new_data_set_use_internal_codec(&data, false);
1600 if (direction == DM_DEVICE_DIRECTION_OUT)
1601 pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
1603 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1605 pa_tz_device_new(&data);
1606 pa_tz_device_new_data_done(&data);
1608 if (!(device = _device_list_get_device(manager, DEVICE_TYPE_USB_AUDIO, system_id)))
1609 pa_log_warn("Can't get usb device for %s", system_id);
1611 pa_tz_device_free(device);
1615 static void handle_bt_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1616 dm_device_direction_t direction;
1617 pa_tz_device *device;
1618 const char *system_id;
1623 pa_log_info("Handle bt pulse device");
1625 direction = pulse_device_get_direction(pdevice);
1626 system_id = pulse_device_get_system_id(pdevice);
1629 pa_tz_device_new_data data;
1632 name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_BT_A2DP);
1634 pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, manager->dbus_conn);
1635 _fill_new_data_basic(&data, DEVICE_TYPE_BT_A2DP, direction, false, manager);
1636 pa_tz_device_new_data_set_name(&data, name);
1637 pa_tz_device_new_data_set_system_id(&data, system_id);
1638 if (direction == DM_DEVICE_DIRECTION_OUT)
1639 pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
1641 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1643 pa_tz_device_new(&data);
1644 pa_tz_device_new_data_done(&data);
1647 if (!(device = _device_list_get_device(manager, DEVICE_TYPE_BT_A2DP, system_id)))
1648 pa_log_warn("Can't get bt device for %s", system_id);
1650 pa_tz_device_free(device);
1654 static void handle_internal_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1655 pa_tz_device *device;
1656 struct composite_type *ctype;
1657 pa_dynarray *ctypes;
1658 dm_device_direction_t direction;
1663 pa_log_info("Handle internal pulse device");
1664 direction = pulse_device_get_direction(pdevice);
1666 /* Get types which this pulse_device belongs to */
1667 if ((ctypes = pulse_device_get_belongs_type(pdevice, manager)) == NULL) {
1668 pa_log_debug("Failed to get device type. Skip this");
1673 /* Put this pulse_device to already loaded devices */
1674 for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
1675 ctype = pa_dynarray_get(ctypes, i);
1676 pa_log_info("Found belongs type %s %s", ctype->type, ctype->role);
1677 if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
1678 pa_log_info("Add this pulse_device to device(%u)", pa_tz_device_get_id(device));
1679 if (direction == DM_DEVICE_DIRECTION_OUT)
1680 pa_tz_device_add_sink(device, ctype->role, PA_SINK(pdevice));
1682 pa_tz_device_add_source(device, ctype->role, PA_SOURCE(pdevice));
1684 pa_log_info("No device for %s", ctype->type);
1688 /* Remove this pulse_device from already loaded devices */
1689 for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
1690 ctype = pa_dynarray_get(ctypes, i);
1691 pa_log_info("Found belongs type %s %s", ctype->type, ctype->role);
1692 if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
1693 pa_log_info("Remove this pulse_device from device(%u)", pa_tz_device_get_id(device));
1694 if (direction == DM_DEVICE_DIRECTION_OUT)
1695 pa_tz_device_remove_sink(device, PA_SINK(pdevice));
1697 pa_tz_device_remove_source(device, PA_SOURCE(pdevice));
1699 pa_log_info("No device for %s", ctype->type);
1704 pa_dynarray_free(ctypes);
1707 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1712 pa_log_info("========== Sink Put Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1714 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1717 if (pulse_device_is_usb(PA_OBJECT(sink))) {
1718 pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
1719 handle_usb_pulse_device(PA_OBJECT(sink), true, dm);
1721 } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
1722 pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
1723 handle_bt_pulse_device(PA_OBJECT(sink), true, dm);
1725 } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
1726 pulse_device_set_use_internal_codec(PA_OBJECT(sink), true);
1727 handle_internal_pulse_device(PA_OBJECT(sink), true, dm);
1730 pa_log_debug("Don't care this sink");
1736 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1741 pa_log_info("=========== Sink unlink Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1743 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1746 if (pulse_device_is_usb(PA_OBJECT(sink))) {
1747 handle_usb_pulse_device(PA_OBJECT(sink), false, dm);
1749 } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
1750 handle_bt_pulse_device(PA_OBJECT(sink), false, dm);
1752 } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
1753 handle_internal_pulse_device(PA_OBJECT(sink), false, dm);
1756 pa_log_debug("Don't care this sink");
1762 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1767 pa_log_info("========== source Put Hook Callback '%s'(%d) ==========", source->name, source->index);
1769 if (pulse_device_is_monitor(PA_OBJECT(source)))
1772 if (pulse_device_is_usb(PA_OBJECT(source))) {
1773 pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
1774 handle_usb_pulse_device(PA_OBJECT(source), true, dm);
1776 } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
1777 pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
1778 handle_bt_pulse_device(PA_OBJECT(source), true, dm);
1780 } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
1781 pulse_device_set_use_internal_codec(PA_OBJECT(source), true);
1782 handle_internal_pulse_device(PA_OBJECT(source), true, dm);
1785 pa_log_debug("Don't care this source");
1791 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1796 pa_log_info("=========== source unlink Hook Callback '%s'(%d) ==========", source->name, source->index);
1798 if (pulse_device_is_monitor(PA_OBJECT(source)))
1801 if (pulse_device_is_usb(PA_OBJECT(source))) {
1802 handle_usb_pulse_device(PA_OBJECT(source), false, dm);
1804 } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
1805 handle_bt_pulse_device(PA_OBJECT(source), false, dm);
1807 } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
1808 handle_internal_pulse_device(PA_OBJECT(source), false, dm);
1811 pa_log_debug("Don't care this source");
1817 #define SINK_NAME_NULL "sink_null"
1818 #define SOURCE_NAME_NULL "source_null"
1819 static pa_hook_result_t sink_source_state_changed_hook_cb(pa_core *c, pa_object *pdevice, pa_device_manager *dm) {
1820 pa_tz_device *device;
1823 pa_object_assert_ref(pdevice);
1826 if (pa_sink_isinstance(pdevice)) {
1827 pa_sink *s = PA_SINK(pdevice);
1828 pa_sink_state_t state = pa_sink_get_state(s);
1829 pa_log_debug("=========== Sink(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
1830 if (!s->use_internal_codec && !pa_streq(s->name, SINK_NAME_NULL))
1831 if ((device = pa_device_manager_get_device_with_sink(s)))
1832 pa_tz_device_set_running_and_notify(device, (state == PA_SINK_RUNNING));
1833 } else if (pa_source_isinstance(pdevice)) {
1834 pa_source *s = PA_SOURCE(pdevice);
1835 pa_source_state_t state = pa_source_get_state(s);
1836 pa_log_debug("=========== Source(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
1837 if (!s->use_internal_codec && !pa_streq(s->name, SOURCE_NAME_NULL))
1838 if ((device = pa_device_manager_get_device_with_source(s)))
1839 pa_tz_device_set_running_and_notify(device, (state == PA_SOURCE_RUNNING));
1841 pa_log_debug("========= sink_source_state_changed_hook_cb END =====");
1847 Build params for load sink or source, and load it.
1850 static void* load_device(pa_core *c, bool is_sink, const char *device_string, const char *device_params) {
1851 const char *args = NULL;
1852 const char *module_name;
1856 uint32_t device_idx;
1857 dm_device_class_t device_class;
1860 pa_assert(device_string);
1861 pa_assert(device_params);
1863 pa_log_info("Load %s Device : String'%s' Param'%s'", is_sink ? "Playback" : "Capture", device_string, device_params);
1865 device_class = device_string_get_class(device_string);
1866 if (device_class <= DM_DEVICE_CLASS_NONE || device_class >= DM_DEVICE_CLASS_MAX) {
1867 pa_log_warn("Invalid device_string '%s'", device_string);
1871 if (!(module_name = device_class_get_module_name(device_class, is_sink))) {
1872 pa_log_error("Get proper module name to load failed");
1875 if (!(args = build_params_to_load_device(device_string, device_params, device_class))) {
1876 pa_log_error("Get proper module name to load failed");
1879 if (!(module = pa_module_load(c, module_name, args))) {
1880 pa_log_error("Load module with name '%s' argu '%s' failed", module_name, args);
1886 PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
1887 if (sink->module == module) {
1892 PA_IDXSET_FOREACH(source, c->sources, device_idx) {
1893 if (source->module == module) {
1902 static void unload_device(pa_core *c, bool is_sink, const char *device_string) {
1903 uint32_t device_idx;
1906 pa_assert(device_string);
1908 pa_log_info("Unload %s Device : String'%s'", is_sink ? "Playback" : "Capture", device_string);
1913 PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
1914 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1916 if (pulse_device_same_device_string(PA_OBJECT(sink), device_string))
1917 pa_module_unload(sink->module, true);
1922 PA_IDXSET_FOREACH(source, c->sources, device_idx) {
1923 if (pulse_device_is_monitor(PA_OBJECT(source)))
1925 if (pulse_device_same_device_string(PA_OBJECT(source), device_string))
1926 pa_module_unload(source->module, true);
1931 static int _load_type_devices(struct device_type_info *type_info, bool is_playback, pa_device_manager *dm) {
1932 pa_hashmap *pcm_devices;
1933 pa_idxset *file_infos;
1936 const char *device_string, *params;
1939 pa_assert(type_info);
1941 pa_log_info("Load type devices : %s %s", type_info->type, is_playback ? "playback" : "capture");
1944 pcm_devices = type_info->playback_devices;
1945 file_infos = dm->file_map->playback;
1947 pcm_devices = type_info->capture_devices;
1948 file_infos = dm->file_map->capture;
1951 if (!pcm_devices || !file_infos) {
1952 pa_log_error("No information to load");
1956 PA_HASHMAP_FOREACH_KV(role, device_string, pcm_devices, state) {
1957 /* skip duplicate load */
1958 if (is_playback && _core_get_sink(dm->core, device_string, NULL)) {
1959 pa_log_debug("Already loaded %s", device_string);
1962 if (!is_playback && _core_get_source(dm->core, device_string, NULL)) {
1963 pa_log_debug("Already loaded %s", device_string);
1967 params = _file_infos_get_param(file_infos, device_string, role);
1968 if (params == NULL) {
1969 pa_log_error("Failed to get param for %s", device_string);
1972 if (!(load_device(dm->core, is_playback, device_string, params))) {
1973 pa_log_warn("load device failed %s %s", device_string, params);
1980 static pa_tz_device* _load_forwarding_device(pa_device_manager *dm) {
1981 pa_tz_device_new_data data;
1982 pa_tz_device *spk_device, *forwarding_device;
1987 pa_log_info("Load forwarding device");
1989 if ((forwarding_device = _device_list_get_device(dm, DEVICE_TYPE_FORWARDING, NULL))) {
1990 pa_log_info("Forwarding device already exists");
1991 return forwarding_device;
1994 if ((spk_device = _device_list_get_device(dm, DEVICE_TYPE_SPEAKER, NULL)) == NULL) {
1995 pa_log_error("Get speaker device failed");
1999 if ((spk_sink = pa_tz_device_get_sink(spk_device, DEVICE_ROLE_NORMAL)) == NULL) {
2000 pa_log_error("Get speaker sink failed");
2004 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
2005 _fill_new_data_basic(&data, DEVICE_TYPE_FORWARDING, DM_DEVICE_DIRECTION_BOTH, true, dm);
2006 pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, spk_sink);
2007 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, spk_sink->monitor_source);
2009 if ((forwarding_device = pa_tz_device_new(&data)) == NULL)
2010 pa_log_error("Failed to create forwarding device");
2012 pa_tz_device_new_data_done(&data);
2014 return forwarding_device;
2018 Handle device connection detected through dbus.
2019 First, update device-status hashmap.
2020 And if correnspondent sink/sources for device_type exist, should make device and notify it.
2021 Use [device_type->roles] mappings in sink/source for find proper sink/source.
2023 static void handle_device_connected(pa_device_manager *dm, const char *type,
2024 const char *name, const char *system_id, device_detected_type_t detected_type) {
2025 struct device_type_info *type_info;
2026 pa_tz_device_new_data data;
2029 pa_assert(dm->device_status);
2030 pa_assert(dm->device_list);
2032 pa_log_info("Device connected, type(%s) name(%s) system_id(%s) detected_type(%d)",
2033 type, pa_strempty(name), pa_strempty(system_id), detected_type);
2035 type_info = _device_manager_get_type_info(dm->type_infos, type);
2037 if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2038 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, dm->dbus_conn);
2039 _fill_new_data_basic(&data, DEVICE_TYPE_BT_SCO, DM_DEVICE_DIRECTION_BOTH, true, dm);
2040 _fill_new_data_sinks(&data, type_info, dm);
2041 _fill_new_data_sources(&data, type_info, dm);
2042 pa_tz_device_new_data_set_name(&data, name);
2043 pa_tz_device_new_data_set_system_id(&data, system_id);
2044 pa_tz_device_new(&data);
2045 pa_tz_device_new_data_done(&data);
2046 } else if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
2047 dm_device_direction_t direction;
2049 if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P)
2050 direction = DM_DEVICE_DIRECTION_BOTH;
2052 direction = DM_DEVICE_DIRECTION_OUT;
2053 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
2054 _fill_new_data_basic(&data, DEVICE_TYPE_AUDIO_JACK, direction, true, dm);
2055 _fill_new_data_sinks(&data, type_info, dm);
2056 _fill_new_data_sources(&data, type_info, dm);
2058 pa_tz_device_new(&data);
2059 pa_tz_device_new_data_done(&data);
2060 } else if (device_type_is_equal(type, DEVICE_TYPE_HDMI)) {
2061 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
2062 _fill_new_data_basic(&data, DEVICE_TYPE_HDMI, DM_DEVICE_DIRECTION_OUT, true, dm);
2063 _fill_new_data_sinks(&data, type_info, dm);
2065 pa_tz_device_new(&data);
2066 pa_tz_device_new_data_done(&data);
2067 } else if (device_type_is_equal(type, DEVICE_TYPE_FORWARDING)) {
2068 _load_forwarding_device(dm);
2070 dm_device_direction_t direction;
2072 direction = device_type_get_static_direction(type);
2073 if (direction != DM_DEVICE_DIRECTION_NONE) {
2074 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
2075 _fill_new_data_basic(&data, type, direction, true, dm);
2076 if (direction & DM_DEVICE_DIRECTION_OUT)
2077 _fill_new_data_sinks(&data, type_info, dm);
2078 if (direction & DM_DEVICE_DIRECTION_IN)
2079 _fill_new_data_sources(&data, type_info, dm);
2081 pa_tz_device_new(&data);
2082 pa_tz_device_new_data_done(&data);
2084 pa_log_error("Invalid case : not static direction");
2093 Handle device disconnection detected through dbus.
2094 First, update device-status hashmap.
2095 And if there is device which has the device_type, remove it.
2097 static int handle_device_disconnected(pa_device_manager *dm, const char *type, const char *system_id) {
2098 pa_tz_device *device;
2101 pa_assert(dm->device_status);
2103 pa_log_info("Device type(%s) system_id(%s) disconnected",
2104 type, pa_strempty(system_id));
2106 device = _device_list_get_device(dm, type, system_id);
2108 pa_log_error("Disconnection detected but no device for that");
2112 pa_tz_device_free(device);
2117 static int load_builtin_devices(pa_device_manager *dm) {
2118 struct device_type_info *type_info;
2120 device_detected_type_t detected_type = DEVICE_CONNECTED;
2125 pa_log_debug("\n==================== Load Builtin Devices ====================");
2127 PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
2129 type = type_info->type;
2131 pa_log_info("type_info : %s", type);
2132 detected_type = _device_get_detected(dm, type, NULL);
2133 if (detected_type == DEVICE_DISCONNECTED) {
2134 pa_log_info("Not detected yet");
2138 if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
2139 if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P) {
2140 _load_type_devices(type_info, true, dm);
2141 _load_type_devices(type_info, false, dm);
2143 _load_type_devices(type_info, true, dm);
2145 handle_device_connected(dm, type, NULL, NULL, detected_type);
2146 } else if (device_type_is_use_external_card(type) == false) {
2147 dm_device_direction_t direction;
2148 direction = device_type_get_static_direction(type);
2149 if (direction == DM_DEVICE_DIRECTION_NONE) {
2150 pa_log_warn("Wrong direction");
2153 if (direction & DM_DEVICE_DIRECTION_OUT)
2154 _load_type_devices(type_info, true, dm);
2155 if (direction & DM_DEVICE_DIRECTION_IN)
2156 _load_type_devices(type_info, false, dm);
2157 handle_device_connected(dm, type, NULL, NULL, detected_type);
2159 pa_log_warn("Invalid case");
2166 /***************** Parse json file *******************/
2167 static pa_hashmap* parse_device_role_object(json_object *device_role_o) {
2168 pa_hashmap *roles = NULL;
2169 const char *params, *device_role;
2170 struct json_object_iterator it, it_end;
2171 json_object *params_o;
2173 pa_assert(device_role_o);
2174 pa_assert(json_object_is_type(device_role_o, json_type_object));
2176 roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2178 pa_log_debug("hashmap new failed");
2182 it = json_object_iter_begin(device_role_o);
2183 it_end = json_object_iter_end(device_role_o);
2185 while (!json_object_iter_equal(&it, &it_end)) {
2186 device_role = json_object_iter_peek_name(&it);
2187 params_o = json_object_iter_peek_value(&it);
2189 if (!(params = json_object_get_string(params_o))) {
2190 pa_log_debug("There is no device params for role '%s'", device_role);
2192 pa_log_info("- Role '%s' -> '%s'", device_role, params);
2193 if (device_role_is_valid(device_role)) {
2194 if (pa_hashmap_put(roles, (void *)device_role, (void *)params)) {
2195 pa_log_error("put new role to hashmap faild");
2199 pa_log_error("Invalid device role '%s'", device_role);
2202 json_object_iter_next(&it);
2205 if (pa_hashmap_size(roles) == 0) {
2206 pa_log_warn("There is no role for device.. free hashmap");
2207 pa_hashmap_free(roles);
2215 pa_hashmap_free(roles);
2220 static struct device_file_info* parse_device_file_object(json_object *device_file_o, const char **device_string_key) {
2221 pa_hashmap *roles = NULL;
2222 json_object *device_file_prop_o = NULL;
2223 const char *device_string = NULL;
2224 struct device_file_info *file_info = NULL;
2226 pa_assert(device_file_o);
2227 pa_assert(device_string_key);
2228 pa_assert(json_object_is_type(device_file_o, json_type_object));
2230 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)) {
2231 if ((device_string = json_object_get_string(device_file_prop_o))) {
2232 pa_log_info("[ Device File - %s ]", device_string);
2234 pa_log_error("Get device-string failed");
2238 pa_log_error("Get device-string object failed");
2242 if (json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_ROLE, &device_file_prop_o)) {
2243 if (!(roles = parse_device_role_object(device_file_prop_o))) {
2244 pa_log_error("Parse device role for '%s' failed", device_string);
2248 pa_log_error("Get device role object failed");
2251 file_info = pa_xmalloc0(sizeof(struct device_file_info));
2252 file_info->device_string = device_string;
2253 file_info->device_types = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2254 file_info->roles = roles;
2256 // *device_string_key = device_string;
2265 static pa_idxset* parse_device_file_array_object(json_object *device_file_array_o) {
2266 int device_file_num, device_file_idx;
2267 struct device_file_info *file_info = NULL;
2268 json_object *device_file_o = NULL;
2269 pa_idxset *device_files = NULL;
2270 const char *device_string = NULL;
2272 pa_assert(device_file_array_o);
2273 pa_assert(json_object_is_type(device_file_array_o, json_type_array));
2275 device_files = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2277 device_file_num = json_object_array_length(device_file_array_o);
2278 for (device_file_idx = 0; device_file_idx < device_file_num; device_file_idx++) {
2279 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)) {
2280 if ((file_info = parse_device_file_object(device_file_o, &device_string))) {
2281 pa_idxset_put(device_files, file_info, NULL);
2283 pa_log_error("parse device file object failed");
2287 pa_log_error("Get device file object failed");
2292 if (pa_idxset_size(device_files) == 0) {
2293 pa_idxset_free(device_files, NULL);
2294 device_files = NULL;
2297 return device_files;
2301 pa_xfree(device_files);
2305 static struct device_file_map *parse_device_file_map() {
2306 struct device_file_map *file_map = NULL;
2307 json_object *o, *device_files_o;
2308 json_object *playback_devices_o = NULL, *capture_devices_o = NULL;
2310 pa_log_info("\nParse device files");
2312 o = json_object_from_file(DEVICE_MAP_FILE);
2315 pa_log_error("Read device-map file failed");
2319 file_map = pa_xmalloc0(sizeof(struct device_file_map));
2321 if (json_object_object_get_ex(o, DEVICE_FILE_OBJECT, &device_files_o) && json_object_is_type(device_files_o, json_type_object)) {
2322 if (json_object_object_get_ex(device_files_o, DEVICE_TYPE_PROP_PLAYBACK_DEVICES, &playback_devices_o)) {
2323 pa_log_info("Playback Device Files");
2324 file_map->playback = parse_device_file_array_object(playback_devices_o);
2326 if (json_object_object_get_ex(device_files_o, DEVICE_TYPE_PROP_CAPTURE_DEVICES, &capture_devices_o)) {
2327 pa_log_info("Capture Device Files");
2328 file_map->capture = parse_device_file_array_object(capture_devices_o);
2331 pa_log_error("Get device files object failed");
2340 static pa_hashmap* parse_device_role_map(json_object *device_role_map_o) {
2341 pa_hashmap *roles = NULL;
2342 const char *device_string, *device_role;
2343 struct json_object_iterator it, it_end;
2344 json_object *device_string_o;
2346 pa_assert(device_role_map_o);
2347 pa_assert(json_object_is_type(device_role_map_o, json_type_object));
2349 roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2351 it = json_object_iter_begin(device_role_map_o);
2352 it_end = json_object_iter_end(device_role_map_o);
2354 while (!json_object_iter_equal(&it, &it_end)) {
2355 device_role = json_object_iter_peek_name(&it);
2356 device_string_o = json_object_iter_peek_value(&it);
2358 if (!(device_string = json_object_get_string(device_string_o))) {
2359 pa_log_debug("There is no device string for role '%s'", device_role);
2361 pa_log_info("- Role '%s' -> '%s'", device_role, device_string);
2362 if (device_role_is_valid(device_role)) {
2363 if (pa_hashmap_put(roles, (void *)device_role, (void *)device_string)) {
2364 pa_log_error("put new role to hashmap faild");
2368 pa_log_error("Invalid device role '%s'", device_role);
2372 json_object_iter_next(&it);
2386 static pa_idxset* parse_device_type_infos() {
2387 json_object *o, *device_array_o = NULL;
2388 int device_type_num = 0;
2389 int device_type_idx = 0;
2390 struct device_type_info *type_info = NULL;
2391 //pa_hashmap *type_infos = NULL;
2392 pa_idxset *type_infos = NULL;
2394 o = json_object_from_file(DEVICE_MAP_FILE);
2396 pa_log_error("Read device-map file failed");
2400 pa_log_info("\nParse device types");
2401 type_infos = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2403 if (json_object_object_get_ex(o, DEVICE_TYPE_OBJECT, &device_array_o) && json_object_is_type(device_array_o, json_type_array)) {
2404 device_type_num = json_object_array_length(device_array_o);
2405 for (device_type_idx = 0; device_type_idx < device_type_num ; device_type_idx++) {
2406 json_object *device_o;
2408 if ((device_o = json_object_array_get_idx(device_array_o, device_type_idx)) && json_object_is_type(device_o, json_type_object)) {
2409 json_object *device_prop_o;
2410 const char *type = NULL;
2412 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)) {
2413 pa_log_error("Get device type failed");
2416 type = json_object_get_string(device_prop_o);
2417 pa_log_info("[ Device - %s ]", type);
2419 type_info = pa_xmalloc0(sizeof(struct device_type_info));
2420 type_info->type = type;
2422 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)) {
2423 pa_log_info("Playback Devices");
2424 type_info->playback_devices = parse_device_role_map(device_prop_o);
2427 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)) {
2428 pa_log_info("Capture Devices");
2429 type_info->capture_devices = parse_device_role_map(device_prop_o);
2431 pa_idxset_put(type_infos, type_info, NULL);
2434 pa_log_debug("Get device type object failed");
2438 pa_log_debug("Get device type array object failed");
2444 pa_xfree(type_infos);
2450 look detected status which is external value, make conversion to internal consistent value, and handle it
2451 device_type, which type of device is detected
2452 system_id : system_id among same device types for support multi-device
2454 static int handle_device_status_changed(pa_device_manager *dm, const char *type,
2455 const char *name, const char *system_id, device_detected_type_t detected) {
2457 pa_assert(device_type_is_valid(type));
2459 pa_log_info("Device Status Changed, type(%s) system_id(%s), detected_type(%d)",
2460 type, pa_strempty(system_id), detected);
2462 if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2463 _device_set_detected(dm, type, name, system_id, detected);
2464 if (detected == DEVICE_DISCONNECTED)
2465 handle_device_disconnected(dm, type, system_id);
2467 handle_device_connected(dm, type, name, system_id, detected);
2468 } else if (device_type_is_need_detect(type)) {
2469 _device_set_detected(dm, type, name, system_id, detected);
2470 if (detected == DEVICE_DISCONNECTED)
2471 handle_device_disconnected(dm, type, system_id);
2473 handle_device_connected(dm, type, name, system_id, detected);
2475 pa_log_debug("No need to detect type %s", type);
2482 Initialize device-status idxset.
2483 This is for device-status detected through dbus.
2484 So, if device_type is not detected through dbus, let's initialize them to detected. (ex. spk, rcv,...)
2485 If not, initialize to not detected.
2487 static void device_type_status_init(pa_device_manager *manager) {
2488 struct device_type_info *type_info;
2493 pa_assert(manager->type_infos);
2495 pa_log_debug("\n==================== Init Device Status ====================");
2497 PA_IDXSET_FOREACH(type_info, manager->type_infos, type_idx) {
2498 type = type_info->type;
2499 if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
2500 int earjack_status = 0;
2501 if (vconf_get_int(VCONFKEY_SYSMAN_EARJACK, &earjack_status) < 0) {
2502 pa_log_error("Get earjack status failed");
2505 if (earjack_status == EARJACK_TYPE_SPK_ONLY)
2506 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_3P);
2507 else if (earjack_status == EARJACK_TYPE_SPK_WITH_MIC)
2508 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_4P);
2509 else if (earjack_status == EARJACK_DISCONNECTED)
2510 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2512 pa_log_warn("Unknown earjack status : %d", earjack_status);
2513 } else if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2514 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2515 } else if (device_type_is_equal(type, DEVICE_TYPE_HDMI)) {
2516 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2517 } else if (device_type_is_equal(type, DEVICE_TYPE_FORWARDING)) {
2518 int miracast_wfd_status = 0;
2519 if (vconf_get_bool(VCONFKEY_MIRACAST_WFD_SOURCE_STATUS, &miracast_wfd_status) < 0) {
2520 pa_log_error("Get mirroring status failed");
2523 if (miracast_wfd_status == FORWARDING_CONNECTED)
2524 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
2526 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
2534 static int _translate_external_value(const char *type, int value, device_detected_type_t *detected) {
2536 if (!type || !detected) {
2537 pa_log_error("Invalid Parameter for translate");
2541 if (device_type_is_equal(DEVICE_TYPE_AUDIO_JACK, type)) {
2542 if (value == EARJACK_DISCONNECTED)
2543 *detected = DEVICE_DISCONNECTED;
2544 else if (value == EARJACK_TYPE_SPK_ONLY)
2545 *detected = DEVICE_CONNECTED_AUDIO_JACK_3P;
2546 else if (value == EARJACK_TYPE_SPK_WITH_MIC)
2547 *detected = DEVICE_CONNECTED_AUDIO_JACK_4P;
2550 } else if (device_type_is_equal(DEVICE_TYPE_HDMI, type)) {
2551 if (value == HDMI_AUDIO_DISCONNECTED)
2552 *detected = DEVICE_DISCONNECTED;
2553 else if (value == HDMI_AUDIO_AVAILABLE)
2554 *detected = DEVICE_CONNECTED;
2557 } else if (device_type_is_equal(DEVICE_TYPE_FORWARDING, type)) {
2558 if (value == FORWARDING_DISCONNECTED)
2559 *detected = DEVICE_DISCONNECTED;
2560 else if (value == FORWARDING_CONNECTED)
2561 *detected = DEVICE_CONNECTED;
2564 } else if (device_type_is_equal(DEVICE_TYPE_BT_SCO, type)) {
2565 if (value == BT_SCO_DISCONNECTED)
2566 *detected = DEVICE_DISCONNECTED;
2567 else if (value == BT_SCO_CONNECTED)
2568 *detected = DEVICE_CONNECTED_SCO;
2576 static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
2579 pa_device_manager *dm = (pa_device_manager *) userdata;
2580 device_detected_type_t detected;
2582 pa_assert(userdata);
2584 if (dbus_message_get_type(s) != DBUS_MESSAGE_TYPE_SIGNAL)
2585 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2587 pa_log_info("Device detect handler : Path(%s) Intf(%s) Member(%s) Signature(%s)",
2588 dbus_message_get_path(s), dbus_message_get_interface(s), dbus_message_get_member(s), dbus_message_get_signature(s));
2590 dbus_error_init(&error);
2592 if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedEarjack")) {
2593 if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2596 if (_translate_external_value(DEVICE_TYPE_AUDIO_JACK, status, &detected) < 0) {
2597 pa_log_warn("failed to translate audio-jack detected value");
2600 handle_device_status_changed(dm, DEVICE_TYPE_AUDIO_JACK, NULL, NULL, detected);
2602 } else if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedHDMIAudio")) {
2603 if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2606 if (_translate_external_value(DEVICE_TYPE_HDMI, status, &detected) < 0) {
2607 pa_log_warn("failed to translate HDMI detected value");
2610 handle_device_status_changed(dm, DEVICE_TYPE_HDMI, NULL, NULL, detected);
2612 } else if (dbus_message_is_signal(s, DBUS_INTERFACE_MIRRORING_SERVER, "miracast_wfd_source_status_changed")) {
2613 if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2616 if (_translate_external_value(DEVICE_TYPE_FORWARDING, status, &detected) < 0) {
2617 pa_log_warn("failed to translate forwarding detected value");
2620 handle_device_status_changed(dm, DEVICE_TYPE_FORWARDING, NULL, NULL, detected);
2622 } else if (dbus_message_is_signal(s, DBUS_INTERFACE_BLUEZ_HEADSET, "PropertyChanged")) {
2623 DBusMessageIter msg_iter, variant_iter;
2624 char *property_name;
2626 pa_log_debug("Got %s PropertyChanged signal", DBUS_INTERFACE_BLUEZ_HEADSET);
2627 dbus_message_iter_init(s, &msg_iter);
2628 if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_STRING) {
2629 pa_log_error("Property name not string");
2632 dbus_message_iter_get_basic(&msg_iter, &property_name);
2633 pa_log_info("Changed Property name : %s", property_name);
2635 if (!dbus_message_iter_next(&msg_iter)) {
2636 pa_log_debug("Property value missing");
2640 if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_VARIANT) {
2641 pa_log_debug("Property value not a variant.");
2645 dbus_message_iter_recurse(&msg_iter, &variant_iter);
2647 if (DBUS_TYPE_BOOLEAN == dbus_message_iter_get_arg_type(&variant_iter)) {
2650 dbus_message_iter_get_basic(&variant_iter, &value);
2651 if (pa_streq(property_name, "Connected")) {
2652 pa_log_info("HFP Connection : %d", value);
2654 method_call_bt_get_name(c, dbus_message_get_path(s), &name);
2655 status = BT_SCO_CONNECTED;
2657 status = BT_SCO_DISCONNECTED;
2659 if (_translate_external_value(DEVICE_TYPE_BT_SCO, status, &detected) < 0) {
2660 pa_log_warn("failed to translate bt-sco detected value");
2663 handle_device_status_changed(dm, DEVICE_TYPE_BT_SCO,
2664 name, dbus_message_get_path(s), detected);
2665 } else if (pa_streq(property_name, "Playing")) {
2666 pa_tz_device *device;
2667 pa_log_info("SCO Playing : %d", value);
2668 if ((device = _device_list_get_device(dm, DEVICE_TYPE_BT_SCO, NULL)) != NULL) {
2669 device->sco_opened = value;
2671 /* update BT band/nrec information */
2672 bool is_wide_band = false;
2674 pa_tz_device_sco_get_property(device, &is_wide_band, &nrec);
2675 pa_log_info("got new wideband:%d, nrec:%d", is_wide_band, nrec);
2677 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-wideband", is_wide_band);
2678 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-nrec", nrec);
2681 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-sco-ready", value);
2685 pa_log_debug("Unknown message, not handle it");
2686 dbus_error_free(&error);
2687 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2690 pa_log_debug("Dbus Message handled");
2692 dbus_error_free(&error);
2693 return DBUS_HANDLER_RESULT_HANDLED;
2696 pa_log_error("Fail to handle dbus signal");
2697 dbus_error_free(&error);
2698 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2701 static int watch_signals(pa_device_manager *dm) {
2705 pa_assert(dm->dbus_conn);
2707 dbus_error_init(&error);
2709 pa_log_info("Watch Dbus signals");
2711 if (!dbus_connection_add_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm, NULL)) {
2712 pa_log_error("Unable to add D-Bus filter : %s: %s", error.name, error.message);
2716 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) {
2717 pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
2723 dbus_error_free(&error);
2727 static void unwatch_signals(pa_device_manager *dm) {
2728 pa_log_info("Unwatch Dbus signals");
2731 pa_assert(dm->dbus_conn);
2733 pa_dbus_remove_matches(pa_dbus_connection_get(dm->dbus_conn), FILTER_DEVICED_SYSNOTI, FILTER_SOUND_SERVER, FILTER_BLUEZ, FILTER_MIRRORING, NULL);
2734 dbus_connection_remove_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm);
2737 static void fill_signal_msg_with_device(const char *description, DBusMessageIter *msg_iter, uint32_t event_id, pa_tz_device *device) {
2738 DBusMessageIter array_iter, device_iter;
2740 dbus_int32_t device_id, direction, state, stream_id;
2741 dbus_int32_t vendor_id, product_id;
2742 dbus_bool_t is_running;
2743 pa_intset *stream_id_set = NULL;
2744 int32_t stream_id_val;
2747 pa_assert(msg_iter);
2750 dbus_message_iter_append_basic(msg_iter, DBUS_TYPE_UINT32, &event_id);
2751 pa_assert_se(dbus_message_iter_open_container(msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2753 direction = (dbus_int32_t) pa_tz_device_get_direction(device);
2754 type = pa_tz_device_get_type(device);
2755 name = pa_tz_device_get_name(device);
2756 device_id = (dbus_int32_t) pa_tz_device_get_id(device);
2757 state = pa_tz_device_get_state(device);
2758 vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
2759 product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
2760 is_running = (dbus_bool_t) pa_tz_device_is_running(device);
2762 simple_device_dump(PA_LOG_INFO, description, device_id, type, name, direction, state);
2764 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2765 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
2766 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
2767 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
2768 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
2769 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
2770 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
2771 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
2772 if (state == DM_DEVICE_STATE_ACTIVATED)
2773 stream_id_set = pa_tz_device_get_stream_list(device);
2774 pa_assert_se(dbus_message_iter_open_container(&device_iter, DBUS_TYPE_ARRAY, "i", &array_iter));
2775 if (state == DM_DEVICE_STATE_ACTIVATED) {
2776 PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
2777 stream_id = stream_id_val;
2778 dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_INT32, &stream_id);
2781 pa_assert_se(dbus_message_iter_close_container(&device_iter, &array_iter));
2783 pa_intset_free(stream_id_set);
2784 pa_assert_se(dbus_message_iter_close_container(msg_iter, &device_iter));
2785 pa_log_info("end of fill signal msg");
2788 static void send_device_connection_changed_signal(uint32_t event_id, pa_tz_device *device, bool connected, pa_device_manager *dm) {
2789 DBusMessage *signal_msg;
2790 DBusMessageIter msg_iter;
2791 dbus_bool_t _connected = connected;
2796 pa_log_info("Send device connection changed signal, event_id(%u)", event_id);
2798 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceConnected"));
2799 dbus_message_iter_init_append(signal_msg, &msg_iter);
2800 fill_signal_msg_with_device(connected ? "[Connected]" : "[Disconnected]", &msg_iter, event_id, device);
2802 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &_connected);
2804 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2806 dbus_message_unref(signal_msg);
2807 pa_log_info("end of send device connection changed signal");
2810 static void send_device_info_changed_signal(uint32_t event_id, pa_tz_device *device, int changed_type, pa_device_manager *dm) {
2811 DBusMessage *signal_msg;
2812 DBusMessageIter msg_iter;
2813 const char *changed_prefix[] = {"[State Changed]", "[Direction Changed]", "[Avail-Mode Changed]"};
2818 pa_log_debug("Send device info changed signal, event_id(%u)", event_id);
2820 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceInfoChanged"));
2821 dbus_message_iter_init_append(signal_msg, &msg_iter);
2822 fill_signal_msg_with_device(changed_prefix[changed_type], &msg_iter, event_id, device);
2823 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &changed_type);
2825 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2827 dbus_message_unref(signal_msg);
2830 static void send_device_state_changed_signal(uint32_t event_id, pa_tz_device *device, bool activated, pa_device_manager *dm) {
2831 DBusMessage *signal_msg;
2832 DBusMessageIter msg_iter;
2837 pa_log_debug("Send device state changed signal, event_id(%u)", event_id);
2839 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceStateChanged"));
2840 dbus_message_iter_init_append(signal_msg, &msg_iter);
2841 fill_signal_msg_with_device(activated ? "[Activated]" : "[Deactivated]", &msg_iter, event_id, device);
2843 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2845 dbus_message_unref(signal_msg);
2848 static void send_device_running_changed_signal(uint32_t event_id, pa_tz_device *device, bool is_running, pa_device_manager *dm) {
2849 DBusMessage *signal_msg;
2850 DBusMessageIter msg_iter;
2855 pa_log_debug("Send device running changed signal, event_id(%u)", event_id);
2857 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceRunningChanged"));
2858 dbus_message_iter_init_append(signal_msg, &msg_iter);
2859 fill_signal_msg_with_device(is_running ? "[Running]" : "[NotRunning]", &msg_iter, event_id, device);
2861 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2863 dbus_message_unref(signal_msg);
2866 static bool device_is_match_direction(pa_tz_device *device, int direction_mask) {
2867 dm_device_direction_t direction;
2869 if (direction_mask == DEVICE_IO_DIRECTION_FLAGS || direction_mask == 0)
2872 direction = pa_tz_device_get_direction(device);
2874 if ((direction_mask & DEVICE_IO_DIRECTION_IN_FLAG) && (direction & DM_DEVICE_DIRECTION_IN))
2876 if ((direction_mask & DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & DM_DEVICE_DIRECTION_OUT))
2878 if ((direction_mask & DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction == DM_DEVICE_DIRECTION_BOTH))
2884 static bool device_is_match_state(pa_tz_device *device, int state_mask) {
2885 dm_device_state_t state;
2887 if (state_mask == DEVICE_STATE_FLAGS || state_mask == 0)
2890 state = pa_tz_device_get_state(device);
2892 if ((state_mask & DEVICE_STATE_DEACTIVATED_FLAG) && (state == DM_DEVICE_STATE_DEACTIVATED))
2894 if ((state_mask & DEVICE_STATE_ACTIVATED_FLAG) && (state == DM_DEVICE_STATE_ACTIVATED))
2900 static bool device_is_match_type(pa_tz_device *device, int type_mask) {
2904 if (type_mask == DEVICE_TYPE_FLAGS || type_mask == 0)
2907 type = pa_tz_device_get_type(device);
2908 is_builtin = device_type_is_builtin(type);
2910 if ((type_mask & DEVICE_TYPE_INTERNAL_FLAG) && is_builtin)
2912 if ((type_mask & DEVICE_TYPE_EXTERNAL_FLAG) && !is_builtin)
2918 static bool device_is_match_with_mask(pa_tz_device *device, int mask) {
2921 if (mask == DEVICE_ALL_FLAG)
2924 return (device_is_match_direction(device, mask & DEVICE_IO_DIRECTION_FLAGS) &&
2925 device_is_match_state(device, mask & DEVICE_STATE_FLAGS) &&
2926 device_is_match_type(device, mask & DEVICE_TYPE_FLAGS));
2929 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name) {
2930 const char *intf = DBUS_INTERFACE_BLUEZ_DEVICE, *prop = "Alias";
2931 DBusMessage *msg, *reply;
2932 DBusMessageIter reply_iter, variant_iter;
2936 pa_assert(device_path);
2939 if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_BLUEZ, device_path, "org.freedesktop.DBus.Properties", "Get"))) {
2940 pa_log_error("dbus method call failed");
2944 dbus_message_append_args(msg,
2945 DBUS_TYPE_STRING, &intf,
2946 DBUS_TYPE_STRING, &prop,
2949 dbus_error_init(&err);
2950 if (!(reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err))) {
2951 pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_BLUEZ_DEVICE, "Get", err.message);
2952 dbus_error_free(&err);
2956 dbus_message_iter_init(reply, &reply_iter);
2958 if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_VARIANT) {
2959 pa_log_error("Cannot get reply argument");
2963 dbus_message_iter_recurse(&reply_iter, &variant_iter);
2965 if (dbus_message_iter_get_arg_type(&variant_iter) == DBUS_TYPE_STRING) {
2966 dbus_message_iter_get_basic(&variant_iter, name);
2969 dbus_message_unref(reply);
2973 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2974 pa_device_manager *dm;
2975 DBusMessage *reply = NULL;
2976 DBusMessageIter msg_iter, array_iter, device_iter;
2977 pa_tz_device *device;
2978 dm_device_state_t state;
2979 uint32_t device_idx;
2980 dbus_int32_t device_id, direction;
2983 dbus_int32_t vendor_id, product_id;
2984 dbus_bool_t is_running;
2988 pa_assert(userdata);
2991 dm = (pa_device_manager*) userdata;
2993 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2995 pa_assert_se(dbus_message_get_args(msg, NULL,
2996 DBUS_TYPE_INT32, &mask,
2997 DBUS_TYPE_INVALID));
2999 pa_log_info("Get connected device list (mask : %d)", mask);
3001 dbus_message_iter_init_append(reply, &msg_iter);
3002 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiisiib)", &array_iter));
3004 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3005 device_id = (dbus_int32_t)pa_tz_device_get_id(device);
3006 state = pa_tz_device_get_state(device);
3007 direction = pa_tz_device_get_direction(device);
3008 type = pa_tz_device_get_type(device);
3009 name = pa_tz_device_get_name(device);
3010 vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
3011 product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
3012 product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
3013 is_running = (dbus_bool_t) pa_tz_device_is_running(device);
3014 if (device_is_match_with_mask(device, mask)) {
3015 simple_device_dump(PA_LOG_INFO, "[MATCH]", device_id, type, name, direction, state);
3016 pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
3017 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
3018 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
3019 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
3020 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
3021 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
3022 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
3023 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
3024 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
3025 pa_assert_se(dbus_message_iter_close_container(&array_iter, &device_iter));
3027 simple_device_dump(PA_LOG_INFO, "[UNMATCH]", device_id, type, name, direction, state);
3031 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
3033 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3034 dbus_message_unref(reply);
3037 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3038 pa_device_manager *manager;
3040 DBusMessageIter msg_iter;
3041 pa_tz_device *device;
3042 dbus_int32_t device_id;
3043 dbus_int32_t id, direction, state;
3044 dbus_int32_t vendor_id, product_id;
3049 pa_assert(userdata);
3051 manager = (pa_device_manager*) userdata;
3053 pa_assert_se(dbus_message_get_args(msg, NULL,
3054 DBUS_TYPE_INT32, &device_id,
3055 DBUS_TYPE_INVALID));
3057 pa_log_info("Get device by id(%d)", device_id);
3059 if ((device = _device_list_get_device_by_id(manager, device_id))) {
3060 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3061 dbus_message_iter_init_append(reply, &msg_iter);
3063 id = (dbus_int32_t)pa_tz_device_get_id(device);
3064 state = pa_tz_device_get_state(device);
3065 direction = pa_tz_device_get_direction(device);
3066 type = pa_tz_device_get_type(device);
3067 name = pa_tz_device_get_name(device);
3068 vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
3069 product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
3071 simple_device_dump(PA_LOG_INFO, "[GET_BY_ID]", device_id, type, name, direction, state);
3073 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &id);
3074 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &type);
3075 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &direction);
3076 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &state);
3077 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
3078 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &vendor_id);
3079 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &product_id);
3081 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3082 dbus_message_unref(reply);
3084 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3088 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3089 pa_device_manager *manager;
3091 pa_tz_device *device;
3092 dbus_bool_t is_on = false;
3093 dbus_int32_t stream_id, device_id;
3094 pa_intset *stream_id_set;
3095 int32_t stream_id_val;
3097 dm_device_state_t state;
3101 pa_assert(userdata);
3103 pa_log_info("Is stream on device");
3105 manager = (pa_device_manager*) userdata;
3108 pa_assert_se(dbus_message_get_args(msg, NULL,
3109 DBUS_TYPE_INT32, &stream_id,
3110 DBUS_TYPE_INT32, &device_id,
3111 DBUS_TYPE_INVALID));
3113 if ((device = _device_list_get_device_by_id(manager, device_id))) {
3114 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3116 state = pa_tz_device_get_state(device);
3117 if (state == DM_DEVICE_STATE_ACTIVATED) {
3118 stream_id_set = pa_tz_device_get_stream_list(device);
3119 PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
3120 if (stream_id_val == stream_id) {
3122 pa_log_info("stream(%d) is on device(%d)", stream_id, device_id);
3126 pa_intset_free(stream_id_set);
3128 pa_log_info("device(%d) is not activated, regard as no stream on it", device_id);
3132 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_on,
3133 DBUS_TYPE_INVALID));
3135 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3136 dbus_message_unref(reply);
3138 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.Internal");
3142 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3143 pa_device_manager *dm;
3144 DBusMessage *reply = NULL;
3145 pa_tz_device *device;
3146 dbus_bool_t is_bt_on = false;
3147 const char *bt_name = "none";
3151 pa_assert(userdata);
3153 pa_log_info("Get BT A2DP list");
3155 dm = (pa_device_manager*) userdata;
3157 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3159 /* FIXME : Give system_id for multi device */
3160 if ((device = _device_list_get_device(dm, DEVICE_TYPE_BT_A2DP, NULL)) != NULL) {
3162 bt_name = pa_tz_device_get_name(device);
3165 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_bt_on,
3166 DBUS_TYPE_STRING, &bt_name,
3167 DBUS_TYPE_INVALID));
3169 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3170 dbus_message_unref(reply);
3175 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3176 pa_device_manager *dm;
3178 DBusMessage *reply = NULL;
3180 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3181 dm = (pa_device_manager *) userdata;
3182 pa_assert_se(dbus_message_get_args(msg, NULL,
3183 DBUS_TYPE_STRING, &type,
3184 DBUS_TYPE_STRING, &role,
3185 DBUS_TYPE_INVALID));
3187 pa_device_manager_load_sink(dm, type, role);
3188 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3189 dbus_message_unref(reply);
3192 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3193 pa_device_manager *dm;
3195 DBusMessage *reply = NULL;
3197 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3198 dm = (pa_device_manager *) userdata;
3199 pa_assert_se(dbus_message_get_args(msg, NULL,
3200 DBUS_TYPE_STRING, &type,
3201 DBUS_TYPE_STRING, &role,
3202 DBUS_TYPE_INVALID));
3204 pa_device_manager_unload_sink(dm, type, role);
3205 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3206 dbus_message_unref(reply);
3209 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3210 pa_device_manager *dm;
3211 char *device_string;
3212 DBusMessage *reply = NULL;
3214 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3215 dm = (pa_device_manager *) userdata;
3216 pa_assert_se(dbus_message_get_args(msg, NULL,
3217 DBUS_TYPE_STRING, &device_string,
3218 DBUS_TYPE_INVALID));
3220 pa_device_manager_unload_sink_with_device_string(dm, device_string);
3221 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3222 dbus_message_unref(reply);
3225 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3226 pa_device_manager *dm;
3228 const char *device_string;
3229 dbus_bool_t is_playback;
3232 dm = (pa_device_manager *) userdata;
3233 pa_assert_se(dbus_message_get_args(msg, NULL,
3234 DBUS_TYPE_BOOLEAN, &is_playback,
3235 DBUS_TYPE_STRING, &type,
3236 DBUS_TYPE_STRING, &role,
3237 DBUS_TYPE_INVALID));
3239 device_string = pa_device_manager_get_device_string(dm, is_playback, type, role);
3240 if (device_string == NULL) {
3241 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3245 pa_log_info("device string : %s", device_string);
3246 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3247 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &device_string,
3248 DBUS_TYPE_INVALID));
3249 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3250 dbus_message_unref(reply);
3253 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3254 pa_device_manager *dm;
3255 pa_tz_device *device;
3256 uint32_t device_idx;
3257 DBusMessage *reply = NULL;
3259 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3260 dm = (pa_device_manager *) userdata;
3262 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3263 pa_tz_device_dump_info(device, PA_LOG_INFO);
3265 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3266 dbus_message_unref(reply);
3269 static bool is_usb_output_device(pa_tz_device *device) {
3271 dm_device_direction_t direction;
3276 type = pa_tz_device_get_type(device);
3277 if (!pa_streq(type, DEVICE_TYPE_USB_AUDIO)) {
3278 pa_log_error("device(id:%d, %s) is not USB AUDIO type", pa_tz_device_get_id(device), type);
3281 direction = pa_tz_device_get_direction(device);
3282 if (direction & DM_DEVICE_DIRECTION_OUT) {
3283 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
3284 pa_log_error("sink is null");
3288 pa_log_error("this device is not for output");
3295 static bool is_supported_sample_rate(uint32_t *supported_sample_rates, uint32_t sample_rate) {
3298 pa_assert(supported_sample_rates);
3300 /* use a supported sample rate selected by user */
3301 for (i = 0; supported_sample_rates[i]; i++) {
3302 if (supported_sample_rates[i] == sample_rate) {
3303 pa_log_info("%u is supported", sample_rate);
3307 pa_log_error("%u is not supported", sample_rate);
3311 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3312 pa_device_manager *dm;
3313 DBusMessage *reply = NULL;
3314 DBusMessageIter msg_iter, array_iter, item_iter;
3315 dbus_int32_t device_id;
3316 pa_tz_device *device;
3322 pa_assert(userdata);
3324 dm = (pa_device_manager *)userdata;
3326 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3328 pa_assert_se(dbus_message_get_args(msg, NULL,
3329 DBUS_TYPE_INT32, &device_id,
3330 DBUS_TYPE_INVALID));
3332 pa_log_info("Get supported sample rates of the device(id:%d)", device_id);
3334 if (!(device = _device_list_get_device_by_id(dm, device_id))) {
3335 pa_log_error("could not find any device with id:%d", device_id);
3336 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3339 if (!is_usb_output_device(device)) {
3340 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.PolicyInternal");
3343 sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
3345 dbus_message_iter_init_append(reply, &msg_iter);
3346 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(u)", &array_iter));
3347 for (i = 0; sink->supported_sample_rates[i]; i++) {
3348 pa_log_info("%u is supported", sink->supported_sample_rates[i]);
3349 pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &item_iter));
3350 dbus_message_iter_append_basic(&item_iter, DBUS_TYPE_UINT32, &sink->supported_sample_rates[i]);
3351 pa_assert_se(dbus_message_iter_close_container(&array_iter, &item_iter));
3353 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
3354 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3355 dbus_message_unref(reply);
3358 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3359 pa_device_manager *dm;
3360 DBusMessage *reply = NULL;
3361 dbus_int32_t device_id;
3362 dbus_uint32_t sample_rate;
3363 uint32_t prev_selected_sample_rate;
3364 pa_tz_device *device;
3371 pa_assert(userdata);
3373 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3374 dm = (pa_device_manager *)userdata;
3375 pa_assert_se(dbus_message_get_args(msg, NULL,
3376 DBUS_TYPE_INT32, &device_id,
3377 DBUS_TYPE_UINT32, &sample_rate,
3378 DBUS_TYPE_INVALID));
3380 pa_log_info("Set sample rate(%u) of the device(id:%d)", sample_rate, device_id);
3382 if (!(device = _device_list_get_device_by_id(dm, device_id))) {
3383 pa_log_error("could not find any device with id:%d", device_id);
3384 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3387 if (!is_usb_output_device(device)) {
3388 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.PolicyInternal");
3391 sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
3393 /* use stream original sample rate if possible */
3394 if (sample_rate == 0) {
3395 sink->avoid_resampling = true;
3396 PA_IDXSET_FOREACH(si, sink->inputs, idx) {
3397 if (pa_sink_reconfigure(sink, &si->sample_spec, pa_sink_input_is_passthrough(si)) == -1) {
3398 pa_log_error("failed to reconfigure");
3399 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3400 sink->avoid_resampling = sink->origin_avoid_resampling;
3404 sink->selected_sample_rate = 0;
3406 pa_log_info("Set sample rate to avoid resampling for the device(%u) successfully", device_id);
3407 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3408 dbus_message_unref(reply);
3412 /* use a supported sample rate selected by user */
3413 if (!is_supported_sample_rate(sink->supported_sample_rates, sample_rate)) {
3414 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3417 prev_selected_sample_rate = sink->selected_sample_rate;
3418 sink->selected_sample_rate = sample_rate;
3420 PA_IDXSET_FOREACH(si, sink->inputs, idx) {
3421 if (pa_sink_reconfigure(sink, &si->sample_spec, pa_sink_input_is_passthrough(si)) == -1) {
3422 pa_log_error("failed to reconfigure");
3423 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3424 sink->selected_sample_rate = prev_selected_sample_rate;
3429 sink->avoid_resampling = sink->origin_avoid_resampling;
3431 pa_log_info("Set sample rate(%u) of the device(id:%d) successfully", sample_rate, device_id);
3432 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3433 dbus_message_unref(reply);
3436 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3437 pa_device_manager *dm;
3438 DBusMessage *reply = NULL;
3439 dbus_int32_t device_id;
3440 pa_tz_device *device;
3445 pa_assert(userdata);
3447 dm = (pa_device_manager *)userdata;
3449 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3451 pa_assert_se(dbus_message_get_args(msg, NULL,
3452 DBUS_TYPE_INT32, &device_id,
3453 DBUS_TYPE_INVALID));
3455 pa_log_info("Get sample rate of the device(id:%d)", device_id);
3457 if (!(device = _device_list_get_device_by_id(dm, device_id))) {
3458 pa_log_error("could not find any device with id:%d", device_id);
3459 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3462 if (!is_usb_output_device(device)) {
3463 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.PolicyInternal");
3466 sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
3468 pa_log_info("Get sample rate(%u) of the device(id:%d) successfully", sink->selected_sample_rate, device_id);
3469 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3470 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &sink->selected_sample_rate, DBUS_TYPE_INVALID));
3471 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3472 dbus_message_unref(reply);
3475 static void handle_set_specific_stream_only(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3476 pa_device_manager *dm;
3477 DBusMessage *reply = NULL;
3478 dbus_int32_t device_id;
3480 pa_tz_device *device;
3484 pa_assert(userdata);
3486 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3487 dm = (pa_device_manager *)userdata;
3488 pa_assert_se(dbus_message_get_args(msg, NULL,
3489 DBUS_TYPE_INT32, &device_id,
3490 DBUS_TYPE_STRING, &stream_role,
3491 DBUS_TYPE_INVALID));
3493 pa_log_info("Set the device(id:%d) only for the stream role(%s)", device_id, stream_role);
3495 if (!(device = _device_list_get_device_by_id(dm, device_id))) {
3496 pa_log_error("could not find any device with id:%d", device_id);
3497 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3500 if (!is_usb_output_device(device)) {
3501 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.PolicyInternal");
3505 device->specified_stream_role = stream_role;
3507 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3508 dbus_message_unref(reply);
3511 static void handle_get_specified_stream(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3512 pa_device_manager *dm;
3513 DBusMessage *reply = NULL;
3514 dbus_int32_t device_id;
3515 char *specified_stream_role;
3516 pa_tz_device *device;
3520 pa_assert(userdata);
3522 dm = (pa_device_manager *)userdata;
3524 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3526 pa_assert_se(dbus_message_get_args(msg, NULL,
3527 DBUS_TYPE_INT32, &device_id,
3528 DBUS_TYPE_INVALID));
3530 pa_log_info("Get specified stream role for the device(id:%d)", device_id);
3532 if (!(device = _device_list_get_device_by_id(dm, device_id))) {
3533 pa_log_error("could not find any device with id:%d", device_id);
3534 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3537 if (!is_usb_output_device(device)) {
3538 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.PolicyInternal");
3542 specified_stream_role = device->specified_stream_role;
3544 pa_log_info("stream role(%s) is specified for the device(id:%d)", device->specified_stream_role, device_id);
3545 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3546 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &specified_stream_role, DBUS_TYPE_INVALID));
3547 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3548 dbus_message_unref(reply);
3551 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3552 pa_device_manager *dm = (pa_device_manager *)userdata;
3554 dbus_int32_t status;
3555 DBusMessage *reply = NULL;
3558 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3560 dbus_error_init(&error);
3561 if (!dbus_message_get_args(msg, NULL,
3562 DBUS_TYPE_STRING, &type,
3563 DBUS_TYPE_INT32, &status,
3564 DBUS_TYPE_INVALID)) {
3565 pa_log_error("failed to get dbus args : %s", error.message);
3566 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
3567 dbus_error_free(&error);
3570 pa_log_debug("handle_test_device_status_change, type:%s, status:%d", type, status);
3572 handle_device_status_changed(dm, type, NULL, NULL, status);
3573 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3574 dbus_message_unref(reply);
3577 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3578 const char *xml = DEVICE_MANAGER_INTROSPECT_XML;
3579 DBusMessage *r = NULL;
3583 pa_assert(userdata);
3585 pa_assert_se(r = dbus_message_new_method_return(msg));
3586 pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
3589 pa_assert_se(dbus_connection_send((conn), r, NULL));
3590 dbus_message_unref(r);
3593 return DBUS_HANDLER_RESULT_HANDLED;
3596 static DBusHandlerResult handle_device_manager_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3601 pa_assert(userdata);
3603 for (method_idx = 0; method_idx < METHOD_HANDLER_MAX; method_idx++) {
3604 if (dbus_message_is_method_call(msg, DBUS_INTERFACE_DEVICE_MANAGER, method_handlers[method_idx].method_name)) {
3605 method_handlers[method_idx].receive_cb(conn, msg, userdata);
3606 return DBUS_HANDLER_RESULT_HANDLED;
3610 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3613 static DBusHandlerResult method_call_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
3614 struct userdata *u = userdata;
3615 const char *path, *interface, *member;
3621 path = dbus_message_get_path(m);
3622 interface = dbus_message_get_interface(m);
3623 member = dbus_message_get_member(m);
3625 pa_log_info("DeviceManager Method Call Handler : path=%s, interface=%s, member=%s", path, interface, member);
3627 if (!pa_streq(path, DBUS_OBJECT_DEVICE_MANAGER))
3628 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3630 if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
3631 return handle_introspect(c, m, u);
3633 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get")) {
3634 return handle_get_property(c, m, u);
3635 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set")) {
3636 return handle_set_property(c, m, u);
3637 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll")) {
3638 return handle_get_all_property(c, m, u);
3641 return handle_device_manager_methods(c, m, u);
3644 return DBUS_HANDLER_RESULT_HANDLED;
3647 static void endpoint_init(pa_device_manager *dm) {
3648 static const DBusObjectPathVTable vtable_endpoint = {
3649 .message_function = method_call_handler,
3652 pa_log_info("Device manager dbus endpoint init");
3654 if (dm && dm->dbus_conn) {
3655 if (!dbus_connection_register_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER, &vtable_endpoint, dm))
3656 pa_log_error("Failed to register object path");
3658 pa_log_error("Cannot get dbus connection to register object path");
3662 static void endpoint_done(pa_device_manager *dm) {
3663 pa_log_info("Device manager dbus endpoint done");
3664 if (dm && dm->dbus_conn) {
3665 if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER))
3666 pa_log_error("Failed to unregister object path");
3668 pa_log_error("Cannot get dbus connection to unregister object path");
3672 static void dbus_init(pa_device_manager *dm) {
3674 pa_dbus_connection *connection = NULL;
3677 pa_log_info("Dbus init");
3678 dbus_error_init(&error);
3680 if (!(connection = pa_dbus_bus_get(dm->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
3682 pa_dbus_connection_unref(connection);
3684 pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
3687 pa_log_info("Got dbus connection");
3690 dm->dbus_conn = connection;
3692 if (watch_signals(dm) < 0)
3693 pa_log_error("dbus watch signals failed");
3695 pa_log_debug("dbus ready to get signals");
3700 dbus_error_free(&error);
3703 static void dbus_deinit(pa_device_manager *dm) {
3706 pa_log_info("Dbus deinit");
3709 unwatch_signals(dm);
3711 if (dm->dbus_conn) {
3712 pa_dbus_connection_unref(dm->dbus_conn);
3713 dm->dbus_conn = NULL;
3718 pa_idxset* pa_device_manager_get_device_list(pa_device_manager *dm) {
3720 pa_assert(dm->device_list);
3722 return dm->device_list;
3725 pa_tz_device* pa_device_manager_get_device(pa_device_manager *dm, const char *type) {
3728 return _device_list_get_device(dm, type, NULL);
3731 pa_tz_device* pa_device_manager_get_device_by_id(pa_device_manager *dm, uint32_t id) {
3734 return _device_list_get_device_by_id(dm, id);
3737 pa_tz_device* pa_device_manager_get_device_with_sink(pa_sink *sink) {
3740 return sink->device_item;
3743 pa_tz_device* pa_device_manager_get_device_with_source(pa_source *source) {
3746 return source->device_item;
3749 pa_tz_device* pa_device_manager_load_forwarding(pa_device_manager *dm) {
3750 return _load_forwarding_device(dm);
3753 void pa_device_manager_unload_forwarding(pa_device_manager *dm) {
3754 pa_tz_device *forwarding_device;
3756 forwarding_device = _device_list_get_device(dm, DEVICE_TYPE_FORWARDING, NULL);
3757 if (forwarding_device)
3758 pa_tz_device_free(forwarding_device);
3760 pa_log_warn("There is no forwarding device");
3763 pa_sink* pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const char *role) {
3764 const char *device_string, *params;
3765 struct device_type_info *type_info;
3766 struct device_file_info *file_info;
3767 pa_tz_device *device;
3769 uint32_t device_idx;
3772 pa_assert(dm->device_list);
3776 pa_log_info("Load Sink for '%s.%s'", type, role);
3777 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3778 if (pa_streq(type, pa_tz_device_get_type(device))) {
3779 if (pa_tz_device_get_sink(device, role)) {
3780 pa_log_warn("Proper sink for '%s.%s' already loaded", type, role);
3786 if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3787 pa_log_error("No type map for %s", type);
3791 if (type_info->playback_devices == NULL) {
3792 pa_log_error("No playback devices for %s", type_info->type);
3796 if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
3797 pa_log_error("No device-string for '%s.%s'", type, role);
3801 if (!(file_info = _device_manager_get_file_info(dm->file_map->playback, device_string))) {
3802 pa_log_error("No playback file-map for '%s'", device_string);
3806 if (!(params = pa_hashmap_get(file_info->roles, role))) {
3807 pa_log_error("No params for '%s,%s'", device_string, role);
3811 if ((sink = load_device(dm->core, true, device_string, params))) {
3812 pa_log_debug("loaded sink '%s' for '%s,%s' success", sink->name, type, role);
3814 pa_log_warn("Cannot load playback device with '%s,%s'", device_string, params);
3824 void pa_device_manager_unload_sink(pa_device_manager *dm, const char *type, const char *role) {
3825 const char *device_string;
3826 struct device_type_info *type_info;
3829 pa_assert(dm->device_list);
3833 pa_log_info("Unload Sink for '%s.%s'", type, role);
3835 if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3836 pa_log_error("No type map for %s", type);
3840 if (type_info->playback_devices == NULL) {
3841 pa_log_error("No playback devices for %s", type_info->type);
3845 if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
3846 pa_log_error("No device-string for '%s.%s'", type, role);
3850 unload_device(dm->core, true, device_string);
3853 void pa_device_manager_unload_sink_with_device_string(pa_device_manager *dm, const char *device_string) {
3855 pa_assert(device_string);
3857 unload_device(dm->core, true, device_string);
3860 pa_source* pa_device_manager_load_source(pa_device_manager *dm, const char *type, const char *role) {
3861 const char *device_string, *params;
3862 struct device_type_info *type_info;
3863 struct device_file_info *file_info;
3864 pa_tz_device *device;
3866 uint32_t device_idx;
3869 pa_assert(dm->device_list);
3873 pa_log_info("Load Source for '%s.%s'", type, role);
3875 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3876 if (pa_streq(type, pa_tz_device_get_type(device))) {
3877 if (pa_tz_device_get_source(device, role)) {
3878 pa_log_warn("Proper source for '%s.%s' already loaded", type, role);
3884 if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3885 pa_log_error("No type map for %s", type);
3889 if (type_info->capture_devices == NULL) {
3890 pa_log_error("No capture devices for %s", type_info->type);
3894 if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
3895 pa_log_error("No device-string for '%s.%s'", type, role);
3899 if (!(file_info = _device_manager_get_file_info(dm->file_map->capture, device_string))) {
3900 pa_log_error("No capture file-map for '%s'", device_string);
3904 if (!(params = pa_hashmap_get(file_info->roles, role))) {
3905 pa_log_error("No params for '%s,%s'", device_string, role);
3909 if ((source = load_device(dm->core, false, device_string, params))) {
3910 pa_log_debug("loaded source '%s' for '%s,%s' success", source->name, type, role);
3912 pa_log_warn("Cannot load capture device with '%s,%s'", device_string, params);
3922 void pa_device_manager_unload_source(pa_device_manager *dm, const char *type, const char *role) {
3923 const char *device_string;
3924 struct device_type_info *type_info;
3927 pa_assert(dm->device_list);
3931 pa_log_info("Unload Source for '%s.%s'", type, role);
3933 if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3934 pa_log_error("No type map for %s", type);
3938 if (type_info->capture_devices == NULL) {
3939 pa_log_error("No capture devices for %s", type_info->type);
3943 if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
3944 pa_log_error("No device-string for '%s.%s'", type, role);
3948 unload_device(dm->core, false, device_string);
3951 void pa_device_manager_unload_source_with_device_string(pa_device_manager *dm, const char *device_string) {
3953 pa_assert(device_string);
3955 unload_device(dm->core, false, device_string);
3958 const char* pa_device_manager_get_device_string(pa_device_manager *dm, bool is_playback, const char *type, const char *role) {
3959 struct device_type_info *type_info;
3965 type_info = _device_manager_get_type_info(dm->type_infos, type);
3966 if (type_info == NULL) {
3967 pa_log_error("No type info for %s", type);
3971 return device_type_info_get_device_string(type_info, is_playback, role);
3974 void pa_device_manager_update_device_running_state(pa_device_manager *dm, uint32_t num_of_devices, pa_device_info *device_infos, bool output_device) {
3980 index = (uint32_t)output_device; /* input:0, output:1 */
3983 if (num_of_devices == 0) {
3984 for (i = 0; i < DEVICE_INDEX_MAX; i++) {
3985 if (!internal_codec_devices[i].is_running[index])
3987 internal_codec_devices[i].is_running[index] = false;
3988 /* change to NOT RUNNING */
3989 if (!internal_codec_devices[i].is_running[!index]) {
3990 find_device_and_set_running(dm, internal_codec_devices[i].type, false);
3991 internal_codec_devices_dump();
3997 for (i = 0; i < DEVICE_INDEX_MAX; i++) {
3999 if (!internal_codec_devices[i].is_running[index])
4001 for (j = 0; j < num_of_devices; j++) {
4002 if (pa_safe_streq(device_infos[j].type, internal_codec_devices[i].type))
4006 internal_codec_devices[i].is_running[index] = false;
4007 /* change to NOT RUNNING */
4008 if (!internal_codec_devices[i].is_running[!index]) {
4009 find_device_and_set_running(dm, internal_codec_devices[i].type, false);
4010 internal_codec_devices_dump();
4015 for (i = 0; i < num_of_devices; i++) {
4016 for (j = 0; j < DEVICE_INDEX_MAX; j++) {
4017 if (!pa_safe_streq(device_infos[i].type, internal_codec_devices[j].type))
4019 if (!internal_codec_devices[j].is_running[index]) {
4020 internal_codec_devices[j].is_running[index] = true;
4021 /* change to RUNNING */
4022 find_device_and_set_running(dm, internal_codec_devices[j].type, true);
4023 internal_codec_devices_dump();
4029 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) {
4030 send_device_connection_changed_signal(data->event_id, data->device, data->is_connected, dm);
4034 /* it will be replaced by running_changed_hook_cb() */
4035 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) {
4036 send_device_info_changed_signal(data->event_id, data->device, DM_DEVICE_CHANGED_INFO_STATE, dm);
4037 send_device_state_changed_signal(data->event_id, data->device, data->activated, dm);
4041 static pa_hook_result_t device_running_changed_hook_cb(pa_core *c, pa_tz_device_hook_data_for_running_changed *data, pa_device_manager *dm) {
4042 send_device_running_changed_signal(data->event_id, data->device, data->is_running, dm);
4043 pa_log_info("RUNNING CHANGED!! device type[%s], is running[%d]", data->device->type, data->is_running);
4047 pa_device_manager* pa_device_manager_get(pa_core *c) {
4048 pa_device_manager *dm;
4052 pa_log_info("pa_device_manager_get");
4054 if ((dm = pa_shared_get(c, SHARED_DEVICE_MANAGER)))
4055 return pa_device_manager_ref(dm);
4057 dm = pa_xnew0(pa_device_manager, 1);
4060 dm->device_list = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4061 dm->device_status = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4065 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);
4066 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);
4067 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);
4068 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);
4069 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);
4070 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);
4071 dm->comm = pa_communicator_get(dm->core);
4072 dm->comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
4073 PA_HOOK_EARLY, (pa_hook_cb_t)device_connection_changed_hook_cb, dm);
4074 dm->comm_hook_device_state_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_STATE_CHANGED),
4075 PA_HOOK_EARLY, (pa_hook_cb_t)device_state_changed_hook_cb, dm);
4076 dm->comm_hook_device_running_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_RUNNING_CHANGED),
4077 PA_HOOK_EARLY, (pa_hook_cb_t)device_running_changed_hook_cb, dm);
4079 dm->hal_interface = pa_hal_interface_get(dm->core);
4081 if (!(dm->type_infos = parse_device_type_infos())) {
4082 pa_log_error("Parse device-type-map failed");
4086 if (!(dm->file_map = parse_device_file_map())) {
4087 pa_log_error("Parse device-file-map failed");
4091 device_type_status_init(dm);
4093 if (load_builtin_devices(dm) != 0) {
4094 pa_log_error("Load Builtin Devices faled");
4098 /* Just for convenience when test*/
4099 if (!_device_manager_set_default_sink(dm, DEVICE_TYPE_SPEAKER, "normal")) {
4100 pa_log_warn("Set default sink with speaker(normal) failed");
4102 if (!_device_manager_set_default_source(dm, DEVICE_TYPE_MIC, "normal")) {
4103 pa_log_warn("Set default source with mic(normal) failed");
4106 pa_shared_set(c, SHARED_DEVICE_MANAGER, dm);
4111 pa_device_manager* pa_device_manager_ref(pa_device_manager *dm) {
4113 pa_assert(PA_REFCNT_VALUE(dm) > 0);
4115 pa_log_info("pa_device_manager_ref");
4121 void pa_device_manager_unref(pa_device_manager *dm) {
4123 pa_assert(PA_REFCNT_VALUE(dm) > 0);
4125 pa_log_info("pa_device_manager_unref");
4126 if (PA_REFCNT_DEC(dm) > 0)
4129 if (dm->comm_hook_device_connection_changed_slot)
4130 pa_hook_slot_free(dm->comm_hook_device_connection_changed_slot);
4131 if (dm->comm_hook_device_state_changed_slot)
4132 pa_hook_slot_free(dm->comm_hook_device_state_changed_slot);
4133 if (dm->comm_hook_device_running_changed_slot)
4134 pa_hook_slot_free(dm->comm_hook_device_running_changed_slot);
4135 if (dm->sink_put_hook_slot)
4136 pa_hook_slot_free(dm->sink_put_hook_slot);
4137 if (dm->sink_unlink_hook_slot)
4138 pa_hook_slot_free(dm->sink_unlink_hook_slot);
4139 if (dm->sink_state_changed_slot)
4140 pa_hook_slot_free(dm->sink_state_changed_slot);
4141 if (dm->source_put_hook_slot)
4142 pa_hook_slot_free(dm->source_put_hook_slot);
4143 if (dm->source_unlink_hook_slot)
4144 pa_hook_slot_free(dm->source_unlink_hook_slot);
4145 if (dm->source_state_changed_slot)
4146 pa_hook_slot_free(dm->source_state_changed_slot);
4148 if (dm->hal_interface)
4149 pa_hal_interface_unref(dm->hal_interface);
4152 pa_communicator_unref(dm->comm);
4155 pa_idxset_free(dm->type_infos, (pa_free_cb_t)type_info_free_func);
4157 if (dm->file_map->playback)
4158 pa_idxset_free(dm->file_map->playback, (pa_free_cb_t)file_info_free_func);
4159 if (dm->file_map->capture)
4160 pa_idxset_free(dm->file_map->capture, (pa_free_cb_t)file_info_free_func);
4161 pa_xfree(dm->file_map);
4163 if (dm->device_list)
4164 pa_idxset_free(dm->device_list, (pa_free_cb_t)pa_tz_device_free);
4165 if (dm->device_status)
4166 pa_idxset_free(dm->device_status, NULL);
4171 pa_shared_remove(dm->core, SHARED_DEVICE_MANAGER);