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 product_id = (dbus_int32_t)pa_tz_device_get_product_id(device);
701 is_running = (dbus_bool_t)pa_tz_device_is_running(device);
703 spec = pa_tz_device_get_sample_spec(device);
704 format = (dbus_int32_t)spec->format;
705 samplerate = (dbus_int32_t)spec->rate;
706 channels = (dbus_int32_t)spec->channels;
708 if (device_is_match_with_mask(device, mask)) {
709 simple_device_dump(PA_LOG_INFO, "[MATCH]", device_id, type, name, direction, state);
710 pa_assert_se(dbus_message_iter_open_container(array_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
711 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
712 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
713 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
714 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
715 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
716 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
717 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
718 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
719 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &format);
720 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &samplerate);
721 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &channels);
723 pa_assert_se(dbus_message_iter_close_container(array_iter, &device_iter));
725 simple_device_dump(PA_LOG_INFO, "[UNMATCH]", device_id, type, name, direction, state);
730 #ifdef __TIZEN_TV_EXTERNAL_BT_SCO__
731 static int include_device_filter_func(const void *d, const void *include_device_type) {
732 pa_tz_device *device = (pa_tz_device *)d;
735 pa_assert(include_device_type);
737 return (int)pa_safe_streq(pa_tz_device_get_type(device), (const char *)include_device_type);
740 static int exclude_device_filter_func(const void *d, const void *exclude_device_type) {
741 pa_tz_device *device = (pa_tz_device *)d;
744 pa_assert(exclude_device_type);
746 return (int)!pa_safe_streq(pa_tz_device_get_type(device), (const char *)exclude_device_type);
748 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
750 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
751 pa_device_manager *dm = (pa_device_manager *)userdata;
752 DBusMessage *reply = NULL;
753 DBusMessageIter msg_iter, array_iter;
755 #ifdef __TIZEN_TV_EXTERNAL_BT_SCO__
756 pa_idxset *idxset1, *idxset2;
763 pa_assert_se((reply = dbus_message_new_method_return(msg)));
765 pa_assert_se(dbus_message_get_args(msg, NULL,
766 DBUS_TYPE_INT32, &mask,
769 pa_log_info("Get connected device list (mask : %d)", mask);
771 dbus_message_iter_init_append(reply, &msg_iter);
772 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiisiibiii)", &array_iter));
774 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
775 array_iter_append(&array_iter, dm->device_list, mask);
777 /* divide into two groups and merge them because dbus message doesn't support sorting or prepend */
778 idxset1 = pa_idxset_filtered_copy(dm->device_list, NULL, include_device_filter_func, DEVICE_TYPE_BT_SCO);
779 idxset2 = pa_idxset_filtered_copy(dm->device_list, NULL, exclude_device_filter_func, DEVICE_TYPE_BT_SCO);
781 array_iter_append(&array_iter, idxset1, mask);
782 array_iter_append(&array_iter, idxset2, mask);
784 pa_idxset_free(idxset1, NULL);
785 pa_idxset_free(idxset2, NULL);
786 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
788 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
790 pa_assert_se(dbus_connection_send(conn, reply, NULL));
791 dbus_message_unref(reply);
794 static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
795 pa_device_manager *dm = (pa_device_manager *)userdata;
797 DBusMessageIter msg_iter;
798 pa_tz_device *device;
799 dbus_int32_t device_id;
800 dbus_int32_t id, direction, state;
801 dbus_int32_t vendor_id, product_id;
808 pa_assert_se(dbus_message_get_args(msg, NULL,
809 DBUS_TYPE_INT32, &device_id,
812 pa_log_info("Get device by id(%d)", device_id);
814 if ((device = device_list_get_device_by_id(dm, device_id))) {
815 pa_assert_se((reply = dbus_message_new_method_return(msg)));
816 dbus_message_iter_init_append(reply, &msg_iter);
818 id = (dbus_int32_t)pa_tz_device_get_id(device);
819 state = pa_tz_device_get_state(device);
820 direction = pa_tz_device_get_direction(device);
821 type = pa_tz_device_get_type(device);
822 name = pa_tz_device_get_name(device);
823 vendor_id = (dbus_int32_t) pa_tz_device_get_vendor_id(device);
824 product_id = (dbus_int32_t) pa_tz_device_get_product_id(device);
826 simple_device_dump(PA_LOG_INFO, "[GET_BY_ID]", device_id, type, name, direction, state);
828 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &id);
829 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &type);
830 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &direction);
831 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &state);
832 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
833 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &vendor_id);
834 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &product_id);
836 pa_assert_se(dbus_connection_send(conn, reply, NULL));
837 dbus_message_unref(reply);
839 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
843 static void handle_is_device_running_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
844 pa_device_manager *dm = (pa_device_manager *)userdata;
845 pa_tz_device *device;
846 dbus_int32_t device_id;
847 dbus_bool_t is_running;
853 pa_assert_se(dbus_message_get_args(msg, NULL,
854 DBUS_TYPE_INT32, &device_id,
857 pa_log_info("Is device running by id(%d)", device_id);
859 if ((device = device_list_get_device_by_id(dm, device_id))) {
860 is_running = pa_tz_device_is_running(device);
862 pa_log_info("device(id:%d) is %s", device_id, is_running ? "Running" : "Not Running");
864 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_running);
866 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
870 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
871 pa_device_manager *dm = (pa_device_manager *)userdata;
872 pa_tz_device *device;
873 dbus_bool_t is_on = FALSE;
874 dbus_int32_t stream_id, device_id;
875 pa_intset *stream_id_set;
876 int32_t stream_id_val;
878 dm_device_state_t state;
884 pa_log_info("Is stream on device");
886 pa_assert_se(dbus_message_get_args(msg, NULL,
887 DBUS_TYPE_INT32, &stream_id,
888 DBUS_TYPE_INT32, &device_id,
891 if ((device = device_list_get_device_by_id(dm, device_id))) {
892 state = pa_tz_device_get_state(device);
893 if (state == DM_DEVICE_STATE_ACTIVATED) {
894 stream_id_set = pa_tz_device_get_stream_list(device);
895 PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
896 if (stream_id_val == stream_id) {
898 pa_log_info("stream(%d) is on device(%d)", stream_id, device_id);
902 pa_intset_free(stream_id_set);
904 pa_log_info("device(%d) is not activated, regard as no stream on it", device_id);
907 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_on);
909 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.Internal");
913 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
914 pa_device_manager *dm = (pa_device_manager *)userdata;
915 DBusMessage *reply = NULL;
916 pa_tz_device *device;
917 dbus_bool_t is_bt_on = FALSE;
918 const char *bt_name = "none";
924 pa_log_info("Get BT A2DP list");
926 /* FIXME : Give system_id for multi device */
927 if ((device = device_list_get_device(dm, DEVICE_TYPE_BT_A2DP, NULL, NULL)) != NULL) {
929 bt_name = pa_tz_device_get_name(device);
932 pa_assert_se((reply = dbus_message_new_method_return(msg)));
933 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_bt_on,
934 DBUS_TYPE_STRING, &bt_name,
936 pa_assert_se(dbus_connection_send(conn, reply, NULL));
937 dbus_message_unref(reply);
940 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
941 pa_device_manager *dm = (pa_device_manager *)userdata;
949 pa_assert_se(dbus_message_get_args(msg, NULL,
950 DBUS_TYPE_STRING, &type,
951 DBUS_TYPE_STRING, &role,
954 if (!(sink = pa_device_manager_load_sink(dm, type, role)))
955 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
957 pa_dbus_send_empty_reply(conn, msg);
960 static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
961 pa_device_manager *dm = (pa_device_manager *)userdata;
968 pa_assert_se(dbus_message_get_args(msg, NULL,
969 DBUS_TYPE_STRING, &type,
970 DBUS_TYPE_STRING, &role,
973 pa_device_manager_unload_sink(dm, type, role);
975 pa_dbus_send_empty_reply(conn, msg);
978 static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
979 pa_device_manager *dm = (pa_device_manager *)userdata;
986 pa_assert_se(dbus_message_get_args(msg, NULL,
987 DBUS_TYPE_STRING, &device_string,
990 pa_device_manager_unload_sink_with_device_string(dm, device_string);
992 pa_dbus_send_empty_reply(conn, msg);
995 static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) {
996 pa_device_manager *dm = (pa_device_manager *)userdata;
998 const char *device_string;
999 dbus_bool_t is_playback;
1005 pa_assert_se(dbus_message_get_args(msg, NULL,
1006 DBUS_TYPE_BOOLEAN, &is_playback,
1007 DBUS_TYPE_STRING, &type,
1008 DBUS_TYPE_STRING, &role,
1009 DBUS_TYPE_INVALID));
1011 device_string = pa_device_manager_get_device_string(dm, is_playback, type, role);
1012 if (device_string == NULL) {
1013 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1017 pa_log_info("device string : %s", device_string);
1019 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &device_string);
1022 static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1023 pa_device_manager *dm = (pa_device_manager *)userdata;
1024 pa_tz_device *device;
1025 uint32_t device_idx;
1031 PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
1032 pa_tz_device_dump_info(device, PA_LOG_INFO);
1035 pa_dbus_send_empty_reply(conn, msg);
1038 static bool is_usb_output_device(pa_tz_device *device) {
1040 dm_device_direction_t direction;
1045 type = pa_tz_device_get_type(device);
1046 if (!pa_safe_streq(type, DEVICE_TYPE_USB_AUDIO)) {
1047 pa_log_error("device(id:%d, %s) is not USB AUDIO type", pa_tz_device_get_id(device), type);
1050 direction = pa_tz_device_get_direction(device);
1051 if (direction & DM_DEVICE_DIRECTION_OUT) {
1052 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1053 pa_log_error("sink is null");
1057 pa_log_error("this device is not for output");
1065 static bool is_supported_sample_format(pa_sample_format_t *supported_sample_formats, pa_sample_format_t sample_format) {
1068 pa_assert(supported_sample_formats);
1069 pa_assert(sample_format != PA_SAMPLE_INVALID);
1071 for (i = 0; supported_sample_formats[i] != PA_SAMPLE_MAX; i++) {
1072 if (supported_sample_formats[i] == sample_format) {
1073 pa_log_info("%s is supported", pa_sample_format_to_string(sample_format));
1077 pa_log_error("%s is not supported", pa_sample_format_to_string(sample_format));
1081 static void handle_get_supported_sample_formats(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1082 pa_device_manager *dm = (pa_device_manager *)userdata;
1083 DBusMessage *reply = NULL;
1084 DBusMessageIter msg_iter, array_iter;
1085 dbus_int32_t device_id;
1086 pa_tz_device *device;
1095 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1097 pa_assert_se(dbus_message_get_args(msg, NULL,
1098 DBUS_TYPE_INT32, &device_id,
1099 DBUS_TYPE_INVALID));
1101 pa_log_info("Get supported sample formats of the device(id:%d)", device_id);
1103 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1104 pa_log_error("could not find any device with id:%d", device_id);
1105 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1108 if (!is_usb_output_device(device)) {
1109 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1112 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1113 pa_log_error("could not get sink for normal role");
1114 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1118 if (!sink->supported_sample_formats) {
1119 pa_log_error("supported sample formats is not set on this sink");
1120 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1124 dbus_message_iter_init_append(reply, &msg_iter);
1125 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "s", &array_iter));
1126 for (i = 0; sink->supported_sample_formats[i] != PA_SAMPLE_MAX; i++) {
1127 format = pa_sample_format_to_string(sink->supported_sample_formats[i]);
1128 pa_log_info("%s is supported", format);
1129 dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &format);
1131 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
1132 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1133 dbus_message_unref(reply);
1136 static void handle_set_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1137 pa_device_manager *dm = (pa_device_manager *)userdata;
1138 dbus_int32_t device_id;
1139 char *sample_format;
1140 pa_sample_format_t prev_selected_sample_format;
1141 pa_tz_device *device;
1143 pa_sample_spec spec;
1149 pa_assert_se(dbus_message_get_args(msg, NULL,
1150 DBUS_TYPE_INT32, &device_id,
1151 DBUS_TYPE_STRING, &sample_format,
1152 DBUS_TYPE_INVALID));
1154 pa_log_info("Set sample format(%s) of the device(id:%d)", sample_format, device_id);
1156 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1157 pa_log_error("could not find any device with id:%d", device_id);
1158 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1161 if (!is_usb_output_device(device)) {
1162 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1165 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1166 pa_log_error("could not get sink for normal role");
1167 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1171 /* use a supported sample format selected by user */
1172 if (!is_supported_sample_format(sink->supported_sample_formats, pa_parse_sample_format(sample_format))) {
1173 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1176 prev_selected_sample_format = sink->selected_sample_format;
1177 sink->selected_sample_format = pa_parse_sample_format(sample_format);
1179 if (prev_selected_sample_format != sink->selected_sample_format) {
1180 FILL_SAMPLE_SPEC_WITH_SELECTED(spec, sink);
1181 pa_sink_reconfigure(sink, &spec, false);
1182 if (sink->selected_sample_format != sink->sample_spec.format) {
1183 pa_log_error("failed to reconfigure");
1184 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1185 sink->selected_sample_format = prev_selected_sample_format;
1188 save_preference(dm, sink);
1191 pa_log_info("Set sample format(%s) of the device(id:%d) successfully", sample_format, device_id);
1193 pa_dbus_send_empty_reply(conn, msg);
1196 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1197 pa_device_manager *dm = (pa_device_manager *)userdata;
1198 dbus_int32_t device_id;
1199 pa_tz_device *device;
1207 pa_assert_se(dbus_message_get_args(msg, NULL,
1208 DBUS_TYPE_INT32, &device_id,
1209 DBUS_TYPE_INVALID));
1211 pa_log_info("Get sample format of the device(id:%d)", device_id);
1213 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1214 pa_log_error("could not find any device with id:%d", device_id);
1215 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1218 if (!is_usb_output_device(device)) {
1219 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1222 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1223 pa_log_error("could not get sink for normal role");
1224 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1228 format = pa_sample_format_to_string(sink->selected_sample_format);
1229 pa_log_info("Get sample format(%s) of the device(id:%d) successfully", format, device_id);
1231 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &format);
1234 static bool is_supported_sample_rate(uint32_t *supported_sample_rates, uint32_t sample_rate) {
1237 pa_assert(supported_sample_rates);
1239 for (i = 0; supported_sample_rates[i]; i++) {
1240 if (supported_sample_rates[i] == sample_rate) {
1241 pa_log_info("%u is supported", sample_rate);
1245 pa_log_error("%u is not supported", sample_rate);
1249 static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1250 pa_device_manager *dm = (pa_device_manager *)userdata;
1251 DBusMessage *reply = NULL;
1252 DBusMessageIter msg_iter, array_iter;
1253 dbus_int32_t device_id;
1254 pa_tz_device *device;
1262 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1264 pa_assert_se(dbus_message_get_args(msg, NULL,
1265 DBUS_TYPE_INT32, &device_id,
1266 DBUS_TYPE_INVALID));
1268 pa_log_info("Get supported sample rates of the device(id:%d)", device_id);
1270 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1271 pa_log_error("could not find any device with id:%d", device_id);
1272 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1275 if (!is_usb_output_device(device)) {
1276 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1279 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1280 pa_log_error("could not get sink for normal role");
1281 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1285 if (!sink->supported_sample_rates) {
1286 pa_log_error("supported sample rates is not set on this sink");
1287 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1291 dbus_message_iter_init_append(reply, &msg_iter);
1292 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "u", &array_iter));
1293 for (i = 0; sink->supported_sample_rates[i]; i++) {
1294 pa_log_info("%u is supported", sink->supported_sample_rates[i]);
1295 dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_UINT32, &sink->supported_sample_rates[i]);
1297 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter));
1298 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1299 dbus_message_unref(reply);
1302 static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1303 pa_device_manager *dm = (pa_device_manager *)userdata;
1304 dbus_int32_t device_id;
1305 dbus_uint32_t sample_rate;
1306 uint32_t prev_selected_sample_rate;
1307 pa_tz_device *device;
1309 pa_sample_spec spec;
1315 pa_assert_se(dbus_message_get_args(msg, NULL,
1316 DBUS_TYPE_INT32, &device_id,
1317 DBUS_TYPE_UINT32, &sample_rate,
1318 DBUS_TYPE_INVALID));
1320 pa_log_info("Set sample rate(%u) of the device(id:%d)", sample_rate, device_id);
1322 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1323 pa_log_error("could not find any device with id:%d", device_id);
1324 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1327 if (!is_usb_output_device(device)) {
1328 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1331 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1332 pa_log_error("could not get sink for normal role");
1333 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1337 /* use a supported sample rate selected by user */
1338 if (!is_supported_sample_rate(sink->supported_sample_rates, sample_rate)) {
1339 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1342 prev_selected_sample_rate = sink->selected_sample_rate;
1343 sink->selected_sample_rate = sample_rate;
1345 if (prev_selected_sample_rate != sink->selected_sample_rate) {
1346 FILL_SAMPLE_SPEC_WITH_SELECTED(spec, sink);
1347 pa_sink_reconfigure(sink, &spec, false);
1348 if (sink->selected_sample_rate != sink->sample_spec.rate) {
1349 pa_log_error("failed to reconfigure");
1350 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1351 sink->selected_sample_rate = prev_selected_sample_rate;
1354 save_preference(dm, sink);
1357 pa_log_info("Set sample rate(%u) of the device(id:%d) successfully", sample_rate, device_id);
1359 pa_dbus_send_empty_reply(conn, msg);
1362 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1363 pa_device_manager *dm = (pa_device_manager *)userdata;
1364 dbus_int32_t device_id;
1365 pa_tz_device *device;
1372 pa_assert_se(dbus_message_get_args(msg, NULL,
1373 DBUS_TYPE_INT32, &device_id,
1374 DBUS_TYPE_INVALID));
1376 pa_log_info("Get sample rate of the device(id:%d)", device_id);
1378 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1379 pa_log_error("could not find any device with id:%d", device_id);
1380 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1383 if (!is_usb_output_device(device)) {
1384 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1387 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1388 pa_log_error("could not get sink for normal role");
1389 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1393 pa_log_info("Get sample rate(%u) of the device(id:%d) successfully", sink->selected_sample_rate, device_id);
1395 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &sink->selected_sample_rate);
1398 static void handle_set_specific_stream_only(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1399 pa_device_manager *dm = (pa_device_manager *)userdata;
1400 dbus_int32_t device_id;
1402 pa_tz_device *device;
1408 pa_assert_se(dbus_message_get_args(msg, NULL,
1409 DBUS_TYPE_INT32, &device_id,
1410 DBUS_TYPE_STRING, &stream_role,
1411 DBUS_TYPE_INVALID));
1413 pa_log_info("Set the device(id:%d) only for the stream role(%s)", device_id, stream_role);
1415 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1416 pa_log_error("could not find any device with id:%d", device_id);
1417 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1420 if (!is_usb_output_device(device)) {
1421 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1424 if (!pa_safe_streq(stream_role, "none") && !pa_stream_manager_is_valid_stream_role(dm->core, stream_role)) {
1425 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1429 pa_xfree(device->specified_stream_role);
1430 device->specified_stream_role = pa_xstrdup(stream_role);
1432 pa_dbus_send_empty_reply(conn, msg);
1435 static void handle_get_specified_stream(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1436 pa_device_manager *dm = (pa_device_manager *)userdata;
1437 dbus_int32_t device_id;
1438 char *specified_stream_role;
1439 pa_tz_device *device;
1445 pa_assert_se(dbus_message_get_args(msg, NULL,
1446 DBUS_TYPE_INT32, &device_id,
1447 DBUS_TYPE_INVALID));
1449 pa_log_info("Get specified stream role for the device(id:%d)", device_id);
1451 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1452 pa_log_error("could not find any device with id:%d", device_id);
1453 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1456 if (!is_usb_output_device(device)) {
1457 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1461 specified_stream_role = device->specified_stream_role;
1463 pa_log_info("stream role(%s) is specified for the device(id:%d)", device->specified_stream_role, device_id);
1465 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &specified_stream_role);
1468 static void handle_set_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1469 pa_device_manager *dm = (pa_device_manager *)userdata;
1470 dbus_int32_t device_id;
1471 dbus_bool_t avoid_resampling;
1472 pa_tz_device *device;
1479 pa_assert_se(dbus_message_get_args(msg, NULL,
1480 DBUS_TYPE_INT32, &device_id,
1481 DBUS_TYPE_BOOLEAN, &avoid_resampling,
1482 DBUS_TYPE_INVALID));
1484 pa_log_info("Set the device(id:%d) avoid-resampling(%d)", device_id, avoid_resampling);
1486 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1487 pa_log_error("could not find any device with id:%d", device_id);
1488 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1491 if (!is_usb_output_device(device)) {
1492 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1495 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1496 pa_log_error("could not get sink for normal role");
1497 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1500 if (sink->avoid_resampling == avoid_resampling) {
1501 pa_log_info("already set to %d", avoid_resampling);
1503 sink->avoid_resampling = avoid_resampling;
1504 save_preference(dm, sink);
1505 pa_log_info("Set avoid-resampling(%d) to the device(id:%d)", avoid_resampling, device_id);
1508 pa_dbus_send_empty_reply(conn, msg);
1511 static void handle_get_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1512 pa_device_manager *dm = (pa_device_manager *)userdata;
1513 dbus_int32_t device_id;
1514 dbus_bool_t avoid_resampling;
1515 pa_tz_device *device;
1522 pa_assert_se(dbus_message_get_args(msg, NULL,
1523 DBUS_TYPE_INT32, &device_id,
1524 DBUS_TYPE_INVALID));
1526 pa_log_info("Get avoid-resampling of the device(id:%d)", device_id);
1528 if (!(device = device_list_get_device_by_id(dm, device_id))) {
1529 pa_log_error("could not find any device with id:%d", device_id);
1530 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.InvalidArgument");
1533 if (!is_usb_output_device(device)) {
1534 pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation");
1537 if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL))) {
1538 pa_log_error("could not get sink for normal role");
1539 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1543 avoid_resampling = sink->avoid_resampling;
1544 pa_log_info("got avoid-resampling(%d) of the device(id:%d)", avoid_resampling, device_id);
1546 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &avoid_resampling);
1549 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1550 pa_device_manager *dm = (pa_device_manager *)userdata;
1552 dbus_int32_t status;
1558 pa_assert_se(dbus_message_get_args(msg, NULL,
1559 DBUS_TYPE_STRING, &type,
1560 DBUS_TYPE_INT32, &status,
1561 DBUS_TYPE_INVALID));
1563 pa_log_debug("handle_test_device_status_change, type:%s, status:%d", type, status);
1565 handle_device_status_changed(dm, type, NULL, NULL, status);
1567 pa_dbus_send_empty_reply(conn, msg);
1570 static void handle_set_acm_mode(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1571 pa_device_manager *dm = (pa_device_manager *)userdata;
1578 pa_assert_se(dbus_message_get_args(msg, NULL,
1579 DBUS_TYPE_UINT32, &mode,
1580 DBUS_TYPE_INVALID));
1582 pa_log_info("Set ACM mode to (%d)", mode);
1585 unload_acm_sink(dm);
1587 /* For now, value of not 0 is just loading ACM sink. */
1588 if (!load_acm_sink(dm)) {
1589 pa_log_error("could not load acm sink");
1590 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal");
1595 pa_dbus_send_empty_reply(conn, msg);
1598 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1599 const char *xml = DEVICE_MANAGER_INTROSPECT_XML;
1600 DBusMessage *r = NULL;
1604 pa_assert(userdata);
1606 pa_assert_se(r = dbus_message_new_method_return(msg));
1607 pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
1610 pa_assert_se(dbus_connection_send((conn), r, NULL));
1611 dbus_message_unref(r);
1614 return DBUS_HANDLER_RESULT_HANDLED;
1617 static DBusHandlerResult handle_device_manager_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1622 pa_assert(userdata);
1624 for (method_idx = 0; method_idx < METHOD_HANDLER_MAX; method_idx++) {
1625 if (dbus_message_is_method_call(msg, DBUS_INTERFACE_DEVICE_MANAGER, method_handlers[method_idx].method_name)) {
1626 method_handlers[method_idx].receive_cb(conn, msg, userdata);
1627 return DBUS_HANDLER_RESULT_HANDLED;
1631 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1634 static DBusHandlerResult method_call_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
1635 struct userdata *u = userdata;
1636 const char *path, *interface, *member;
1642 path = dbus_message_get_path(m);
1643 interface = dbus_message_get_interface(m);
1644 member = dbus_message_get_member(m);
1646 pa_log_info("DeviceManager Method Call Handler : path=%s, interface=%s, member=%s", path, interface, member);
1648 if (!pa_safe_streq(path, DBUS_OBJECT_DEVICE_MANAGER))
1649 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1651 if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1652 return handle_introspect(c, m, u);
1654 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get")) {
1655 return handle_get_property(c, m, u);
1656 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set")) {
1657 return handle_set_property(c, m, u);
1658 } else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll")) {
1659 return handle_get_all_property(c, m, u);
1662 return handle_device_manager_methods(c, m, u);
1665 return DBUS_HANDLER_RESULT_HANDLED;
1668 static void fill_signal_msg_with_device(const char *description, DBusMessageIter *msg_iter, uint32_t event_id, pa_tz_device *device) {
1669 DBusMessageIter array_iter, device_iter;
1671 dbus_int32_t device_id, direction, state, stream_id;
1672 dbus_int32_t vendor_id, product_id;
1673 dbus_bool_t is_running;
1674 pa_intset *stream_id_set = NULL;
1675 int32_t stream_id_val;
1678 pa_assert(msg_iter);
1681 dbus_message_iter_append_basic(msg_iter, DBUS_TYPE_UINT32, &event_id);
1682 pa_assert_se(dbus_message_iter_open_container(msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
1684 direction = (dbus_int32_t)pa_tz_device_get_direction(device);
1685 type = pa_tz_device_get_type(device);
1686 name = pa_tz_device_get_name(device);
1687 device_id = (dbus_int32_t)pa_tz_device_get_id(device);
1688 state = pa_tz_device_get_state(device);
1689 vendor_id = (dbus_int32_t)pa_tz_device_get_vendor_id(device);
1690 product_id = (dbus_int32_t)pa_tz_device_get_product_id(device);
1691 is_running = (dbus_bool_t)pa_tz_device_is_running(device);
1693 simple_device_dump(PA_LOG_INFO, description, device_id, type, name, direction, state);
1695 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
1696 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
1697 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
1698 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
1699 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
1700 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &vendor_id);
1701 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &product_id);
1702 dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_BOOLEAN, &is_running);
1703 if (state == DM_DEVICE_STATE_ACTIVATED)
1704 stream_id_set = pa_tz_device_get_stream_list(device);
1705 pa_assert_se(dbus_message_iter_open_container(&device_iter, DBUS_TYPE_ARRAY, "i", &array_iter));
1706 if (state == DM_DEVICE_STATE_ACTIVATED) {
1707 PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
1708 stream_id = stream_id_val;
1709 dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_INT32, &stream_id);
1712 pa_assert_se(dbus_message_iter_close_container(&device_iter, &array_iter));
1714 pa_intset_free(stream_id_set);
1715 pa_assert_se(dbus_message_iter_close_container(msg_iter, &device_iter));
1716 pa_log_info("end of fill signal msg");
1719 void send_device_connection_changed_signal(uint32_t event_id, pa_tz_device *device, bool connected, pa_device_manager *dm) {
1720 DBusMessage *signal_msg;
1721 DBusMessageIter msg_iter;
1722 dbus_bool_t _connected = (dbus_bool_t)connected;
1727 pa_log_info("Send device connection changed signal, event_id(%u)", event_id);
1729 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceConnected"));
1730 dbus_message_iter_init_append(signal_msg, &msg_iter);
1731 fill_signal_msg_with_device(connected ? "[Connected]" : "[Disconnected]", &msg_iter, event_id, device);
1733 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &_connected);
1735 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1737 dbus_message_unref(signal_msg);
1738 pa_log_info("end of send device connection changed signal");
1741 void send_device_info_changed_signal(uint32_t event_id, pa_tz_device *device, int changed_type, pa_device_manager *dm) {
1742 DBusMessage *signal_msg;
1743 DBusMessageIter msg_iter;
1744 const char *changed_prefix[] = {"[State Changed]", "[Direction Changed]", "[Avail-Mode Changed]"};
1749 pa_log_debug("Send device info changed signal, event_id(%u)", event_id);
1751 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceInfoChanged"));
1752 dbus_message_iter_init_append(signal_msg, &msg_iter);
1753 fill_signal_msg_with_device(changed_prefix[changed_type], &msg_iter, event_id, device);
1754 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &changed_type);
1756 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1758 dbus_message_unref(signal_msg);
1761 void send_device_state_changed_signal(uint32_t event_id, pa_tz_device *device, bool activated, pa_device_manager *dm) {
1762 DBusMessage *signal_msg;
1763 DBusMessageIter msg_iter;
1768 pa_log_debug("Send device state changed signal, event_id(%u)", event_id);
1770 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceStateChanged"));
1771 dbus_message_iter_init_append(signal_msg, &msg_iter);
1772 fill_signal_msg_with_device(activated ? "[Activated]" : "[Deactivated]", &msg_iter, event_id, device);
1774 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1776 dbus_message_unref(signal_msg);
1779 void send_device_running_changed_signal(uint32_t event_id, pa_tz_device *device, bool is_running, pa_device_manager *dm) {
1780 DBusMessage *signal_msg;
1781 DBusMessageIter msg_iter;
1786 pa_log_debug("Send device running changed signal, event_id(%u)", event_id);
1788 pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceRunningChanged"));
1789 dbus_message_iter_init_append(signal_msg, &msg_iter);
1790 fill_signal_msg_with_device(is_running ? "[Running]" : "[NotRunning]", &msg_iter, event_id, device);
1792 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
1794 dbus_message_unref(signal_msg);
1797 static void endpoint_init(pa_device_manager *dm) {
1798 static const DBusObjectPathVTable vtable_endpoint = {
1799 .message_function = method_call_handler,
1802 pa_log_info("Device manager dbus endpoint init");
1804 if (dm && dm->dbus_conn) {
1805 if (!dbus_connection_register_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER, &vtable_endpoint, dm))
1806 pa_log_error("Failed to register object path");
1808 pa_log_error("Cannot get dbus connection to register object path");
1812 static void endpoint_done(pa_device_manager *dm) {
1813 pa_log_info("Device manager dbus endpoint done");
1814 if (dm && dm->dbus_conn) {
1815 if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(dm->dbus_conn), DBUS_OBJECT_DEVICE_MANAGER))
1816 pa_log_error("Failed to unregister object path");
1818 pa_log_error("Cannot get dbus connection to unregister object path");
1822 static int watch_signals(pa_device_manager *dm) {
1826 pa_assert(dm->dbus_conn);
1828 dbus_error_init(&error);
1830 pa_log_info("Watch Dbus signals");
1832 if (!dbus_connection_add_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm, NULL)) {
1833 pa_log_error("Unable to add D-Bus filter : %s: %s", error.name, error.message);
1837 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) {
1838 pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
1844 dbus_error_free(&error);
1848 static void unwatch_signals(pa_device_manager *dm) {
1849 pa_log_info("Unwatch Dbus signals");
1852 pa_assert(dm->dbus_conn);
1854 pa_dbus_remove_matches(pa_dbus_connection_get(dm->dbus_conn), FILTER_DEVICED_SYSNOTI, FILTER_SOUND_SERVER, FILTER_BLUEZ, FILTER_MIRRORING, NULL);
1855 dbus_connection_remove_filter(pa_dbus_connection_get(dm->dbus_conn), dbus_filter_device_detect_handler, dm);
1858 void init_dm_dbus(pa_device_manager *dm) {
1860 pa_dbus_connection *connection = NULL;
1863 pa_log_info("init Dbus");
1864 dbus_error_init(&error);
1866 if (!(connection = pa_dbus_bus_get(dm->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
1868 pa_dbus_connection_unref(connection);
1870 pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
1873 pa_log_info("Got dbus connection");
1876 dm->dbus_conn = connection;
1878 if (watch_signals(dm) < 0)
1879 pa_log_error("dbus watch signals failed");
1881 pa_log_debug("dbus ready to get signals");
1886 dbus_error_free(&error);
1889 void deinit_dm_dbus(pa_device_manager *dm) {
1892 pa_log_info("deinit Dbus");
1895 unwatch_signals(dm);
1897 if (dm->dbus_conn) {
1898 pa_dbus_connection_unref(dm->dbus_conn);
1899 dm->dbus_conn = NULL;