1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2009 Tanu Kaskinen 5 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. 10 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. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20#ifdef HAVE_CONFIG_H 21#include <config.h> 22#endif 23 24#include <pulsecore/core-util.h> 25#include <pulsecore/dbus-util.h> 26#include <pulsecore/protocol-dbus.h> 27 28#include "iface-device-port.h" 29 30#include "iface-device.h" 31 32#define SINK_OBJECT_NAME "sink" 33#define SOURCE_OBJECT_NAME "source" 34 35static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata); 36static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata); 37static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata); 38static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata); 39static void handle_get_card(DBusConnection *conn, DBusMessage *msg, void *userdata); 40static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata); 41static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata); 42static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata); 43static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata); 44static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata); 45static void handle_get_has_flat_volume(DBusConnection *conn, DBusMessage *msg, void *userdata); 46static void handle_get_has_convertible_to_decibel_volume(DBusConnection *conn, DBusMessage *msg, void *userdata); 47static void handle_get_base_volume(DBusConnection *conn, DBusMessage *msg, void *userdata); 48static void handle_get_volume_steps(DBusConnection *conn, DBusMessage *msg, void *userdata); 49static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata); 50static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata); 51static void handle_get_has_hardware_volume(DBusConnection *conn, DBusMessage *msg, void *userdata); 52static void handle_get_has_hardware_mute(DBusConnection *conn, DBusMessage *msg, void *userdata); 53static void handle_get_configured_latency(DBusConnection *conn, DBusMessage *msg, void *userdata); 54static void handle_get_has_dynamic_latency(DBusConnection *conn, DBusMessage *msg, void *userdata); 55static void handle_get_latency(DBusConnection *conn, DBusMessage *msg, void *userdata); 56static void handle_get_is_hardware_device(DBusConnection *conn, DBusMessage *msg, void *userdata); 57static void handle_get_is_network_device(DBusConnection *conn, DBusMessage *msg, void *userdata); 58static void handle_get_state(DBusConnection *conn, DBusMessage *msg, void *userdata); 59static void handle_get_ports(DBusConnection *conn, DBusMessage *msg, void *userdata); 60static void handle_get_active_port(DBusConnection *conn, DBusMessage *msg, void *userdata); 61static void handle_set_active_port(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata); 62static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata); 63 64static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata); 65 66static void handle_suspend(DBusConnection *conn, DBusMessage *msg, void *userdata); 67static void handle_get_port_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata); 68 69static void handle_sink_get_monitor_source(DBusConnection *conn, DBusMessage *msg, void *userdata); 70 71static void handle_sink_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata); 72 73static void handle_source_get_monitor_of_sink(DBusConnection *conn, DBusMessage *msg, void *userdata); 74 75static void handle_source_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata); 76 77struct pa_dbusiface_device { 78 pa_dbusiface_core *core; 79 80 union { 81 pa_sink *sink; 82 pa_source *source; 83 }; 84 pa_device_type_t type; 85 char *path; 86 pa_cvolume volume; 87 dbus_bool_t mute; 88 union { 89 pa_sink_state_t sink_state; 90 pa_source_state_t source_state; 91 }; 92 pa_hashmap *ports; 93 uint32_t next_port_index; 94 pa_device_port *active_port; 95 pa_proplist *proplist; 96 97 pa_hook_slot *volume_changed_slot; 98 pa_hook_slot *mute_changed_slot; 99 pa_hook_slot *state_changed_slot; 100 pa_hook_slot *port_changed_slot; 101 pa_hook_slot *proplist_changed_slot; 102 103 pa_dbus_protocol *dbus_protocol; 104}; 105 106enum property_handler_index { 107 PROPERTY_HANDLER_INDEX, 108 PROPERTY_HANDLER_NAME, 109 PROPERTY_HANDLER_DRIVER, 110 PROPERTY_HANDLER_OWNER_MODULE, 111 PROPERTY_HANDLER_CARD, 112 PROPERTY_HANDLER_SAMPLE_FORMAT, 113 PROPERTY_HANDLER_SAMPLE_RATE, 114 PROPERTY_HANDLER_CHANNELS, 115 PROPERTY_HANDLER_VOLUME, 116 PROPERTY_HANDLER_HAS_FLAT_VOLUME, 117 PROPERTY_HANDLER_HAS_CONVERTIBLE_TO_DECIBEL_VOLUME, 118 PROPERTY_HANDLER_BASE_VOLUME, 119 PROPERTY_HANDLER_VOLUME_STEPS, 120 PROPERTY_HANDLER_MUTE, 121 PROPERTY_HANDLER_HAS_HARDWARE_VOLUME, 122 PROPERTY_HANDLER_HAS_HARDWARE_MUTE, 123 PROPERTY_HANDLER_CONFIGURED_LATENCY, 124 PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY, 125 PROPERTY_HANDLER_LATENCY, 126 PROPERTY_HANDLER_IS_HARDWARE_DEVICE, 127 PROPERTY_HANDLER_IS_NETWORK_DEVICE, 128 PROPERTY_HANDLER_STATE, 129 PROPERTY_HANDLER_PORTS, 130 PROPERTY_HANDLER_ACTIVE_PORT, 131 PROPERTY_HANDLER_PROPERTY_LIST, 132 PROPERTY_HANDLER_MAX 133}; 134 135enum sink_property_handler_index { 136 SINK_PROPERTY_HANDLER_MONITOR_SOURCE, 137 SINK_PROPERTY_HANDLER_MAX 138}; 139 140enum source_property_handler_index { 141 SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK, 142 SOURCE_PROPERTY_HANDLER_MAX 143}; 144 145static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = { 146 [PROPERTY_HANDLER_INDEX] = { .property_name = "Index", .type = "u", .get_cb = handle_get_index, .set_cb = NULL }, 147 [PROPERTY_HANDLER_NAME] = { .property_name = "Name", .type = "s", .get_cb = handle_get_name, .set_cb = NULL }, 148 [PROPERTY_HANDLER_DRIVER] = { .property_name = "Driver", .type = "s", .get_cb = handle_get_driver, .set_cb = NULL }, 149 [PROPERTY_HANDLER_OWNER_MODULE] = { .property_name = "OwnerModule", .type = "o", .get_cb = handle_get_owner_module, .set_cb = NULL }, 150 [PROPERTY_HANDLER_CARD] = { .property_name = "Card", .type = "o", .get_cb = handle_get_card, .set_cb = NULL }, 151 [PROPERTY_HANDLER_SAMPLE_FORMAT] = { .property_name = "SampleFormat", .type = "u", .get_cb = handle_get_sample_format, .set_cb = NULL }, 152 [PROPERTY_HANDLER_SAMPLE_RATE] = { .property_name = "SampleRate", .type = "u", .get_cb = handle_get_sample_rate, .set_cb = NULL }, 153 [PROPERTY_HANDLER_CHANNELS] = { .property_name = "Channels", .type = "au", .get_cb = handle_get_channels, .set_cb = NULL }, 154 [PROPERTY_HANDLER_VOLUME] = { .property_name = "Volume", .type = "au", .get_cb = handle_get_volume, .set_cb = handle_set_volume }, 155 [PROPERTY_HANDLER_HAS_FLAT_VOLUME] = { .property_name = "HasFlatVolume", .type = "b", .get_cb = handle_get_has_flat_volume, .set_cb = NULL }, 156 [PROPERTY_HANDLER_HAS_CONVERTIBLE_TO_DECIBEL_VOLUME] = { .property_name = "HasConvertibleToDecibelVolume", .type = "b", .get_cb = handle_get_has_convertible_to_decibel_volume, .set_cb = NULL }, 157 [PROPERTY_HANDLER_BASE_VOLUME] = { .property_name = "BaseVolume", .type = "u", .get_cb = handle_get_base_volume, .set_cb = NULL }, 158 [PROPERTY_HANDLER_VOLUME_STEPS] = { .property_name = "VolumeSteps", .type = "u", .get_cb = handle_get_volume_steps, .set_cb = NULL }, 159 [PROPERTY_HANDLER_MUTE] = { .property_name = "Mute", .type = "b", .get_cb = handle_get_mute, .set_cb = handle_set_mute }, 160 [PROPERTY_HANDLER_HAS_HARDWARE_VOLUME] = { .property_name = "HasHardwareVolume", .type = "b", .get_cb = handle_get_has_hardware_volume, .set_cb = NULL }, 161 [PROPERTY_HANDLER_HAS_HARDWARE_MUTE] = { .property_name = "HasHardwareMute", .type = "b", .get_cb = handle_get_has_hardware_mute, .set_cb = NULL }, 162 [PROPERTY_HANDLER_CONFIGURED_LATENCY] = { .property_name = "ConfiguredLatency", .type = "t", .get_cb = handle_get_configured_latency, .set_cb = NULL }, 163 [PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY] = { .property_name = "HasDynamicLatency", .type = "b", .get_cb = handle_get_has_dynamic_latency, .set_cb = NULL }, 164 [PROPERTY_HANDLER_LATENCY] = { .property_name = "Latency", .type = "t", .get_cb = handle_get_latency, .set_cb = NULL }, 165 [PROPERTY_HANDLER_IS_HARDWARE_DEVICE] = { .property_name = "IsHardwareDevice", .type = "b", .get_cb = handle_get_is_hardware_device, .set_cb = NULL }, 166 [PROPERTY_HANDLER_IS_NETWORK_DEVICE] = { .property_name = "IsNetworkDevice", .type = "b", .get_cb = handle_get_is_network_device, .set_cb = NULL }, 167 [PROPERTY_HANDLER_STATE] = { .property_name = "State", .type = "u", .get_cb = handle_get_state, .set_cb = NULL }, 168 [PROPERTY_HANDLER_PORTS] = { .property_name = "Ports", .type = "ao", .get_cb = handle_get_ports, .set_cb = NULL }, 169 [PROPERTY_HANDLER_ACTIVE_PORT] = { .property_name = "ActivePort", .type = "o", .get_cb = handle_get_active_port, .set_cb = handle_set_active_port }, 170 [PROPERTY_HANDLER_PROPERTY_LIST] = { .property_name = "PropertyList", .type = "a{say}", .get_cb = handle_get_property_list, .set_cb = NULL } 171}; 172 173static pa_dbus_property_handler sink_property_handlers[SINK_PROPERTY_HANDLER_MAX] = { 174 [SINK_PROPERTY_HANDLER_MONITOR_SOURCE] = { .property_name = "MonitorSource", .type = "o", .get_cb = handle_sink_get_monitor_source, .set_cb = NULL } 175}; 176 177static pa_dbus_property_handler source_property_handlers[SOURCE_PROPERTY_HANDLER_MAX] = { 178 [SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK] = { .property_name = "MonitorOfSink", .type = "o", .get_cb = handle_source_get_monitor_of_sink, .set_cb = NULL } 179}; 180 181enum method_handler_index { 182 METHOD_HANDLER_SUSPEND, 183 METHOD_HANDLER_GET_PORT_BY_NAME, 184 METHOD_HANDLER_MAX 185}; 186 187static pa_dbus_arg_info suspend_args[] = { { "suspend", "b", "in" } }; 188static pa_dbus_arg_info get_port_by_name_args[] = { { "name", "s", "in" }, { "port", "o", "out" } }; 189 190static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = { 191 [METHOD_HANDLER_SUSPEND] = { 192 .method_name = "Suspend", 193 .arguments = suspend_args, 194 .n_arguments = sizeof(suspend_args) / sizeof(pa_dbus_arg_info), 195 .receive_cb = handle_suspend }, 196 [METHOD_HANDLER_GET_PORT_BY_NAME] = { 197 .method_name = "GetPortByName", 198 .arguments = get_port_by_name_args, 199 .n_arguments = sizeof(get_port_by_name_args) / sizeof(pa_dbus_arg_info), 200 .receive_cb = handle_get_port_by_name } 201}; 202 203enum signal_index { 204 SIGNAL_VOLUME_UPDATED, 205 SIGNAL_MUTE_UPDATED, 206 SIGNAL_STATE_UPDATED, 207 SIGNAL_ACTIVE_PORT_UPDATED, 208 SIGNAL_PROPERTY_LIST_UPDATED, 209 SIGNAL_MAX 210}; 211 212static pa_dbus_arg_info volume_updated_args[] = { { "volume", "au", NULL } }; 213static pa_dbus_arg_info mute_updated_args[] = { { "muted", "b", NULL } }; 214static pa_dbus_arg_info state_updated_args[] = { { "state", "u", NULL } }; 215static pa_dbus_arg_info active_port_updated_args[] = { { "port", "o", NULL } }; 216static pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } }; 217 218static pa_dbus_signal_info signals[SIGNAL_MAX] = { 219 [SIGNAL_VOLUME_UPDATED] = { .name = "VolumeUpdated", .arguments = volume_updated_args, .n_arguments = 1 }, 220 [SIGNAL_MUTE_UPDATED] = { .name = "MuteUpdated", .arguments = mute_updated_args, .n_arguments = 1 }, 221 [SIGNAL_STATE_UPDATED] = { .name = "StateUpdated", .arguments = state_updated_args, .n_arguments = 1 }, 222 [SIGNAL_ACTIVE_PORT_UPDATED] = { .name = "ActivePortUpdated", .arguments = active_port_updated_args, .n_arguments = 1 }, 223 [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 } 224}; 225 226static pa_dbus_interface_info device_interface_info = { 227 .name = PA_DBUSIFACE_DEVICE_INTERFACE, 228 .method_handlers = method_handlers, 229 .n_method_handlers = METHOD_HANDLER_MAX, 230 .property_handlers = property_handlers, 231 .n_property_handlers = PROPERTY_HANDLER_MAX, 232 .get_all_properties_cb = handle_get_all, 233 .signals = signals, 234 .n_signals = SIGNAL_MAX 235}; 236 237static pa_dbus_interface_info sink_interface_info = { 238 .name = PA_DBUSIFACE_SINK_INTERFACE, 239 .method_handlers = NULL, 240 .n_method_handlers = 0, 241 .property_handlers = sink_property_handlers, 242 .n_property_handlers = SINK_PROPERTY_HANDLER_MAX, 243 .get_all_properties_cb = handle_sink_get_all, 244 .signals = NULL, 245 .n_signals = 0 246}; 247 248static pa_dbus_interface_info source_interface_info = { 249 .name = PA_DBUSIFACE_SOURCE_INTERFACE, 250 .method_handlers = NULL, 251 .n_method_handlers = 0, 252 .property_handlers = source_property_handlers, 253 .n_property_handlers = SOURCE_PROPERTY_HANDLER_MAX, 254 .get_all_properties_cb = handle_source_get_all, 255 .signals = NULL, 256 .n_signals = 0 257}; 258 259static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) { 260 pa_dbusiface_device *d = userdata; 261 dbus_uint32_t idx = 0; 262 263 pa_assert(conn); 264 pa_assert(msg); 265 pa_assert(d); 266 267 idx = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->index : d->source->index; 268 269 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx); 270} 271 272static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) { 273 pa_dbusiface_device *d = userdata; 274 const char *name = NULL; 275 276 pa_assert(conn); 277 pa_assert(msg); 278 pa_assert(d); 279 280 name = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->name : d->source->name; 281 282 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &name); 283} 284 285static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) { 286 pa_dbusiface_device *d = userdata; 287 const char *driver = NULL; 288 289 pa_assert(conn); 290 pa_assert(msg); 291 pa_assert(d); 292 293 driver = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->driver : d->source->driver; 294 295 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &driver); 296} 297 298static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata) { 299 pa_dbusiface_device *d = userdata; 300 pa_module *owner_module = NULL; 301 const char *object_path = NULL; 302 303 pa_assert(conn); 304 pa_assert(msg); 305 pa_assert(d); 306 307 owner_module = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->module : d->source->module; 308 309 if (!owner_module) { 310 if (d->type == PA_DEVICE_TYPE_SINK) 311 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, 312 "Sink %s doesn't have an owner module.", d->sink->name); 313 else 314 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, 315 "Source %s doesn't have an owner module.", d->source->name); 316 return; 317 } 318 319 object_path = pa_dbusiface_core_get_module_path(d->core, owner_module); 320 321 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path); 322} 323 324static void handle_get_card(DBusConnection *conn, DBusMessage *msg, void *userdata) { 325 pa_dbusiface_device *d = userdata; 326 pa_card *card = NULL; 327 const char *object_path = NULL; 328 329 pa_assert(conn); 330 pa_assert(msg); 331 pa_assert(d); 332 333 card = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->card : d->source->card; 334 335 if (!card) { 336 if (d->type == PA_DEVICE_TYPE_SINK) 337 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, 338 "Sink %s doesn't belong to any card.", d->sink->name); 339 else 340 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, 341 "Source %s doesn't belong to any card.", d->source->name); 342 return; 343 } 344 345 object_path = pa_dbusiface_core_get_card_path(d->core, card); 346 347 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path); 348} 349 350static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) { 351 pa_dbusiface_device *d = userdata; 352 dbus_uint32_t sample_format = 0; 353 354 pa_assert(conn); 355 pa_assert(msg); 356 pa_assert(d); 357 358 sample_format = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->sample_spec.format : d->source->sample_spec.format; 359 360 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_format); 361} 362 363static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) { 364 pa_dbusiface_device *d = userdata; 365 dbus_uint32_t sample_rate = 0; 366 367 pa_assert(conn); 368 pa_assert(msg); 369 pa_assert(d); 370 371 sample_rate = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->sample_spec.rate : d->source->sample_spec.rate; 372 373 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_rate); 374} 375 376static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata) { 377 pa_dbusiface_device *d = userdata; 378 pa_channel_map *channel_map = NULL; 379 dbus_uint32_t channels[PA_CHANNELS_MAX]; 380 unsigned i = 0; 381 382 pa_assert(conn); 383 pa_assert(msg); 384 pa_assert(d); 385 386 channel_map = (d->type == PA_DEVICE_TYPE_SINK) ? &d->sink->channel_map : &d->source->channel_map; 387 388 for (i = 0; i < channel_map->channels; ++i) 389 channels[i] = channel_map->map[i]; 390 391 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, channels, channel_map->channels); 392} 393 394static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) { 395 pa_dbusiface_device *d = userdata; 396 dbus_uint32_t volume[PA_CHANNELS_MAX]; 397 unsigned i = 0; 398 399 pa_assert(conn); 400 pa_assert(msg); 401 pa_assert(d); 402 403 for (i = 0; i < d->volume.channels; ++i) 404 volume[i] = d->volume.values[i]; 405 406 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, volume, d->volume.channels); 407} 408 409static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) { 410 pa_dbusiface_device *d = userdata; 411 DBusMessageIter array_iter; 412 int device_channels = 0; 413 dbus_uint32_t *volume = NULL; 414 int n_volume_entries = 0; 415 pa_cvolume new_vol; 416 int i = 0; 417 418 pa_assert(conn); 419 pa_assert(msg); 420 pa_assert(iter); 421 pa_assert(d); 422 423 device_channels = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->channel_map.channels : d->source->channel_map.channels; 424 425 dbus_message_iter_recurse(iter, &array_iter); 426 dbus_message_iter_get_fixed_array(&array_iter, &volume, &n_volume_entries); 427 428 if (n_volume_entries != device_channels && n_volume_entries != 1) { 429 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, 430 "Expected %u volume entries, got %i.", device_channels, n_volume_entries); 431 return; 432 } 433 434 pa_cvolume_init(&new_vol); 435 new_vol.channels = n_volume_entries; 436 437 for (i = 0; i < n_volume_entries; ++i) { 438 if (!PA_VOLUME_IS_VALID(volume[i])) { 439 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Too large volume value: %u", volume[i]); 440 return; 441 } 442 new_vol.values[i] = volume[i]; 443 } 444 445 if (d->type == PA_DEVICE_TYPE_SINK) 446 pa_sink_set_volume(d->sink, &new_vol, true, true); 447 else 448 pa_source_set_volume(d->source, &new_vol, true, true); 449 450 pa_dbus_send_empty_reply(conn, msg); 451} 452 453static void handle_get_has_flat_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) { 454 pa_dbusiface_device *d = userdata; 455 dbus_bool_t has_flat_volume = FALSE; 456 457 pa_assert(conn); 458 pa_assert(msg); 459 pa_assert(d); 460 461 has_flat_volume = (d->type == PA_DEVICE_TYPE_SINK) ? !!(d->sink->flags & PA_SINK_FLAT_VOLUME) : FALSE; 462 463 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_flat_volume); 464} 465 466static void handle_get_has_convertible_to_decibel_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) { 467 pa_dbusiface_device *d = userdata; 468 dbus_bool_t has_convertible_to_decibel_volume = FALSE; 469 470 pa_assert(conn); 471 pa_assert(msg); 472 pa_assert(d); 473 474 has_convertible_to_decibel_volume = (d->type == PA_DEVICE_TYPE_SINK) 475 ? !!(d->sink->flags & PA_SINK_DECIBEL_VOLUME) 476 : !!(d->source->flags & PA_SOURCE_DECIBEL_VOLUME); 477 478 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_convertible_to_decibel_volume); 479} 480 481static void handle_get_base_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) { 482 pa_dbusiface_device *d = userdata; 483 dbus_uint32_t base_volume; 484 485 pa_assert(conn); 486 pa_assert(msg); 487 pa_assert(d); 488 489 base_volume = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->base_volume : d->source->base_volume; 490 491 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &base_volume); 492} 493 494static void handle_get_volume_steps(DBusConnection *conn, DBusMessage *msg, void *userdata) { 495 pa_dbusiface_device *d = userdata; 496 dbus_uint32_t volume_steps; 497 498 pa_assert(conn); 499 pa_assert(msg); 500 pa_assert(d); 501 502 volume_steps = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->n_volume_steps : d->source->n_volume_steps; 503 504 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &volume_steps); 505} 506 507static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) { 508 pa_dbusiface_device *d = userdata; 509 510 pa_assert(conn); 511 pa_assert(msg); 512 pa_assert(d); 513 514 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &d->mute); 515} 516 517static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) { 518 pa_dbusiface_device *d = userdata; 519 dbus_bool_t mute = FALSE; 520 521 pa_assert(conn); 522 pa_assert(msg); 523 pa_assert(iter); 524 pa_assert(d); 525 526 dbus_message_iter_get_basic(iter, &mute); 527 528 if (d->type == PA_DEVICE_TYPE_SINK) 529 pa_sink_set_mute(d->sink, mute, true); 530 else 531 pa_source_set_mute(d->source, mute, true); 532 533 pa_dbus_send_empty_reply(conn, msg); 534} 535 536static void handle_get_has_hardware_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) { 537 pa_dbusiface_device *d = userdata; 538 dbus_bool_t has_hardware_volume = FALSE; 539 540 pa_assert(conn); 541 pa_assert(msg); 542 pa_assert(d); 543 544 has_hardware_volume = (d->type == PA_DEVICE_TYPE_SINK) 545 ? !!(d->sink->flags & PA_SINK_HW_VOLUME_CTRL) 546 : !!(d->source->flags & PA_SOURCE_HW_VOLUME_CTRL); 547 548 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_hardware_volume); 549} 550 551static void handle_get_has_hardware_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) { 552 pa_dbusiface_device *d = userdata; 553 dbus_bool_t has_hardware_mute = FALSE; 554 555 pa_assert(conn); 556 pa_assert(msg); 557 pa_assert(d); 558 559 has_hardware_mute = (d->type == PA_DEVICE_TYPE_SINK) 560 ? !!(d->sink->flags & PA_SINK_HW_MUTE_CTRL) 561 : !!(d->source->flags & PA_SOURCE_HW_MUTE_CTRL); 562 563 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_hardware_mute); 564} 565 566static void handle_get_configured_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) { 567 pa_dbusiface_device *d = userdata; 568 dbus_uint64_t configured_latency = 0; 569 570 pa_assert(conn); 571 pa_assert(msg); 572 pa_assert(d); 573 574 configured_latency = (d->type == PA_DEVICE_TYPE_SINK) 575 ? pa_sink_get_requested_latency(d->sink) 576 : pa_source_get_requested_latency(d->source); 577 578 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &configured_latency); 579} 580 581static void handle_get_has_dynamic_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) { 582 pa_dbusiface_device *d = userdata; 583 dbus_bool_t has_dynamic_latency = FALSE; 584 585 pa_assert(conn); 586 pa_assert(msg); 587 pa_assert(d); 588 589 has_dynamic_latency = (d->type == PA_DEVICE_TYPE_SINK) 590 ? !!(d->sink->flags & PA_SINK_DYNAMIC_LATENCY) 591 : !!(d->source->flags & PA_SOURCE_DYNAMIC_LATENCY); 592 593 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_dynamic_latency); 594} 595 596static void handle_get_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) { 597 pa_dbusiface_device *d = userdata; 598 dbus_uint64_t latency = 0; 599 600 pa_assert(conn); 601 pa_assert(msg); 602 pa_assert(d); 603 604 if (d->type == PA_DEVICE_TYPE_SINK && !(d->sink->flags & PA_SINK_LATENCY)) { 605 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, 606 "Sink %s doesn't support latency querying.", d->sink->name); 607 return; 608 } 609 610 if (d->type == PA_DEVICE_TYPE_SOURCE && !(d->source->flags & PA_SOURCE_LATENCY)) { 611 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, 612 "Source %s doesn't support latency querying.", d->source->name); 613 return; 614 } 615 616 latency = (d->type == PA_DEVICE_TYPE_SINK) ? pa_sink_get_latency(d->sink) : pa_source_get_latency(d->source); 617 618 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &latency); 619} 620 621static void handle_get_is_hardware_device(DBusConnection *conn, DBusMessage *msg, void *userdata) { 622 pa_dbusiface_device *d = userdata; 623 dbus_bool_t is_hardware_device = FALSE; 624 625 pa_assert(conn); 626 pa_assert(msg); 627 pa_assert(d); 628 629 is_hardware_device = (d->type == PA_DEVICE_TYPE_SINK) 630 ? !!(d->sink->flags & PA_SINK_HARDWARE) 631 : !!(d->source->flags & PA_SOURCE_HARDWARE); 632 633 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_hardware_device); 634} 635 636static void handle_get_is_network_device(DBusConnection *conn, DBusMessage *msg, void *userdata) { 637 pa_dbusiface_device *d = userdata; 638 dbus_bool_t is_network_device = FALSE; 639 640 pa_assert(conn); 641 pa_assert(msg); 642 pa_assert(d); 643 644 is_network_device = (d->type == PA_DEVICE_TYPE_SINK) 645 ? !!(d->sink->flags & PA_SINK_NETWORK) 646 : !!(d->source->flags & PA_SOURCE_NETWORK); 647 648 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_network_device); 649} 650 651static void handle_get_state(DBusConnection *conn, DBusMessage *msg, void *userdata) { 652 pa_dbusiface_device *d = userdata; 653 dbus_uint32_t state; 654 655 pa_assert(conn); 656 pa_assert(msg); 657 pa_assert(d); 658 659 state = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink_state : d->source_state; 660 661 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &state); 662} 663 664/* The caller frees the array, but not the strings. */ 665static const char **get_ports(pa_dbusiface_device *d, unsigned *n) { 666 const char **ports; 667 unsigned i = 0; 668 void *state = NULL; 669 pa_dbusiface_device_port *port = NULL; 670 671 pa_assert(d); 672 pa_assert(n); 673 674 *n = pa_hashmap_size(d->ports); 675 676 if (*n == 0) 677 return NULL; 678 679 ports = pa_xnew(const char *, *n); 680 681 PA_HASHMAP_FOREACH(port, d->ports, state) 682 ports[i++] = pa_dbusiface_device_port_get_path(port); 683 684 return ports; 685} 686 687static void handle_get_ports(DBusConnection *conn, DBusMessage *msg, void *userdata) { 688 pa_dbusiface_device *d = userdata; 689 const char **ports = NULL; 690 unsigned n_ports = 0; 691 692 pa_assert(conn); 693 pa_assert(msg); 694 pa_assert(d); 695 696 ports = get_ports(d, &n_ports); 697 698 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, ports, n_ports); 699 700 pa_xfree(ports); 701} 702 703static void handle_get_active_port(DBusConnection *conn, DBusMessage *msg, void *userdata) { 704 pa_dbusiface_device *d = userdata; 705 const char *active_port; 706 707 pa_assert(conn); 708 pa_assert(msg); 709 pa_assert(d); 710 711 if (!d->active_port) { 712 pa_assert(pa_hashmap_isempty(d->ports)); 713 714 if (d->type == PA_DEVICE_TYPE_SINK) 715 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, 716 "The sink %s has no ports, and therefore there's no active port either.", d->sink->name); 717 else 718 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, 719 "The source %s has no ports, and therefore there's no active port either.", d->source->name); 720 return; 721 } 722 723 active_port = pa_dbusiface_device_port_get_path(pa_hashmap_get(d->ports, d->active_port->name)); 724 725 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &active_port); 726} 727 728static void handle_set_active_port(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) { 729 pa_dbusiface_device *d = userdata; 730 const char *new_active_path; 731 pa_dbusiface_device_port *port; 732 void *state; 733 pa_dbusiface_device_port *new_active = NULL; 734 int r; 735 736 pa_assert(conn); 737 pa_assert(msg); 738 pa_assert(iter); 739 pa_assert(d); 740 741 if (!d->active_port) { 742 pa_assert(pa_hashmap_isempty(d->ports)); 743 744 if (d->type == PA_DEVICE_TYPE_SINK) 745 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, 746 "The sink %s has no ports, and therefore there's no active port either.", d->sink->name); 747 else 748 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, 749 "The source %s has no ports, and therefore there's no active port either.", d->source->name); 750 return; 751 } 752 753 dbus_message_iter_get_basic(iter, &new_active_path); 754 755 PA_HASHMAP_FOREACH(port, d->ports, state) { 756 if (pa_streq(pa_dbusiface_device_port_get_path(port), new_active_path)) { 757 new_active = port; 758 break; 759 } 760 } 761 762 if (!new_active) { 763 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "No such port: %s", new_active_path); 764 return; 765 } 766 767 if (d->type == PA_DEVICE_TYPE_SINK) { 768 if ((r = pa_sink_set_port(d->sink, pa_dbusiface_device_port_get_name(new_active), true)) < 0) { 769 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, 770 "Internal error in PulseAudio: pa_sink_set_port() failed with error code %i.", r); 771 return; 772 } 773 } else { 774 if ((r = pa_source_set_port(d->source, pa_dbusiface_device_port_get_name(new_active), true)) < 0) { 775 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, 776 "Internal error in PulseAudio: pa_source_set_port() failed with error code %i.", r); 777 return; 778 } 779 } 780 781 pa_dbus_send_empty_reply(conn, msg); 782} 783 784static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) { 785 pa_dbusiface_device *d = userdata; 786 787 pa_assert(conn); 788 pa_assert(msg); 789 pa_assert(d); 790 791 pa_dbus_send_proplist_variant_reply(conn, msg, d->proplist); 792} 793 794static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) { 795 pa_dbusiface_device *d = userdata; 796 DBusMessage *reply = NULL; 797 DBusMessageIter msg_iter; 798 DBusMessageIter dict_iter; 799 dbus_uint32_t idx = 0; 800 const char *name = NULL; 801 const char *driver = NULL; 802 pa_module *owner_module = NULL; 803 const char *owner_module_path = NULL; 804 pa_card *card = NULL; 805 const char *card_path = NULL; 806 dbus_uint32_t sample_format = 0; 807 dbus_uint32_t sample_rate = 0; 808 pa_channel_map *channel_map = NULL; 809 dbus_uint32_t channels[PA_CHANNELS_MAX]; 810 dbus_uint32_t volume[PA_CHANNELS_MAX]; 811 dbus_bool_t has_flat_volume = FALSE; 812 dbus_bool_t has_convertible_to_decibel_volume = FALSE; 813 dbus_uint32_t base_volume = 0; 814 dbus_uint32_t volume_steps = 0; 815 dbus_bool_t has_hardware_volume = FALSE; 816 dbus_bool_t has_hardware_mute = FALSE; 817 dbus_uint64_t configured_latency = 0; 818 dbus_bool_t has_dynamic_latency = FALSE; 819 dbus_uint64_t latency = 0; 820 dbus_bool_t is_hardware_device = FALSE; 821 dbus_bool_t is_network_device = FALSE; 822 dbus_uint32_t state = 0; 823 const char **ports = NULL; 824 unsigned n_ports = 0; 825 const char *active_port = NULL; 826 unsigned i = 0; 827 828 pa_assert(conn); 829 pa_assert(msg); 830 pa_assert(d); 831 832 if (d->type == PA_DEVICE_TYPE_SINK) { 833 idx = d->sink->index; 834 name = d->sink->name; 835 driver = d->sink->driver; 836 owner_module = d->sink->module; 837 card = d->sink->card; 838 sample_format = d->sink->sample_spec.format; 839 sample_rate = d->sink->sample_spec.rate; 840 channel_map = &d->sink->channel_map; 841 has_flat_volume = !!(d->sink->flags & PA_SINK_FLAT_VOLUME); 842 has_convertible_to_decibel_volume = !!(d->sink->flags & PA_SINK_DECIBEL_VOLUME); 843 base_volume = d->sink->base_volume; 844 volume_steps = d->sink->n_volume_steps; 845 has_hardware_volume = !!(d->sink->flags & PA_SINK_HW_VOLUME_CTRL); 846 has_hardware_mute = !!(d->sink->flags & PA_SINK_HW_MUTE_CTRL); 847 configured_latency = pa_sink_get_requested_latency(d->sink); 848 has_dynamic_latency = !!(d->sink->flags & PA_SINK_DYNAMIC_LATENCY); 849 latency = pa_sink_get_latency(d->sink); 850 is_hardware_device = !!(d->sink->flags & PA_SINK_HARDWARE); 851 is_network_device = !!(d->sink->flags & PA_SINK_NETWORK); 852 state = d->sink->state; 853 } else { 854 idx = d->source->index; 855 name = d->source->name; 856 driver = d->source->driver; 857 owner_module = d->source->module; 858 card = d->source->card; 859 sample_format = d->source->sample_spec.format; 860 sample_rate = d->source->sample_spec.rate; 861 channel_map = &d->source->channel_map; 862 has_flat_volume = FALSE; 863 has_convertible_to_decibel_volume = !!(d->source->flags & PA_SOURCE_DECIBEL_VOLUME); 864 base_volume = d->source->base_volume; 865 volume_steps = d->source->n_volume_steps; 866 has_hardware_volume = !!(d->source->flags & PA_SOURCE_HW_VOLUME_CTRL); 867 has_hardware_mute = !!(d->source->flags & PA_SOURCE_HW_MUTE_CTRL); 868 configured_latency = pa_source_get_requested_latency(d->source); 869 has_dynamic_latency = !!(d->source->flags & PA_SOURCE_DYNAMIC_LATENCY); 870 latency = pa_source_get_latency(d->source); 871 is_hardware_device = !!(d->source->flags & PA_SOURCE_HARDWARE); 872 is_network_device = !!(d->source->flags & PA_SOURCE_NETWORK); 873 state = d->source->state; 874 } 875 if (owner_module) 876 owner_module_path = pa_dbusiface_core_get_module_path(d->core, owner_module); 877 if (card) 878 card_path = pa_dbusiface_core_get_card_path(d->core, card); 879 for (i = 0; i < channel_map->channels; ++i) 880 channels[i] = channel_map->map[i]; 881 for (i = 0; i < d->volume.channels; ++i) 882 volume[i] = d->volume.values[i]; 883 ports = get_ports(d, &n_ports); 884 if (d->active_port) 885 active_port = pa_dbusiface_device_port_get_path(pa_hashmap_get(d->ports, d->active_port->name)); 886 887 pa_assert_se((reply = dbus_message_new_method_return(msg))); 888 889 dbus_message_iter_init_append(reply, &msg_iter); 890 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)); 891 892 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx); 893 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &name); 894 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &driver); 895 896 if (owner_module) 897 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module_path); 898 899 if (card) 900 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CARD].property_name, DBUS_TYPE_OBJECT_PATH, &card_path); 901 902 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format); 903 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &sample_rate); 904 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, channel_map->channels); 905 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, d->volume.channels); 906 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_HAS_FLAT_VOLUME].property_name, DBUS_TYPE_BOOLEAN, &has_flat_volume); 907 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_HAS_CONVERTIBLE_TO_DECIBEL_VOLUME].property_name, DBUS_TYPE_BOOLEAN, &has_convertible_to_decibel_volume); 908 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BASE_VOLUME].property_name, DBUS_TYPE_UINT32, &base_volume); 909 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME_STEPS].property_name, DBUS_TYPE_UINT32, &volume_steps); 910 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &d->mute); 911 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_HAS_HARDWARE_VOLUME].property_name, DBUS_TYPE_BOOLEAN, &has_hardware_volume); 912 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_HAS_HARDWARE_MUTE].property_name, DBUS_TYPE_BOOLEAN, &has_hardware_mute); 913 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CONFIGURED_LATENCY].property_name, DBUS_TYPE_UINT64, &configured_latency); 914 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY].property_name, DBUS_TYPE_BOOLEAN, &has_dynamic_latency); 915 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_LATENCY].property_name, DBUS_TYPE_UINT64, &latency); 916 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_IS_HARDWARE_DEVICE].property_name, DBUS_TYPE_BOOLEAN, &is_hardware_device); 917 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_IS_NETWORK_DEVICE].property_name, DBUS_TYPE_BOOLEAN, &is_network_device); 918 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_STATE].property_name, DBUS_TYPE_UINT32, &state); 919 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PORTS].property_name, DBUS_TYPE_OBJECT_PATH, ports, n_ports); 920 921 if (active_port) 922 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_ACTIVE_PORT].property_name, DBUS_TYPE_OBJECT_PATH, &active_port); 923 924 pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, d->proplist); 925 926 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter)); 927 928 pa_assert_se(dbus_connection_send(conn, reply, NULL)); 929 930 dbus_message_unref(reply); 931 932 pa_xfree(ports); 933} 934 935static void handle_suspend(DBusConnection *conn, DBusMessage *msg, void *userdata) { 936 pa_dbusiface_device *d = userdata; 937 dbus_bool_t suspend = FALSE; 938 pa_client *client; 939 940 pa_assert(conn); 941 pa_assert(msg); 942 pa_assert(d); 943 944 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &suspend, DBUS_TYPE_INVALID)); 945 pa_assert_se(client = pa_dbus_protocol_get_client(d->dbus_protocol, conn)); 946 947 if (d->type == PA_DEVICE_TYPE_SINK) { 948 pa_log_debug("%s sink %s requested by client %" PRIu32 ".", suspend ? "Suspending" : "Resuming", d->sink->name, client->index); 949 950 if (pa_sink_suspend(d->sink, suspend, PA_SUSPEND_USER) < 0) { 951 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Internal error in PulseAudio: pa_sink_suspend() failed."); 952 return; 953 } 954 955 } else { 956 pa_log_debug("%s source %s requested by client %" PRIu32 ".", suspend ? "Suspending" : "Resuming", d->source->name, client->index); 957 958 if (pa_source_suspend(d->source, suspend, PA_SUSPEND_USER) < 0) { 959 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Internal error in PulseAudio: pa_source_suspend() failed."); 960 return; 961 } 962 } 963 964 pa_dbus_send_empty_reply(conn, msg); 965} 966 967static void handle_get_port_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata) { 968 pa_dbusiface_device *d = userdata; 969 const char *port_name = NULL; 970 pa_dbusiface_device_port *port = NULL; 971 const char *port_path = NULL; 972 973 pa_assert(conn); 974 pa_assert(msg); 975 pa_assert(d); 976 977 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &port_name, DBUS_TYPE_INVALID)); 978 979 if (!(port = pa_hashmap_get(d->ports, port_name))) { 980 if (d->type == PA_DEVICE_TYPE_SINK) 981 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, 982 "%s: No such port on sink %s.", port_name, d->sink->name); 983 else 984 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, 985 "%s: No such port on source %s.", port_name, d->source->name); 986 return; 987 } 988 989 port_path = pa_dbusiface_device_port_get_path(port); 990 991 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &port_path); 992} 993 994static void handle_sink_get_monitor_source(DBusConnection *conn, DBusMessage *msg, void *userdata) { 995 pa_dbusiface_device *d = userdata; 996 const char *monitor_source = NULL; 997 998 pa_assert(conn); 999 pa_assert(msg); 1000 pa_assert(d); 1001 pa_assert(d->type == PA_DEVICE_TYPE_SINK); 1002 1003 monitor_source = pa_dbusiface_core_get_source_path(d->core, d->sink->monitor_source); 1004 1005 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &monitor_source); 1006} 1007 1008static void handle_sink_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) { 1009 pa_dbusiface_device *d = userdata; 1010 DBusMessage *reply = NULL; 1011 DBusMessageIter msg_iter; 1012 DBusMessageIter dict_iter; 1013 const char *monitor_source = NULL; 1014 1015 pa_assert(conn); 1016 pa_assert(msg); 1017 pa_assert(d); 1018 pa_assert(d->type == PA_DEVICE_TYPE_SINK); 1019 1020 monitor_source = pa_dbusiface_core_get_source_path(d->core, d->sink->monitor_source); 1021 1022 pa_assert_se((reply = dbus_message_new_method_return(msg))); 1023 1024 dbus_message_iter_init_append(reply, &msg_iter); 1025 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)); 1026 1027 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[SINK_PROPERTY_HANDLER_MONITOR_SOURCE].property_name, DBUS_TYPE_OBJECT_PATH, &monitor_source); 1028 1029 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter)); 1030 1031 pa_assert_se(dbus_connection_send(conn, reply, NULL)); 1032 1033 dbus_message_unref(reply); 1034} 1035 1036static void handle_source_get_monitor_of_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) { 1037 pa_dbusiface_device *d = userdata; 1038 const char *monitor_of_sink = NULL; 1039 1040 pa_assert(conn); 1041 pa_assert(msg); 1042 pa_assert(d); 1043 pa_assert(d->type == PA_DEVICE_TYPE_SOURCE); 1044 1045 if (!d->source->monitor_of) { 1046 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Source %s is not a monitor source.", d->source->name); 1047 return; 1048 } 1049 1050 monitor_of_sink = pa_dbusiface_core_get_sink_path(d->core, d->source->monitor_of); 1051 1052 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &monitor_of_sink); 1053} 1054 1055static void handle_source_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) { 1056 pa_dbusiface_device *d = userdata; 1057 DBusMessage *reply = NULL; 1058 DBusMessageIter msg_iter; 1059 DBusMessageIter dict_iter; 1060 const char *monitor_of_sink = NULL; 1061 1062 pa_assert(conn); 1063 pa_assert(msg); 1064 pa_assert(d); 1065 pa_assert(d->type == PA_DEVICE_TYPE_SOURCE); 1066 1067 if (d->source->monitor_of) 1068 monitor_of_sink = pa_dbusiface_core_get_sink_path(d->core, d->source->monitor_of); 1069 1070 pa_assert_se((reply = dbus_message_new_method_return(msg))); 1071 1072 dbus_message_iter_init_append(reply, &msg_iter); 1073 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)); 1074 1075 if (monitor_of_sink) 1076 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK].property_name, DBUS_TYPE_OBJECT_PATH, &monitor_of_sink); 1077 1078 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter)); 1079 1080 pa_assert_se(dbus_connection_send(conn, reply, NULL)); 1081 1082 dbus_message_unref(reply); 1083} 1084 1085static pa_hook_result_t volume_changed_cb(void *hook_data, void *call_data, void *slot_data) { 1086 pa_dbusiface_device *d = slot_data; 1087 DBusMessage *signal_msg = NULL; 1088 const pa_cvolume *new_volume = NULL; 1089 unsigned i = 0; 1090 1091 if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != call_data) || 1092 (d->type == PA_DEVICE_TYPE_SOURCE && d->source != call_data)) 1093 return PA_HOOK_OK; 1094 1095 new_volume = (d->type == PA_DEVICE_TYPE_SINK) 1096 ? pa_sink_get_volume(d->sink, false) 1097 : pa_source_get_volume(d->source, false); 1098 1099 if (!pa_cvolume_equal(&d->volume, new_volume)) { 1100 dbus_uint32_t volume[PA_CHANNELS_MAX]; 1101 dbus_uint32_t *volume_ptr = volume; 1102 1103 d->volume = *new_volume; 1104 1105 for (i = 0; i < d->volume.channels; ++i) 1106 volume[i] = d->volume.values[i]; 1107 1108 pa_assert_se(signal_msg = dbus_message_new_signal(d->path, 1109 PA_DBUSIFACE_DEVICE_INTERFACE, 1110 signals[SIGNAL_VOLUME_UPDATED].name)); 1111 pa_assert_se(dbus_message_append_args(signal_msg, 1112 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, d->volume.channels, 1113 DBUS_TYPE_INVALID)); 1114 1115 pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg); 1116 dbus_message_unref(signal_msg); 1117 } 1118 1119 return PA_HOOK_OK; 1120} 1121 1122static pa_hook_result_t mute_changed_cb(void *hook_data, void *call_data, void *slot_data) { 1123 pa_dbusiface_device *d = slot_data; 1124 DBusMessage *signal_msg = NULL; 1125 bool new_mute = false; 1126 1127 if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != call_data) || 1128 (d->type == PA_DEVICE_TYPE_SOURCE && d->source != call_data)) 1129 return PA_HOOK_OK; 1130 1131 new_mute = (d->type == PA_DEVICE_TYPE_SINK) 1132 ? pa_sink_get_mute(d->sink, false) 1133 : pa_source_get_mute(d->source, false); 1134 1135 if (d->mute != new_mute) { 1136 d->mute = new_mute; 1137 1138 pa_assert_se(signal_msg = dbus_message_new_signal(d->path, 1139 PA_DBUSIFACE_DEVICE_INTERFACE, 1140 signals[SIGNAL_MUTE_UPDATED].name)); 1141 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &d->mute, DBUS_TYPE_INVALID)); 1142 1143 pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg); 1144 dbus_message_unref(signal_msg); 1145 } 1146 1147 return PA_HOOK_OK; 1148} 1149 1150static pa_hook_result_t state_changed_cb(void *hook_data, void *call_data, void *slot_data) { 1151 pa_dbusiface_device *d = slot_data; 1152 DBusMessage *signal_msg = NULL; 1153 pa_sink_state_t new_sink_state = 0; 1154 pa_source_state_t new_source_state = 0; 1155 1156 if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != call_data) || 1157 (d->type == PA_DEVICE_TYPE_SOURCE && d->source != call_data)) 1158 return PA_HOOK_OK; 1159 1160 if (d->type == PA_DEVICE_TYPE_SINK) 1161 new_sink_state = d->sink->state; 1162 else 1163 new_source_state = d->source->state; 1164 1165 if ((d->type == PA_DEVICE_TYPE_SINK && d->sink_state != new_sink_state) 1166 || (d->type == PA_DEVICE_TYPE_SOURCE && d->source_state != new_source_state)) { 1167 dbus_uint32_t state = 0; 1168 1169 if (d->type == PA_DEVICE_TYPE_SINK) 1170 d->sink_state = new_sink_state; 1171 else 1172 d->source_state = new_source_state; 1173 1174 state = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink_state : d->source_state; 1175 1176 pa_assert_se(signal_msg = dbus_message_new_signal(d->path, 1177 PA_DBUSIFACE_DEVICE_INTERFACE, 1178 signals[SIGNAL_STATE_UPDATED].name)); 1179 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID)); 1180 1181 pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg); 1182 dbus_message_unref(signal_msg); 1183 } 1184 1185 return PA_HOOK_OK; 1186} 1187 1188static pa_hook_result_t port_changed_cb(void *hook_data, void *call_data, void *slot_data) { 1189 pa_dbusiface_device *d = slot_data; 1190 DBusMessage *signal_msg = NULL; 1191 pa_device_port *new_active_port = NULL; 1192 1193 if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != call_data) || 1194 (d->type == PA_DEVICE_TYPE_SOURCE && d->source != call_data)) 1195 return PA_HOOK_OK; 1196 1197 new_active_port = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->active_port : d->source->active_port; 1198 1199 if (d->active_port != new_active_port) { 1200 const char *object_path = NULL; 1201 1202 d->active_port = new_active_port; 1203 object_path = pa_dbusiface_device_port_get_path(pa_hashmap_get(d->ports, d->active_port->name)); 1204 1205 pa_assert_se(signal_msg = dbus_message_new_signal(d->path, 1206 PA_DBUSIFACE_DEVICE_INTERFACE, 1207 signals[SIGNAL_ACTIVE_PORT_UPDATED].name)); 1208 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); 1209 1210 pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg); 1211 dbus_message_unref(signal_msg); 1212 } 1213 1214 return PA_HOOK_OK; 1215} 1216 1217static pa_hook_result_t proplist_changed_cb(void *hook_data, void *call_data, void *slot_data) { 1218 pa_dbusiface_device *d = slot_data; 1219 DBusMessage *signal_msg = NULL; 1220 pa_proplist *new_proplist = NULL; 1221 1222 if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != call_data) || 1223 (d->type == PA_DEVICE_TYPE_SOURCE && d->source != call_data)) 1224 return PA_HOOK_OK; 1225 1226 new_proplist = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->proplist : d->source->proplist; 1227 1228 if (!pa_proplist_equal(d->proplist, new_proplist)) { 1229 DBusMessageIter msg_iter; 1230 1231 pa_proplist_update(d->proplist, PA_UPDATE_SET, new_proplist); 1232 1233 pa_assert_se(signal_msg = dbus_message_new_signal(d->path, 1234 PA_DBUSIFACE_DEVICE_INTERFACE, 1235 signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); 1236 dbus_message_iter_init_append(signal_msg, &msg_iter); 1237 pa_dbus_append_proplist(&msg_iter, d->proplist); 1238 1239 pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg); 1240 dbus_message_unref(signal_msg); 1241 } 1242 1243 return PA_HOOK_OK; 1244} 1245 1246pa_dbusiface_device *pa_dbusiface_device_new_sink(pa_dbusiface_core *core, pa_sink *sink) { 1247 pa_dbusiface_device *d = NULL; 1248 pa_device_port *port; 1249 void *state; 1250 1251 pa_assert(core); 1252 pa_assert(sink); 1253 1254 d = pa_xnew0(pa_dbusiface_device, 1); 1255 d->core = core; 1256 d->sink = pa_sink_ref(sink); 1257 d->type = PA_DEVICE_TYPE_SINK; 1258 d->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, SINK_OBJECT_NAME, sink->index); 1259 d->volume = *pa_sink_get_volume(sink, false); 1260 d->mute = pa_sink_get_mute(sink, false); 1261 d->sink_state = sink->state; 1262 d->ports = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) pa_dbusiface_device_port_free); 1263 d->next_port_index = 0; 1264 d->active_port = sink->active_port; 1265 d->proplist = pa_proplist_copy(sink->proplist); 1266 d->dbus_protocol = pa_dbus_protocol_get(sink->core); 1267 d->volume_changed_slot = pa_hook_connect(&sink->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED], 1268 PA_HOOK_NORMAL, volume_changed_cb, d); 1269 d->mute_changed_slot = pa_hook_connect(&sink->core->hooks[PA_CORE_HOOK_SINK_MUTE_CHANGED], 1270 PA_HOOK_NORMAL, mute_changed_cb, d); 1271 d->state_changed_slot = pa_hook_connect(&sink->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], 1272 PA_HOOK_NORMAL, state_changed_cb, d); 1273 d->port_changed_slot = pa_hook_connect(&sink->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], 1274 PA_HOOK_NORMAL, port_changed_cb, d); 1275 d->proplist_changed_slot = pa_hook_connect(&sink->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], 1276 PA_HOOK_NORMAL, proplist_changed_cb, d); 1277 1278 PA_HASHMAP_FOREACH(port, sink->ports, state) { 1279 pa_dbusiface_device_port *p = pa_dbusiface_device_port_new(d, sink->core, port, d->next_port_index++); 1280 pa_hashmap_put(d->ports, (char *) pa_dbusiface_device_port_get_name(p), p); 1281 } 1282 1283 pa_assert_se(pa_dbus_protocol_add_interface(d->dbus_protocol, d->path, &device_interface_info, d) >= 0); 1284 pa_assert_se(pa_dbus_protocol_add_interface(d->dbus_protocol, d->path, &sink_interface_info, d) >= 0); 1285 1286 return d; 1287} 1288 1289pa_dbusiface_device *pa_dbusiface_device_new_source(pa_dbusiface_core *core, pa_source *source) { 1290 pa_dbusiface_device *d = NULL; 1291 pa_device_port *port; 1292 void *state; 1293 1294 pa_assert(core); 1295 pa_assert(source); 1296 1297 d = pa_xnew0(pa_dbusiface_device, 1); 1298 d->core = core; 1299 d->source = pa_source_ref(source); 1300 d->type = PA_DEVICE_TYPE_SOURCE; 1301 d->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, SOURCE_OBJECT_NAME, source->index); 1302 d->volume = *pa_source_get_volume(source, false); 1303 d->mute = pa_source_get_mute(source, false); 1304 d->source_state = source->state; 1305 d->ports = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) pa_dbusiface_device_port_free); 1306 d->next_port_index = 0; 1307 d->active_port = source->active_port; 1308 d->proplist = pa_proplist_copy(source->proplist); 1309 d->dbus_protocol = pa_dbus_protocol_get(source->core); 1310 d->volume_changed_slot = pa_hook_connect(&source->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED], 1311 PA_HOOK_NORMAL, volume_changed_cb, d); 1312 d->mute_changed_slot = pa_hook_connect(&source->core->hooks[PA_CORE_HOOK_SOURCE_MUTE_CHANGED], 1313 PA_HOOK_NORMAL, mute_changed_cb, d); 1314 d->state_changed_slot = pa_hook_connect(&source->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], 1315 PA_HOOK_NORMAL, state_changed_cb, d); 1316 d->port_changed_slot = pa_hook_connect(&source->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], 1317 PA_HOOK_NORMAL, port_changed_cb, d); 1318 d->proplist_changed_slot = pa_hook_connect(&source->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], 1319 PA_HOOK_NORMAL, proplist_changed_cb, d); 1320 1321 PA_HASHMAP_FOREACH(port, source->ports, state) { 1322 pa_dbusiface_device_port *p = pa_dbusiface_device_port_new(d, source->core, port, d->next_port_index++); 1323 pa_hashmap_put(d->ports, (char *) pa_dbusiface_device_port_get_name(p), p); 1324 } 1325 1326 pa_assert_se(pa_dbus_protocol_add_interface(d->dbus_protocol, d->path, &device_interface_info, d) >= 0); 1327 pa_assert_se(pa_dbus_protocol_add_interface(d->dbus_protocol, d->path, &source_interface_info, d) >= 0); 1328 1329 return d; 1330} 1331 1332void pa_dbusiface_device_free(pa_dbusiface_device *d) { 1333 pa_assert(d); 1334 1335 pa_hook_slot_free(d->volume_changed_slot); 1336 pa_hook_slot_free(d->mute_changed_slot); 1337 pa_hook_slot_free(d->state_changed_slot); 1338 pa_hook_slot_free(d->port_changed_slot); 1339 pa_hook_slot_free(d->proplist_changed_slot); 1340 1341 pa_assert_se(pa_dbus_protocol_remove_interface(d->dbus_protocol, d->path, device_interface_info.name) >= 0); 1342 1343 if (d->type == PA_DEVICE_TYPE_SINK) { 1344 pa_assert_se(pa_dbus_protocol_remove_interface(d->dbus_protocol, d->path, sink_interface_info.name) >= 0); 1345 pa_sink_unref(d->sink); 1346 1347 } else { 1348 pa_assert_se(pa_dbus_protocol_remove_interface(d->dbus_protocol, d->path, source_interface_info.name) >= 0); 1349 pa_source_unref(d->source); 1350 } 1351 pa_hashmap_free(d->ports); 1352 pa_proplist_free(d->proplist); 1353 pa_dbus_protocol_unref(d->dbus_protocol); 1354 1355 pa_xfree(d->path); 1356 pa_xfree(d); 1357} 1358 1359const char *pa_dbusiface_device_get_path(pa_dbusiface_device *d) { 1360 pa_assert(d); 1361 1362 return d->path; 1363} 1364 1365pa_sink *pa_dbusiface_device_get_sink(pa_dbusiface_device *d) { 1366 pa_assert(d); 1367 pa_assert(d->type == PA_DEVICE_TYPE_SINK); 1368 1369 return d->sink; 1370} 1371 1372pa_source *pa_dbusiface_device_get_source(pa_dbusiface_device *d) { 1373 pa_assert(d); 1374 pa_assert(d->type == PA_DEVICE_TYPE_SOURCE); 1375 1376 return d->source; 1377} 1378