1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2009 Tanu Kaskinen 5 Copyright 2009 Vincent Filali-Ansary <filali.v@azurdigitalnetworks.net> 6 7 PulseAudio is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published 9 by the Free Software Foundation; either version 2.1 of the License, 10 or (at your option) any later version. 11 12 PulseAudio is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 19***/ 20 21#ifdef HAVE_CONFIG_H 22#include <config.h> 23#endif 24 25#include <pulsecore/core-util.h> 26#include <pulsecore/dbus-util.h> 27#include <pulsecore/protocol-dbus.h> 28 29#include "iface-stream.h" 30 31#define PLAYBACK_OBJECT_NAME "playback_stream" 32#define RECORD_OBJECT_NAME "record_stream" 33 34enum stream_type { 35 STREAM_TYPE_PLAYBACK, 36 STREAM_TYPE_RECORD 37}; 38 39struct pa_dbusiface_stream { 40 pa_dbusiface_core *core; 41 42 union { 43 pa_sink_input *sink_input; 44 pa_source_output *source_output; 45 }; 46 enum stream_type type; 47 char *path; 48 union { 49 pa_sink *sink; 50 pa_source *source; 51 }; 52 uint32_t sample_rate; 53 pa_cvolume volume; 54 dbus_bool_t mute; 55 pa_proplist *proplist; 56 57 bool has_volume; 58 59 pa_dbus_protocol *dbus_protocol; 60 pa_hook_slot *send_event_slot; 61 pa_hook_slot *move_finish_slot; 62 pa_hook_slot *volume_changed_slot; 63 pa_hook_slot *mute_changed_slot; 64 pa_hook_slot *proplist_changed_slot; 65 pa_hook_slot *state_changed_slot; 66}; 67 68static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata); 69static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata); 70static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata); 71static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata); 72static void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata); 73static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata); 74static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata); 75static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata); 76static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata); 77static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata); 78static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata); 79static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata); 80static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata); 81static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata); 82static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata); 83static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata); 84 85static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata); 86 87static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata); 88static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata); 89 90enum property_handler_index { 91 PROPERTY_HANDLER_INDEX, 92 PROPERTY_HANDLER_DRIVER, 93 PROPERTY_HANDLER_OWNER_MODULE, 94 PROPERTY_HANDLER_CLIENT, 95 PROPERTY_HANDLER_DEVICE, 96 PROPERTY_HANDLER_SAMPLE_FORMAT, 97 PROPERTY_HANDLER_SAMPLE_RATE, 98 PROPERTY_HANDLER_CHANNELS, 99 PROPERTY_HANDLER_VOLUME, 100 PROPERTY_HANDLER_MUTE, 101 PROPERTY_HANDLER_BUFFER_LATENCY, 102 PROPERTY_HANDLER_DEVICE_LATENCY, 103 PROPERTY_HANDLER_RESAMPLE_METHOD, 104 PROPERTY_HANDLER_PROPERTY_LIST, 105 PROPERTY_HANDLER_MAX 106}; 107 108static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = { 109 [PROPERTY_HANDLER_INDEX] = { .property_name = "Index", .type = "u", .get_cb = handle_get_index, .set_cb = NULL }, 110 [PROPERTY_HANDLER_DRIVER] = { .property_name = "Driver", .type = "s", .get_cb = handle_get_driver, .set_cb = NULL }, 111 [PROPERTY_HANDLER_OWNER_MODULE] = { .property_name = "OwnerModule", .type = "o", .get_cb = handle_get_owner_module, .set_cb = NULL }, 112 [PROPERTY_HANDLER_CLIENT] = { .property_name = "Client", .type = "o", .get_cb = handle_get_client, .set_cb = NULL }, 113 [PROPERTY_HANDLER_DEVICE] = { .property_name = "Device", .type = "o", .get_cb = handle_get_device, .set_cb = NULL }, 114 [PROPERTY_HANDLER_SAMPLE_FORMAT] = { .property_name = "SampleFormat", .type = "u", .get_cb = handle_get_sample_format, .set_cb = NULL }, 115 [PROPERTY_HANDLER_SAMPLE_RATE] = { .property_name = "SampleRate", .type = "u", .get_cb = handle_get_sample_rate, .set_cb = NULL }, 116 [PROPERTY_HANDLER_CHANNELS] = { .property_name = "Channels", .type = "au", .get_cb = handle_get_channels, .set_cb = NULL }, 117 [PROPERTY_HANDLER_VOLUME] = { .property_name = "Volume", .type = "au", .get_cb = handle_get_volume, .set_cb = handle_set_volume }, 118 [PROPERTY_HANDLER_MUTE] = { .property_name = "Mute", .type = "b", .get_cb = handle_get_mute, .set_cb = handle_set_mute }, 119 [PROPERTY_HANDLER_BUFFER_LATENCY] = { .property_name = "BufferLatency", .type = "t", .get_cb = handle_get_buffer_latency, .set_cb = NULL }, 120 [PROPERTY_HANDLER_DEVICE_LATENCY] = { .property_name = "DeviceLatency", .type = "t", .get_cb = handle_get_device_latency, .set_cb = NULL }, 121 [PROPERTY_HANDLER_RESAMPLE_METHOD] = { .property_name = "ResampleMethod", .type = "s", .get_cb = handle_get_resample_method, .set_cb = NULL }, 122 [PROPERTY_HANDLER_PROPERTY_LIST] = { .property_name = "PropertyList", .type = "a{say}", .get_cb = handle_get_property_list, .set_cb = NULL } 123}; 124 125enum method_handler_index { 126 METHOD_HANDLER_MOVE, 127 METHOD_HANDLER_KILL, 128 METHOD_HANDLER_MAX 129}; 130 131static pa_dbus_arg_info move_args[] = { { "device", "o", "in" } }; 132 133static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = { 134 [METHOD_HANDLER_MOVE] = { 135 .method_name = "Move", 136 .arguments = move_args, 137 .n_arguments = sizeof(move_args) / sizeof(pa_dbus_arg_info), 138 .receive_cb = handle_move }, 139 [METHOD_HANDLER_KILL] = { 140 .method_name = "Kill", 141 .arguments = NULL, 142 .n_arguments = 0, 143 .receive_cb = handle_kill } 144}; 145 146enum signal_index { 147 SIGNAL_DEVICE_UPDATED, 148 SIGNAL_SAMPLE_RATE_UPDATED, 149 SIGNAL_VOLUME_UPDATED, 150 SIGNAL_MUTE_UPDATED, 151 SIGNAL_PROPERTY_LIST_UPDATED, 152 SIGNAL_STREAM_EVENT, 153 SIGNAL_MAX 154}; 155 156static pa_dbus_arg_info device_updated_args[] = { { "device", "o", NULL } }; 157static pa_dbus_arg_info sample_rate_updated_args[] = { { "sample_rate", "u", NULL } }; 158static pa_dbus_arg_info volume_updated_args[] = { { "volume", "au", NULL } }; 159static pa_dbus_arg_info mute_updated_args[] = { { "muted", "b", NULL } }; 160static pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } }; 161static pa_dbus_arg_info stream_event_args[] = { { "name", "s", NULL }, { "property_list", "a{say}", NULL } }; 162 163static pa_dbus_signal_info signals[SIGNAL_MAX] = { 164 [SIGNAL_DEVICE_UPDATED] = { .name = "DeviceUpdated", .arguments = device_updated_args, .n_arguments = 1 }, 165 [SIGNAL_SAMPLE_RATE_UPDATED] = { .name = "SampleRateUpdated", .arguments = sample_rate_updated_args, .n_arguments = 1 }, 166 [SIGNAL_VOLUME_UPDATED] = { .name = "VolumeUpdated", .arguments = volume_updated_args, .n_arguments = 1 }, 167 [SIGNAL_MUTE_UPDATED] = { .name = "MuteUpdated", .arguments = mute_updated_args, .n_arguments = 1 }, 168 [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 }, 169 [SIGNAL_STREAM_EVENT] = { .name = "StreamEvent", .arguments = stream_event_args, .n_arguments = sizeof(stream_event_args) / sizeof(pa_dbus_arg_info) } 170}; 171 172static pa_dbus_interface_info stream_interface_info = { 173 .name = PA_DBUSIFACE_STREAM_INTERFACE, 174 .method_handlers = method_handlers, 175 .n_method_handlers = METHOD_HANDLER_MAX, 176 .property_handlers = property_handlers, 177 .n_property_handlers = PROPERTY_HANDLER_MAX, 178 .get_all_properties_cb = handle_get_all, 179 .signals = signals, 180 .n_signals = SIGNAL_MAX 181}; 182 183static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) { 184 pa_dbusiface_stream *s = userdata; 185 dbus_uint32_t idx; 186 187 pa_assert(conn); 188 pa_assert(msg); 189 pa_assert(s); 190 191 idx = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->index : s->source_output->index; 192 193 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx); 194} 195 196/* The returned string has to be freed with pa_xfree() by the caller. */ 197static char *stream_to_string(pa_dbusiface_stream *s) { 198 if (s->type == STREAM_TYPE_PLAYBACK) 199 return pa_sprintf_malloc("Playback stream %u", (unsigned) s->sink_input->index); 200 else 201 return pa_sprintf_malloc("Record stream %u", (unsigned) s->source_output->index); 202} 203 204static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) { 205 pa_dbusiface_stream *s = userdata; 206 const char *driver = NULL; 207 208 pa_assert(conn); 209 pa_assert(msg); 210 pa_assert(s); 211 212 driver = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->driver : s->source_output->driver; 213 214 if (!driver) { 215 char *str = stream_to_string(s); 216 217 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have a driver.", str); 218 pa_xfree(str); 219 220 return; 221 } 222 223 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &driver); 224} 225 226static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata) { 227 pa_dbusiface_stream *s = userdata; 228 pa_module *owner_module = NULL; 229 const char *object_path = NULL; 230 231 pa_assert(conn); 232 pa_assert(msg); 233 pa_assert(s); 234 235 owner_module = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->module : s->source_output->module; 236 237 if (!owner_module) { 238 char *str = stream_to_string(s); 239 240 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have an owner module.", str); 241 pa_xfree(str); 242 243 return; 244 } 245 246 object_path = pa_dbusiface_core_get_module_path(s->core, owner_module); 247 248 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path); 249} 250 251static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata) { 252 pa_dbusiface_stream *s = userdata; 253 pa_client *client = NULL; 254 const char *object_path = NULL; 255 256 pa_assert(conn); 257 pa_assert(msg); 258 pa_assert(s); 259 260 client = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->client : s->source_output->client; 261 262 if (!client) { 263 char *str = stream_to_string(s); 264 265 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s isn't associated to any client.", str); 266 pa_xfree(str); 267 268 return; 269 } 270 271 object_path = pa_dbusiface_core_get_client_path(s->core, client); 272 273 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path); 274} 275 276static void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata) { 277 pa_dbusiface_stream *s = userdata; 278 const char *device = NULL; 279 280 pa_assert(conn); 281 pa_assert(msg); 282 pa_assert(s); 283 284 if (s->type == STREAM_TYPE_PLAYBACK) 285 device = pa_dbusiface_core_get_sink_path(s->core, s->sink); 286 else 287 device = pa_dbusiface_core_get_source_path(s->core, s->source); 288 289 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &device); 290} 291 292static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) { 293 pa_dbusiface_stream *s = userdata; 294 dbus_uint32_t sample_format = 0; 295 296 pa_assert(conn); 297 pa_assert(msg); 298 pa_assert(s); 299 300 sample_format = (s->type == STREAM_TYPE_PLAYBACK) 301 ? s->sink_input->sample_spec.format 302 : s->source_output->sample_spec.format; 303 304 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_format); 305} 306 307static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) { 308 pa_dbusiface_stream *s = userdata; 309 310 pa_assert(conn); 311 pa_assert(msg); 312 pa_assert(s); 313 314 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &s->sample_rate); 315} 316 317static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata) { 318 pa_dbusiface_stream *s = userdata; 319 pa_channel_map *channel_map = NULL; 320 dbus_uint32_t channels[PA_CHANNELS_MAX]; 321 unsigned i = 0; 322 323 pa_assert(conn); 324 pa_assert(msg); 325 pa_assert(s); 326 327 channel_map = (s->type == STREAM_TYPE_PLAYBACK) ? &s->sink_input->channel_map : &s->source_output->channel_map; 328 329 for (i = 0; i < channel_map->channels; ++i) 330 channels[i] = channel_map->map[i]; 331 332 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, channels, channel_map->channels); 333} 334 335static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) { 336 pa_dbusiface_stream *s = userdata; 337 dbus_uint32_t volume[PA_CHANNELS_MAX]; 338 unsigned i = 0; 339 340 pa_assert(conn); 341 pa_assert(msg); 342 pa_assert(s); 343 344 if (!s->has_volume) { 345 char *str = stream_to_string(s); 346 347 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str); 348 pa_xfree(str); 349 350 return; 351 } 352 353 for (i = 0; i < s->volume.channels; ++i) 354 volume[i] = s->volume.values[i]; 355 356 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, volume, s->volume.channels); 357} 358 359static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) { 360 pa_dbusiface_stream *s = userdata; 361 bool volume_writable = true; 362 DBusMessageIter array_iter; 363 int stream_channels = 0; 364 dbus_uint32_t *volume = NULL; 365 int n_volume_entries = 0; 366 pa_cvolume new_vol; 367 int i = 0; 368 369 pa_assert(conn); 370 pa_assert(msg); 371 pa_assert(iter); 372 pa_assert(s); 373 374 volume_writable = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->volume_writable : false; 375 376 if (!s->has_volume || !volume_writable) { 377 char *str = stream_to_string(s); 378 379 if (!s->has_volume) 380 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str); 381 else if (!volume_writable) 382 pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "%s has read-only volume.", str); 383 pa_xfree(str); 384 385 return; 386 } 387 388 stream_channels = s->sink_input->channel_map.channels; 389 390 dbus_message_iter_recurse(iter, &array_iter); 391 dbus_message_iter_get_fixed_array(&array_iter, &volume, &n_volume_entries); 392 393 if (n_volume_entries != stream_channels && n_volume_entries != 1) { 394 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, 395 "Expected %u volume entries, got %u.", stream_channels, n_volume_entries); 396 return; 397 } 398 399 pa_cvolume_init(&new_vol); 400 new_vol.channels = n_volume_entries; 401 402 for (i = 0; i < n_volume_entries; ++i) { 403 if (!PA_VOLUME_IS_VALID(volume[i])) { 404 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume: %u", volume[i]); 405 return; 406 } 407 new_vol.values[i] = volume[i]; 408 } 409 410 pa_sink_input_set_volume(s->sink_input, &new_vol, true, true); 411 412 pa_dbus_send_empty_reply(conn, msg); 413} 414 415static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) { 416 pa_dbusiface_stream *s = userdata; 417 418 pa_assert(conn); 419 pa_assert(msg); 420 pa_assert(s); 421 422 if (s->type == STREAM_TYPE_RECORD) { 423 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute."); 424 return; 425 } 426 427 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &s->mute); 428} 429 430static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) { 431 pa_dbusiface_stream *s = userdata; 432 dbus_bool_t mute = FALSE; 433 434 pa_assert(conn); 435 pa_assert(msg); 436 pa_assert(iter); 437 pa_assert(s); 438 439 dbus_message_iter_get_basic(iter, &mute); 440 441 if (s->type == STREAM_TYPE_RECORD) { 442 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute."); 443 return; 444 } 445 446 pa_sink_input_set_mute(s->sink_input, mute, true); 447 448 pa_dbus_send_empty_reply(conn, msg); 449} 450 451static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) { 452 pa_dbusiface_stream *s = userdata; 453 dbus_uint64_t buffer_latency = 0; 454 455 pa_assert(conn); 456 pa_assert(msg); 457 pa_assert(s); 458 459 if (s->type == STREAM_TYPE_PLAYBACK) 460 buffer_latency = pa_sink_input_get_latency(s->sink_input, NULL); 461 else 462 buffer_latency = pa_source_output_get_latency(s->source_output, NULL); 463 464 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &buffer_latency); 465} 466 467static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) { 468 pa_dbusiface_stream *s = userdata; 469 dbus_uint64_t device_latency = 0; 470 471 pa_assert(conn); 472 pa_assert(msg); 473 pa_assert(s); 474 475 if (s->type == STREAM_TYPE_PLAYBACK) 476 pa_sink_input_get_latency(s->sink_input, &device_latency); 477 else 478 pa_source_output_get_latency(s->source_output, &device_latency); 479 480 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &device_latency); 481} 482 483static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata) { 484 pa_dbusiface_stream *s = userdata; 485 const char *resample_method = NULL; 486 487 pa_assert(conn); 488 pa_assert(msg); 489 pa_assert(s); 490 491 if (s->type == STREAM_TYPE_PLAYBACK) 492 resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method); 493 else 494 resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method); 495 496 if (!resample_method) 497 resample_method = ""; 498 499 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &resample_method); 500} 501 502static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) { 503 pa_dbusiface_stream *s = userdata; 504 505 pa_assert(conn); 506 pa_assert(msg); 507 pa_assert(s); 508 509 pa_dbus_send_proplist_variant_reply(conn, msg, s->proplist); 510} 511 512static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) { 513 pa_dbusiface_stream *s = userdata; 514 DBusMessage *reply = NULL; 515 DBusMessageIter msg_iter; 516 DBusMessageIter dict_iter; 517 dbus_uint32_t idx = 0; 518 const char *driver = NULL; 519 pa_module *owner_module = NULL; 520 const char *owner_module_path = NULL; 521 pa_client *client = NULL; 522 const char *client_path = NULL; 523 const char *device = NULL; 524 dbus_uint32_t sample_format = 0; 525 pa_channel_map *channel_map = NULL; 526 dbus_uint32_t channels[PA_CHANNELS_MAX]; 527 dbus_uint32_t volume[PA_CHANNELS_MAX]; 528 dbus_uint64_t buffer_latency = 0; 529 dbus_uint64_t device_latency = 0; 530 const char *resample_method = NULL; 531 unsigned i = 0; 532 533 pa_assert(conn); 534 pa_assert(msg); 535 pa_assert(s); 536 537 if (s->has_volume) { 538 for (i = 0; i < s->volume.channels; ++i) 539 volume[i] = s->volume.values[i]; 540 } 541 542 if (s->type == STREAM_TYPE_PLAYBACK) { 543 idx = s->sink_input->index; 544 driver = s->sink_input->driver; 545 owner_module = s->sink_input->module; 546 client = s->sink_input->client; 547 device = pa_dbusiface_core_get_sink_path(s->core, s->sink); 548 sample_format = s->sink_input->sample_spec.format; 549 channel_map = &s->sink_input->channel_map; 550 buffer_latency = pa_sink_input_get_latency(s->sink_input, &device_latency); 551 resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method); 552 } else { 553 idx = s->source_output->index; 554 driver = s->source_output->driver; 555 owner_module = s->source_output->module; 556 client = s->source_output->client; 557 device = pa_dbusiface_core_get_source_path(s->core, s->source); 558 sample_format = s->source_output->sample_spec.format; 559 channel_map = &s->source_output->channel_map; 560 buffer_latency = pa_source_output_get_latency(s->source_output, &device_latency); 561 resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method); 562 } 563 if (owner_module) 564 owner_module_path = pa_dbusiface_core_get_module_path(s->core, owner_module); 565 if (client) 566 client_path = pa_dbusiface_core_get_client_path(s->core, client); 567 for (i = 0; i < channel_map->channels; ++i) 568 channels[i] = channel_map->map[i]; 569 if (!resample_method) 570 resample_method = ""; 571 572 pa_assert_se((reply = dbus_message_new_method_return(msg))); 573 574 dbus_message_iter_init_append(reply, &msg_iter); 575 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)); 576 577 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx); 578 579 if (driver) 580 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &driver); 581 582 if (owner_module) 583 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module_path); 584 585 if (client) 586 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CLIENT].property_name, DBUS_TYPE_OBJECT_PATH, &client_path); 587 588 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE].property_name, DBUS_TYPE_OBJECT_PATH, &device); 589 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format); 590 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &s->sample_rate); 591 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, channel_map->channels); 592 593 if (s->has_volume) { 594 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, s->volume.channels); 595 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &s->mute); 596 } 597 598 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BUFFER_LATENCY].property_name, DBUS_TYPE_UINT64, &buffer_latency); 599 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE_LATENCY].property_name, DBUS_TYPE_UINT64, &device_latency); 600 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_RESAMPLE_METHOD].property_name, DBUS_TYPE_STRING, &resample_method); 601 pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, s->proplist); 602 603 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter)); 604 pa_assert_se(dbus_connection_send(conn, reply, NULL)); 605 dbus_message_unref(reply); 606} 607 608static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata) { 609 pa_dbusiface_stream *s = userdata; 610 const char *device = NULL; 611 612 pa_assert(conn); 613 pa_assert(msg); 614 pa_assert(s); 615 616 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device, DBUS_TYPE_INVALID)); 617 618 if (s->type == STREAM_TYPE_PLAYBACK) { 619 pa_sink *sink = pa_dbusiface_core_get_sink(s->core, device); 620 621 if (!sink) { 622 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", device); 623 return; 624 } 625 626 if (pa_sink_input_move_to(s->sink_input, sink, true) < 0) { 627 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, 628 "Moving playback stream %u to sink %s failed.", s->sink_input->index, sink->name); 629 return; 630 } 631 } else { 632 pa_source *source = pa_dbusiface_core_get_source(s->core, device); 633 634 if (!source) { 635 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", device); 636 return; 637 } 638 639 if (pa_source_output_move_to(s->source_output, source, true) < 0) { 640 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, 641 "Moving record stream %u to source %s failed.", s->source_output->index, source->name); 642 return; 643 } 644 } 645 646 pa_dbus_send_empty_reply(conn, msg); 647} 648 649static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata) { 650 pa_dbusiface_stream *s = userdata; 651 652 pa_assert(conn); 653 pa_assert(msg); 654 pa_assert(s); 655 656 if (s->type == STREAM_TYPE_PLAYBACK) 657 pa_sink_input_kill(s->sink_input); 658 else 659 pa_source_output_kill(s->source_output); 660 661 pa_dbus_send_empty_reply(conn, msg); 662} 663 664static void check_and_signal_rate(pa_dbusiface_stream *s) { 665 DBusMessage *signal_msg = NULL; 666 uint32_t new_sample_rate = 0; 667 668 pa_assert(s); 669 670 new_sample_rate = (s->type == STREAM_TYPE_PLAYBACK) 671 ? s->sink_input->sample_spec.rate 672 : s->source_output->sample_spec.rate; 673 674 if (s->sample_rate != new_sample_rate) { 675 s->sample_rate = new_sample_rate; 676 677 pa_assert_se(signal_msg = dbus_message_new_signal(s->path, 678 PA_DBUSIFACE_STREAM_INTERFACE, 679 signals[SIGNAL_SAMPLE_RATE_UPDATED].name)); 680 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID)); 681 682 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); 683 dbus_message_unref(signal_msg); 684 } 685} 686 687static pa_hook_result_t move_finish_cb(void *hook_data, void *call_data, void *slot_data) { 688 pa_dbusiface_stream *s = slot_data; 689 const char *new_device_path = NULL; 690 DBusMessage *signal_msg = NULL; 691 692 if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) || 693 (s->type == STREAM_TYPE_RECORD && s->source_output != call_data)) 694 return PA_HOOK_OK; 695 696 if (s->type == STREAM_TYPE_PLAYBACK) { 697 pa_sink *new_sink = s->sink_input->sink; 698 699 if (s->sink != new_sink) { 700 pa_sink_unref(s->sink); 701 s->sink = pa_sink_ref(new_sink); 702 703 new_device_path = pa_dbusiface_core_get_sink_path(s->core, new_sink); 704 705 pa_assert_se(signal_msg = dbus_message_new_signal(s->path, 706 PA_DBUSIFACE_STREAM_INTERFACE, 707 signals[SIGNAL_DEVICE_UPDATED].name)); 708 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID)); 709 710 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); 711 dbus_message_unref(signal_msg); 712 } 713 } else { 714 pa_source *new_source = s->source_output->source; 715 716 if (s->source != new_source) { 717 pa_source_unref(s->source); 718 s->source = pa_source_ref(new_source); 719 720 new_device_path = pa_dbusiface_core_get_source_path(s->core, new_source); 721 722 pa_assert_se(signal_msg = dbus_message_new_signal(s->path, 723 PA_DBUSIFACE_STREAM_INTERFACE, 724 signals[SIGNAL_DEVICE_UPDATED].name)); 725 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID)); 726 727 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); 728 dbus_message_unref(signal_msg); 729 } 730 } 731 732 check_and_signal_rate(s); 733 734 return PA_HOOK_OK; 735} 736 737static pa_hook_result_t volume_changed_cb(void *hook_data, void *call_data, void *slot_data) { 738 pa_dbusiface_stream *s = slot_data; 739 DBusMessage *signal_msg = NULL; 740 unsigned i = 0; 741 742 if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) || 743 (s->type == STREAM_TYPE_RECORD && s->source_output != call_data)) 744 return PA_HOOK_OK; 745 746 if (s->type == STREAM_TYPE_PLAYBACK && s->has_volume) { 747 pa_cvolume new_volume; 748 749 pa_sink_input_get_volume(s->sink_input, &new_volume, true); 750 751 if (!pa_cvolume_equal(&s->volume, &new_volume)) { 752 dbus_uint32_t volume[PA_CHANNELS_MAX]; 753 dbus_uint32_t *volume_ptr = volume; 754 755 s->volume = new_volume; 756 757 for (i = 0; i < s->volume.channels; ++i) 758 volume[i] = s->volume.values[i]; 759 760 pa_assert_se(signal_msg = dbus_message_new_signal(s->path, 761 PA_DBUSIFACE_STREAM_INTERFACE, 762 signals[SIGNAL_VOLUME_UPDATED].name)); 763 pa_assert_se(dbus_message_append_args(signal_msg, 764 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels, 765 DBUS_TYPE_INVALID)); 766 767 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); 768 dbus_message_unref(signal_msg); 769 } 770 } 771 772 return PA_HOOK_OK; 773} 774 775static pa_hook_result_t mute_changed_cb(void *hook_data, void *call_data, void *slot_data) { 776 pa_dbusiface_stream *s = slot_data; 777 DBusMessage *signal_msg = NULL; 778 779 if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) || 780 (s->type == STREAM_TYPE_RECORD && s->source_output != call_data)) 781 return PA_HOOK_OK; 782 783 if (s->type == STREAM_TYPE_PLAYBACK) { 784 bool new_mute = false; 785 786 new_mute = s->sink_input->muted; 787 788 if (s->mute != new_mute) { 789 s->mute = new_mute; 790 791 pa_assert_se(signal_msg = dbus_message_new_signal(s->path, 792 PA_DBUSIFACE_STREAM_INTERFACE, 793 signals[SIGNAL_MUTE_UPDATED].name)); 794 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &s->mute, DBUS_TYPE_INVALID)); 795 796 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); 797 dbus_message_unref(signal_msg); 798 signal_msg = NULL; 799 } 800 } 801 802 return PA_HOOK_OK; 803} 804 805static pa_hook_result_t proplist_changed_cb(void *hook_data, void *call_data, void *slot_data) { 806 pa_dbusiface_stream *s = slot_data; 807 DBusMessage *signal_msg = NULL; 808 pa_proplist *new_proplist = NULL; 809 810 if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) || 811 (s->type == STREAM_TYPE_RECORD && s->source_output != call_data)) 812 return PA_HOOK_OK; 813 814 new_proplist = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->proplist : s->source_output->proplist; 815 816 if (!pa_proplist_equal(s->proplist, new_proplist)) { 817 DBusMessageIter msg_iter; 818 819 pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist); 820 821 pa_assert_se(signal_msg = dbus_message_new_signal(s->path, 822 PA_DBUSIFACE_STREAM_INTERFACE, 823 signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); 824 dbus_message_iter_init_append(signal_msg, &msg_iter); 825 pa_dbus_append_proplist(&msg_iter, s->proplist); 826 827 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); 828 dbus_message_unref(signal_msg); 829 } 830 831 return PA_HOOK_OK; 832} 833 834static pa_hook_result_t state_changed_cb(void *hook_data, void *call_data, void *slot_data) { 835 pa_dbusiface_stream *s = slot_data; 836 837 pa_assert(s); 838 839 if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) || 840 (s->type == STREAM_TYPE_RECORD && s->source_output != call_data)) 841 return PA_HOOK_OK; 842 843 check_and_signal_rate(s); 844 845 return PA_HOOK_OK; 846} 847 848static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *slot_data) { 849 pa_dbusiface_stream *s = slot_data; 850 DBusMessage *signal_msg = NULL; 851 DBusMessageIter msg_iter; 852 const char *name = NULL; 853 pa_proplist *property_list = NULL; 854 855 pa_assert(call_data); 856 pa_assert(s); 857 858 if (s->type == STREAM_TYPE_PLAYBACK) { 859 pa_sink_input_send_event_hook_data *data = call_data; 860 861 if (data->sink_input != s->sink_input) 862 return PA_HOOK_OK; 863 864 name = data->event; 865 property_list = data->data; 866 } else { 867 pa_source_output_send_event_hook_data *data = call_data; 868 869 if (data->source_output != s->source_output) 870 return PA_HOOK_OK; 871 872 name = data->event; 873 property_list = data->data; 874 } 875 876 pa_assert_se(signal_msg = dbus_message_new_signal(s->path, 877 PA_DBUSIFACE_STREAM_INTERFACE, 878 signals[SIGNAL_STREAM_EVENT].name)); 879 dbus_message_iter_init_append(signal_msg, &msg_iter); 880 pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name)); 881 pa_dbus_append_proplist(&msg_iter, property_list); 882 883 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); 884 dbus_message_unref(signal_msg); 885 886 return PA_HOOK_OK; 887} 888 889pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, pa_sink_input *sink_input) { 890 pa_dbusiface_stream *s; 891 892 pa_assert(core); 893 pa_assert(sink_input); 894 895 s = pa_xnew(pa_dbusiface_stream, 1); 896 s->core = core; 897 s->sink_input = pa_sink_input_ref(sink_input); 898 s->type = STREAM_TYPE_PLAYBACK; 899 s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, PLAYBACK_OBJECT_NAME, sink_input->index); 900 s->sink = pa_sink_ref(sink_input->sink); 901 s->sample_rate = sink_input->sample_spec.rate; 902 s->has_volume = pa_sink_input_is_volume_readable(sink_input); 903 904 if (s->has_volume) 905 pa_sink_input_get_volume(sink_input, &s->volume, true); 906 else 907 pa_cvolume_init(&s->volume); 908 909 s->mute = sink_input->muted; 910 s->proplist = pa_proplist_copy(sink_input->proplist); 911 s->dbus_protocol = pa_dbus_protocol_get(sink_input->core); 912 s->send_event_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT], 913 PA_HOOK_NORMAL, 914 send_event_cb, 915 s); 916 s->move_finish_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], 917 PA_HOOK_NORMAL, move_finish_cb, s); 918 s->volume_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED], 919 PA_HOOK_NORMAL, volume_changed_cb, s); 920 s->mute_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED], 921 PA_HOOK_NORMAL, mute_changed_cb, s); 922 s->proplist_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], 923 PA_HOOK_NORMAL, proplist_changed_cb, s); 924 s->state_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], 925 PA_HOOK_NORMAL, state_changed_cb, s); 926 927 pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0); 928 929 return s; 930} 931 932pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_source_output *source_output) { 933 pa_dbusiface_stream *s; 934 935 pa_assert(core); 936 pa_assert(source_output); 937 938 s = pa_xnew(pa_dbusiface_stream, 1); 939 s->core = core; 940 s->source_output = pa_source_output_ref(source_output); 941 s->type = STREAM_TYPE_RECORD; 942 s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, RECORD_OBJECT_NAME, source_output->index); 943 s->source = pa_source_ref(source_output->source); 944 s->sample_rate = source_output->sample_spec.rate; 945 pa_cvolume_init(&s->volume); 946 s->mute = false; 947 s->proplist = pa_proplist_copy(source_output->proplist); 948 s->has_volume = false; 949 s->dbus_protocol = pa_dbus_protocol_get(source_output->core); 950 s->send_event_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT], 951 PA_HOOK_NORMAL, 952 send_event_cb, 953 s); 954 s->move_finish_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], 955 PA_HOOK_NORMAL, move_finish_cb, s); 956 s->volume_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED], 957 PA_HOOK_NORMAL, volume_changed_cb, s); 958 s->mute_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED], 959 PA_HOOK_NORMAL, mute_changed_cb, s); 960 s->proplist_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], 961 PA_HOOK_NORMAL, proplist_changed_cb, s); 962 s->state_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], 963 PA_HOOK_NORMAL, state_changed_cb, s); 964 965 pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0); 966 967 return s; 968} 969 970void pa_dbusiface_stream_free(pa_dbusiface_stream *s) { 971 pa_assert(s); 972 973 pa_assert_se(pa_dbus_protocol_remove_interface(s->dbus_protocol, s->path, stream_interface_info.name) >= 0); 974 975 if (s->type == STREAM_TYPE_PLAYBACK) { 976 pa_sink_input_unref(s->sink_input); 977 pa_sink_unref(s->sink); 978 } else { 979 pa_source_output_unref(s->source_output); 980 pa_source_unref(s->source); 981 } 982 983 pa_proplist_free(s->proplist); 984 pa_dbus_protocol_unref(s->dbus_protocol); 985 pa_hook_slot_free(s->send_event_slot); 986 pa_hook_slot_free(s->move_finish_slot); 987 pa_hook_slot_free(s->volume_changed_slot); 988 pa_hook_slot_free(s->mute_changed_slot); 989 pa_hook_slot_free(s->proplist_changed_slot); 990 pa_hook_slot_free(s->state_changed_slot); 991 992 pa_xfree(s->path); 993 pa_xfree(s); 994} 995 996const char *pa_dbusiface_stream_get_path(pa_dbusiface_stream *s) { 997 pa_assert(s); 998 999 return s->path; 1000} 1001