2 This file is part of PulseAudio.
4 Copyright 2018 Sangchul Lee <sc11.lee@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 <pulsecore/log.h>
34 #include "stream-manager.h"
35 #include "device-manager.h"
36 #include "device-manager-priv.h"
37 #include "device-manager-db-priv.h"
40 #define DBUS_INTERFACE_DEVICE_MANAGER "org.pulseaudio.DeviceManager"
41 #define DBUS_OBJECT_DEVICE_MANAGER "/org/pulseaudio/DeviceManager"
43 #define DBUS_INTERFACE_DEVICED_SYSNOTI "org.tizen.system.deviced.SysNoti"
44 #define DBUS_OBJECT_DEVICED_SYSNOTI "/Org/Tizen/System/DeviceD/SysNoti"
46 #define DBUS_INTERFACE_SOUND_SERVER "org.tizen.SoundServer1"
47 #define DBUS_OBJECT_SOUND_SERVER "/org/tizen/SoundServer1"
49 #define DBUS_SERVICE_BLUEZ "org.bluez"
50 #define DBUS_INTERFACE_BLUEZ_HEADSET "org.bluez.Headset"
51 #define DBUS_INTERFACE_BLUEZ_DEVICE "org.bluez.Device1"
52 #define DBUS_OBJECT_BLUEZ "/org/bluez"
54 #define DBUS_INTERFACE_MIRRORING_SERVER "org.tizen.scmirroring.server"
55 #define DBUS_OBJECT_MIRRORING_SERVER "/org/tizen/scmirroring/server"
57 #define DBUS_SERVICE_HFP_AGENT "org.bluez.ag_agent"
58 #define DBUS_OBJECT_HFP_AGENT "/org/bluez/hfp_agent"
59 #define DBUS_INTERFACE_HFP_AGENT "Org.Hfp.App.Interface"
61 #define DEVICE_MANAGER_INTROSPECT_XML \
62 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
64 " <interface name=\"" DBUS_INTERFACE_DEVICE_MANAGER "\">\n" \
65 " <method name=\"GetConnectedDeviceList\">\n" \
66 " <arg name=\"mask_flags\" direction=\"in\" type=\"i\"/>\n" \
67 " <arg name=\"ConnectedDeviceList\" direction=\"out\" type=\"a(isiisiibiii)\"/>\n" \
69 " <method name=\"GetDeviceById\">\n" \
70 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
71 " <arg name=\"device\" direction=\"out\" type=\"(isiisii)\"/>\n" \
73 " <method name=\"IsDeviceRunningById\">\n" \
74 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
75 " <arg name=\"is_running\" direction=\"out\" type=\"b\"/>\n" \
77 " <method name=\"IsStreamOnDevice\">\n" \
78 " <arg name=\"stream_id\" direction=\"in\" type=\"i\"/>\n" \
79 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
80 " <arg name=\"is_on\" direction=\"out\" type=\"b\"/>\n" \
82 " <method name='GetBTA2DPStatus'>" \
83 " <arg type='b' name='is_bt_on' direction='out'/>" \
84 " <arg type='s' name='bt_name' direction='out'/>" \
86 " <method name=\"LoadSink\">\n" \
87 " <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n" \
88 " <arg name=\"role\" direction=\"in\" type=\"s\"/>\n" \
90 " <method name=\"UnloadSink\">\n" \
91 " <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n" \
92 " <arg name=\"role\" direction=\"in\" type=\"s\"/>\n" \
94 " <method name=\"GetSupportedSampleFormats\">\n" \
95 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
96 " <arg name=\"sample_formats\" direction=\"out\" type=\"a(s)\"/>\n" \
98 " <method name=\"SetSampleFormat\">\n" \
99 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
100 " <arg name=\"sample_format\" direction=\"in\" type=\"s\"/>\n" \
102 " <method name=\"GetSampleFormat\">\n" \
103 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
104 " <arg name=\"sample_format\" direction=\"out\" type=\"s\"/>\n" \
106 " <method name=\"GetSupportedSampleRates\">\n" \
107 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
108 " <arg name=\"sample_rates\" direction=\"out\" type=\"a(u)\"/>\n" \
110 " <method name=\"SetSampleRate\">\n" \
111 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
112 " <arg name=\"sample_rate\" direction=\"in\" type=\"u\"/>\n" \
114 " <method name=\"GetSampleRate\">\n" \
115 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
116 " <arg name=\"sample_rate\" direction=\"out\" type=\"u\"/>\n" \
118 " <method name=\"SetSpecificStreamOnly\">\n" \
119 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
120 " <arg name=\"stream_role\" direction=\"in\" type=\"s\"/>\n" \
122 " <method name=\"GetSpecifiedStream\">\n" \
123 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
124 " <arg name=\"stream_role\" direction=\"out\" type=\"s\"/>\n" \
126 " <method name=\"SetAvoidResampling\">\n" \
127 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
128 " <arg name=\"avoid_resampling\" direction=\"in\" type=\"b\"/>\n" \
130 " <method name=\"GetAvoidResampling\">\n" \
131 " <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n" \
132 " <arg name=\"avoid_resampling\" direction=\"out\" type=\"b\"/>\n" \
134 " <method name=\"DumpDeviceList\">\n" \
136 " <method name=\"TestStatusChange\">\n" \
137 " <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n" \
138 " <arg name=\"status\" direction=\"in\" type=\"i\"/>\n" \
140 " <method name=\"SetAcmMode\">\n" \
141 " <arg name=\"mode\" direction=\"in\" type=\"u\"/>\n" \
143 " <property name=\"PropertyTest1\" type=\"i\" access=\"readwrite\"/>\n" \
144 " <property name=\"PropertyTest2\" type=\"s\" access=\"read\"/>\n" \
145 " <signal name=\"DeviceConnected\">\n" \
146 " <arg name=\"arg1\" type=\"i\"/>\n" \
148 " <signal name=\"DeviceInfoChanged\">\n" \
149 " <arg name=\"arg1\" type=\"s\"/>\n" \
152 " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n" \
153 " <method name=\"Introspect\">\n" \
154 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \
157 " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n" \
158 " <method name=\"Get\">\n" \
159 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
160 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" \
161 " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n" \
163 " <method name=\"Set\">\n" \
164 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
165 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" \
166 " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n" \
168 " <method name=\"GetAll\">\n" \
169 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" \
170 " <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n" \
175 #define FILTER_DEVICED_SYSNOTI \
177 " interface='" DBUS_INTERFACE_DEVICED_SYSNOTI "'"
179 #define FILTER_SOUND_SERVER \
181 " interface='" DBUS_INTERFACE_SOUND_SERVER "'"
183 #define FILTER_MIRRORING \
185 " interface='" DBUS_INTERFACE_MIRRORING_SERVER "', member='miracast_wfd_source_status_changed'"
187 #define FILTER_BLUEZ \
189 " interface='" DBUS_INTERFACE_BLUEZ_HEADSET "', member='PropertyChanged'"
191 #define FILL_SAMPLE_SPEC_WITH_SELECTED(x_spec, x_sink) \
193 x_spec.format = x_sink->selected_sample_format; \
194 x_spec.rate = x_sink->selected_sample_rate; \
195 x_spec.channels = 2; \
198 /*** Defines for method handle ***/
199 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
200 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata);
201 static void handle_is_device_running_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata);
202 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
203 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
204 static void handle_get_supported_sample_formats(DBusConnection *conn, DBusMessage *msg, void *userdata);
205 static void handle_set_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
206 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
207 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata);
208 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
209 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
210 static void handle_set_specific_stream_only(DBusConnection *conn, DBusMessage *msg, void *userdata);
211 static void handle_get_specified_stream(DBusConnection *conn, DBusMessage *msg, void *userdata);
212 static void handle_set_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata);
213 static void handle_get_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata);
214 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
215 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
216 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata);
217 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata);
218 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
219 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata);
220 static void handle_set_acm_mode(DBusConnection *conn, DBusMessage *msg, void *userdata);
222 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
223 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name);
226 enum method_handler_index {
227 METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST,
228 METHOD_HANDLER_GET_DEVICE_BY_ID,
229 METHOD_HANDLER_IS_DEVICE_RUNNING_BY_ID,
230 METHOD_HANDLER_IS_STREAM_ON_DEVICE,
231 METHOD_HANDLER_GET_BT_A2DP_STATUS,
232 METHOD_HANDLER_LOAD_SINK,
233 METHOD_HANDLER_UNLOAD_SINK,
234 METHOD_HANDLER_UNLOAD_SINK_WITH_DEVICE_STRING,
235 METHOD_HANDLER_GET_DEVICE_STRING,
236 METHOD_HANDLER_GET_SUPPORTED_SAMPLE_FORMATS,
237 METHOD_HANDLER_SET_SAMPLE_FORMAT,
238 METHOD_HANDLER_GET_SAMPLE_FORMAT,
239 METHOD_HANDLER_GET_SUPPORTED_SAMPLE_RATES,
240 METHOD_HANDLER_SET_SAMPLE_RATE,
241 METHOD_HANDLER_GET_SAMPLE_RATE,
242 METHOD_HANDLER_SET_SPECIFIC_STREAM_ONLY,
243 METHOD_HANDLER_GET_SPECIFIED_STREAM,
244 METHOD_HANDLER_SET_AVOID_RESAMPLING,
245 METHOD_HANDLER_GET_AVOID_RESAMPLING,
246 METHOD_HANDLER_DUMP_DEVICE_LIST,
247 METHOD_HANDLER_STATUS_TEST,
248 METHOD_HANDLER_SET_ACM_MODE,
252 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
253 [METHOD_HANDLER_GET_CONNECTED_DEVICE_LIST] = {
254 .method_name = "GetConnectedDeviceList",
255 .receive_cb = handle_get_connected_device_list },
256 [METHOD_HANDLER_GET_DEVICE_BY_ID] = {
257 .method_name = "GetDeviceById",
258 .receive_cb = handle_get_device_by_id },
259 [METHOD_HANDLER_IS_DEVICE_RUNNING_BY_ID] = {
260 .method_name = "IsDeviceRunningById",
261 .receive_cb = handle_is_device_running_by_id },
262 [METHOD_HANDLER_IS_STREAM_ON_DEVICE] = {
263 .method_name = "IsStreamOnDevice",
264 .receive_cb = handle_is_stream_on_device },
265 [METHOD_HANDLER_GET_BT_A2DP_STATUS] = {
266 .method_name = "GetBTA2DPStatus",
267 .receive_cb = handle_get_bt_a2dp_status },
268 [METHOD_HANDLER_LOAD_SINK] = {
269 .method_name = "LoadSink",
270 .receive_cb = handle_load_sink },
271 [METHOD_HANDLER_UNLOAD_SINK] = {
272 .method_name = "UnloadSink",
273 .receive_cb = handle_unload_sink },
274 [METHOD_HANDLER_UNLOAD_SINK_WITH_DEVICE_STRING] = {
275 .method_name = "UnloadSinkWithDeviceString",
276 .receive_cb = handle_unload_sink_with_device_string },
277 [METHOD_HANDLER_GET_DEVICE_STRING] = {
278 .method_name = "GetDeviceString",
279 .receive_cb = handle_get_device_string },
280 [METHOD_HANDLER_GET_SUPPORTED_SAMPLE_FORMATS] = {
281 .method_name = "GetSupportedSampleFormats",
282 .receive_cb = handle_get_supported_sample_formats },
283 [METHOD_HANDLER_SET_SAMPLE_FORMAT] = {
284 .method_name = "SetSampleFormat",
285 .receive_cb = handle_set_sample_format },
286 [METHOD_HANDLER_GET_SAMPLE_FORMAT] = {
287 .method_name = "GetSampleFormat",
288 .receive_cb = handle_get_sample_format },
289 [METHOD_HANDLER_GET_SUPPORTED_SAMPLE_RATES] = {
290 .method_name = "GetSupportedSampleRates",
291 .receive_cb = handle_get_supported_sample_rates },
292 [METHOD_HANDLER_SET_SAMPLE_RATE] = {
293 .method_name = "SetSampleRate",
294 .receive_cb = handle_set_sample_rate },
295 [METHOD_HANDLER_GET_SAMPLE_RATE] = {
296 .method_name = "GetSampleRate",
297 .receive_cb = handle_get_sample_rate },
298 [METHOD_HANDLER_SET_SPECIFIC_STREAM_ONLY] = {
299 .method_name = "SetSpecificStreamOnly",
300 .receive_cb = handle_set_specific_stream_only },
301 [METHOD_HANDLER_GET_SPECIFIED_STREAM] = {
302 .method_name = "GetSpecifiedStream",
303 .receive_cb = handle_get_specified_stream },
304 [METHOD_HANDLER_SET_AVOID_RESAMPLING] = {
305 .method_name = "SetAvoidResampling",
306 .receive_cb = handle_set_avoid_resampling },
307 [METHOD_HANDLER_GET_AVOID_RESAMPLING] = {
308 .method_name = "GetAvoidResampling",
309 .receive_cb = handle_get_avoid_resampling },
310 [METHOD_HANDLER_DUMP_DEVICE_LIST] = {
311 .method_name = "DumpDeviceList",
312 .receive_cb = handle_dump_device_list },
313 [METHOD_HANDLER_STATUS_TEST] = {
314 .method_name = "TestStatusChange",
315 .receive_cb = handle_test_device_status_change },
316 [METHOD_HANDLER_SET_ACM_MODE] = {
317 .method_name = "SetAcmMode",
318 .receive_cb = handle_set_acm_mode },
321 static void save_preference(pa_device_manager *dm, pa_sink *sink) {
328 e.avoid_resampling = sink->avoid_resampling;
329 e.format = sink->selected_sample_format;
330 e.rate = sink->selected_sample_rate;
331 if ((key = build_key_from_proplist(sink->proplist)))
332 write_prefer_entry(dm, key, &e);
336 Handle device disconnection detected through dbus.
337 First, update device-status hashmap.
338 And if there is device which has the device_type, remove it.
340 static int handle_device_disconnected(pa_device_manager *dm, const char *type, const char *system_id) {
341 pa_tz_device *device;
344 pa_assert(dm->device_status);
346 pa_log_info("Device type(%s) system_id(%s) disconnected",
347 type, pa_strempty(system_id));
349 device = device_list_get_device(dm, type, NULL, system_id);
351 pa_log_error("Disconnection detected but no device for that");
355 pa_tz_device_free(device);
361 look detected status which is external value, make conversion to internal consistent value, and handle it
362 device_type, which type of device is detected
363 system_id : system_id among same device types for support multi-device
365 static int handle_device_status_changed(pa_device_manager *dm, const char *type,
366 const char *name, const char *system_id, device_detected_type_t detected) {
369 pa_log_info("Device Status Changed, type(%s) system_id(%s), detected_type(%d)",
370 type, pa_strempty(system_id), detected);
372 if (!device_type_is_valid(type)) {
373 pa_log_error("Invalid device type %s", type);
375 } else if (device_type_is_equal(type, DEVICE_TYPE_BT_SCO)) {
376 device_set_detected(dm, type, name, system_id, detected);
377 if (detected == DEVICE_DISCONNECTED)
378 handle_device_disconnected(dm, type, system_id);
380 handle_device_connected(dm, type, name, system_id, detected, NULL);
381 } else if (device_type_is_need_detect(type)) {
382 device_set_detected(dm, type, name, system_id, detected);
383 if (detected == DEVICE_DISCONNECTED)
384 handle_device_disconnected(dm, type, system_id);
386 handle_device_connected(dm, type, name, system_id, detected, NULL);
388 pa_log_debug("No need to detect type %s", type);
394 static int _translate_external_value(const char *type, int value, device_detected_type_t *detected) {
396 if (!type || !detected) {
397 pa_log_error("Invalid Parameter for translate");
401 if (device_type_is_equal(DEVICE_TYPE_AUDIO_JACK, type)) {
402 if (value == EARJACK_DISCONNECTED)
403 *detected = DEVICE_DISCONNECTED;
404 else if (value == EARJACK_TYPE_SPK_ONLY)
405 *detected = DEVICE_CONNECTED_AUDIO_JACK_3P;
406 else if (value == EARJACK_TYPE_SPK_WITH_MIC)
407 *detected = DEVICE_CONNECTED_AUDIO_JACK_4P;
410 } else if (device_type_is_equal(DEVICE_TYPE_FORWARDING, type)) {
411 if (value == FORWARDING_DISCONNECTED)
412 *detected = DEVICE_DISCONNECTED;
413 else if (value == FORWARDING_CONNECTED)
414 *detected = DEVICE_CONNECTED;
417 } else if (device_type_is_equal(DEVICE_TYPE_BT_SCO, type)) {
418 if (value == BT_SCO_DISCONNECTED)
419 *detected = DEVICE_DISCONNECTED;
420 else if (value == BT_SCO_CONNECTED)
421 *detected = DEVICE_CONNECTED_SCO;
429 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
430 static int handle_bluez_headset_property_changed(DBusConnection *c, DBusMessage *s, pa_device_manager *dm) {
431 DBusMessageIter msg_iter, variant_iter;
440 pa_log_debug("Got %s PropertyChanged signal", DBUS_INTERFACE_BLUEZ_HEADSET);
441 dbus_message_iter_init(s, &msg_iter);
442 if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_STRING) {
443 pa_log_error("Property name not string");
446 dbus_message_iter_get_basic(&msg_iter, &property_name);
447 pa_log_info("Changed Property name : %s", property_name);
449 if (!dbus_message_iter_next(&msg_iter)) {
450 pa_log_debug("Property value missing");
454 if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_VARIANT) {
455 pa_log_debug("Property value not a variant.");
459 dbus_message_iter_recurse(&msg_iter, &variant_iter);
461 if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_BOOLEAN)
462 return 0; /* Returning 0 here to keep the same behavior comparing with the previous codes */
464 dbus_message_iter_get_basic(&variant_iter, &value);
465 if (pa_safe_streq(property_name, "Connected")) {
466 device_detected_type_t detected;
468 pa_log_info("HFP Connection : %d", value);
470 method_call_bt_get_name(c, dbus_message_get_path(s), &name);
471 status = BT_SCO_CONNECTED;
473 status = BT_SCO_DISCONNECTED;
475 if (_translate_external_value(DEVICE_TYPE_BT_SCO, status, &detected) < 0) {
476 pa_log_warn("failed to translate bt-sco detected value");
480 handle_device_status_changed(dm, DEVICE_TYPE_BT_SCO, name, dbus_message_get_path(s), detected);
482 } else if (pa_safe_streq(property_name, "Playing")) {
483 pa_tz_device *device;
484 pa_log_info("SCO Playing : %d", value);
485 if ((device = device_list_get_device(dm, DEVICE_TYPE_BT_SCO, NULL, NULL)) != NULL) {
486 device->sco_opened = value;
488 /* update BT band/nrec information */
489 bool is_wide_band = false;
491 pa_tz_device_sco_get_property(device, &is_wide_band, &nrec);
492 pa_log_info("got new wideband:%d, nrec:%d", is_wide_band, nrec);
494 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-wideband", is_wide_band);
495 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-nrec", nrec);
498 UPDATE_HAL_ROUTE_OPTION(dm->hal_interface, NULL, "bt-sco-ready", value);
503 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
505 static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
508 pa_device_manager *dm = (pa_device_manager *)userdata;
509 device_detected_type_t detected;
513 if (dbus_message_get_type(s) != DBUS_MESSAGE_TYPE_SIGNAL)
514 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
516 pa_log_info("Device detect handler : Path(%s) Intf(%s) Member(%s) Signature(%s)",
517 dbus_message_get_path(s), dbus_message_get_interface(s), dbus_message_get_member(s), dbus_message_get_signature(s));
519 dbus_error_init(&error);
521 if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedEarjack")) {
522 if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID))
525 if (_translate_external_value(DEVICE_TYPE_AUDIO_JACK, status, &detected) < 0) {
526 pa_log_warn("failed to translate audio-jack detected value");
529 handle_device_status_changed(dm, DEVICE_TYPE_AUDIO_JACK, NULL, NULL, detected);
531 } else if (dbus_message_is_signal(s, DBUS_INTERFACE_MIRRORING_SERVER, "miracast_wfd_source_status_changed")) {
532 if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID))
535 if (_translate_external_value(DEVICE_TYPE_FORWARDING, status, &detected) < 0) {
536 pa_log_warn("failed to translate forwarding detected value");
539 handle_device_status_changed(dm, DEVICE_TYPE_FORWARDING, NULL, NULL, detected);
540 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
541 } else if (dbus_message_is_signal(s, DBUS_INTERFACE_BLUEZ_HEADSET, "PropertyChanged")) {
542 if (handle_bluez_headset_property_changed(c, s, dm) < 0)
546 pa_log_debug("Unknown message, not handle it");
547 dbus_error_free(&error);
548 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
551 pa_log_debug("Dbus Message handled");
553 dbus_error_free(&error);
554 return DBUS_HANDLER_RESULT_HANDLED;
557 pa_log_error("Fail to handle dbus signal");
558 dbus_error_free(&error);
559 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
562 static bool device_is_match_direction(pa_tz_device *device, int direction_mask) {
563 dm_device_direction_t direction;
565 if (direction_mask == DEVICE_IO_DIRECTION_FLAGS || direction_mask == 0)
568 direction = pa_tz_device_get_direction(device);
570 if ((direction_mask & DEVICE_IO_DIRECTION_IN_FLAG) && (direction & DM_DEVICE_DIRECTION_IN))
572 if ((direction_mask & DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & DM_DEVICE_DIRECTION_OUT))
574 if ((direction_mask & DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction == DM_DEVICE_DIRECTION_BOTH))
580 static bool device_is_match_state(pa_tz_device *device, int state_mask) {
581 dm_device_state_t state;
583 if (state_mask == DEVICE_STATE_FLAGS || state_mask == 0)
586 state = pa_tz_device_get_state(device);
588 if ((state_mask & DEVICE_STATE_DEACTIVATED_FLAG) && (state == DM_DEVICE_STATE_DEACTIVATED))
590 if ((state_mask & DEVICE_STATE_ACTIVATED_FLAG) && (state == DM_DEVICE_STATE_ACTIVATED))
596 static bool device_is_match_type(pa_tz_device *device, int type_mask) {
600 if (type_mask == DEVICE_TYPE_FLAGS || type_mask == 0)
603 type = pa_tz_device_get_type(device);
604 is_builtin = device_type_is_builtin(type);
606 if ((type_mask & DEVICE_TYPE_INTERNAL_FLAG) && is_builtin)
608 if ((type_mask & DEVICE_TYPE_EXTERNAL_FLAG) && !is_builtin)
614 static bool device_is_match_with_mask(pa_tz_device *device, int mask) {
617 if (mask == DEVICE_ALL_FLAG)
620 return (device_is_match_direction(device, mask & DEVICE_IO_DIRECTION_FLAGS) &&
621 device_is_match_state(device, mask & DEVICE_STATE_FLAGS) &&
622 device_is_match_type(device, mask & DEVICE_TYPE_FLAGS));
625 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
626 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name) {
627 const char *intf = DBUS_INTERFACE_BLUEZ_DEVICE, *prop = "Alias";
628 DBusMessage *msg, *reply;
629 DBusMessageIter reply_iter, variant_iter;
634 pa_assert(device_path);
637 if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_BLUEZ, device_path, "org.freedesktop.DBus.Properties", "Get"))) {
638 pa_log_error("dbus method call failed");
642 pa_assert_se(dbus_message_append_args(msg, DBUS_TYPE_STRING, &intf,
643 DBUS_TYPE_STRING, &prop,
646 dbus_error_init(&err);
648 reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_TIMEOUT_USE_DEFAULT, &err);
649 dbus_message_unref(msg);
651 pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_BLUEZ_DEVICE, "Get", err.message);
652 dbus_error_free(&err);
656 dbus_message_iter_init(reply, &reply_iter);
658 if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_VARIANT) {
659 pa_log_error("Cannot get reply argument");
663 dbus_message_iter_recurse(&reply_iter, &variant_iter);
665 if (dbus_message_iter_get_arg_type(&variant_iter) == DBUS_TYPE_STRING) {
666 dbus_message_iter_get_basic(&variant_iter, &_name);
667 *name = pa_xstrdup(_name);
670 dbus_message_unref(reply);
673 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
675 static void array_iter_append(DBusMessageIter *array_iter, pa_idxset *device_list, int mask) {
677 dm_device_state_t state;
678 dbus_int32_t device_id, direction;
680 dbus_int32_t vendor_id, product_id;
681 dbus_bool_t is_running;
682 pa_tz_device *device;
683 DBusMessageIter device_iter;
684 const pa_sample_spec *spec = NULL;
685 dbus_int32_t format, samplerate, channels;
687 pa_assert(array_iter);
692 PA_IDXSET_FOREACH(device, device_list, device_idx) {
693 device_id = (dbus_int32_t)pa_tz_device_get_id(device);
694 state = pa_tz_device_get_state(device);
695 direction = pa_tz_device_get_direction(device);
696 type = pa_tz_device_get_type(device);
697 name = pa_tz_device_get_name(device);
698 vendor_id = (dbus_int32_t)pa_tz_device_get_vendor_id(device);
699 product_id = (dbus_int32_t)pa_tz_device_get_product_id(device);
700 is_running = (dbus_bool_t)pa_tz_device_is_running(device);
702 format = samplerate = channels = 0;
703 spec = pa_tz_device_get_sample_spec(device);
705 format = (dbus_int32_t)spec->format;
706 samplerate = (dbus_int32_t)spec->rate;
707 channels = (dbus_int32_t)spec->channels;
710 if (device_is_match_with_mask(device, mask)) {
711 simple_device_dump(PA_LOG_INFO, "[MATCH]", device_id, type, name, direction, state);
712 pa_assert_se(dbus_message_iter_open_container(array_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
713 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
714 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
715 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
716 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
717 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
718 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
719 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
720 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
721 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &format);
722 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &samplerate);
723 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &channels);
725 pa_assert_se(dbus_message_iter_close_container(array_iter, &device_iter));
727 simple_device_dump(PA_LOG_INFO, "[UNMATCH]", device_id, type, name, direction, state);
732 #ifdef __TIZEN_TV_EXTERNAL_BT_SCO__
733 static int include_device_filter_func(const void *d, const void *include_device_type) {
734 pa_tz_device *device = (pa_tz_device *)d;
737 pa_assert(include_device_type);
739 return (int)pa_safe_streq(pa_tz_device_get_type(device), (const char *)include_device_type);
742 static int exclude_device_filter_func(const void *d, const void *exclude_device_type) {
743 pa_tz_device *device = (pa_tz_device *)d;
746 pa_assert(exclude_device_type);
748 return (int)!pa_safe_streq(pa_tz_device_get_type(device), (const char *)exclude_device_type);
750 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
752 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
753 pa_device_manager *dm = (pa_device_manager *)userdata;
754 DBusMessage *reply = NULL;
755 DBusMessageIter msg_iter, array_iter;
757 #ifdef __TIZEN_TV_EXTERNAL_BT_SCO__
758 pa_idxset *idxset1, *idxset2;
765 pa_assert_se((reply = dbus_message_new_method_return(msg)));
767 pa_assert_se(dbus_message_get_args(msg, NULL,
768 DBUS_TYPE_INT32, &mask,
771 pa_log_info("Get connected device list (mask : %d)", mask);
773 dbus_message_iter_init_append(reply, &msg_iter);
774 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiisiibiii)", &array_iter));
776 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
777 array_iter_append(&array_iter, dm->device_list, mask);
779 /* divide into two groups and merge them because dbus message doesn't support sorting or prepend */
780 idxset1 = pa_idxset_filtered_copy(dm->device_list, NULL, include_device_filter_func, DEVICE_TYPE_BT_SCO);
781 idxset2 = pa_idxset_filtered_copy(dm->device_list, NULL, exclude_device_filter_func, DEVICE_TYPE_BT_SCO);
783 array_iter_append(&array_iter, idxset1, mask);
784 array_iter_append(&array_iter, idxset2, mask);
786 pa_idxset_free(idxset1, NULL);
787 pa_idxset_free(idxset2, NULL);
788 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
790 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
792 pa_assert_se(dbus_connection_send(conn, reply, NULL));
793 dbus_message_unref(reply);
796 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
797 pa_device_manager *dm = (pa_device_manager *)userdata;
799 DBusMessageIter msg_iter;
800 pa_tz_device *device;
801 dbus_int32_t device_id;
802 dbus_int32_t id, direction, state;
803 dbus_int32_t vendor_id, product_id;
810 pa_assert_se(dbus_message_get_args(msg, NULL,
811 DBUS_TYPE_INT32, &device_id,
814 pa_log_info("Get device by id(%d)", device_id);
816 if ((device = device_list_get_device_by_id(dm, device_id))) {
817 pa_assert_se((reply = dbus_message_new_method_return(msg)));
818 dbus_message_iter_init_append(reply, &msg_iter);
820 id = (dbus_int32_t)pa_tz_device_get_id(device);
821 state = pa_tz_device_get_state(device);
822 direction = pa_tz_device_get_direction(device);
823 type = pa_tz_device_get_type(device);
824 name = pa_tz_device_get_name(device);
825 vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
826 product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
828 simple_device_dump(PA_LOG_INFO, "[GET_BY_ID]", device_id, type, name, direction, state);
830 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &id);
831 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &type);
832 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &direction);
833 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &state);
834 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
835 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &vendor_id);
836 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &product_id);
838 pa_assert_se(dbus_connection_send(conn, reply, NULL));
839 dbus_message_unref(reply);
841 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
845 static void handle_is_device_running_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
846 pa_device_manager *dm = (pa_device_manager *)userdata;
847 pa_tz_device *device;
848 dbus_int32_t device_id;
849 dbus_bool_t is_running;
855 pa_assert_se(dbus_message_get_args(msg, NULL,
856 DBUS_TYPE_INT32, &device_id,
859 pa_log_info("Is device running by id(%d)", device_id);
861 if ((device = device_list_get_device_by_id(dm, device_id))) {
862 is_running = pa_tz_device_is_running(device);
864 pa_log_info("device(id:%d) is %s", device_id, is_running ? "Running" : "Not Running");
866 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_running);
868 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
872 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
873 pa_device_manager *dm = (pa_device_manager *)userdata;
874 pa_tz_device *device;
875 dbus_bool_t is_on = FALSE;
876 dbus_int32_t stream_id, device_id;
877 pa_intset *stream_id_set;
878 int32_t stream_id_val;
880 dm_device_state_t state;
886 pa_log_info("Is stream on device");
888 pa_assert_se(dbus_message_get_args(msg, NULL,
889 DBUS_TYPE_INT32, &stream_id,
890 DBUS_TYPE_INT32, &device_id,
893 if ((device = device_list_get_device_by_id(dm, device_id))) {
894 state = pa_tz_device_get_state(device);
895 if (state == DM_DEVICE_STATE_ACTIVATED) {
896 stream_id_set = pa_tz_device_get_stream_list(device);
897 PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
898 if (stream_id_val == stream_id) {
900 pa_log_info("stream(%d) is on device(%d)", stream_id, device_id);
904 pa_intset_free(stream_id_set);
906 pa_log_info("device(%d) is not activated, regard as no stream on it", device_id);
909 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_on);
911 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.Internal");
915 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
916 pa_device_manager *dm = (pa_device_manager *)userdata;
917 DBusMessage *reply = NULL;
918 pa_tz_device *device;
919 dbus_bool_t is_bt_on = FALSE;
920 const char *bt_name = "none";
926 pa_log_info("Get BT A2DP list");
928 /* FIXME : Give system_id for multi device */
929 if ((device = device_list_get_device(dm, DEVICE_TYPE_BT_A2DP, NULL, NULL)) != NULL) {
931 bt_name = pa_tz_device_get_name(device);
934 pa_assert_se((reply = dbus_message_new_method_return(msg)));
935 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_bt_on,
936 DBUS_TYPE_STRING, &bt_name,
938 pa_assert_se(dbus_connection_send(conn, reply, NULL));
939 dbus_message_unref(reply);
942 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
943 pa_device_manager *dm = (pa_device_manager *)userdata;
951 pa_assert_se(dbus_message_get_args(msg, NULL,
952 DBUS_TYPE_STRING, &type,
953 DBUS_TYPE_STRING, &role,
956 if (!(sink = pa_device_manager_load_sink(dm, type, role)))
957 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
959 pa_dbus_send_empty_reply(conn, msg);
962 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
963 pa_device_manager *dm = (pa_device_manager *)userdata;
970 pa_assert_se(dbus_message_get_args(msg, NULL,
971 DBUS_TYPE_STRING, &type,
972 DBUS_TYPE_STRING, &role,
975 pa_device_manager_unload_sink(dm, type, role);
977 pa_dbus_send_empty_reply(conn, msg);
980 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
981 pa_device_manager *dm = (pa_device_manager *)userdata;
988 pa_assert_se(dbus_message_get_args(msg, NULL,
989 DBUS_TYPE_STRING, &device_string,
992 pa_device_manager_unload_sink_with_device_string(dm, device_string);
994 pa_dbus_send_empty_reply(conn, msg);
997 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
998 pa_device_manager *dm = (pa_device_manager *)userdata;
1000 const char *device_string;
1001 dbus_bool_t is_playback;
1007 pa_assert_se(dbus_message_get_args(msg, NULL,
1008 DBUS_TYPE_BOOLEAN, &is_playback,
1009 DBUS_TYPE_STRING, &type,
1010 DBUS_TYPE_STRING, &role,
1011 DBUS_TYPE_INVALID));
1013 device_string = pa_device_manager_get_device_string(dm, is_playback, type, role);
1014 if (device_string == NULL) {
1015 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1019 pa_log_info("device string : %s", device_string);
1021 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &device_string);
1024 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1025 pa_device_manager *dm = (pa_device_manager *)userdata;
1026 pa_tz_device *device;
1027 uint32_t device_idx;
1033 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
1034 pa_tz_device_dump_info(device, PA_LOG_INFO);
1037 pa_dbus_send_empty_reply(conn, msg);
1040 static bool is_usb_output_device(pa_tz_device *device) {
1042 dm_device_direction_t direction;
1047 type = pa_tz_device_get_type(device);
1048 if (!pa_safe_streq(type, DEVICE_TYPE_USB_AUDIO)) {
1049 pa_log_error("device(id:%d, %s) is not USB AUDIO type", pa_tz_device_get_id(device), type);
1052 direction = pa_tz_device_get_direction(device);
1053 if (direction & DM_DEVICE_DIRECTION_OUT) {
1054 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1055 pa_log_error("sink is null");
1059 pa_log_error("this device is not for output");
1067 static bool is_supported_sample_format(pa_sample_format_t *supported_sample_formats, pa_sample_format_t sample_format) {
1070 pa_assert(supported_sample_formats);
1071 pa_assert(sample_format != PA_SAMPLE_INVALID);
1073 for (i = 0; supported_sample_formats[i] != PA_SAMPLE_MAX; i++) {
1074 if (supported_sample_formats[i] == sample_format) {
1075 pa_log_info("%s is supported", pa_sample_format_to_string(sample_format));
1079 pa_log_error("%s is not supported", pa_sample_format_to_string(sample_format));
1083 static void handle_get_supported_sample_formats(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1084 pa_device_manager *dm = (pa_device_manager *)userdata;
1085 DBusMessage *reply = NULL;
1086 DBusMessageIter msg_iter, array_iter;
1087 dbus_int32_t device_id;
1088 pa_tz_device *device;
1097 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1099 pa_assert_se(dbus_message_get_args(msg, NULL,
1100 DBUS_TYPE_INT32, &device_id,
1101 DBUS_TYPE_INVALID));
1103 pa_log_info("Get supported sample formats of the device(id:%d)", device_id);
1105 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1106 pa_log_error("could not find any device with id:%d", device_id);
1107 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1110 if (!is_usb_output_device(device)) {
1111 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1114 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1115 pa_log_error("could not get sink for normal role");
1116 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1120 if (!sink->supported_sample_formats) {
1121 pa_log_error("supported sample formats is not set on this sink");
1122 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1126 dbus_message_iter_init_append(reply, &msg_iter);
1127 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "s", &array_iter));
1128 for (i = 0; sink->supported_sample_formats[i] != PA_SAMPLE_MAX; i++) {
1129 format = pa_sample_format_to_string(sink->supported_sample_formats[i]);
1130 pa_log_info("%s is supported", format);
1131 dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &format);
1133 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
1134 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1135 dbus_message_unref(reply);
1138 static void handle_set_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1139 pa_device_manager *dm = (pa_device_manager *)userdata;
1140 dbus_int32_t device_id;
1141 char *sample_format;
1142 pa_sample_format_t prev_selected_sample_format;
1143 pa_tz_device *device;
1145 pa_sample_spec spec;
1151 pa_assert_se(dbus_message_get_args(msg, NULL,
1152 DBUS_TYPE_INT32, &device_id,
1153 DBUS_TYPE_STRING, &sample_format,
1154 DBUS_TYPE_INVALID));
1156 pa_log_info("Set sample format(%s) of the device(id:%d)", sample_format, device_id);
1158 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1159 pa_log_error("could not find any device with id:%d", device_id);
1160 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1163 if (!is_usb_output_device(device)) {
1164 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1167 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1168 pa_log_error("could not get sink for normal role");
1169 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1173 /* use a supported sample format selected by user */
1174 if (!is_supported_sample_format(sink->supported_sample_formats, pa_parse_sample_format(sample_format))) {
1175 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1178 prev_selected_sample_format = sink->selected_sample_format;
1179 sink->selected_sample_format = pa_parse_sample_format(sample_format);
1181 if (prev_selected_sample_format != sink->selected_sample_format) {
1182 FILL_SAMPLE_SPEC_WITH_SELECTED(spec, sink);
1183 pa_sink_reconfigure(sink, &spec, false);
1184 if (sink->selected_sample_format != sink->sample_spec.format) {
1185 pa_log_error("failed to reconfigure");
1186 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1187 sink->selected_sample_format = prev_selected_sample_format;
1190 save_preference(dm, sink);
1193 pa_log_info("Set sample format(%s) of the device(id:%d) successfully", sample_format, device_id);
1195 pa_dbus_send_empty_reply(conn, msg);
1198 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1199 pa_device_manager *dm = (pa_device_manager *)userdata;
1200 dbus_int32_t device_id;
1201 pa_tz_device *device;
1209 pa_assert_se(dbus_message_get_args(msg, NULL,
1210 DBUS_TYPE_INT32, &device_id,
1211 DBUS_TYPE_INVALID));
1213 pa_log_info("Get sample format of the device(id:%d)", device_id);
1215 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1216 pa_log_error("could not find any device with id:%d", device_id);
1217 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1220 if (!is_usb_output_device(device)) {
1221 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1224 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1225 pa_log_error("could not get sink for normal role");
1226 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1230 format = pa_sample_format_to_string(sink->selected_sample_format);
1231 pa_log_info("Get sample format(%s) of the device(id:%d) successfully", format, device_id);
1233 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &format);
1236 static bool is_supported_sample_rate(uint32_t *supported_sample_rates, uint32_t sample_rate) {
1239 pa_assert(supported_sample_rates);
1241 for (i = 0; supported_sample_rates[i]; i++) {
1242 if (supported_sample_rates[i] == sample_rate) {
1243 pa_log_info("%u is supported", sample_rate);
1247 pa_log_error("%u is not supported", sample_rate);
1251 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1252 pa_device_manager *dm = (pa_device_manager *)userdata;
1253 DBusMessage *reply = NULL;
1254 DBusMessageIter msg_iter, array_iter;
1255 dbus_int32_t device_id;
1256 pa_tz_device *device;
1264 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1266 pa_assert_se(dbus_message_get_args(msg, NULL,
1267 DBUS_TYPE_INT32, &device_id,
1268 DBUS_TYPE_INVALID));
1270 pa_log_info("Get supported sample rates of the device(id:%d)", device_id);
1272 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1273 pa_log_error("could not find any device with id:%d", device_id);
1274 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1277 if (!is_usb_output_device(device)) {
1278 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1281 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1282 pa_log_error("could not get sink for normal role");
1283 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1287 if (!sink->supported_sample_rates) {
1288 pa_log_error("supported sample rates is not set on this sink");
1289 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1293 dbus_message_iter_init_append(reply, &msg_iter);
1294 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "u", &array_iter));
1295 for (i = 0; sink->supported_sample_rates[i]; i++) {
1296 pa_log_info("%u is supported", sink->supported_sample_rates[i]);
1297 dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_UINT32, &sink->supported_sample_rates[i]);
1299 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
1300 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1301 dbus_message_unref(reply);
1304 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1305 pa_device_manager *dm = (pa_device_manager *)userdata;
1306 dbus_int32_t device_id;
1307 dbus_uint32_t sample_rate;
1308 uint32_t prev_selected_sample_rate;
1309 pa_tz_device *device;
1311 pa_sample_spec spec;
1317 pa_assert_se(dbus_message_get_args(msg, NULL,
1318 DBUS_TYPE_INT32, &device_id,
1319 DBUS_TYPE_UINT32, &sample_rate,
1320 DBUS_TYPE_INVALID));
1322 pa_log_info("Set sample rate(%u) of the device(id:%d)", sample_rate, device_id);
1324 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1325 pa_log_error("could not find any device with id:%d", device_id);
1326 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1329 if (!is_usb_output_device(device)) {
1330 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1333 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1334 pa_log_error("could not get sink for normal role");
1335 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1339 /* use a supported sample rate selected by user */
1340 if (!is_supported_sample_rate(sink->supported_sample_rates, sample_rate)) {
1341 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1344 prev_selected_sample_rate = sink->selected_sample_rate;
1345 sink->selected_sample_rate = sample_rate;
1347 if (prev_selected_sample_rate != sink->selected_sample_rate) {
1348 FILL_SAMPLE_SPEC_WITH_SELECTED(spec, sink);
1349 pa_sink_reconfigure(sink, &spec, false);
1350 if (sink->selected_sample_rate != sink->sample_spec.rate) {
1351 pa_log_error("failed to reconfigure");
1352 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1353 sink->selected_sample_rate = prev_selected_sample_rate;
1356 save_preference(dm, sink);
1359 pa_log_info("Set sample rate(%u) of the device(id:%d) successfully", sample_rate, device_id);
1361 pa_dbus_send_empty_reply(conn, msg);
1364 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1365 pa_device_manager *dm = (pa_device_manager *)userdata;
1366 dbus_int32_t device_id;
1367 pa_tz_device *device;
1374 pa_assert_se(dbus_message_get_args(msg, NULL,
1375 DBUS_TYPE_INT32, &device_id,
1376 DBUS_TYPE_INVALID));
1378 pa_log_info("Get sample rate of the device(id:%d)", device_id);
1380 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1381 pa_log_error("could not find any device with id:%d", device_id);
1382 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1385 if (!is_usb_output_device(device)) {
1386 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1389 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1390 pa_log_error("could not get sink for normal role");
1391 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1395 pa_log_info("Get sample rate(%u) of the device(id:%d) successfully", sink->selected_sample_rate, device_id);
1397 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &sink->selected_sample_rate);
1400 static void handle_set_specific_stream_only(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1401 pa_device_manager *dm = (pa_device_manager *)userdata;
1402 dbus_int32_t device_id;
1404 pa_tz_device *device;
1410 pa_assert_se(dbus_message_get_args(msg, NULL,
1411 DBUS_TYPE_INT32, &device_id,
1412 DBUS_TYPE_STRING, &stream_role,
1413 DBUS_TYPE_INVALID));
1415 pa_log_info("Set the device(id:%d) only for the stream role(%s)", device_id, stream_role);
1417 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1418 pa_log_error("could not find any device with id:%d", device_id);
1419 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1422 if (!is_usb_output_device(device)) {
1423 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1426 if (!pa_safe_streq(stream_role, "none") && !pa_stream_manager_is_valid_stream_role(dm->core, stream_role)) {
1427 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1431 pa_xfree(device->specified_stream_role);
1432 device->specified_stream_role = pa_xstrdup(stream_role);
1434 pa_dbus_send_empty_reply(conn, msg);
1437 static void handle_get_specified_stream(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1438 pa_device_manager *dm = (pa_device_manager *)userdata;
1439 dbus_int32_t device_id;
1440 char *specified_stream_role;
1441 pa_tz_device *device;
1447 pa_assert_se(dbus_message_get_args(msg, NULL,
1448 DBUS_TYPE_INT32, &device_id,
1449 DBUS_TYPE_INVALID));
1451 pa_log_info("Get specified stream role for the device(id:%d)", device_id);
1453 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1454 pa_log_error("could not find any device with id:%d", device_id);
1455 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1458 if (!is_usb_output_device(device)) {
1459 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1463 specified_stream_role = device->specified_stream_role;
1465 pa_log_info("stream role(%s) is specified for the device(id:%d)", device->specified_stream_role, device_id);
1467 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &specified_stream_role);
1470 static void handle_set_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1471 pa_device_manager *dm = (pa_device_manager *)userdata;
1472 dbus_int32_t device_id;
1473 dbus_bool_t avoid_resampling;
1474 pa_tz_device *device;
1481 pa_assert_se(dbus_message_get_args(msg, NULL,
1482 DBUS_TYPE_INT32, &device_id,
1483 DBUS_TYPE_BOOLEAN, &avoid_resampling,
1484 DBUS_TYPE_INVALID));
1486 pa_log_info("Set the device(id:%d) avoid-resampling(%d)", device_id, avoid_resampling);
1488 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1489 pa_log_error("could not find any device with id:%d", device_id);
1490 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1493 if (!is_usb_output_device(device)) {
1494 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1497 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1498 pa_log_error("could not get sink for normal role");
1499 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1502 if (sink->avoid_resampling == avoid_resampling) {
1503 pa_log_info("already set to %d", avoid_resampling);
1505 sink->avoid_resampling = avoid_resampling;
1506 save_preference(dm, sink);
1507 pa_log_info("Set avoid-resampling(%d) to the device(id:%d)", avoid_resampling, device_id);
1510 pa_dbus_send_empty_reply(conn, msg);
1513 static void handle_get_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1514 pa_device_manager *dm = (pa_device_manager *)userdata;
1515 dbus_int32_t device_id;
1516 dbus_bool_t avoid_resampling;
1517 pa_tz_device *device;
1524 pa_assert_se(dbus_message_get_args(msg, NULL,
1525 DBUS_TYPE_INT32, &device_id,
1526 DBUS_TYPE_INVALID));
1528 pa_log_info("Get avoid-resampling of the device(id:%d)", device_id);
1530 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1531 pa_log_error("could not find any device with id:%d", device_id);
1532 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1535 if (!is_usb_output_device(device)) {
1536 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1539 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1540 pa_log_error("could not get sink for normal role");
1541 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1545 avoid_resampling = sink->avoid_resampling;
1546 pa_log_info("got avoid-resampling(%d) of the device(id:%d)", avoid_resampling, device_id);
1548 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &avoid_resampling);
1551 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1552 pa_device_manager *dm = (pa_device_manager *)userdata;
1554 dbus_int32_t status;
1560 pa_assert_se(dbus_message_get_args(msg, NULL,
1561 DBUS_TYPE_STRING, &type,
1562 DBUS_TYPE_INT32, &status,
1563 DBUS_TYPE_INVALID));
1565 pa_log_debug("handle_test_device_status_change, type:%s, status:%d", type, status);
1567 handle_device_status_changed(dm, type, NULL, NULL, status);
1569 pa_dbus_send_empty_reply(conn, msg);
1572 static void handle_set_acm_mode(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1573 pa_device_manager *dm = (pa_device_manager *)userdata;
1580 pa_assert_se(dbus_message_get_args(msg, NULL,
1581 DBUS_TYPE_UINT32, &mode,
1582 DBUS_TYPE_INVALID));
1584 pa_log_info("Set ACM mode to (%d)", mode);
1587 unload_acm_sink(dm);
1589 /* For now, value of not 0 is just loading ACM sink. */
1590 if (!load_acm_sink(dm)) {
1591 pa_log_error("could not load acm sink");
1592 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1597 pa_dbus_send_empty_reply(conn, msg);
1600 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1601 const char *xml = DEVICE_MANAGER_INTROSPECT_XML;
1602 DBusMessage *r = NULL;
1606 pa_assert(userdata);
1608 pa_assert_se(r = dbus_message_new_method_return(msg));
1609 pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
1612 pa_assert_se(dbus_connection_send((conn), r, NULL));
1613 dbus_message_unref(r);
1616 return DBUS_HANDLER_RESULT_HANDLED;
1619 static DBusHandlerResult handle_device_manager_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1624 pa_assert(userdata);
1626 for (method_idx = 0; method_idx < METHOD_HANDLER_MAX; method_idx++) {
1627 if (dbus_message_is_method_call(msg, DBUS_INTERFACE_DEVICE_MANAGER, method_handlers[method_idx].method_name)) {
1628 method_handlers[method_idx].receive_cb(conn, msg, userdata);
1629 return DBUS_HANDLER_RESULT_HANDLED;
1633 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1636 static DBusHandlerResult method_call_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
1637 struct userdata *u = userdata;
1638 const char *path, *interface, *member;
1644 path = dbus_message_get_path(m);
1645 interface = dbus_message_get_interface(m);
1646 member = dbus_message_get_member(m);
1648 pa_log_info("DeviceManager Method Call Handler : path=%s, interface=%s, member=%s", path, interface, member);
1650 if (!pa_safe_streq(path, DBUS_OBJECT_DEVICE_MANAGER))
1651 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1653 if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1654 return handle_introspect(c, m, u);
1656 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get")) {
1657 return handle_get_property(c, m, u);
1658 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set")) {
1659 return handle_set_property(c, m, u);
1660 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll")) {
1661 return handle_get_all_property(c, m, u);
1664 return handle_device_manager_methods(c, m, u);
1667 return DBUS_HANDLER_RESULT_HANDLED;
1670 static void fill_signal_msg_with_device(const char *description, DBusMessageIter *msg_iter, uint32_t event_id, pa_tz_device *device) {
1671 DBusMessageIter array_iter, device_iter;
1673 dbus_int32_t device_id, direction, state, stream_id;
1674 dbus_int32_t vendor_id, product_id;
1675 dbus_bool_t is_running;
1676 pa_intset *stream_id_set = NULL;
1677 int32_t stream_id_val;
1680 pa_assert(msg_iter);
1683 dbus_message_iter_append_basic(msg_iter, DBUS_TYPE_UINT32, &event_id);
1684 pa_assert_se(dbus_message_iter_open_container(msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
1686 direction = (dbus_int32_t)pa_tz_device_get_direction(device);
1687 type = pa_tz_device_get_type(device);
1688 name = pa_tz_device_get_name(device);
1689 device_id = (dbus_int32_t)pa_tz_device_get_id(device);
1690 state = pa_tz_device_get_state(device);
1691 vendor_id = (dbus_int32_t)pa_tz_device_get_vendor_id(device);
1692 product_id = (dbus_int32_t)pa_tz_device_get_product_id(device);
1693 is_running = (dbus_bool_t)pa_tz_device_is_running(device);
1695 simple_device_dump(PA_LOG_INFO, description, device_id, type, name, direction, state);
1697 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
1698 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
1699 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
1700 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
1701 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
1702 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
1703 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
1704 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
1705 if (state == DM_DEVICE_STATE_ACTIVATED)
1706 stream_id_set = pa_tz_device_get_stream_list(device);
1707 pa_assert_se(dbus_message_iter_open_container(&device_iter, DBUS_TYPE_ARRAY, "i", &array_iter));
1708 if (state == DM_DEVICE_STATE_ACTIVATED) {
1709 PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
1710 stream_id = stream_id_val;
1711 dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_INT32, &stream_id);
1714 pa_assert_se(dbus_message_iter_close_container(&device_iter, &array_iter));
1716 pa_intset_free(stream_id_set);
1717 pa_assert_se(dbus_message_iter_close_container(msg_iter, &device_iter));
1718 pa_log_info("end of fill signal msg");
1721 void send_device_connection_changed_signal(uint32_t event_id, pa_tz_device *device, bool connected, pa_device_manager *dm) {
1722 DBusMessage *signal_msg;
1723 DBusMessageIter msg_iter;
1724 dbus_bool_t _connected = (dbus_bool_t)connected;
1729 pa_log_info("Send device connection changed signal, event_id(%u)", event_id);
1731 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceConnected"));
1732 dbus_message_iter_init_append(signal_msg, &msg_iter);
1733 fill_signal_msg_with_device(connected ? "[Connected]" : "[Disconnected]", &msg_iter, event_id, device);
1735 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &_connected);
1737 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1739 dbus_message_unref(signal_msg);
1740 pa_log_info("end of send device connection changed signal");
1743 void send_device_info_changed_signal(uint32_t event_id, pa_tz_device *device, int changed_type, pa_device_manager *dm) {
1744 DBusMessage *signal_msg;
1745 DBusMessageIter msg_iter;
1746 const char *changed_prefix[] = {"[State Changed]", "[Direction Changed]", "[Avail-Mode Changed]"};
1751 pa_log_debug("Send device info changed signal, event_id(%u)", event_id);
1753 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceInfoChanged"));
1754 dbus_message_iter_init_append(signal_msg, &msg_iter);
1755 fill_signal_msg_with_device(changed_prefix[changed_type], &msg_iter, event_id, device);
1756 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &changed_type);
1758 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1760 dbus_message_unref(signal_msg);
1763 void send_device_state_changed_signal(uint32_t event_id, pa_tz_device *device, bool activated, pa_device_manager *dm) {
1764 DBusMessage *signal_msg;
1765 DBusMessageIter msg_iter;
1770 pa_log_debug("Send device state changed signal, event_id(%u)", event_id);
1772 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceStateChanged"));
1773 dbus_message_iter_init_append(signal_msg, &msg_iter);
1774 fill_signal_msg_with_device(activated ? "[Activated]" : "[Deactivated]", &msg_iter, event_id, device);
1776 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1778 dbus_message_unref(signal_msg);
1781 void send_device_running_changed_signal(uint32_t event_id, pa_tz_device *device, bool is_running, pa_device_manager *dm) {
1782 DBusMessage *signal_msg;
1783 DBusMessageIter msg_iter;
1788 pa_log_debug("Send device running changed signal, event_id(%u)", event_id);
1790 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceRunningChanged"));
1791 dbus_message_iter_init_append(signal_msg, &msg_iter);
1792 fill_signal_msg_with_device(is_running ? "[Running]" : "[NotRunning]", &msg_iter, event_id, device);
1794 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1796 dbus_message_unref(signal_msg);
1799 static void endpoint_init(pa_device_manager *dm) {
1800 static const DBusObjectPathVTable vtable_endpoint = {
1801 .message_function = method_call_handler,
1804 pa_log_info("Device manager dbus endpoint init");
1806 if (dm && dm->dbus_conn) {
1807 if (!dbus_connection_register_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER, &vtable_endpoint, dm))
1808 pa_log_error("Failed to register object path");
1810 pa_log_error("Cannot get dbus connection to register object path");
1814 static void endpoint_done(pa_device_manager *dm) {
1815 pa_log_info("Device manager dbus endpoint done");
1816 if (dm && dm->dbus_conn) {
1817 if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER))
1818 pa_log_error("Failed to unregister object path");
1820 pa_log_error("Cannot get dbus connection to unregister object path");
1824 static int watch_signals(pa_device_manager *dm) {
1828 pa_assert(dm->dbus_conn);
1830 dbus_error_init(&error);
1832 pa_log_info("Watch Dbus signals");
1834 if (!dbus_connection_add_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm, NULL)) {
1835 pa_log_error("Unable to add D-Bus filter : %s: %s", error.name, error.message);
1839 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) {
1840 pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
1846 dbus_error_free(&error);
1850 static void unwatch_signals(pa_device_manager *dm) {
1851 pa_log_info("Unwatch Dbus signals");
1854 pa_assert(dm->dbus_conn);
1856 pa_dbus_remove_matches(pa_dbus_connection_get(dm->dbus_conn), FILTER_DEVICED_SYSNOTI, FILTER_SOUND_SERVER, FILTER_BLUEZ, FILTER_MIRRORING, NULL);
1857 dbus_connection_remove_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm);
1860 void init_dm_dbus(pa_device_manager *dm) {
1862 pa_dbus_connection *connection = NULL;
1865 pa_log_info("init Dbus");
1866 dbus_error_init(&error);
1868 if (!(connection = pa_dbus_bus_get(dm->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
1870 pa_dbus_connection_unref(connection);
1872 pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
1875 pa_log_info("Got dbus connection");
1878 dm->dbus_conn = connection;
1880 if (watch_signals(dm) < 0)
1881 pa_log_error("dbus watch signals failed");
1883 pa_log_debug("dbus ready to get signals");
1888 dbus_error_free(&error);
1891 void deinit_dm_dbus(pa_device_manager *dm) {
1894 pa_log_info("deinit Dbus");
1897 unwatch_signals(dm);
1899 if (dm->dbus_conn) {
1900 pa_dbus_connection_unref(dm->dbus_conn);
1901 dm->dbus_conn = NULL;