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 "device-manager.h"
55 #define SHARED_DEVICE_MANAGER "tizen-device-manager"
57 #define DEVICE_MAP_FILE "/etc/pulse/device-map.json"
58 #define DEVICE_STR_MAX 30
59 #define DEVICE_DIRECTION_MAX 3
60 #define DEVICE_PARAM_STRING_MAX 150
61 #define DEVICE_AVAIL_COND_NUM_MAX 2
62 #define DEVICE_AVAIL_COND_STR_MAX 6
63 #define DEVICE_FILE_PER_TYPE_MAX 4
64 #define DEVICE_FILE_STRING_MAX 4
65 #define DEVICE_TYPE_STR_MAX 20
66 #define DEVICE_ROLE_STR_MAX 15
68 #define DEVICE_TYPE_OBJECT "device-types"
69 #define DEVICE_FILE_OBJECT "device-files"
70 #define DEVICE_TYPE_PROP_DEVICE_TYPE "device-type"
71 #define DEVICE_TYPE_PROP_PLAYBACK_DEVICES "playback-devices"
72 #define DEVICE_TYPE_PROP_CAPTURE_DEVICES "capture-devices"
73 #define DEVICE_TYPE_PROP_DEVICE_STRING "device-string"
74 #define DEVICE_TYPE_PROP_ROLE "role"
76 #define DEVICE_TYPE_STR_MAX 20
78 /* Properties of sink/sources */
79 #define DEVICE_API_BLUEZ "bluez"
80 #define DEVICE_API_ALSA "alsa"
81 #define DEVICE_API_NULL "null"
82 #define DEVICE_BUS_USB "usb"
83 #define DEVICE_CLASS_SOUND "sound"
84 #define DEVICE_CLASS_MONITOR "monitor"
87 #define DBUS_INTERFACE_DEVICE_MANAGER "org.pulseaudio.DeviceManager"
88 #define DBUS_OBJECT_DEVICE_MANAGER "/org/pulseaudio/DeviceManager"
90 #define DBUS_INTERFACE_DEVICED_SYSNOTI "org.tizen.system.deviced.SysNoti"
91 #define DBUS_OBJECT_DEVICED_SYSNOTI "/Org/Tizen/System/DeviceD/SysNoti"
93 #define DBUS_INTERFACE_SOUND_SERVER "org.tizen.SoundServer1"
94 #define DBUS_OBJECT_SOUND_SERVER "/org/tizen/SoundServer1"
96 #define DBUS_SERVICE_BLUEZ "org.bluez"
97 #define DBUS_INTERFACE_BLUEZ_HEADSET "org.bluez.Headset"
98 #define DBUS_INTERFACE_BLUEZ_DEVICE "org.bluez.Device1"
99 #define DBUS_OBJECT_BLUEZ "/org/bluez"
101 #define DBUS_INTERFACE_MIRRORING_SERVER "org.tizen.scmirroring.server"
102 #define DBUS_OBJECT_MIRRORING_SERVER "/org/tizen/scmirroring/server"
104 #define DBUS_SERVICE_HFP_AGENT "org.bluez.ag_agent"
105 #define DBUS_OBJECT_HFP_AGENT "/org/bluez/hfp_agent"
106 #define DBUS_INTERFACE_HFP_AGENT "Org.Hfp.App.Interface"
108 #define DEVICE_MANAGER_INTROSPECT_XML \
109 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
111 " <interface name=\"" DBUS_INTERFACE_DEVICE_MANAGER "\">\n" \
112 " <method name=\"GetConnectedDeviceList\">\n" \
113 " <arg name=\"mask_flags\" direction=\"in\" type=\"i\"/>\n" \
114 " <arg name=\"ConnectedDeviceList\" direction=\"out\" type=\"a(isiisii)\"/>\n" \
116 " <method name=\"GetDeviceById\">\n" \
117 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
118 " <arg name=\"device\" direction=\"out\" type=\"(isiisii)\"/>\n" \
120 " <method name=\"IsStreamOnDevice\">\n" \
121 " <arg name=\"stream_id\" direction=\"in\" type=\"i\"/>\n" \
122 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
123 " <arg name=\"is_on\" direction=\"out\" type=\"b\"/>\n" \
125 " <method name='GetBTA2DPStatus'>" \
126 " <arg type='b' name='is_bt_on' direction='out'/>" \
127 " <arg type='s' name='bt_name' direction='out'/>" \
129 " <method name=\"LoadSink\">\n" \
130 " <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n" \
131 " <arg name=\"role\" direction=\"in\" type=\"s\"/>\n" \
133 " <method name=\"UnloadSink\">\n" \
134 " <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n" \
135 " <arg name=\"role\" direction=\"in\" type=\"s\"/>\n" \
137 " <method name=\"GetSupportedSampleRates\">\n" \
138 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
139 " <arg name=\"sample_rates\" direction=\"out\" type=\"a(u)\"/>\n" \
141 " <method name=\"SetSampleRate\">\n" \
142 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
143 " <arg name=\"sample_rate\" direction=\"in\" type=\"u\"/>\n" \
145 " <method name=\"GetSampleRate\">\n" \
146 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
147 " <arg name=\"sample_rate\" direction=\"out\" type=\"u\"/>\n" \
149 " <method name=\"DumpDeviceList\">\n" \
151 " <method name=\"TestStatusChange\">\n" \
152 " <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n" \
153 " <arg name=\"status\" direction=\"in\" type=\"i\"/>\n" \
155 " <property name=\"PropertyTest1\" type=\"i\" access=\"readwrite\"/>\n" \
156 " <property name=\"PropertyTest2\" type=\"s\" access=\"read\"/>\n" \
157 " <signal name=\"DeviceConnected\">\n" \
158 " <arg name=\"arg1\" type=\"i\"/>\n" \
160 " <signal name=\"DeviceInfoChanged\">\n" \
161 " <arg name=\"arg1\" type=\"s\"/>\n" \
164 " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n" \
165 " <method name=\"Introspect\">\n" \
166 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \
169 " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n" \
170 " <method name=\"Get\">\n" \
171 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
172 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" \
173 " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n" \
175 " <method name=\"Set\">\n" \
176 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
177 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" \
178 " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n" \
180 " <method name=\"GetAll\">\n" \
181 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
182 " <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n" \
187 #define FILTER_DEVICED_SYSNOTI \
189 " interface='" DBUS_INTERFACE_DEVICED_SYSNOTI "'"
191 #define FILTER_SOUND_SERVER \
193 " interface='" DBUS_INTERFACE_SOUND_SERVER "'"
195 #define FILTER_MIRRORING \
197 " interface='" DBUS_INTERFACE_MIRRORING_SERVER "', member='miracast_wfd_source_status_changed'"
199 #define FILTER_BLUEZ \
201 " interface='" DBUS_INTERFACE_BLUEZ_HEADSET "', member='PropertyChanged'"
203 static const char* const valid_alsa_device_modargs[] = {
221 "tsched_buffer_size",
222 "tsched_buffer_watermark",
227 "deferred_volume_safety_margin",
228 "deferred_volume_extra_delay",
229 "fixed_latency_range",
235 #define BT_CVSD_CODEC_ID 1 // narrow-band
236 #define BT_MSBC_CODEC_ID 2 // wide-band
238 Enums for represent values which is defined on other module.
239 This is needed to identify values which are sent by dbus or vconf.
241 typedef enum external_value_earjack_type {
242 EARJACK_DISCONNECTED = 0,
243 EARJACK_TYPE_SPK_ONLY = 1,
244 EARJACK_TYPE_SPK_WITH_MIC = 3,
245 } external_value_earjack_t;
247 typedef enum external_value_bt_sco_type {
248 BT_SCO_DISCONNECTED = 0,
249 BT_SCO_CONNECTED = 1,
250 } external_value_bt_sco_t;
252 typedef enum external_value_forwarding_type {
253 FORWARDING_DISCONNECTED = 0,
254 FORWARDING_CONNECTED = 1,
255 } external_value_mirroring_t;
257 typedef enum external_value_hdmi_type {
258 HDMI_AUDIO_DISCONNECTED = -1,
259 HDMI_AUDIO_NOT_AVAILABLE = 0,
260 HDMI_AUDIO_AVAILABLE = 1,
261 } external_value_hdmi_t;
265 Enums for represent device detected status (through dbus)
266 When some device is detected, one of these values should be saved in device_status hashmap.
267 device_detected_type_t is needed to distinguish detected device-types ( ex. earjack which can be out or both way)
268 So If you just want to know whether detected or not, can device_detected_t as mask.
271 typedef enum device_detected_type {
272 DEVICE_DISCONNECTED = 0x0,
273 DEVICE_CONNECTED = 0x1,
274 DEVICE_CONNECTED_AUDIO_JACK_4P = DEVICE_CONNECTED | 0x2,
275 DEVICE_CONNECTED_AUDIO_JACK_3P = DEVICE_CONNECTED | 0x4,
276 DEVICE_CONNECTED_SCO = DEVICE_CONNECTED | 0x8,
277 DEVICE_OPENED_SCO = DEVICE_CONNECTED | 0xF,
278 } device_detected_type_t;
280 typedef enum dm_device_class_type {
281 DM_DEVICE_CLASS_NONE,
282 DM_DEVICE_CLASS_ALSA,
283 DM_DEVICE_CLASS_TIZEN,
285 DM_DEVICE_CLASS_NULL,
290 DEVICE_IO_DIRECTION_IN_FLAG = 0x0001, /**< Flag for input devices */
291 DEVICE_IO_DIRECTION_OUT_FLAG = 0x0002, /**< Flag for output devices */
292 DEVICE_IO_DIRECTION_BOTH_FLAG = 0x0004, /**< Flag for input/output devices (both directions are available) */
293 DEVICE_TYPE_INTERNAL_FLAG = 0x0010, /**< Flag for built-in devices */
294 DEVICE_TYPE_EXTERNAL_FLAG = 0x0020, /**< Flag for external devices */
295 DEVICE_STATE_DEACTIVATED_FLAG = 0x1000, /**< Flag for deactivated devices */
296 DEVICE_STATE_ACTIVATED_FLAG = 0x2000, /**< Flag for activated devices */
297 DEVICE_ALL_FLAG = 0xFFFF, /**< Flag for all devices */
301 DEVICE_IO_DIRECTION_FLAGS = 0x000F, /**< Flag for io direction */
302 DEVICE_TYPE_FLAGS = 0x00F0, /**< Flag for device type */
303 DEVICE_STATE_FLAGS = 0xF000, /**< Flag for device state */
304 } device_flags_type_t;
306 typedef enum dm_device_bt_mode_type {
307 DM_DEVICE_BT_MODE_MEDIA = 0x1,
308 DM_DEVICE_BT_MODE_VOICE = 0x2
309 } dm_device_bt_mode_t;
311 typedef enum dm_device_changed_into_type {
312 DM_DEVICE_CHANGED_INFO_STATE,
313 DM_DEVICE_CHANGED_INFO_IO_DIRECTION,
314 DM_DEVICE_CHANGED_INFO_MAX
315 } dm_device_changed_info_t;
319 Structure to save parsed information about device-file.
321 struct device_file_map {
322 /* { key:device_string -> value:device_file_prop } */
327 /***************** structures for static information get from json *********/
330 Structure for informations related to some device-file(ex. 0:0)
332 struct device_file_info {
334 String for identify target device.
335 ex) alsa:0,0 or null ..
337 const char *device_string;
339 For save roles which are supported on device file, and parameters.
340 { key:device_role -> value:parameters for load sink/source }
341 ex) "normal"->"rate=44100 tsched=0", "uhqa"->"rate=192000 mmap=1"
345 For save device-types related to device file.
346 { key:device_type-> value:pulse_device_prop }
348 pa_hashmap *device_types;
351 /* structure for represent device-types(ex. builtin-speaker) properties*/
352 struct device_type_info {
355 For save supported roles and related device-file.
356 { key:role -> value:device_string ]
358 pa_hashmap *playback_devices;
359 pa_hashmap *capture_devices;
362 struct device_status_info {
365 /* Identify devices among same device-types (for multi-device), currently not works*/
367 device_detected_type_t detected;
370 struct pulse_device_prop {
371 /* roles related to (device_type + device_file)*/
373 /* For save that this devie_type is activated or not on sink/source */
376 /******************************************************************************/
377 struct pa_device_manager {
381 pa_hook_slot *sink_put_hook_slot, *sink_unlink_hook_slot, *sink_state_changed_slot;
382 pa_hook_slot *source_put_hook_slot, *source_unlink_hook_slot, *source_state_changed_slot;
383 pa_hook_slot *comm_hook_device_connection_changed_slot;
384 pa_hook_slot *comm_hook_device_state_changed_slot;
385 pa_hook_slot *comm_hook_device_running_changed_slot;
386 pa_communicator *comm;
387 pa_hal_interface *hal_interface;
390 Idxset for save parsed information about device-type.
393 pa_idxset *type_infos;
394 /* For save Parsed information about device-file */
395 struct device_file_map *file_map;
398 pa_idxset *device_list;
400 Hashmap for save statuses got through dbus.
401 { key:device_type -> value:(audio_detected_type_t or device_detected_t) }
403 pa_idxset *device_status;
404 pa_dbus_connection *dbus_conn;
407 struct composite_type {
414 /*** Defines for method handle ***/
415 /* method handlers */
416 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
417 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata);
418 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
419 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
420 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata);
421 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
422 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
423 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
424 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
425 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata);
426 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata);
427 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
428 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata);
430 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name);
432 enum method_handler_index {
433 METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST,
434 METHOD_HANDLER_GET_DEVICE_BY_ID,
435 METHOD_HANDLER_IS_STREAM_ON_DEVICE,
436 METHOD_HANDLER_GET_BT_A2DP_STATUS,
437 METHOD_HANDLER_LOAD_SINK,
438 METHOD_HANDLER_UNLOAD_SINK,
439 METHOD_HANDLER_UNLOAD_SINK_WITH_DEVICE_STRING,
440 METHOD_HANDLER_GET_DEVICE_STRING,
441 METHOD_HANDLER_GET_SUPPORTED_SAMPLE_RATES,
442 METHOD_HANDLER_SET_SAMPLE_RATE,
443 METHOD_HANDLER_GET_SAMPLE_RATE,
444 METHOD_HANDLER_DUMP_DEVICE_LIST,
445 METHOD_HANDLER_STATUS_TEST,
449 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
450 [METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST] = {
451 .method_name = "GetConnectedDeviceList",
452 .receive_cb = handle_get_connected_device_list },
453 [METHOD_HANDLER_GET_DEVICE_BY_ID] = {
454 .method_name = "GetDeviceById",
455 .receive_cb = handle_get_device_by_id },
456 [METHOD_HANDLER_IS_STREAM_ON_DEVICE] = {
457 .method_name = "IsStreamOnDevice",
458 .receive_cb = handle_is_stream_on_device },
459 [METHOD_HANDLER_GET_BT_A2DP_STATUS] = {
460 .method_name = "GetBTA2DPStatus",
461 .receive_cb = handle_get_bt_a2dp_status },
462 [METHOD_HANDLER_LOAD_SINK] = {
463 .method_name = "LoadSink",
464 .receive_cb = handle_load_sink },
465 [METHOD_HANDLER_UNLOAD_SINK] = {
466 .method_name = "UnloadSink",
467 .receive_cb = handle_unload_sink },
468 [METHOD_HANDLER_UNLOAD_SINK_WITH_DEVICE_STRING] = {
469 .method_name = "UnloadSinkWithDeviceString",
470 .receive_cb = handle_unload_sink_with_device_string },
471 [METHOD_HANDLER_GET_DEVICE_STRING] = {
472 .method_name = "GetDeviceString",
473 .receive_cb = handle_get_device_string },
474 [METHOD_HANDLER_GET_SUPPORTED_SAMPLE_RATES] = {
475 .method_name = "GetSupportedSampleRates",
476 .receive_cb = handle_get_supported_sample_rates },
477 [METHOD_HANDLER_SET_SAMPLE_RATE] = {
478 .method_name = "SetSampleRate",
479 .receive_cb = handle_set_sample_rate },
480 [METHOD_HANDLER_GET_SAMPLE_RATE] = {
481 .method_name = "GetSampleRate",
482 .receive_cb = handle_get_sample_rate },
483 [METHOD_HANDLER_DUMP_DEVICE_LIST] = {
484 .method_name = "DumpDeviceList",
485 .receive_cb = handle_dump_device_list },
486 [METHOD_HANDLER_STATUS_TEST] = {
487 .method_name = "TestStatusChange",
488 .receive_cb = handle_test_device_status_change },
493 enum internal_codec_device_index {
494 DEVICE_INDEX_BUILTIN_SPEAKER,
495 DEVICE_INDEX_BUILTIN_RECEIVER,
496 DEVICE_INDEX_BUILTIN_MIC,
497 DEVICE_INDEX_AUDIO_JACK,
502 typedef struct _internal_codec_device {
504 bool is_running[2]; /* index[in:0, out:1] */
505 } internal_codec_device;
507 static internal_codec_device internal_codec_devices[DEVICE_INDEX_MAX] = {
508 [DEVICE_INDEX_BUILTIN_SPEAKER] = {
509 .type = DEVICE_TYPE_SPEAKER,
510 .is_running[0] = false,
511 .is_running[1] = false },
512 [DEVICE_INDEX_BUILTIN_RECEIVER] = {
513 .type = DEVICE_TYPE_RECEIVER,
514 .is_running[0] = false,
515 .is_running[1] = false },
516 [DEVICE_INDEX_BUILTIN_MIC] = {
517 .type = DEVICE_TYPE_MIC,
518 .is_running[0] = false,
519 .is_running[1] = false },
520 [DEVICE_INDEX_AUDIO_JACK] = {
521 .type = DEVICE_TYPE_AUDIO_JACK,
522 .is_running[0] = false,
523 .is_running[1] = false },
524 [DEVICE_INDEX_BT_SCO] = {
525 .type = DEVICE_TYPE_BT_SCO,
526 .is_running[0] = false,
527 .is_running[1] = false },
530 static inline void internal_codec_devices_dump() {
532 pa_log_info("========== devices using internal codec ==========");
533 for (i = 0; i < DEVICE_INDEX_MAX; i++)
534 pa_log_info(" type[%18s], is_running[in:%d,out:%d]", internal_codec_devices[i].type,
535 internal_codec_devices[i].is_running[0], internal_codec_devices[i].is_running[1]);
536 pa_log_info("==================================================");
539 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) {
540 pa_logl(level, "%s device id(%d) type(%s) name (%s) direction(%d) state(%d)",
541 pa_strempty(prefix), id, pa_strnull(type), pa_strnull(name), direction, state);
544 static void find_device_and_set_running(pa_device_manager *dm, const char *type, bool is_running) {
545 pa_tz_device* device;
552 pa_log_info("find device [%s]", type);
554 if ((device = pa_device_manager_get_device(dm, type))) {
555 if (pa_tz_device_is_use_internal_codec(device))
556 pa_tz_device_set_running_and_notify(device, is_running);
558 pa_log_warn("this device [%s] does not use internal codec, skip it", type);
560 pa_log_warn("cound not find a device of [%s]", type);
564 static void type_info_free_func(struct device_type_info *type_info) {
568 if (type_info->playback_devices)
569 pa_hashmap_free(type_info->playback_devices);
570 if (type_info->capture_devices)
571 pa_hashmap_free(type_info->capture_devices);
575 static void file_info_free_func(struct device_file_info *file_info) {
579 if (file_info->roles)
580 pa_hashmap_free(file_info->roles);
583 static dm_device_class_t device_string_get_class(const char *device_string) {
584 if (!device_string) {
585 return DM_DEVICE_CLASS_NONE;
588 if (device_string == strstr(device_string, "alsa")) {
589 return DM_DEVICE_CLASS_ALSA;
590 } else if (device_string == strstr(device_string, "null")) {
591 return DM_DEVICE_CLASS_NULL;
592 } else if (device_string == strstr(device_string, "tizen")) {
593 return DM_DEVICE_CLASS_TIZEN;
595 return DM_DEVICE_CLASS_NONE;
599 static const char* device_string_get_value(const char *device_string) {
601 const char *end_p, *value_p;
603 if (!device_string) {
607 len = strlen(device_string);
608 end_p = device_string + len -1;
610 if (!(value_p = strchr(device_string, ':'))) {
613 if (value_p < end_p) {
620 static pa_proplist* pulse_device_get_proplist(pa_object *pdevice) {
621 if (pa_sink_isinstance(pdevice))
622 return PA_SINK(pdevice)->proplist;
624 return PA_SOURCE(pdevice)->proplist;
627 static bool pulse_device_is_alsa(pa_object *pdevice) {
628 const char *api_name = NULL;
631 if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
634 if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
635 if (pa_streq(api_name, DEVICE_API_ALSA)) {
645 static bool pulse_device_is_bluez(pa_object *pdevice) {
646 const char *api_name = NULL;
649 if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
652 if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
653 if (pa_streq(api_name, DEVICE_API_BLUEZ)) {
663 static bool pulse_device_is_tizenaudio(pa_object *pdevice) {
667 if (pa_sink_isinstance(pdevice)) {
668 pa_sink *sink = PA_SINK(pdevice);
669 return pa_streq(sink->module->name, "module-tizenaudio-sink");
671 pa_source *source = PA_SOURCE(pdevice);
672 return pa_streq(source->module->name, "module-tizenaudio-source");
676 static bool pulse_device_is_usb(pa_object *pdevice) {
677 const char *bus_name = NULL;
680 if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
683 if ((bus_name = pa_proplist_gets(prop, PA_PROP_DEVICE_BUS))) {
684 if (pa_streq(bus_name, DEVICE_BUS_USB)) {
690 pa_log_debug("This device doesn't have property '%s'", PA_PROP_DEVICE_BUS);
695 static bool pulse_device_is_null(pa_object *pdevice) {
702 if (pa_sink_isinstance(pdevice)) {
703 sink = PA_SINK(pdevice);
704 return pa_streq(sink->module->name, "module-null-sink");
706 source = PA_SOURCE(pdevice);
707 return pa_streq(source->module->name, "module-null-source");
711 static const char* pulse_device_get_device_string_removed_argument(pa_object *pdevice) {
712 static char removed_param[DEVICE_PARAM_STRING_MAX] = {0,};
713 char *device_string_p = NULL;
715 const char *params_p, *params;
717 int len = 0, prev_len = 0;
721 if (pa_sink_isinstance(pdevice)) {
722 sink = PA_SINK(pdevice);
723 params = sink->module->argument;
725 source = PA_SOURCE(pdevice);
726 params = source->module->argument;
734 if (!(device_string_p = strstr(params, "device="))) {
738 next_p = device_string_p;
739 while (!isblank(*next_p)) {
742 while (isblank(*next_p)) {
746 pa_strlcpy(removed_param, next_p, DEVICE_PARAM_STRING_MAX);
748 if (device_string_p > params_p) {
749 prev_len = device_string_p - params_p;
750 len = strlen(removed_param);
751 end_p = removed_param + len;
754 strncpy(end_p, params_p, prev_len);
757 return removed_param;
760 static dm_device_class_t pulse_device_get_class(pa_object *pdevice) {
763 pa_log_error("pdevice null");
764 return DM_DEVICE_CLASS_NONE;
767 if (pulse_device_is_null(pdevice)) {
768 return DM_DEVICE_CLASS_NULL;
769 } else if (pulse_device_is_alsa(pdevice)) {
770 return DM_DEVICE_CLASS_ALSA;
771 } else if (pulse_device_is_tizenaudio(pdevice)) {
772 return DM_DEVICE_CLASS_TIZEN;
773 } else if (pulse_device_is_bluez(pdevice)) {
774 return DM_DEVICE_CLASS_BT;
776 return DM_DEVICE_CLASS_NONE;
780 static dm_device_direction_t pulse_device_get_direction(pa_object *pdevice) {
781 if (pa_sink_isinstance(pdevice))
782 return DM_DEVICE_DIRECTION_OUT;
784 return DM_DEVICE_DIRECTION_IN;
787 static bool pulse_device_is_monitor(pa_object *pdevice) {
788 const char *device_class = NULL;
791 prop = pulse_device_get_proplist(pdevice);
793 if ((device_class = pa_proplist_gets(prop, PA_PROP_DEVICE_CLASS))) {
794 if (device_class && pa_streq(device_class, DEVICE_CLASS_MONITOR)) {
804 static int pulse_device_get_alsa_device_string(pa_proplist *prop, char **device_string) {
805 const char *device_string_prop = NULL;
806 char *device_string_tmp;
808 if (!prop || !device_string) {
809 pa_log_error("Invalid Parameter");
813 if (!(device_string_prop = pa_proplist_gets(prop, "device.string"))) {
814 pa_log_error("failed to get property 'device.string'");
817 if (!(device_string_tmp = strchr(device_string_prop, ':'))) {
818 pa_log_error("failed to parse device string");
822 *device_string = device_string_tmp + 1;
827 static const char* device_class_get_module_name(dm_device_class_t device_class, bool is_sink) {
828 if (device_class == DM_DEVICE_CLASS_NONE) {
830 } else if (device_class == DM_DEVICE_CLASS_ALSA) {
831 return is_sink ? "module-alsa-sink" : "module-alsa-source";
832 } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
833 return is_sink ? "module-tizenaudio-sink" : NULL;
834 } else if (device_class == DM_DEVICE_CLASS_BT) {
835 return is_sink ? "module-bluez5-device" : NULL;
836 } else if (device_class == DM_DEVICE_CLASS_NULL) {
837 return is_sink ? "module-null-sink" : "module-null-source";
843 static struct device_type_info* _device_manager_get_type_info(pa_idxset *type_infos, const char *type) {
844 struct device_type_info *type_info;
847 PA_IDXSET_FOREACH(type_info, type_infos, type_idx) {
848 if (device_type_is_equal(type_info->type, type)) {
856 static struct device_file_info* _device_manager_get_file_info(pa_idxset *file_infos, const char *device_string) {
857 struct device_file_info *file_info;
860 pa_assert(file_infos);
862 PA_IDXSET_FOREACH(file_info, file_infos, file_idx) {
863 if (file_info->device_string) {
864 if (pa_streq(file_info->device_string, device_string)) {
873 static struct device_status_info* _device_status_new(const char *type,
874 const char *name, const char *system_id) {
875 struct device_status_info *status_info;
877 status_info = (struct device_status_info *) pa_xmalloc0(sizeof(struct device_status_info));
878 status_info->type = pa_xstrdup(type);
879 status_info->name = pa_xstrdup(name);
880 status_info->system_id = pa_xstrdup(system_id);
881 status_info->detected = DEVICE_DISCONNECTED;
886 static void _device_status_free(struct device_status_info *status_info) {
890 pa_xfree(status_info->type);
891 pa_xfree(status_info->name);
892 pa_xfree(status_info->system_id);
893 pa_xfree(status_info);
896 static struct device_status_info* _get_device_status(pa_device_manager *manager, const char *type,
897 const char *system_id) {
898 struct device_status_info *status_info = NULL;
902 pa_assert(manager->device_status);
904 PA_IDXSET_FOREACH(status_info, manager->device_status, status_idx) {
905 if (device_type_is_equal(status_info->type, type)) {
906 if (device_type_is_avail_multi_device(type)) {
907 /* if system_id is null, just compare type */
908 if (system_id == NULL)
910 else if (status_info->system_id == NULL)
912 else if (pa_streq(status_info->system_id, system_id))
925 static const char* _file_infos_get_param(pa_idxset *file_infos, const char *device_string, const char *role) {
926 struct device_file_info *file_info;
929 if (!(file_info = _device_manager_get_file_info(file_infos, device_string))) {
930 pa_log_error("No file map for '%s'", device_string);
934 if (!(params = pa_hashmap_get(file_info->roles, role)))
935 pa_log_error("No params for '%s:%s'", device_string, role);
940 static device_detected_type_t _device_get_detected(pa_device_manager *manager, const char *type,
941 const char *system_id) {
942 struct device_status_info *status_info;
945 pa_assert(manager->device_status);
948 if (!device_type_is_need_detect(type))
949 return DEVICE_CONNECTED;
951 status_info = _get_device_status(manager, type, system_id);
953 pa_log_info("No status info for type(%s) system_id(%s)",
954 type, pa_strempty(system_id));
955 return DEVICE_DISCONNECTED;
958 pa_log_debug("Get device detected, type(%s) system_id(%s) : %s(%d)",
959 type, pa_strempty(system_id),
960 (status_info->detected & DEVICE_CONNECTED) ? "Connected" : "Disconnected", status_info->detected);
962 return status_info->detected;
965 static void _device_set_detected(pa_device_manager *manager, const char *type,
966 const char *name, const char *system_id, device_detected_type_t detected_type) {
967 struct device_status_info *status_info;
970 pa_assert(manager->device_status);
973 if (!device_type_is_need_detect(type))
976 pa_log_info("Set device detected, type(%s) system_id(%s) -> %s(%d)",
977 type, pa_strempty(system_id),
978 (detected_type & DEVICE_CONNECTED) ? "Connected" : "Disconnected", detected_type);
980 if (detected_type & DEVICE_CONNECTED) {
981 status_info = _get_device_status(manager, type, system_id);
983 status_info = _device_status_new(type, name, system_id);
984 pa_idxset_put(manager->device_status, status_info, NULL);
986 status_info->detected = detected_type;
988 status_info = _get_device_status(manager, type, system_id);
990 pa_idxset_remove_by_data(manager->device_status, status_info, NULL);
991 _device_status_free(status_info);
996 static pa_tz_device* _device_list_get_device(pa_device_manager *manager, const char *type, const char *system_id) {
997 pa_tz_device *device;
999 char *_type, *_system_id;
1002 pa_assert(manager->device_list);
1005 PA_IDXSET_FOREACH(device, manager->device_list, idx) {
1006 _type = pa_tz_device_get_type(device);
1007 _system_id = pa_tz_device_get_system_id(device);
1008 if (pa_streq(_type, type)) {
1009 if (device_type_is_avail_multi_device(type)) {
1010 if (system_id == NULL)
1012 else if (_system_id == NULL)
1014 else if (pa_streq(_system_id, system_id))
1028 static pa_tz_device* _device_list_get_device_by_id(pa_device_manager *manager, uint32_t id) {
1029 pa_tz_device *device;
1033 pa_assert(manager->device_list);
1035 PA_IDXSET_FOREACH(device, manager->device_list, idx) {
1036 if (pa_tz_device_get_id(device) == id) {
1043 static const char* build_params_to_load_device(const char *device_string, const char *params, dm_device_class_t device_class) {
1044 pa_strbuf *args_buf;
1045 static char args[DEVICE_PARAM_STRING_MAX] = {0,};
1047 if (!device_string) {
1048 pa_log_error("device string null");
1052 if (device_class == DM_DEVICE_CLASS_NULL) {
1054 } else if (device_class == DM_DEVICE_CLASS_ALSA) {
1055 const char *alsa_device_name;
1056 if (!(alsa_device_name = device_string_get_value(device_string))) {
1057 pa_log_error("Invalid device string for alsa-device, '%s'", device_string);
1060 args_buf = pa_strbuf_new();
1061 pa_strbuf_printf(args_buf, "device=hw:%s ", alsa_device_name);
1063 pa_strbuf_printf(args_buf, "%s", params);
1065 pa_strlcpy(args, pa_strbuf_to_string_free(args_buf), DEVICE_PARAM_STRING_MAX);
1070 return (const char*) args;
1073 static bool device_params_is_equal(const char *params1, const char *params2) {
1074 const char *key = NULL;
1075 const char *value1, *value2;
1076 pa_modargs *modargs1, *modargs2;
1080 if (!params1 && !params2)
1082 if (!params1 || !params2)
1085 modargs1 = pa_modargs_new(params1, valid_alsa_device_modargs);
1086 modargs2 = pa_modargs_new(params2, valid_alsa_device_modargs);
1088 if (!modargs1 || !modargs2) {
1093 for (state = NULL, key = pa_modargs_iterate(modargs1, &state); key; key = pa_modargs_iterate(modargs1, &state)) {
1094 value1 = pa_modargs_get_value(modargs1, key, NULL);
1095 value2 = pa_modargs_get_value(modargs2, key, NULL);
1096 if (!value1 || !value2 || !pa_streq(value1, value2)) {
1102 for (state = NULL, key = pa_modargs_iterate(modargs2, &state); key; key = pa_modargs_iterate(modargs2, &state)) {
1103 value1 = pa_modargs_get_value(modargs1, key, NULL);
1104 value2 = pa_modargs_get_value(modargs2, key, NULL);
1105 if (!value1 || !value2 || !pa_streq(value1, value2)) {
1114 pa_modargs_free(modargs1);
1116 pa_modargs_free(modargs2);
1122 static bool pulse_device_params_is_equal(pa_object *pdevice, const char *params) {
1123 const char *removed_module_args;
1124 const char *module_args;
1130 if (pa_sink_isinstance(pdevice)) {
1131 sink = PA_SINK(pdevice);
1132 module_args = sink->module->argument;
1134 source = PA_SOURCE(pdevice);
1135 module_args = source->module->argument;
1138 if (!params && !module_args)
1140 if (!params || !module_args)
1143 removed_module_args = pulse_device_get_device_string_removed_argument(pdevice);
1144 return device_params_is_equal(params, removed_module_args);
1147 static const char* pulse_device_get_device_string(pa_object *pdevice) {
1148 dm_device_class_t device_class;
1149 static char device_string[DEVICE_STR_MAX] = {0,};
1150 char *device_string_val = NULL;
1155 device_class = pulse_device_get_class(pdevice);
1156 prop = pulse_device_get_proplist(pdevice);
1158 if (device_class == DM_DEVICE_CLASS_ALSA) {
1159 if (pulse_device_get_alsa_device_string(prop, &device_string_val) < 0)
1161 snprintf(device_string, DEVICE_STR_MAX, "alsa:%s", device_string_val);
1162 return device_string;
1163 } else if (device_class == DM_DEVICE_CLASS_NULL) {
1165 } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
1167 } else if (device_class == DM_DEVICE_CLASS_BT) {
1170 return device_string;
1174 /* pdevice is sink or source */
1175 static bool pulse_device_same_device_string(pa_object *pdevice, const char *device_string) {
1176 const char *_device_string;
1179 pa_assert(device_string);
1181 if (!(_device_string = pulse_device_get_device_string(pdevice)))
1184 return pa_streq(_device_string, device_string);
1187 static const char* device_type_info_get_device_string(struct device_type_info *type_info, bool is_playback, const char *role) {
1188 const char *_role, *device_string;
1190 pa_hashmap *pcm_devices;
1192 pcm_devices = is_playback ? type_info->playback_devices : type_info->capture_devices;
1193 if (pcm_devices == NULL) {
1194 pa_log_error("No pcm device config for %s %s %s", is_playback ? "Playback" : "Capture", type_info->type, role);
1198 PA_HASHMAP_FOREACH_KV(_role, device_string, pcm_devices, state) {
1199 if (pa_safe_streq(role, _role))
1200 return device_string;
1206 pa_dynarray* pulse_device_get_belongs_type(pa_object *pdevice, pa_device_manager *dm) {
1207 pa_dynarray *ctypes;
1208 struct composite_type *ctype;
1209 struct device_type_info *type_info;
1210 const char *device_string, *role, *param;
1212 pa_device_type_t pdt;
1213 pa_idxset *file_infos;
1214 pa_hashmap *pcm_devices;
1220 pa_log_info("pulse device get belongs type");
1222 if (pulse_device_is_monitor(pdevice))
1224 if (pulse_device_is_usb(pdevice))
1226 if (pulse_device_is_bluez(pdevice))
1229 ctypes = pa_dynarray_new(pa_xfree);
1231 if (pa_sink_isinstance(pdevice)) {
1232 pdt = PA_DEVICE_TYPE_SINK;
1233 file_infos = dm->file_map->playback;
1235 pdt = PA_DEVICE_TYPE_SOURCE;
1236 file_infos = dm->file_map->capture;
1239 /* iterate "device-types" in device-map.json */
1240 PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
1241 if (pdt == PA_DEVICE_TYPE_SINK)
1242 pcm_devices = type_info->playback_devices;
1244 pcm_devices = type_info->capture_devices;
1245 if (pcm_devices == NULL)
1247 /* iterate "{playback,capture}-devices" in specific device-type */
1248 PA_HASHMAP_FOREACH_KV(role, device_string, pcm_devices, state) {
1249 if (pulse_device_same_device_string(pdevice, device_string) == false)
1251 param = _file_infos_get_param(file_infos, device_string, role);
1252 if (pulse_device_params_is_equal(pdevice, param) == false)
1254 /* Found type.role which is matching with pulse_device */
1255 ctype = pa_xmalloc0(sizeof(struct composite_type));
1256 ctype->type = type_info->type;
1258 pa_dynarray_append(ctypes, ctype);
1262 if (pa_dynarray_size(ctypes) == 0) {
1263 pa_dynarray_free(ctypes);
1270 static const char* pulse_device_get_device_name(pa_object *pdevice, const char *type) {
1274 pa_assert(device_type_is_valid(type));
1276 prop = pulse_device_get_proplist(pdevice);
1278 if (pa_streq(type, DEVICE_TYPE_USB_AUDIO))
1279 return pa_proplist_gets(prop, "udev.id");
1280 else if (pa_streq(type, DEVICE_TYPE_BT_A2DP))
1281 return pa_proplist_gets(prop, "bluez.alias");
1286 /* If fails return -1 */
1287 static int atoi_base16(const char *s) {
1294 l = strtol(s, &x, 16);
1296 if (!x || *x || errno) {
1297 pa_log_error("Convert Failed");
1302 pa_log_error("Range error, does not fit into int");
1309 static int pulse_device_get_vendor_id(pa_object *pdevice) {
1311 const char *vendor_id_s;
1316 if (pulse_device_is_usb(pdevice) == false) {
1317 pa_log_warn("Not USB device");
1321 prop = pulse_device_get_proplist(pdevice);
1323 if ((vendor_id_s = pa_proplist_gets(prop, PA_PROP_DEVICE_VENDOR_ID)) == NULL) {
1324 pa_log_error("No vendor id");
1328 if ((vendor_id = atoi_base16(vendor_id_s)) == -1) {
1329 pa_log_error("Failed to convert to int");
1336 static int pulse_device_get_product_id(pa_object *pdevice) {
1338 const char *product_id_s;
1343 if (pulse_device_is_usb(pdevice) == false) {
1344 pa_log_warn("Not USB device");
1348 prop = pulse_device_get_proplist(pdevice);
1350 if ((product_id_s = pa_proplist_gets(prop, PA_PROP_DEVICE_PRODUCT_ID)) == NULL) {
1351 pa_log_error("No product id");
1355 if ((product_id = atoi_base16(product_id_s)) == -1) {
1356 pa_log_error("Failed to convert to int");
1363 static void pulse_device_set_use_internal_codec(pa_object *pdevice, bool use_internal_codec) {
1366 if (pa_sink_isinstance(pdevice)) {
1367 pa_sink *sink = PA_SINK(pdevice);
1368 sink->use_internal_codec = use_internal_codec;
1370 pa_source *source = PA_SOURCE(pdevice);
1371 source->use_internal_codec = use_internal_codec;
1375 /* Get system_id of physical device, if external device */
1376 static const char* pulse_device_get_system_id(pa_object *pdevice) {
1379 prop = pulse_device_get_proplist(pdevice);
1380 if (pulse_device_is_usb(pdevice))
1381 return pa_proplist_gets(prop, "sysfs.path");
1382 else if (pulse_device_is_bluez(pdevice))
1383 return pa_proplist_gets(prop, "bluez.path");
1388 static pa_sink* _core_get_sink(pa_core *core, const char *device_string, const char *params) {
1389 uint32_t device_idx;
1393 pa_assert(device_string);
1395 PA_IDXSET_FOREACH(sink, core->sinks, device_idx) {
1396 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1398 if (pulse_device_same_device_string(PA_OBJECT(sink), device_string)) {
1401 else if (pulse_device_params_is_equal(PA_OBJECT(sink), params))
1409 static pa_source* _core_get_source(pa_core *core, const char *device_string, const char *params) {
1410 uint32_t device_idx;
1414 pa_assert(device_string);
1416 PA_IDXSET_FOREACH(source, core->sources, device_idx) {
1417 if (pulse_device_is_monitor(PA_OBJECT(source)))
1419 if (pulse_device_same_device_string(PA_OBJECT(source), device_string)) {
1422 else if (pulse_device_params_is_equal(PA_OBJECT(source), params))
1431 static void _fill_new_data_basic(pa_tz_device_new_data *data, const char *type,
1432 dm_device_direction_t direction, bool use_internal_codec, pa_device_manager *dm) {
1435 pa_tz_device_new_data_set_type(data, type);
1436 pa_tz_device_new_data_set_direction(data, direction);
1437 pa_tz_device_new_data_set_use_internal_codec(data, use_internal_codec);
1440 static int _fill_new_data_sinks(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
1442 const char *device_string, *role, *param;
1444 pa_idxset *file_infos;
1447 pa_assert(type_info);
1449 if (type_info->playback_devices == NULL) {
1450 pa_log_error("No playback devices for %s", type_info->type);
1454 file_infos = dm->file_map->playback;
1455 if (file_infos == NULL) {
1456 pa_log_error("No playback pcm device config");
1460 PA_HASHMAP_FOREACH_KV(role, device_string, type_info->playback_devices, state) {
1461 param = _file_infos_get_param(file_infos, device_string, role);
1462 sink = _core_get_sink(dm->core, device_string, param);
1464 pa_tz_device_new_data_add_sink(data, role, sink);
1466 pa_log_warn("No matching sink for %s %s", device_string, role);
1472 static int _fill_new_data_sources(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
1474 const char *device_string, *role, *param;
1476 pa_idxset *file_infos;
1479 pa_assert(type_info);
1481 if (type_info->capture_devices == NULL) {
1482 pa_log_error("No capture devices for %s", type_info->type);
1486 file_infos = dm->file_map->capture;
1487 if (file_infos == NULL) {
1488 pa_log_error("No capture pcm device config");
1492 PA_HASHMAP_FOREACH_KV(role, device_string, type_info->capture_devices, state) {
1493 param = _file_infos_get_param(file_infos, device_string, role);
1494 source = _core_get_source(dm->core, device_string, param);
1496 pa_tz_device_new_data_add_source(data, role, source);
1498 pa_log_warn("No matching source for %s %s", device_string, role);
1504 static pa_sink* _device_manager_set_default_sink(pa_device_manager *dm, const char *type, const char *role) {
1505 pa_tz_device *device;
1508 if (!type || !role) {
1509 pa_log_warn("Argument for set_default_sink invalid");
1513 if (!(device = _device_list_get_device(dm, type, NULL))) {
1514 pa_log_warn("cannot get device item for %s", type);
1518 if (!(sink = pa_tz_device_get_sink(device, role))) {
1519 pa_log_warn("cannot get sink for %s", role);
1523 // sink = pa_namereg_set_default_sink(dm->core, sink);
1527 static pa_source* _device_manager_set_default_source(pa_device_manager *dm, const char *type, const char *role) {
1528 pa_tz_device *device;
1531 if (!type || !role) {
1532 pa_log_warn("Argument for set_default_source invalid");
1536 if (!(device = _device_list_get_device(dm, type, NULL))) {
1537 pa_log_warn("cannot get device item for %s", type);
1541 if (!(source = pa_tz_device_get_source(device, role))) {
1542 pa_log_warn("cannot get source for %s", role);
1546 // source = pa_namereg_set_default_source(dm->core, source);
1550 static void handle_usb_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1551 const char *name, *system_id;
1552 dm_device_direction_t direction;
1553 pa_tz_device *device;
1558 pa_log_info("Handle usb pulse device");
1560 system_id = pulse_device_get_system_id(pdevice);
1561 direction = pulse_device_get_direction(pdevice);
1564 pa_tz_device_new_data data;
1565 int product_id, vendor_id;
1567 name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_USB_AUDIO);
1568 vendor_id = pulse_device_get_vendor_id(pdevice);
1569 product_id = pulse_device_get_product_id(pdevice);
1571 pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, NULL);
1572 pa_tz_device_new_data_set_type(&data, DEVICE_TYPE_USB_AUDIO);
1573 pa_tz_device_new_data_set_name(&data, name);
1574 pa_tz_device_new_data_set_direction(&data, direction);
1575 pa_tz_device_new_data_set_system_id(&data, system_id);
1577 pa_tz_device_new_data_set_vendor_id(&data, vendor_id);
1579 pa_tz_device_new_data_set_product_id(&data, product_id);
1580 pa_tz_device_new_data_set_use_internal_codec(&data, false);
1581 if (direction == DM_DEVICE_DIRECTION_OUT)
1582 pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
1584 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1586 pa_tz_device_new(&data);
1587 pa_tz_device_new_data_done(&data);
1589 if (!(device = _device_list_get_device(manager, DEVICE_TYPE_USB_AUDIO, system_id)))
1590 pa_log_warn("Can't get usb device for %s", system_id);
1592 pa_tz_device_free(device);
1596 static void handle_bt_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1597 dm_device_direction_t direction;
1598 pa_tz_device *device;
1599 const char *system_id;
1604 pa_log_info("Handle bt pulse device");
1606 direction = pulse_device_get_direction(pdevice);
1607 system_id = pulse_device_get_system_id(pdevice);
1610 pa_tz_device_new_data data;
1613 name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_BT_A2DP);
1615 pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, manager->dbus_conn);
1616 _fill_new_data_basic(&data, DEVICE_TYPE_BT_A2DP, direction, false, manager);
1617 pa_tz_device_new_data_set_name(&data, name);
1618 pa_tz_device_new_data_set_system_id(&data, system_id);
1619 if (direction == DM_DEVICE_DIRECTION_OUT)
1620 pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
1622 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
1624 pa_tz_device_new(&data);
1625 pa_tz_device_new_data_done(&data);
1628 if (!(device = _device_list_get_device(manager, DEVICE_TYPE_BT_A2DP, system_id)))
1629 pa_log_warn("Can't get bt device for %s", system_id);
1631 pa_tz_device_free(device);
1635 static void handle_internal_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
1636 pa_tz_device *device;
1637 struct composite_type *ctype;
1638 pa_dynarray *ctypes;
1639 dm_device_direction_t direction;
1644 pa_log_info("Handle internal pulse device");
1645 direction = pulse_device_get_direction(pdevice);
1647 /* Get types which this pulse_device belongs to */
1648 if ((ctypes = pulse_device_get_belongs_type(pdevice, manager)) == NULL) {
1649 pa_log_debug("Failed to get device type. Skip this");
1654 /* Put this pulse_device to already loaded devices */
1655 for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
1656 ctype = pa_dynarray_get(ctypes, i);
1657 pa_log_info("Found belongs type %s %s", ctype->type, ctype->role);
1658 if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
1659 pa_log_info("Add this pulse_device to device(%u)", pa_tz_device_get_id(device));
1660 if (direction == DM_DEVICE_DIRECTION_OUT)
1661 pa_tz_device_add_sink(device, ctype->role, PA_SINK(pdevice));
1663 pa_tz_device_add_source(device, ctype->role, PA_SOURCE(pdevice));
1665 pa_log_info("No device for %s", ctype->type);
1669 /* Remove this pulse_device from already loaded devices */
1670 for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
1671 ctype = pa_dynarray_get(ctypes, i);
1672 pa_log_info("Found belongs type %s %s", ctype->type, ctype->role);
1673 if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
1674 pa_log_info("Remove this pulse_device from device(%u)", pa_tz_device_get_id(device));
1675 if (direction == DM_DEVICE_DIRECTION_OUT)
1676 pa_tz_device_remove_sink(device, PA_SINK(pdevice));
1678 pa_tz_device_remove_source(device, PA_SOURCE(pdevice));
1680 pa_log_info("No device for %s", ctype->type);
1685 pa_dynarray_free(ctypes);
1688 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1693 pa_log_info("========== Sink Put Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1695 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1698 if (pulse_device_is_usb(PA_OBJECT(sink))) {
1699 pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
1700 handle_usb_pulse_device(PA_OBJECT(sink), true, dm);
1702 } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
1703 pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
1704 handle_bt_pulse_device(PA_OBJECT(sink), true, dm);
1706 } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
1707 pulse_device_set_use_internal_codec(PA_OBJECT(sink), true);
1708 handle_internal_pulse_device(PA_OBJECT(sink), true, dm);
1711 pa_log_debug("Don't care this sink");
1717 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
1722 pa_log_info("=========== Sink unlink Hook Callback '%s'(%d) ==========", sink->name, sink->index);
1724 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1727 if (pulse_device_is_usb(PA_OBJECT(sink))) {
1728 handle_usb_pulse_device(PA_OBJECT(sink), false, dm);
1730 } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
1731 handle_bt_pulse_device(PA_OBJECT(sink), false, dm);
1733 } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
1734 handle_internal_pulse_device(PA_OBJECT(sink), false, dm);
1737 pa_log_debug("Don't care this sink");
1743 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1748 pa_log_info("========== source Put Hook Callback '%s'(%d) ==========", source->name, source->index);
1750 if (pulse_device_is_monitor(PA_OBJECT(source)))
1753 if (pulse_device_is_usb(PA_OBJECT(source))) {
1754 pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
1755 handle_usb_pulse_device(PA_OBJECT(source), true, dm);
1757 } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
1758 pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
1759 handle_bt_pulse_device(PA_OBJECT(source), true, dm);
1761 } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
1762 pulse_device_set_use_internal_codec(PA_OBJECT(source), true);
1763 handle_internal_pulse_device(PA_OBJECT(source), true, dm);
1766 pa_log_debug("Don't care this source");
1772 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
1777 pa_log_info("=========== source unlink Hook Callback '%s'(%d) ==========", source->name, source->index);
1779 if (pulse_device_is_monitor(PA_OBJECT(source)))
1782 if (pulse_device_is_usb(PA_OBJECT(source))) {
1783 handle_usb_pulse_device(PA_OBJECT(source), false, dm);
1785 } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
1786 handle_bt_pulse_device(PA_OBJECT(source), false, dm);
1788 } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
1789 handle_internal_pulse_device(PA_OBJECT(source), false, dm);
1792 pa_log_debug("Don't care this source");
1798 #define SINK_NAME_NULL "sink_null"
1799 #define SOURCE_NAME_NULL "source_null"
1800 static pa_hook_result_t sink_source_state_changed_hook_cb(pa_core *c, pa_object *pdevice, pa_device_manager *dm) {
1801 pa_tz_device *device;
1804 pa_object_assert_ref(pdevice);
1807 if (pa_sink_isinstance(pdevice)) {
1808 pa_sink *s = PA_SINK(pdevice);
1809 pa_sink_state_t state = pa_sink_get_state(s);
1810 pa_log_debug("=========== Sink(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
1811 if (!s->use_internal_codec && !pa_streq(s->name, SINK_NAME_NULL))
1812 if ((device = pa_device_manager_get_device_with_sink(s)))
1813 pa_tz_device_set_running_and_notify(device, (state == PA_SINK_RUNNING));
1814 } else if (pa_source_isinstance(pdevice)) {
1815 pa_source *s = PA_SOURCE(pdevice);
1816 pa_source_state_t state = pa_source_get_state(s);
1817 pa_log_debug("=========== Source(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
1818 if (!s->use_internal_codec && !pa_streq(s->name, SOURCE_NAME_NULL))
1819 if ((device = pa_device_manager_get_device_with_source(s)))
1820 pa_tz_device_set_running_and_notify(device, (state == PA_SOURCE_RUNNING));
1822 pa_log_debug("========= sink_source_state_changed_hook_cb END =====");
1828 Build params for load sink or source, and load it.
1831 static void* load_device(pa_core *c, bool is_sink, const char *device_string, const char *device_params) {
1832 const char *args = NULL;
1833 const char *module_name;
1837 uint32_t device_idx;
1838 dm_device_class_t device_class;
1841 pa_assert(device_string);
1842 pa_assert(device_params);
1844 pa_log_info("Load %s Device : String'%s' Param'%s'", is_sink ? "Playback" : "Capture", device_string, device_params);
1846 device_class = device_string_get_class(device_string);
1847 if (device_class <= DM_DEVICE_CLASS_NONE || device_class >= DM_DEVICE_CLASS_MAX) {
1848 pa_log_warn("Invalid device_string '%s'", device_string);
1852 if (!(module_name = device_class_get_module_name(device_class, is_sink))) {
1853 pa_log_error("Get proper module name to load failed");
1856 if (!(args = build_params_to_load_device(device_string, device_params, device_class))) {
1857 pa_log_error("Get proper module name to load failed");
1860 if (!(module = pa_module_load(c, module_name, args))) {
1861 pa_log_error("Load module with name '%s' argu '%s' failed", module_name, args);
1867 PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
1868 if (sink->module == module) {
1873 PA_IDXSET_FOREACH(source, c->sources, device_idx) {
1874 if (source->module == module) {
1883 static void unload_device(pa_core *c, bool is_sink, const char *device_string) {
1884 uint32_t device_idx;
1887 pa_assert(device_string);
1889 pa_log_info("Unload %s Device : String'%s'", is_sink ? "Playback" : "Capture", device_string);
1894 PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
1895 if (pulse_device_is_monitor(PA_OBJECT(sink)))
1897 if (pulse_device_same_device_string(PA_OBJECT(sink), device_string))
1898 pa_module_unload(sink->module, true);
1903 PA_IDXSET_FOREACH(source, c->sources, device_idx) {
1904 if (pulse_device_is_monitor(PA_OBJECT(source)))
1906 if (pulse_device_same_device_string(PA_OBJECT(source), device_string))
1907 pa_module_unload(source->module, true);
1912 static int _load_type_devices(struct device_type_info *type_info, bool is_playback, pa_device_manager *dm) {
1913 pa_hashmap *pcm_devices;
1914 pa_idxset *file_infos;
1917 const char *device_string, *params;
1920 pa_assert(type_info);
1922 pa_log_info("Load type devices : %s %s", type_info->type, is_playback ? "playback" : "capture");
1925 pcm_devices = type_info->playback_devices;
1926 file_infos = dm->file_map->playback;
1928 pcm_devices = type_info->capture_devices;
1929 file_infos = dm->file_map->capture;
1932 if (!pcm_devices || !file_infos) {
1933 pa_log_error("No information to load");
1937 PA_HASHMAP_FOREACH_KV(role, device_string, pcm_devices, state) {
1938 /* skip duplicate load */
1939 if (is_playback && _core_get_sink(dm->core, device_string, NULL)) {
1940 pa_log_debug("Already loaded %s", device_string);
1943 if (!is_playback && _core_get_source(dm->core, device_string, NULL)) {
1944 pa_log_debug("Already loaded %s", device_string);
1948 params = _file_infos_get_param(file_infos, device_string, role);
1949 if (params == NULL) {
1950 pa_log_error("Failed to get param for %s", device_string);
1953 if (!(load_device(dm->core, is_playback, device_string, params))) {
1954 pa_log_warn("load device failed %s %s", device_string, params);
1961 static pa_tz_device* _load_forwarding_device(pa_device_manager *dm) {
1962 pa_tz_device_new_data data;
1963 pa_tz_device *spk_device, *forwarding_device;
1968 pa_log_info("Load forwarding device");
1970 if ((forwarding_device = _device_list_get_device(dm, DEVICE_TYPE_FORWARDING, NULL))) {
1971 pa_log_info("Forwarding device already exists");
1972 return forwarding_device;
1975 if ((spk_device = _device_list_get_device(dm, DEVICE_TYPE_SPEAKER, NULL)) == NULL) {
1976 pa_log_error("Get speaker device failed");
1980 if ((spk_sink = pa_tz_device_get_sink(spk_device, DEVICE_ROLE_NORMAL)) == NULL) {
1981 pa_log_error("Get speaker sink failed");
1985 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
1986 _fill_new_data_basic(&data, DEVICE_TYPE_FORWARDING, DM_DEVICE_DIRECTION_BOTH, true, dm);
1987 pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, spk_sink);
1988 pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, spk_sink->monitor_source);
1990 if ((forwarding_device = pa_tz_device_new(&data)) == NULL)
1991 pa_log_error("Failed to create forwarding device");
1993 pa_tz_device_new_data_done(&data);
1995 return forwarding_device;
1999 Handle device connection detected through dbus.
2000 First, update device-status hashmap.
2001 And if correnspondent sink/sources for device_type exist, should make device and notify it.
2002 Use [device_type->roles] mappings in sink/source for find proper sink/source.
2004 static void handle_device_connected(pa_device_manager *dm, const char *type,
2005 const char *name, const char *system_id, device_detected_type_t detected_type) {
2006 struct device_type_info *type_info;
2007 pa_tz_device_new_data data;
2010 pa_assert(dm->device_status);
2011 pa_assert(dm->device_list);
2013 pa_log_info("Device connected, type(%s) name(%s) system_id(%s) detected_type(%d)",
2014 type, pa_strempty(name), pa_strempty(system_id), detected_type);
2016 type_info = _device_manager_get_type_info(dm->type_infos, type);
2018 if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2019 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, dm->dbus_conn);
2020 _fill_new_data_basic(&data, DEVICE_TYPE_BT_SCO, DM_DEVICE_DIRECTION_BOTH, true, dm);
2021 _fill_new_data_sinks(&data, type_info, dm);
2022 _fill_new_data_sources(&data, type_info, dm);
2023 pa_tz_device_new_data_set_name(&data, name);
2024 pa_tz_device_new_data_set_system_id(&data, system_id);
2025 pa_tz_device_new(&data);
2026 pa_tz_device_new_data_done(&data);
2027 } else if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
2028 dm_device_direction_t direction;
2030 if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P)
2031 direction = DM_DEVICE_DIRECTION_BOTH;
2033 direction = DM_DEVICE_DIRECTION_OUT;
2034 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
2035 _fill_new_data_basic(&data, DEVICE_TYPE_AUDIO_JACK, direction, true, dm);
2036 _fill_new_data_sinks(&data, type_info, dm);
2037 _fill_new_data_sources(&data, type_info, dm);
2039 pa_tz_device_new(&data);
2040 pa_tz_device_new_data_done(&data);
2041 } else if (device_type_is_equal(type, DEVICE_TYPE_HDMI)) {
2042 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
2043 _fill_new_data_basic(&data, DEVICE_TYPE_HDMI, DM_DEVICE_DIRECTION_OUT, true, dm);
2044 _fill_new_data_sinks(&data, type_info, dm);
2046 pa_tz_device_new(&data);
2047 pa_tz_device_new_data_done(&data);
2048 } else if (device_type_is_equal(type, DEVICE_TYPE_FORWARDING)) {
2049 _load_forwarding_device(dm);
2051 dm_device_direction_t direction;
2053 direction = device_type_get_static_direction(type);
2054 if (direction != DM_DEVICE_DIRECTION_NONE) {
2055 pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
2056 _fill_new_data_basic(&data, type, direction, true, dm);
2057 if (direction & DM_DEVICE_DIRECTION_OUT)
2058 _fill_new_data_sinks(&data, type_info, dm);
2059 if (direction & DM_DEVICE_DIRECTION_IN)
2060 _fill_new_data_sources(&data, type_info, dm);
2062 pa_tz_device_new(&data);
2063 pa_tz_device_new_data_done(&data);
2065 pa_log_error("Invalid case : not static direction");
2074 Handle device disconnection detected through dbus.
2075 First, update device-status hashmap.
2076 And if there is device which has the device_type, remove it.
2078 static int handle_device_disconnected(pa_device_manager *dm, const char *type, const char *system_id) {
2079 pa_tz_device *device;
2082 pa_assert(dm->device_status);
2084 pa_log_info("Device type(%s) system_id(%s) disconnected",
2085 type, pa_strempty(system_id));
2087 device = _device_list_get_device(dm, type, system_id);
2089 pa_log_error("Disconnection detected but no device for that");
2093 pa_tz_device_free(device);
2098 static int load_builtin_devices(pa_device_manager *dm) {
2099 struct device_type_info *type_info;
2101 device_detected_type_t detected_type = DEVICE_CONNECTED;
2106 pa_log_debug("\n==================== Load Builtin Devices ====================");
2108 PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
2110 type = type_info->type;
2112 pa_log_info("type_info : %s", type);
2113 detected_type = _device_get_detected(dm, type, NULL);
2114 if (detected_type == DEVICE_DISCONNECTED) {
2115 pa_log_info("Not detected yet");
2119 if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
2120 if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P) {
2121 _load_type_devices(type_info, true, dm);
2122 _load_type_devices(type_info, false, dm);
2124 _load_type_devices(type_info, true, dm);
2126 handle_device_connected(dm, type, NULL, NULL, detected_type);
2127 } else if (device_type_is_use_external_card(type) == false) {
2128 dm_device_direction_t direction;
2129 direction = device_type_get_static_direction(type);
2130 if (direction == DM_DEVICE_DIRECTION_NONE) {
2131 pa_log_warn("Wrong direction");
2134 if (direction & DM_DEVICE_DIRECTION_OUT)
2135 _load_type_devices(type_info, true, dm);
2136 if (direction & DM_DEVICE_DIRECTION_IN)
2137 _load_type_devices(type_info, false, dm);
2138 handle_device_connected(dm, type, NULL, NULL, detected_type);
2140 pa_log_warn("Invalid case");
2147 /***************** Parse json file *******************/
2148 static pa_hashmap* parse_device_role_object(json_object *device_role_o) {
2149 pa_hashmap *roles = NULL;
2150 const char *params, *device_role;
2151 struct json_object_iterator it, it_end;
2152 json_object *params_o;
2154 pa_assert(device_role_o);
2155 pa_assert(json_object_is_type(device_role_o, json_type_object));
2157 roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2159 pa_log_debug("hashmap new failed");
2163 it = json_object_iter_begin(device_role_o);
2164 it_end = json_object_iter_end(device_role_o);
2166 while (!json_object_iter_equal(&it, &it_end)) {
2167 device_role = json_object_iter_peek_name(&it);
2168 params_o = json_object_iter_peek_value(&it);
2170 if (!(params = json_object_get_string(params_o))) {
2171 pa_log_debug("There is no device params for role '%s'", device_role);
2173 pa_log_info("- Role '%s' -> '%s'", device_role, params);
2174 if (device_role_is_valid(device_role)) {
2175 if (pa_hashmap_put(roles, (void *)device_role, (void *)params)) {
2176 pa_log_error("put new role to hashmap faild");
2180 pa_log_error("Invalid device role '%s'", device_role);
2183 json_object_iter_next(&it);
2186 if (pa_hashmap_size(roles) == 0) {
2187 pa_log_warn("There is no role for device.. free hashmap");
2188 pa_hashmap_free(roles);
2196 pa_hashmap_free(roles);
2201 static struct device_file_info* parse_device_file_object(json_object *device_file_o, const char **device_string_key) {
2202 pa_hashmap *roles = NULL;
2203 json_object *device_file_prop_o = NULL;
2204 const char *device_string = NULL;
2205 struct device_file_info *file_info = NULL;
2207 pa_assert(device_file_o);
2208 pa_assert(device_string_key);
2209 pa_assert(json_object_is_type(device_file_o, json_type_object));
2211 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)) {
2212 if ((device_string = json_object_get_string(device_file_prop_o))) {
2213 pa_log_info("[ Device File - %s ]", device_string);
2215 pa_log_error("Get device-string failed");
2219 pa_log_error("Get device-string object failed");
2223 if (json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_ROLE, &device_file_prop_o)) {
2224 if (!(roles = parse_device_role_object(device_file_prop_o))) {
2225 pa_log_error("Parse device role for '%s' failed", device_string);
2229 pa_log_error("Get device role object failed");
2232 file_info = pa_xmalloc0(sizeof(struct device_file_info));
2233 file_info->device_string = device_string;
2234 file_info->device_types = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2235 file_info->roles = roles;
2237 // *device_string_key = device_string;
2246 static pa_idxset* parse_device_file_array_object(json_object *device_file_array_o) {
2247 int device_file_num, device_file_idx;
2248 struct device_file_info *file_info = NULL;
2249 json_object *device_file_o = NULL;
2250 pa_idxset *device_files = NULL;
2251 const char *device_string = NULL;
2253 pa_assert(device_file_array_o);
2254 pa_assert(json_object_is_type(device_file_array_o, json_type_array));
2256 device_files = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2258 device_file_num = json_object_array_length(device_file_array_o);
2259 for (device_file_idx = 0; device_file_idx < device_file_num; device_file_idx++) {
2260 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)) {
2261 if ((file_info = parse_device_file_object(device_file_o, &device_string))) {
2262 pa_idxset_put(device_files, file_info, NULL);
2264 pa_log_error("parse device file object failed");
2268 pa_log_error("Get device file object failed");
2273 if (pa_idxset_size(device_files) == 0) {
2274 pa_idxset_free(device_files, NULL);
2275 device_files = NULL;
2278 return device_files;
2282 pa_xfree(device_files);
2286 static struct device_file_map *parse_device_file_map() {
2287 struct device_file_map *file_map = NULL;
2288 json_object *o, *device_files_o;
2289 json_object *playback_devices_o = NULL, *capture_devices_o = NULL;
2291 pa_log_info("\nParse device files");
2293 o = json_object_from_file(DEVICE_MAP_FILE);
2296 pa_log_error("Read device-map file failed");
2300 file_map = pa_xmalloc0(sizeof(struct device_file_map));
2302 if (json_object_object_get_ex(o, DEVICE_FILE_OBJECT, &device_files_o) && json_object_is_type(device_files_o, json_type_object)) {
2303 if (json_object_object_get_ex(device_files_o, DEVICE_TYPE_PROP_PLAYBACK_DEVICES, &playback_devices_o)) {
2304 pa_log_info("Playback Device Files");
2305 file_map->playback = parse_device_file_array_object(playback_devices_o);
2307 if (json_object_object_get_ex(device_files_o, DEVICE_TYPE_PROP_CAPTURE_DEVICES, &capture_devices_o)) {
2308 pa_log_info("Capture Device Files");
2309 file_map->capture = parse_device_file_array_object(capture_devices_o);
2312 pa_log_error("Get device files object failed");
2321 static pa_hashmap* parse_device_role_map(json_object *device_role_map_o) {
2322 pa_hashmap *roles = NULL;
2323 const char *device_string, *device_role;
2324 struct json_object_iterator it, it_end;
2325 json_object *device_string_o;
2327 pa_assert(device_role_map_o);
2328 pa_assert(json_object_is_type(device_role_map_o, json_type_object));
2330 roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2332 it = json_object_iter_begin(device_role_map_o);
2333 it_end = json_object_iter_end(device_role_map_o);
2335 while (!json_object_iter_equal(&it, &it_end)) {
2336 device_role = json_object_iter_peek_name(&it);
2337 device_string_o = json_object_iter_peek_value(&it);
2339 if (!(device_string = json_object_get_string(device_string_o))) {
2340 pa_log_debug("There is no device string for role '%s'", device_role);
2342 pa_log_info("- Role '%s' -> '%s'", device_role, device_string);
2343 if (device_role_is_valid(device_role)) {
2344 if (pa_hashmap_put(roles, (void *)device_role, (void *)device_string)) {
2345 pa_log_error("put new role to hashmap faild");
2349 pa_log_error("Invalid device role '%s'", device_role);
2353 json_object_iter_next(&it);
2367 static pa_idxset* parse_device_type_infos() {
2368 json_object *o, *device_array_o = NULL;
2369 int device_type_num = 0;
2370 int device_type_idx = 0;
2371 struct device_type_info *type_info = NULL;
2372 //pa_hashmap *type_infos = NULL;
2373 pa_idxset *type_infos = NULL;
2375 o = json_object_from_file(DEVICE_MAP_FILE);
2377 pa_log_error("Read device-map file failed");
2381 pa_log_info("\nParse device types");
2382 type_infos = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2384 if (json_object_object_get_ex(o, DEVICE_TYPE_OBJECT, &device_array_o) && json_object_is_type(device_array_o, json_type_array)) {
2385 device_type_num = json_object_array_length(device_array_o);
2386 for (device_type_idx = 0; device_type_idx < device_type_num ; device_type_idx++) {
2387 json_object *device_o;
2389 if ((device_o = json_object_array_get_idx(device_array_o, device_type_idx)) && json_object_is_type(device_o, json_type_object)) {
2390 json_object *device_prop_o;
2391 const char *type = NULL;
2393 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)) {
2394 pa_log_error("Get device type failed");
2397 type = json_object_get_string(device_prop_o);
2398 pa_log_info("[ Device - %s ]", type);
2400 type_info = pa_xmalloc0(sizeof(struct device_type_info));
2401 type_info->type = type;
2403 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)) {
2404 pa_log_info("Playback Devices");
2405 type_info->playback_devices = parse_device_role_map(device_prop_o);
2408 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)) {
2409 pa_log_info("Capture Devices");
2410 type_info->capture_devices = parse_device_role_map(device_prop_o);
2412 pa_idxset_put(type_infos, type_info, NULL);
2415 pa_log_debug("Get device type object failed");
2419 pa_log_debug("Get device type array object failed");
2425 pa_xfree(type_infos);
2431 look detected status which is external value, make conversion to internal consistent value, and handle it
2432 device_type, which type of device is detected
2433 system_id : system_id among same device types for support multi-device
2435 static int handle_device_status_changed(pa_device_manager *dm, const char *type,
2436 const char *name, const char *system_id, device_detected_type_t detected) {
2438 pa_assert(device_type_is_valid(type));
2440 pa_log_info("Device Status Changed, type(%s) system_id(%s), detected_type(%d)",
2441 type, pa_strempty(system_id), detected);
2443 if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2444 _device_set_detected(dm, type, name, system_id, detected);
2445 if (detected == DEVICE_DISCONNECTED)
2446 handle_device_disconnected(dm, type, system_id);
2448 handle_device_connected(dm, type, name, system_id, detected);
2449 } else if (device_type_is_need_detect(type)) {
2450 _device_set_detected(dm, type, name, system_id, detected);
2451 if (detected == DEVICE_DISCONNECTED)
2452 handle_device_disconnected(dm, type, system_id);
2454 handle_device_connected(dm, type, name, system_id, detected);
2456 pa_log_debug("No need to detect type %s", type);
2463 Initialize device-status idxset.
2464 This is for device-status detected through dbus.
2465 So, if device_type is not detected through dbus, let's initialize them to detected. (ex. spk, rcv,...)
2466 If not, initialize to not detected.
2468 static void device_type_status_init(pa_device_manager *manager) {
2469 struct device_type_info *type_info;
2474 pa_assert(manager->type_infos);
2476 pa_log_debug("\n==================== Init Device Status ====================");
2478 PA_IDXSET_FOREACH(type_info, manager->type_infos, type_idx) {
2479 type = type_info->type;
2480 if (device_type_is_equal(type, DEVICE_TYPE_AUDIO_JACK)) {
2481 int earjack_status = 0;
2482 if (vconf_get_int(VCONFKEY_SYSMAN_EARJACK, &earjack_status) < 0) {
2483 pa_log_error("Get earjack status failed");
2486 if (earjack_status == EARJACK_TYPE_SPK_ONLY)
2487 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_3P);
2488 else if (earjack_status == EARJACK_TYPE_SPK_WITH_MIC)
2489 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_4P);
2490 else if (earjack_status == EARJACK_DISCONNECTED)
2491 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2493 pa_log_warn("Unknown earjack status : %d", earjack_status);
2494 } else if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
2495 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2496 } else if (device_type_is_equal(type, DEVICE_TYPE_HDMI)) {
2497 _device_set_detected(manager, type, NULL, NULL, DEVICE_DISCONNECTED);
2498 } else if (device_type_is_equal(type, DEVICE_TYPE_FORWARDING)) {
2499 int miracast_wfd_status = 0;
2500 if (vconf_get_bool(VCONFKEY_MIRACAST_WFD_SOURCE_STATUS, &miracast_wfd_status) < 0) {
2501 pa_log_error("Get mirroring status failed");
2504 if (miracast_wfd_status == FORWARDING_CONNECTED)
2505 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
2507 _device_set_detected(manager, type, NULL, NULL, DEVICE_CONNECTED);
2515 static int _translate_external_value(const char *type, int value, device_detected_type_t *detected) {
2517 if (!type || !detected) {
2518 pa_log_error("Invalid Parameter for translate");
2522 if (device_type_is_equal(DEVICE_TYPE_AUDIO_JACK, type)) {
2523 if (value == EARJACK_DISCONNECTED)
2524 *detected = DEVICE_DISCONNECTED;
2525 else if (value == EARJACK_TYPE_SPK_ONLY)
2526 *detected = DEVICE_CONNECTED_AUDIO_JACK_3P;
2527 else if (value == EARJACK_TYPE_SPK_WITH_MIC)
2528 *detected = DEVICE_CONNECTED_AUDIO_JACK_4P;
2531 } else if (device_type_is_equal(DEVICE_TYPE_HDMI, type)) {
2532 if (value == HDMI_AUDIO_DISCONNECTED)
2533 *detected = DEVICE_DISCONNECTED;
2534 else if (value == HDMI_AUDIO_AVAILABLE)
2535 *detected = DEVICE_CONNECTED;
2538 } else if (device_type_is_equal(DEVICE_TYPE_FORWARDING, type)) {
2539 if (value == FORWARDING_DISCONNECTED)
2540 *detected = DEVICE_DISCONNECTED;
2541 else if (value == FORWARDING_CONNECTED)
2542 *detected = DEVICE_CONNECTED;
2545 } else if (device_type_is_equal(DEVICE_TYPE_BT_SCO, type)) {
2546 if (value == BT_SCO_DISCONNECTED)
2547 *detected = DEVICE_DISCONNECTED;
2548 else if (value == BT_SCO_CONNECTED)
2549 *detected = DEVICE_CONNECTED_SCO;
2557 static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
2560 pa_device_manager *dm = (pa_device_manager *) userdata;
2561 device_detected_type_t detected;
2563 pa_assert(userdata);
2565 if (dbus_message_get_type(s) != DBUS_MESSAGE_TYPE_SIGNAL)
2566 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2568 pa_log_info("Device detect handler : Path(%s) Intf(%s) Member(%s) Signature(%s)",
2569 dbus_message_get_path(s), dbus_message_get_interface(s), dbus_message_get_member(s), dbus_message_get_signature(s));
2571 dbus_error_init(&error);
2573 if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedEarjack")) {
2574 if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2577 if (_translate_external_value(DEVICE_TYPE_AUDIO_JACK, status, &detected) < 0) {
2578 pa_log_warn("failed to translate audio-jack detected value");
2581 handle_device_status_changed(dm, DEVICE_TYPE_AUDIO_JACK, NULL, NULL, detected);
2583 } else if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedHDMIAudio")) {
2584 if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2587 if (_translate_external_value(DEVICE_TYPE_HDMI, status, &detected) < 0) {
2588 pa_log_warn("failed to translate HDMI detected value");
2591 handle_device_status_changed(dm, DEVICE_TYPE_HDMI, NULL, NULL, detected);
2593 } else if (dbus_message_is_signal(s, DBUS_INTERFACE_MIRRORING_SERVER, "miracast_wfd_source_status_changed")) {
2594 if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
2597 if (_translate_external_value(DEVICE_TYPE_FORWARDING, status, &detected) < 0) {
2598 pa_log_warn("failed to translate forwarding detected value");
2601 handle_device_status_changed(dm, DEVICE_TYPE_FORWARDING, NULL, NULL, detected);
2603 } else if (dbus_message_is_signal(s, DBUS_INTERFACE_BLUEZ_HEADSET, "PropertyChanged")) {
2604 DBusMessageIter msg_iter, variant_iter;
2605 char *property_name;
2607 pa_log_debug("Got %s PropertyChanged signal", DBUS_INTERFACE_BLUEZ_HEADSET);
2608 dbus_message_iter_init(s, &msg_iter);
2609 if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_STRING) {
2610 pa_log_error("Property name not string");
2613 dbus_message_iter_get_basic(&msg_iter, &property_name);
2614 pa_log_info("Changed Property name : %s", property_name);
2616 if (!dbus_message_iter_next(&msg_iter)) {
2617 pa_log_debug("Property value missing");
2621 if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_VARIANT) {
2622 pa_log_debug("Property value not a variant.");
2626 dbus_message_iter_recurse(&msg_iter, &variant_iter);
2628 if (DBUS_TYPE_BOOLEAN == dbus_message_iter_get_arg_type(&variant_iter)) {
2631 dbus_message_iter_get_basic(&variant_iter, &value);
2632 if (pa_streq(property_name, "Connected")) {
2633 pa_log_info("HFP Connection : %d", value);
2635 method_call_bt_get_name(c, dbus_message_get_path(s), &name);
2636 status = BT_SCO_CONNECTED;
2638 status = BT_SCO_DISCONNECTED;
2640 if (_translate_external_value(DEVICE_TYPE_BT_SCO, status, &detected) < 0) {
2641 pa_log_warn("failed to translate bt-sco detected value");
2644 handle_device_status_changed(dm, DEVICE_TYPE_BT_SCO,
2645 name, dbus_message_get_path(s), detected);
2646 } else if (pa_streq(property_name, "Playing")) {
2647 pa_tz_device *device;
2648 pa_log_info("SCO Playing : %d", value);
2649 if ((device = _device_list_get_device(dm, DEVICE_TYPE_BT_SCO, NULL)) != NULL) {
2650 device->sco_opened = value;
2652 /* update BT band/nrec information */
2653 bool is_wide_band = false;
2655 pa_tz_device_sco_get_property(device, &is_wide_band, &nrec);
2656 pa_log_info("got new wideband:%d, nrec:%d", is_wide_band, nrec);
2658 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-wideband", is_wide_band);
2659 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-nrec", nrec);
2662 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-sco-ready", value);
2666 pa_log_debug("Unknown message, not handle it");
2667 dbus_error_free(&error);
2668 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2671 pa_log_debug("Dbus Message handled");
2673 dbus_error_free(&error);
2674 return DBUS_HANDLER_RESULT_HANDLED;
2677 pa_log_error("Fail to handle dbus signal");
2678 dbus_error_free(&error);
2679 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2682 static int watch_signals(pa_device_manager *dm) {
2686 pa_assert(dm->dbus_conn);
2688 dbus_error_init(&error);
2690 pa_log_info("Watch Dbus signals");
2692 if (!dbus_connection_add_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm, NULL)) {
2693 pa_log_error("Unable to add D-Bus filter : %s: %s", error.name, error.message);
2697 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) {
2698 pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
2704 dbus_error_free(&error);
2708 static void unwatch_signals(pa_device_manager *dm) {
2709 pa_log_info("Unwatch Dbus signals");
2712 pa_assert(dm->dbus_conn);
2714 pa_dbus_remove_matches(pa_dbus_connection_get(dm->dbus_conn), FILTER_DEVICED_SYSNOTI, FILTER_SOUND_SERVER, FILTER_BLUEZ, FILTER_MIRRORING, NULL);
2715 dbus_connection_remove_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm);
2718 static void fill_signal_msg_with_device(const char *description, DBusMessageIter *msg_iter, uint32_t event_id, pa_tz_device *device) {
2719 DBusMessageIter array_iter, device_iter;
2721 dbus_int32_t device_id, direction, state, stream_id;
2722 dbus_int32_t vendor_id, product_id;
2723 dbus_bool_t is_running;
2724 pa_intset *stream_id_set = NULL;
2725 int32_t stream_id_val;
2728 pa_assert(msg_iter);
2731 dbus_message_iter_append_basic(msg_iter, DBUS_TYPE_UINT32, &event_id);
2732 pa_assert_se(dbus_message_iter_open_container(msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2734 direction = (dbus_int32_t) pa_tz_device_get_direction(device);
2735 type = pa_tz_device_get_type(device);
2736 name = pa_tz_device_get_name(device);
2737 device_id = (dbus_int32_t) pa_tz_device_get_id(device);
2738 state = pa_tz_device_get_state(device);
2739 vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
2740 product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
2741 is_running = (dbus_bool_t) pa_tz_device_is_running(device);
2743 simple_device_dump(PA_LOG_INFO, description, device_id, type, name, direction, state);
2745 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2746 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
2747 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
2748 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
2749 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
2750 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
2751 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
2752 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
2753 if (state == DM_DEVICE_STATE_ACTIVATED)
2754 stream_id_set = pa_tz_device_get_stream_list(device);
2755 pa_assert_se(dbus_message_iter_open_container(&device_iter, DBUS_TYPE_ARRAY, "i", &array_iter));
2756 if (state == DM_DEVICE_STATE_ACTIVATED) {
2757 PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
2758 stream_id = stream_id_val;
2759 dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_INT32, &stream_id);
2762 pa_assert_se(dbus_message_iter_close_container(&device_iter, &array_iter));
2764 pa_intset_free(stream_id_set);
2765 pa_assert_se(dbus_message_iter_close_container(msg_iter, &device_iter));
2766 pa_log_info("end of fill signal msg");
2769 static void send_device_connection_changed_signal(uint32_t event_id, pa_tz_device *device, bool connected, pa_device_manager *dm) {
2770 DBusMessage *signal_msg;
2771 DBusMessageIter msg_iter;
2772 dbus_bool_t _connected = connected;
2777 pa_log_info("Send device connection changed signal, event_id(%u)", event_id);
2779 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceConnected"));
2780 dbus_message_iter_init_append(signal_msg, &msg_iter);
2781 fill_signal_msg_with_device(connected ? "[Connected]" : "[Disconnected]", &msg_iter, event_id, device);
2783 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &_connected);
2785 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2787 dbus_message_unref(signal_msg);
2788 pa_log_info("end of send device connection changed signal");
2791 static void send_device_info_changed_signal(uint32_t event_id, pa_tz_device *device, int changed_type, pa_device_manager *dm) {
2792 DBusMessage *signal_msg;
2793 DBusMessageIter msg_iter;
2794 const char *changed_prefix[] = {"[State Changed]", "[Direction Changed]", "[Avail-Mode Changed]"};
2799 pa_log_debug("Send device info changed signal, event_id(%u)", event_id);
2801 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceInfoChanged"));
2802 dbus_message_iter_init_append(signal_msg, &msg_iter);
2803 fill_signal_msg_with_device(changed_prefix[changed_type], &msg_iter, event_id, device);
2804 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &changed_type);
2806 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2808 dbus_message_unref(signal_msg);
2811 static void send_device_state_changed_signal(uint32_t event_id, pa_tz_device *device, bool activated, pa_device_manager *dm) {
2812 DBusMessage *signal_msg;
2813 DBusMessageIter msg_iter;
2818 pa_log_debug("Send device state 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, "DeviceStateChanged"));
2821 dbus_message_iter_init_append(signal_msg, &msg_iter);
2822 fill_signal_msg_with_device(activated ? "[Activated]" : "[Deactivated]", &msg_iter, event_id, device);
2824 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2826 dbus_message_unref(signal_msg);
2829 static void send_device_running_changed_signal(uint32_t event_id, pa_tz_device *device, bool is_running, pa_device_manager *dm) {
2830 DBusMessage *signal_msg;
2831 DBusMessageIter msg_iter;
2836 pa_log_debug("Send device running changed signal, event_id(%u)", event_id);
2838 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceRunningChanged"));
2839 dbus_message_iter_init_append(signal_msg, &msg_iter);
2840 fill_signal_msg_with_device(is_running ? "[Running]" : "[NotRunning]", &msg_iter, event_id, device);
2842 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
2844 dbus_message_unref(signal_msg);
2847 static bool device_is_match_direction(pa_tz_device *device, int direction_mask) {
2848 dm_device_direction_t direction;
2850 if (direction_mask == DEVICE_IO_DIRECTION_FLAGS || direction_mask == 0)
2853 direction = pa_tz_device_get_direction(device);
2855 if ((direction_mask & DEVICE_IO_DIRECTION_IN_FLAG) && (direction & DM_DEVICE_DIRECTION_IN))
2857 if ((direction_mask & DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & DM_DEVICE_DIRECTION_OUT))
2859 if ((direction_mask & DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction == DM_DEVICE_DIRECTION_BOTH))
2865 static bool device_is_match_state(pa_tz_device *device, int state_mask) {
2866 dm_device_state_t state;
2868 if (state_mask == DEVICE_STATE_FLAGS || state_mask == 0)
2871 state = pa_tz_device_get_state(device);
2873 if ((state_mask & DEVICE_STATE_DEACTIVATED_FLAG) && (state == DM_DEVICE_STATE_DEACTIVATED))
2875 if ((state_mask & DEVICE_STATE_ACTIVATED_FLAG) && (state == DM_DEVICE_STATE_ACTIVATED))
2881 static bool device_is_match_type(pa_tz_device *device, int type_mask) {
2885 if (type_mask == DEVICE_TYPE_FLAGS || type_mask == 0)
2888 type = pa_tz_device_get_type(device);
2889 is_builtin = device_type_is_builtin(type);
2891 if ((type_mask & DEVICE_TYPE_INTERNAL_FLAG) && is_builtin)
2893 if ((type_mask & DEVICE_TYPE_EXTERNAL_FLAG) && !is_builtin)
2899 static bool device_is_match_with_mask(pa_tz_device *device, int mask) {
2902 if (mask == DEVICE_ALL_FLAG)
2905 return (device_is_match_direction(device, mask & DEVICE_IO_DIRECTION_FLAGS) &&
2906 device_is_match_state(device, mask & DEVICE_STATE_FLAGS) &&
2907 device_is_match_type(device, mask & DEVICE_TYPE_FLAGS));
2910 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name) {
2911 const char *intf = DBUS_INTERFACE_BLUEZ_DEVICE, *prop = "Alias";
2912 DBusMessage *msg, *reply;
2913 DBusMessageIter reply_iter, variant_iter;
2917 pa_assert(device_path);
2920 if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_BLUEZ, device_path, "org.freedesktop.DBus.Properties", "Get"))) {
2921 pa_log_error("dbus method call failed");
2925 dbus_message_append_args(msg,
2926 DBUS_TYPE_STRING, &intf,
2927 DBUS_TYPE_STRING, &prop,
2930 dbus_error_init(&err);
2931 if (!(reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err))) {
2932 pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_BLUEZ_DEVICE, "Get", err.message);
2933 dbus_error_free(&err);
2937 dbus_message_iter_init(reply, &reply_iter);
2939 if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_VARIANT) {
2940 pa_log_error("Cannot get reply argument");
2944 dbus_message_iter_recurse(&reply_iter, &variant_iter);
2946 if (dbus_message_iter_get_arg_type(&variant_iter) == DBUS_TYPE_STRING) {
2947 dbus_message_iter_get_basic(&variant_iter, name);
2950 dbus_message_unref(reply);
2954 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2955 pa_device_manager *dm;
2956 DBusMessage *reply = NULL;
2957 DBusMessageIter msg_iter, array_iter, device_iter;
2958 pa_tz_device *device;
2959 dm_device_state_t state;
2960 uint32_t device_idx;
2961 dbus_int32_t device_id, direction;
2964 dbus_int32_t vendor_id, product_id;
2965 dbus_bool_t is_running;
2969 pa_assert(userdata);
2972 dm = (pa_device_manager*) userdata;
2974 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2976 pa_assert_se(dbus_message_get_args(msg, NULL,
2977 DBUS_TYPE_INT32, &mask,
2978 DBUS_TYPE_INVALID));
2980 pa_log_info("Get connected device list (mask : %d)", mask);
2982 dbus_message_iter_init_append(reply, &msg_iter);
2983 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiisiib)", &array_iter));
2985 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
2986 device_id = (dbus_int32_t)pa_tz_device_get_id(device);
2987 state = pa_tz_device_get_state(device);
2988 direction = pa_tz_device_get_direction(device);
2989 type = pa_tz_device_get_type(device);
2990 name = pa_tz_device_get_name(device);
2991 vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
2992 product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
2993 product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
2994 is_running = (dbus_bool_t) pa_tz_device_is_running(device);
2995 if (device_is_match_with_mask(device, mask)) {
2996 simple_device_dump(PA_LOG_INFO, "[MATCH]", device_id, type, name, direction, state);
2997 pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
2998 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
2999 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
3000 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
3001 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
3002 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
3003 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
3004 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
3005 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
3006 pa_assert_se(dbus_message_iter_close_container(&array_iter, &device_iter));
3008 simple_device_dump(PA_LOG_INFO, "[UNMATCH]", device_id, type, name, direction, state);
3012 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
3014 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3015 dbus_message_unref(reply);
3018 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3019 pa_device_manager *manager;
3021 DBusMessageIter msg_iter;
3022 pa_tz_device *device;
3023 dbus_int32_t device_id;
3024 dbus_int32_t id, direction, state;
3025 dbus_int32_t vendor_id, product_id;
3030 pa_assert(userdata);
3032 manager = (pa_device_manager*) userdata;
3034 pa_assert_se(dbus_message_get_args(msg, NULL,
3035 DBUS_TYPE_INT32, &device_id,
3036 DBUS_TYPE_INVALID));
3038 pa_log_info("Get device by id(%d)", device_id);
3040 if ((device = _device_list_get_device_by_id(manager, device_id))) {
3041 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3042 dbus_message_iter_init_append(reply, &msg_iter);
3044 id = (dbus_int32_t)pa_tz_device_get_id(device);
3045 state = pa_tz_device_get_state(device);
3046 direction = pa_tz_device_get_direction(device);
3047 type = pa_tz_device_get_type(device);
3048 name = pa_tz_device_get_name(device);
3049 vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
3050 product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
3052 simple_device_dump(PA_LOG_INFO, "[GET_BY_ID]", device_id, type, name, direction, state);
3054 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &id);
3055 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &type);
3056 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &direction);
3057 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &state);
3058 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
3059 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &vendor_id);
3060 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &product_id);
3062 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3063 dbus_message_unref(reply);
3065 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3069 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3070 pa_device_manager *manager;
3072 pa_tz_device *device;
3073 dbus_bool_t is_on = false;
3074 dbus_int32_t stream_id, device_id;
3075 pa_intset *stream_id_set;
3076 int32_t stream_id_val;
3078 dm_device_state_t state;
3082 pa_assert(userdata);
3084 pa_log_info("Is stream on device");
3086 manager = (pa_device_manager*) userdata;
3089 pa_assert_se(dbus_message_get_args(msg, NULL,
3090 DBUS_TYPE_INT32, &stream_id,
3091 DBUS_TYPE_INT32, &device_id,
3092 DBUS_TYPE_INVALID));
3094 if ((device = _device_list_get_device_by_id(manager, device_id))) {
3095 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3097 state = pa_tz_device_get_state(device);
3098 if (state == DM_DEVICE_STATE_ACTIVATED) {
3099 stream_id_set = pa_tz_device_get_stream_list(device);
3100 PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
3101 if (stream_id_val == stream_id) {
3103 pa_log_info("stream(%d) is on device(%d)", stream_id, device_id);
3107 pa_intset_free(stream_id_set);
3109 pa_log_info("device(%d) is not activated, regard as no stream on it", device_id);
3113 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_on,
3114 DBUS_TYPE_INVALID));
3116 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3117 dbus_message_unref(reply);
3119 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.Internal");
3123 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3124 pa_device_manager *dm;
3125 DBusMessage *reply = NULL;
3126 pa_tz_device *device;
3127 dbus_bool_t is_bt_on = false;
3128 const char *bt_name = "none";
3132 pa_assert(userdata);
3134 pa_log_info("Get BT A2DP list");
3136 dm = (pa_device_manager*) userdata;
3138 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3140 /* FIXME : Give system_id for multi device */
3141 if ((device = _device_list_get_device(dm, DEVICE_TYPE_BT_A2DP, NULL)) != NULL) {
3143 bt_name = pa_tz_device_get_name(device);
3146 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_bt_on,
3147 DBUS_TYPE_STRING, &bt_name,
3148 DBUS_TYPE_INVALID));
3150 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3151 dbus_message_unref(reply);
3156 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3157 pa_device_manager *dm;
3159 DBusMessage *reply = NULL;
3161 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3162 dm = (pa_device_manager *) userdata;
3163 pa_assert_se(dbus_message_get_args(msg, NULL,
3164 DBUS_TYPE_STRING, &type,
3165 DBUS_TYPE_STRING, &role,
3166 DBUS_TYPE_INVALID));
3168 pa_device_manager_load_sink(dm, type, role);
3169 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3170 dbus_message_unref(reply);
3173 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3174 pa_device_manager *dm;
3176 DBusMessage *reply = NULL;
3178 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3179 dm = (pa_device_manager *) userdata;
3180 pa_assert_se(dbus_message_get_args(msg, NULL,
3181 DBUS_TYPE_STRING, &type,
3182 DBUS_TYPE_STRING, &role,
3183 DBUS_TYPE_INVALID));
3185 pa_device_manager_unload_sink(dm, type, role);
3186 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3187 dbus_message_unref(reply);
3190 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3191 pa_device_manager *dm;
3192 char *device_string;
3193 DBusMessage *reply = NULL;
3195 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3196 dm = (pa_device_manager *) userdata;
3197 pa_assert_se(dbus_message_get_args(msg, NULL,
3198 DBUS_TYPE_STRING, &device_string,
3199 DBUS_TYPE_INVALID));
3201 pa_device_manager_unload_sink_with_device_string(dm, device_string);
3202 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3203 dbus_message_unref(reply);
3206 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3207 pa_device_manager *dm;
3209 const char *device_string;
3210 dbus_bool_t is_playback;
3213 dm = (pa_device_manager *) userdata;
3214 pa_assert_se(dbus_message_get_args(msg, NULL,
3215 DBUS_TYPE_BOOLEAN, &is_playback,
3216 DBUS_TYPE_STRING, &type,
3217 DBUS_TYPE_STRING, &role,
3218 DBUS_TYPE_INVALID));
3220 device_string = pa_device_manager_get_device_string(dm, is_playback, type, role);
3221 if (device_string == NULL) {
3222 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3226 pa_log_info("device string : %s", device_string);
3227 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3228 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &device_string,
3229 DBUS_TYPE_INVALID));
3230 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3231 dbus_message_unref(reply);
3234 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3235 pa_device_manager *dm;
3236 pa_tz_device *device;
3237 uint32_t device_idx;
3238 DBusMessage *reply = NULL;
3240 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3241 dm = (pa_device_manager *) userdata;
3243 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3244 pa_tz_device_dump_info(device, PA_LOG_INFO);
3246 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3247 dbus_message_unref(reply);
3250 static bool is_usb_output_device(pa_tz_device *device) {
3252 dm_device_direction_t direction;
3257 type = pa_tz_device_get_type(device);
3258 if (!pa_streq(type, DEVICE_TYPE_USB_AUDIO)) {
3259 pa_log_error("device(id:%d, %s) is not USB AUDIO type", pa_tz_device_get_id(device), type);
3262 direction = pa_tz_device_get_direction(device);
3263 if (direction & DM_DEVICE_DIRECTION_OUT) {
3264 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
3265 pa_log_error("sink is null");
3269 pa_log_error("this device is not for output");
3276 static bool is_supported_sample_rate(uint32_t *supported_sample_rates, uint32_t sample_rate) {
3279 pa_assert(supported_sample_rates);
3281 /* use a supported sample rate selected by user */
3282 for (i = 0; supported_sample_rates[i]; i++) {
3283 if (supported_sample_rates[i] == sample_rate) {
3284 pa_log_info("%u is supported", sample_rate);
3288 pa_log_error("%u is not supported", sample_rate);
3292 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3293 pa_device_manager *dm;
3294 DBusMessage *reply = NULL;
3295 DBusMessageIter msg_iter, array_iter, item_iter;
3296 dbus_int32_t device_id;
3297 pa_tz_device *device;
3303 pa_assert(userdata);
3305 dm = (pa_device_manager *)userdata;
3307 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3309 pa_assert_se(dbus_message_get_args(msg, NULL,
3310 DBUS_TYPE_INT32, &device_id,
3311 DBUS_TYPE_INVALID));
3313 pa_log_info("Get supported sample rates of the device(id:%d)", device_id);
3315 if (!(device = _device_list_get_device_by_id(dm, device_id))) {
3316 pa_log_error("could not find any device with id:%d", device_id);
3317 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3320 if (!is_usb_output_device(device)) {
3321 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.PolicyInternal");
3324 sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
3326 dbus_message_iter_init_append(reply, &msg_iter);
3327 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(u)", &array_iter));
3328 for (i = 0; sink->supported_sample_rates[i]; i++) {
3329 pa_log_info("%u is supported", sink->supported_sample_rates[i]);
3330 pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &item_iter));
3331 dbus_message_iter_append_basic(&item_iter, DBUS_TYPE_UINT32, &sink->supported_sample_rates[i]);
3332 pa_assert_se(dbus_message_iter_close_container(&array_iter, &item_iter));
3334 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
3335 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3336 dbus_message_unref(reply);
3339 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3340 pa_device_manager *dm;
3341 DBusMessage *reply = NULL;
3342 dbus_int32_t device_id;
3343 dbus_uint32_t sample_rate;
3344 uint32_t prev_selected_sample_rate;
3345 pa_tz_device *device;
3352 pa_assert(userdata);
3354 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3355 dm = (pa_device_manager *)userdata;
3356 pa_assert_se(dbus_message_get_args(msg, NULL,
3357 DBUS_TYPE_INT32, &device_id,
3358 DBUS_TYPE_UINT32, &sample_rate,
3359 DBUS_TYPE_INVALID));
3361 pa_log_info("Set sample rate(%u) of the device(id:%d)", sample_rate, device_id);
3363 if (!(device = _device_list_get_device_by_id(dm, device_id))) {
3364 pa_log_error("could not find any device with id:%d", device_id);
3365 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3368 if (!is_usb_output_device(device)) {
3369 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.PolicyInternal");
3372 sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
3374 /* use stream original sample rate if possible */
3375 if (sample_rate == 0) {
3376 sink->avoid_resampling = true;
3377 PA_IDXSET_FOREACH(si, sink->inputs, idx) {
3378 if (pa_sink_reconfigure(sink, &si->sample_spec, pa_sink_input_is_passthrough(si)) == -1) {
3379 pa_log_error("failed to reconfigure");
3380 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3381 sink->avoid_resampling = sink->origin_avoid_resampling;
3385 sink->selected_sample_rate = 0;
3387 pa_log_info("Set sample rate to avoid resampling for the device(%u) successfully", device_id);
3388 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3389 dbus_message_unref(reply);
3393 /* use a supported sample rate selected by user */
3394 if (!is_supported_sample_rate(sink->supported_sample_rates, sample_rate)) {
3395 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3398 prev_selected_sample_rate = sink->selected_sample_rate;
3399 sink->selected_sample_rate = sample_rate;
3401 PA_IDXSET_FOREACH(si, sink->inputs, idx) {
3402 if (pa_sink_reconfigure(sink, &si->sample_spec, pa_sink_input_is_passthrough(si)) == -1) {
3403 pa_log_error("failed to reconfigure");
3404 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
3405 sink->selected_sample_rate = prev_selected_sample_rate;
3410 sink->avoid_resampling = sink->origin_avoid_resampling;
3412 pa_log_info("Set sample rate(%u) of the device(id:%d) successfully", sample_rate, device_id);
3413 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3414 dbus_message_unref(reply);
3417 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3418 pa_device_manager *dm;
3419 DBusMessage *reply = NULL;
3420 dbus_int32_t device_id;
3421 pa_tz_device *device;
3426 pa_assert(userdata);
3428 dm = (pa_device_manager *)userdata;
3430 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3432 pa_assert_se(dbus_message_get_args(msg, NULL,
3433 DBUS_TYPE_INT32, &device_id,
3434 DBUS_TYPE_INVALID));
3436 pa_log_info("Get sample rate of the device(id:%d)", device_id);
3438 if (!(device = _device_list_get_device_by_id(dm, device_id))) {
3439 pa_log_error("could not find any device with id:%d", device_id);
3440 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
3443 if (!is_usb_output_device(device)) {
3444 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.PolicyInternal");
3447 sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
3449 pa_log_info("Get sample rate(%u) of the device(id:%d) successfully", sink->selected_sample_rate, device_id);
3450 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3451 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &sink->selected_sample_rate, DBUS_TYPE_INVALID));
3452 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3453 dbus_message_unref(reply);
3456 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3457 pa_device_manager *dm = (pa_device_manager *)userdata;
3459 dbus_int32_t status;
3460 DBusMessage *reply = NULL;
3463 pa_assert_se((reply = dbus_message_new_method_return(msg)));
3465 dbus_error_init(&error);
3466 if (!dbus_message_get_args(msg, NULL,
3467 DBUS_TYPE_STRING, &type,
3468 DBUS_TYPE_INT32, &status,
3469 DBUS_TYPE_INVALID)) {
3470 pa_log_error("failed to get dbus args : %s", error.message);
3471 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
3472 dbus_error_free(&error);
3475 pa_log_debug("handle_test_device_status_change, type:%s, status:%d", type, status);
3477 handle_device_status_changed(dm, type, NULL, NULL, status);
3478 pa_assert_se(dbus_connection_send(conn, reply, NULL));
3479 dbus_message_unref(reply);
3482 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3483 const char *xml = DEVICE_MANAGER_INTROSPECT_XML;
3484 DBusMessage *r = NULL;
3488 pa_assert(userdata);
3490 pa_assert_se(r = dbus_message_new_method_return(msg));
3491 pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
3494 pa_assert_se(dbus_connection_send((conn), r, NULL));
3495 dbus_message_unref(r);
3498 return DBUS_HANDLER_RESULT_HANDLED;
3501 static DBusHandlerResult handle_device_manager_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
3506 pa_assert(userdata);
3508 for (method_idx = 0; method_idx < METHOD_HANDLER_MAX; method_idx++) {
3509 if (dbus_message_is_method_call(msg, DBUS_INTERFACE_DEVICE_MANAGER, method_handlers[method_idx].method_name)) {
3510 method_handlers[method_idx].receive_cb(conn, msg, userdata);
3511 return DBUS_HANDLER_RESULT_HANDLED;
3515 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3518 static DBusHandlerResult method_call_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
3519 struct userdata *u = userdata;
3520 const char *path, *interface, *member;
3526 path = dbus_message_get_path(m);
3527 interface = dbus_message_get_interface(m);
3528 member = dbus_message_get_member(m);
3530 pa_log_info("DeviceManager Method Call Handler : path=%s, interface=%s, member=%s", path, interface, member);
3532 if (!pa_streq(path, DBUS_OBJECT_DEVICE_MANAGER))
3533 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3535 if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
3536 return handle_introspect(c, m, u);
3538 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get")) {
3539 return handle_get_property(c, m, u);
3540 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set")) {
3541 return handle_set_property(c, m, u);
3542 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll")) {
3543 return handle_get_all_property(c, m, u);
3546 return handle_device_manager_methods(c, m, u);
3549 return DBUS_HANDLER_RESULT_HANDLED;
3552 static void endpoint_init(pa_device_manager *dm) {
3553 static const DBusObjectPathVTable vtable_endpoint = {
3554 .message_function = method_call_handler,
3557 pa_log_info("Device manager dbus endpoint init");
3559 if (dm && dm->dbus_conn) {
3560 if (!dbus_connection_register_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER, &vtable_endpoint, dm))
3561 pa_log_error("Failed to register object path");
3563 pa_log_error("Cannot get dbus connection to register object path");
3567 static void endpoint_done(pa_device_manager *dm) {
3568 pa_log_info("Device manager dbus endpoint done");
3569 if (dm && dm->dbus_conn) {
3570 if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER))
3571 pa_log_error("Failed to unregister object path");
3573 pa_log_error("Cannot get dbus connection to unregister object path");
3577 static void dbus_init(pa_device_manager *dm) {
3579 pa_dbus_connection *connection = NULL;
3582 pa_log_info("Dbus init");
3583 dbus_error_init(&error);
3585 if (!(connection = pa_dbus_bus_get(dm->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
3587 pa_dbus_connection_unref(connection);
3589 pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
3592 pa_log_info("Got dbus connection");
3595 dm->dbus_conn = connection;
3597 if (watch_signals(dm) < 0)
3598 pa_log_error("dbus watch signals failed");
3600 pa_log_debug("dbus ready to get signals");
3605 dbus_error_free(&error);
3608 static void dbus_deinit(pa_device_manager *dm) {
3611 pa_log_info("Dbus deinit");
3614 unwatch_signals(dm);
3616 if (dm->dbus_conn) {
3617 pa_dbus_connection_unref(dm->dbus_conn);
3618 dm->dbus_conn = NULL;
3623 pa_idxset* pa_device_manager_get_device_list(pa_device_manager *dm) {
3625 pa_assert(dm->device_list);
3627 return dm->device_list;
3630 pa_tz_device* pa_device_manager_get_device(pa_device_manager *dm, const char *type) {
3633 return _device_list_get_device(dm, type, NULL);
3636 pa_tz_device* pa_device_manager_get_device_by_id(pa_device_manager *dm, uint32_t id) {
3639 return _device_list_get_device_by_id(dm, id);
3642 pa_tz_device* pa_device_manager_get_device_with_sink(pa_sink *sink) {
3645 return sink->device_item;
3648 pa_tz_device* pa_device_manager_get_device_with_source(pa_source *source) {
3651 return source->device_item;
3654 pa_tz_device* pa_device_manager_load_forwarding(pa_device_manager *dm) {
3655 return _load_forwarding_device(dm);
3658 void pa_device_manager_unload_forwarding(pa_device_manager *dm) {
3659 pa_tz_device *forwarding_device;
3661 forwarding_device = _device_list_get_device(dm, DEVICE_TYPE_FORWARDING, NULL);
3662 if (forwarding_device)
3663 pa_tz_device_free(forwarding_device);
3665 pa_log_warn("There is no forwarding device");
3668 pa_sink* pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const char *role) {
3669 const char *device_string, *params;
3670 struct device_type_info *type_info;
3671 struct device_file_info *file_info;
3672 pa_tz_device *device;
3674 uint32_t device_idx;
3677 pa_assert(dm->device_list);
3681 pa_log_info("Load Sink for '%s.%s'", type, role);
3682 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3683 if (pa_streq(type, pa_tz_device_get_type(device))) {
3684 if (pa_tz_device_get_sink(device, role)) {
3685 pa_log_warn("Proper sink for '%s.%s' already loaded", type, role);
3691 if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3692 pa_log_error("No type map for %s", type);
3696 if (type_info->playback_devices == NULL) {
3697 pa_log_error("No playback devices for %s", type_info->type);
3701 if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
3702 pa_log_error("No device-string for '%s.%s'", type, role);
3706 if (!(file_info = _device_manager_get_file_info(dm->file_map->playback, device_string))) {
3707 pa_log_error("No playback file-map for '%s'", device_string);
3711 if (!(params = pa_hashmap_get(file_info->roles, role))) {
3712 pa_log_error("No params for '%s,%s'", device_string, role);
3716 if ((sink = load_device(dm->core, true, device_string, params))) {
3717 pa_log_debug("loaded sink '%s' for '%s,%s' success", sink->name, type, role);
3719 pa_log_warn("Cannot load playback device with '%s,%s'", device_string, params);
3729 void pa_device_manager_unload_sink(pa_device_manager *dm, const char *type, const char *role) {
3730 const char *device_string;
3731 struct device_type_info *type_info;
3734 pa_assert(dm->device_list);
3738 pa_log_info("Unload Sink for '%s.%s'", type, role);
3740 if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3741 pa_log_error("No type map for %s", type);
3745 if (type_info->playback_devices == NULL) {
3746 pa_log_error("No playback devices for %s", type_info->type);
3750 if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
3751 pa_log_error("No device-string for '%s.%s'", type, role);
3755 unload_device(dm->core, true, device_string);
3758 void pa_device_manager_unload_sink_with_device_string(pa_device_manager *dm, const char *device_string) {
3760 pa_assert(device_string);
3762 unload_device(dm->core, true, device_string);
3765 pa_source* pa_device_manager_load_source(pa_device_manager *dm, const char *type, const char *role) {
3766 const char *device_string, *params;
3767 struct device_type_info *type_info;
3768 struct device_file_info *file_info;
3769 pa_tz_device *device;
3771 uint32_t device_idx;
3774 pa_assert(dm->device_list);
3778 pa_log_info("Load Source for '%s.%s'", type, role);
3780 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
3781 if (pa_streq(type, pa_tz_device_get_type(device))) {
3782 if (pa_tz_device_get_source(device, role)) {
3783 pa_log_warn("Proper source for '%s.%s' already loaded", type, role);
3789 if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3790 pa_log_error("No type map for %s", type);
3794 if (type_info->capture_devices == NULL) {
3795 pa_log_error("No capture devices for %s", type_info->type);
3799 if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
3800 pa_log_error("No device-string for '%s.%s'", type, role);
3804 if (!(file_info = _device_manager_get_file_info(dm->file_map->capture, device_string))) {
3805 pa_log_error("No capture file-map for '%s'", device_string);
3809 if (!(params = pa_hashmap_get(file_info->roles, role))) {
3810 pa_log_error("No params for '%s,%s'", device_string, role);
3814 if ((source = load_device(dm->core, false, device_string, params))) {
3815 pa_log_debug("loaded source '%s' for '%s,%s' success", source->name, type, role);
3817 pa_log_warn("Cannot load capture device with '%s,%s'", device_string, params);
3827 void pa_device_manager_unload_source(pa_device_manager *dm, const char *type, const char *role) {
3828 const char *device_string;
3829 struct device_type_info *type_info;
3832 pa_assert(dm->device_list);
3836 pa_log_info("Unload Source for '%s.%s'", type, role);
3838 if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
3839 pa_log_error("No type map for %s", type);
3843 if (type_info->capture_devices == NULL) {
3844 pa_log_error("No capture devices for %s", type_info->type);
3848 if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
3849 pa_log_error("No device-string for '%s.%s'", type, role);
3853 unload_device(dm->core, false, device_string);
3856 void pa_device_manager_unload_source_with_device_string(pa_device_manager *dm, const char *device_string) {
3858 pa_assert(device_string);
3860 unload_device(dm->core, false, device_string);
3863 const char* pa_device_manager_get_device_string(pa_device_manager *dm, bool is_playback, const char *type, const char *role) {
3864 struct device_type_info *type_info;
3870 type_info = _device_manager_get_type_info(dm->type_infos, type);
3871 if (type_info == NULL) {
3872 pa_log_error("No type info for %s", type);
3876 return device_type_info_get_device_string(type_info, is_playback, role);
3879 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) {
3885 index = (uint32_t)output_device; /* input:0, output:1 */
3888 if (num_of_devices == 0) {
3889 for (i = 0; i < DEVICE_INDEX_MAX; i++) {
3890 if (!internal_codec_devices[i].is_running[index])
3892 internal_codec_devices[i].is_running[index] = false;
3893 /* change to NOT RUNNING */
3894 if (!internal_codec_devices[i].is_running[!index]) {
3895 find_device_and_set_running(dm, internal_codec_devices[i].type, false);
3896 internal_codec_devices_dump();
3902 for (i = 0; i < DEVICE_INDEX_MAX; i++) {
3904 if (!internal_codec_devices[i].is_running[index])
3906 for (j = 0; j < num_of_devices; j++) {
3907 if (pa_safe_streq(device_infos[j].type, internal_codec_devices[i].type))
3911 internal_codec_devices[i].is_running[index] = false;
3912 /* change to NOT RUNNING */
3913 if (!internal_codec_devices[i].is_running[!index]) {
3914 find_device_and_set_running(dm, internal_codec_devices[i].type, false);
3915 internal_codec_devices_dump();
3920 for (i = 0; i < num_of_devices; i++) {
3921 for (j = 0; j < DEVICE_INDEX_MAX; j++) {
3922 if (!pa_safe_streq(device_infos[i].type, internal_codec_devices[j].type))
3924 if (!internal_codec_devices[j].is_running[index]) {
3925 internal_codec_devices[j].is_running[index] = true;
3926 /* change to RUNNING */
3927 find_device_and_set_running(dm, internal_codec_devices[j].type, true);
3928 internal_codec_devices_dump();
3934 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) {
3935 send_device_connection_changed_signal(data->event_id, data->device, data->is_connected, dm);
3939 /* it will be replaced by running_changed_hook_cb() */
3940 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) {
3941 send_device_info_changed_signal(data->event_id, data->device, DM_DEVICE_CHANGED_INFO_STATE, dm);
3942 send_device_state_changed_signal(data->event_id, data->device, data->activated, dm);
3946 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) {
3947 send_device_running_changed_signal(data->event_id, data->device, data->is_running, dm);
3948 pa_log_info("RUNNING CHANGED!! device type[%s], is running[%d]", data->device->type, data->is_running);
3952 pa_device_manager* pa_device_manager_get(pa_core *c) {
3953 pa_device_manager *dm;
3957 pa_log_info("pa_device_manager_get");
3959 if ((dm = pa_shared_get(c, SHARED_DEVICE_MANAGER)))
3960 return pa_device_manager_ref(dm);
3962 dm = pa_xnew0(pa_device_manager, 1);
3965 dm->device_list = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3966 dm->device_status = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3970 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);
3971 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);
3972 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);
3973 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);
3974 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);
3975 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);
3976 dm->comm = pa_communicator_get(dm->core);
3977 dm->comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
3978 PA_HOOK_EARLY, (pa_hook_cb_t)device_connection_changed_hook_cb, dm);
3979 dm->comm_hook_device_state_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_STATE_CHANGED),
3980 PA_HOOK_EARLY, (pa_hook_cb_t)device_state_changed_hook_cb, dm);
3981 dm->comm_hook_device_running_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_RUNNING_CHANGED),
3982 PA_HOOK_EARLY, (pa_hook_cb_t)device_running_changed_hook_cb, dm);
3984 dm->hal_interface = pa_hal_interface_get(dm->core);
3986 if (!(dm->type_infos = parse_device_type_infos())) {
3987 pa_log_error("Parse device-type-map failed");
3991 if (!(dm->file_map = parse_device_file_map())) {
3992 pa_log_error("Parse device-file-map failed");
3996 device_type_status_init(dm);
3998 if (load_builtin_devices(dm) != 0) {
3999 pa_log_error("Load Builtin Devices faled");
4003 /* Just for convenience when test*/
4004 if (!_device_manager_set_default_sink(dm, DEVICE_TYPE_SPEAKER, "normal")) {
4005 pa_log_warn("Set default sink with speaker(normal) failed");
4007 if (!_device_manager_set_default_source(dm, DEVICE_TYPE_MIC, "normal")) {
4008 pa_log_warn("Set default source with mic(normal) failed");
4011 pa_shared_set(c, SHARED_DEVICE_MANAGER, dm);
4016 pa_device_manager* pa_device_manager_ref(pa_device_manager *dm) {
4018 pa_assert(PA_REFCNT_VALUE(dm) > 0);
4020 pa_log_info("pa_device_manager_ref");
4026 void pa_device_manager_unref(pa_device_manager *dm) {
4028 pa_assert(PA_REFCNT_VALUE(dm) > 0);
4030 pa_log_info("pa_device_manager_unref");
4031 if (PA_REFCNT_DEC(dm) > 0)
4034 if (dm->comm_hook_device_connection_changed_slot)
4035 pa_hook_slot_free(dm->comm_hook_device_connection_changed_slot);
4036 if (dm->comm_hook_device_state_changed_slot)
4037 pa_hook_slot_free(dm->comm_hook_device_state_changed_slot);
4038 if (dm->comm_hook_device_running_changed_slot)
4039 pa_hook_slot_free(dm->comm_hook_device_running_changed_slot);
4040 if (dm->sink_put_hook_slot)
4041 pa_hook_slot_free(dm->sink_put_hook_slot);
4042 if (dm->sink_unlink_hook_slot)
4043 pa_hook_slot_free(dm->sink_unlink_hook_slot);
4044 if (dm->sink_state_changed_slot)
4045 pa_hook_slot_free(dm->sink_state_changed_slot);
4046 if (dm->source_put_hook_slot)
4047 pa_hook_slot_free(dm->source_put_hook_slot);
4048 if (dm->source_unlink_hook_slot)
4049 pa_hook_slot_free(dm->source_unlink_hook_slot);
4050 if (dm->source_state_changed_slot)
4051 pa_hook_slot_free(dm->source_state_changed_slot);
4053 if (dm->hal_interface)
4054 pa_hal_interface_unref(dm->hal_interface);
4057 pa_communicator_unref(dm->comm);
4060 pa_idxset_free(dm->type_infos, (pa_free_cb_t)type_info_free_func);
4062 if (dm->file_map->playback)
4063 pa_idxset_free(dm->file_map->playback, (pa_free_cb_t)file_info_free_func);
4064 if (dm->file_map->capture)
4065 pa_idxset_free(dm->file_map->capture, (pa_free_cb_t)file_info_free_func);
4066 pa_xfree(dm->file_map);
4068 if (dm->device_list)
4069 pa_idxset_free(dm->device_list, (pa_free_cb_t)pa_tz_device_free);
4070 if (dm->device_status)
4071 pa_idxset_free(dm->device_status, NULL);
4076 pa_shared_remove(dm->core, SHARED_DEVICE_MANAGER);