2 This file is part of PulseAudio.
4 Copyright 2009 Tanu Kaskinen
5 Copyright 2009 Vincent Filali-Ansary <filali.v@azurdigitalnetworks.net>
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.
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.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 #include <pulsecore/core-util.h>
28 #include <pulsecore/dbus-util.h>
29 #include <pulsecore/protocol-dbus.h>
31 #include "iface-stream.h"
33 #define PLAYBACK_OBJECT_NAME "playback_stream"
34 #define RECORD_OBJECT_NAME "record_stream"
41 struct pa_dbusiface_stream {
42 pa_dbusiface_core *core;
45 pa_sink_input *sink_input;
46 pa_source_output *source_output;
48 enum stream_type type;
57 pa_proplist *proplist;
60 pa_bool_t read_only_volume;
62 pa_dbus_protocol *dbus_protocol;
63 pa_subscription *subscription;
64 pa_hook_slot *send_event_slot;
67 static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
68 static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata);
69 static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata);
70 static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata);
71 static void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
72 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
73 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
74 static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);
75 static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
76 static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
77 static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
78 static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
79 static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
80 static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
81 static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata);
82 static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
84 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
86 static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata);
87 static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata);
89 enum property_handler_index {
90 PROPERTY_HANDLER_INDEX,
91 PROPERTY_HANDLER_DRIVER,
92 PROPERTY_HANDLER_OWNER_MODULE,
93 PROPERTY_HANDLER_CLIENT,
94 PROPERTY_HANDLER_DEVICE,
95 PROPERTY_HANDLER_SAMPLE_FORMAT,
96 PROPERTY_HANDLER_SAMPLE_RATE,
97 PROPERTY_HANDLER_CHANNELS,
98 PROPERTY_HANDLER_VOLUME,
99 PROPERTY_HANDLER_MUTE,
100 PROPERTY_HANDLER_BUFFER_LATENCY,
101 PROPERTY_HANDLER_DEVICE_LATENCY,
102 PROPERTY_HANDLER_RESAMPLE_METHOD,
103 PROPERTY_HANDLER_PROPERTY_LIST,
107 static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
108 [PROPERTY_HANDLER_INDEX] = { .property_name = "Index", .type = "u", .get_cb = handle_get_index, .set_cb = NULL },
109 [PROPERTY_HANDLER_DRIVER] = { .property_name = "Driver", .type = "s", .get_cb = handle_get_driver, .set_cb = NULL },
110 [PROPERTY_HANDLER_OWNER_MODULE] = { .property_name = "OwnerModule", .type = "o", .get_cb = handle_get_owner_module, .set_cb = NULL },
111 [PROPERTY_HANDLER_CLIENT] = { .property_name = "Client", .type = "o", .get_cb = handle_get_client, .set_cb = NULL },
112 [PROPERTY_HANDLER_DEVICE] = { .property_name = "Device", .type = "o", .get_cb = handle_get_device, .set_cb = NULL },
113 [PROPERTY_HANDLER_SAMPLE_FORMAT] = { .property_name = "SampleFormat", .type = "u", .get_cb = handle_get_sample_format, .set_cb = NULL },
114 [PROPERTY_HANDLER_SAMPLE_RATE] = { .property_name = "SampleRate", .type = "u", .get_cb = handle_get_sample_rate, .set_cb = NULL },
115 [PROPERTY_HANDLER_CHANNELS] = { .property_name = "Channels", .type = "au", .get_cb = handle_get_channels, .set_cb = NULL },
116 [PROPERTY_HANDLER_VOLUME] = { .property_name = "Volume", .type = "au", .get_cb = handle_get_volume, .set_cb = handle_set_volume },
117 [PROPERTY_HANDLER_MUTE] = { .property_name = "Mute", .type = "b", .get_cb = handle_get_mute, .set_cb = handle_set_mute },
118 [PROPERTY_HANDLER_BUFFER_LATENCY] = { .property_name = "BufferLatency", .type = "t", .get_cb = handle_get_buffer_latency, .set_cb = NULL },
119 [PROPERTY_HANDLER_DEVICE_LATENCY] = { .property_name = "DeviceLatency", .type = "t", .get_cb = handle_get_device_latency, .set_cb = NULL },
120 [PROPERTY_HANDLER_RESAMPLE_METHOD] = { .property_name = "ResampleMethod", .type = "s", .get_cb = handle_get_resample_method, .set_cb = NULL },
121 [PROPERTY_HANDLER_PROPERTY_LIST] = { .property_name = "PropertyList", .type = "a{say}", .get_cb = handle_get_property_list, .set_cb = NULL }
124 enum method_handler_index {
130 static pa_dbus_arg_info move_args[] = { { "device", "o", "in" } };
132 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
133 [METHOD_HANDLER_MOVE] = {
134 .method_name = "Move",
135 .arguments = move_args,
136 .n_arguments = sizeof(move_args) / sizeof(pa_dbus_arg_info),
137 .receive_cb = handle_move },
138 [METHOD_HANDLER_KILL] = {
139 .method_name = "Kill",
142 .receive_cb = handle_kill }
146 SIGNAL_DEVICE_UPDATED,
147 SIGNAL_SAMPLE_RATE_UPDATED,
148 SIGNAL_VOLUME_UPDATED,
150 SIGNAL_PROPERTY_LIST_UPDATED,
155 static pa_dbus_arg_info device_updated_args[] = { { "device", "o", NULL } };
156 static pa_dbus_arg_info sample_rate_updated_args[] = { { "sample_rate", "u", NULL } };
157 static pa_dbus_arg_info volume_updated_args[] = { { "volume", "au", NULL } };
158 static pa_dbus_arg_info mute_updated_args[] = { { "muted", "b", NULL } };
159 static pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } };
160 static pa_dbus_arg_info stream_event_args[] = { { "name", "s", NULL }, { "property_list", "a{say}", NULL } };
162 static pa_dbus_signal_info signals[SIGNAL_MAX] = {
163 [SIGNAL_DEVICE_UPDATED] = { .name = "DeviceUpdated", .arguments = device_updated_args, .n_arguments = 1 },
164 [SIGNAL_SAMPLE_RATE_UPDATED] = { .name = "SampleRateUpdated", .arguments = sample_rate_updated_args, .n_arguments = 1 },
165 [SIGNAL_VOLUME_UPDATED] = { .name = "VolumeUpdated", .arguments = volume_updated_args, .n_arguments = 1 },
166 [SIGNAL_MUTE_UPDATED] = { .name = "MuteUpdated", .arguments = mute_updated_args, .n_arguments = 1 },
167 [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 },
168 [SIGNAL_STREAM_EVENT] = { .name = "StreamEvent", .arguments = stream_event_args, .n_arguments = sizeof(stream_event_args) / sizeof(pa_dbus_arg_info) }
171 static pa_dbus_interface_info stream_interface_info = {
172 .name = PA_DBUSIFACE_STREAM_INTERFACE,
173 .method_handlers = method_handlers,
174 .n_method_handlers = METHOD_HANDLER_MAX,
175 .property_handlers = property_handlers,
176 .n_property_handlers = PROPERTY_HANDLER_MAX,
177 .get_all_properties_cb = handle_get_all,
179 .n_signals = SIGNAL_MAX
182 static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
183 pa_dbusiface_stream *s = userdata;
190 idx = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->index : s->source_output->index;
192 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
195 /* The returned string has to be freed with pa_xfree() by the caller. */
196 static char *stream_to_string(pa_dbusiface_stream *s) {
197 if (s->type == STREAM_TYPE_PLAYBACK)
198 return pa_sprintf_malloc("Playback stream %u", (unsigned) s->sink_input->index);
200 return pa_sprintf_malloc("Record stream %u", (unsigned) s->source_output->index);
203 static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) {
204 pa_dbusiface_stream *s = userdata;
205 const char *driver = NULL;
211 driver = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->driver : s->source_output->driver;
214 char *str = stream_to_string(s);
216 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have a driver.", str);
222 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &driver);
225 static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata) {
226 pa_dbusiface_stream *s = userdata;
227 pa_module *owner_module = NULL;
228 const char *object_path = NULL;
234 owner_module = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->module : s->source_output->module;
237 char *str = stream_to_string(s);
239 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have an owner module.", str);
245 object_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
247 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
250 static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata) {
251 pa_dbusiface_stream *s = userdata;
252 pa_client *client = NULL;
253 const char *object_path = NULL;
259 client = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->client : s->source_output->client;
262 char *str = stream_to_string(s);
264 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s isn't associated to any client.", str);
270 object_path = pa_dbusiface_core_get_client_path(s->core, client);
272 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
275 static void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
276 pa_dbusiface_stream *s = userdata;
277 const char *device = NULL;
283 if (s->type == STREAM_TYPE_PLAYBACK)
284 device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
286 device = pa_dbusiface_core_get_source_path(s->core, s->source);
288 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &device);
291 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
292 pa_dbusiface_stream *s = userdata;
293 dbus_uint32_t sample_format = 0;
299 sample_format = (s->type == STREAM_TYPE_PLAYBACK)
300 ? s->sink_input->sample_spec.format
301 : s->source_output->sample_spec.format;
303 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_format);
306 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
307 pa_dbusiface_stream *s = userdata;
313 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &s->sample_rate);
316 static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata) {
317 pa_dbusiface_stream *s = userdata;
318 pa_channel_map *channel_map = NULL;
319 dbus_uint32_t channels[PA_CHANNELS_MAX];
326 channel_map = (s->type == STREAM_TYPE_PLAYBACK) ? &s->sink_input->channel_map : &s->source_output->channel_map;
328 for (i = 0; i < channel_map->channels; ++i)
329 channels[i] = channel_map->map[i];
331 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, channels, channel_map->channels);
334 static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
335 pa_dbusiface_stream *s = userdata;
336 dbus_uint32_t volume[PA_CHANNELS_MAX];
343 if (!s->has_volume) {
344 char *str = stream_to_string(s);
346 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str);
352 for (i = 0; i < s->volume.channels; ++i)
353 volume[i] = s->volume.values[i];
355 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, volume, s->volume.channels);
358 static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
359 pa_dbusiface_stream *s = userdata;
360 DBusMessageIter array_iter;
361 int stream_channels = 0;
362 dbus_uint32_t *volume = NULL;
363 int n_volume_entries = 0;
372 if (!s->has_volume || s->read_only_volume) {
373 char *str = stream_to_string(s);
376 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str);
377 else if (s->read_only_volume)
378 pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "%s has read-only volume.", str);
384 pa_cvolume_init(&new_vol);
386 stream_channels = s->sink_input->channel_map.channels;
388 new_vol.channels = stream_channels;
390 dbus_message_iter_recurse(iter, &array_iter);
391 dbus_message_iter_get_fixed_array(&array_iter, &volume, &n_volume_entries);
393 if (n_volume_entries != stream_channels) {
394 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
395 "Expected %u volume entries, got %u.", stream_channels, n_volume_entries);
399 for (i = 0; i < n_volume_entries; ++i) {
400 if (!PA_VOLUME_IS_VALID(volume[i])) {
401 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume: %u", volume[i]);
404 new_vol.values[i] = volume[i];
407 pa_sink_input_set_volume(s->sink_input, &new_vol, TRUE, TRUE);
409 pa_dbus_send_empty_reply(conn, msg);
412 static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
413 pa_dbusiface_stream *s = userdata;
419 if (s->type == STREAM_TYPE_RECORD) {
420 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
424 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &s->mute);
427 static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
428 pa_dbusiface_stream *s = userdata;
429 dbus_bool_t mute = FALSE;
436 dbus_message_iter_get_basic(iter, &mute);
438 if (s->type == STREAM_TYPE_RECORD) {
439 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
443 pa_sink_input_set_mute(s->sink_input, mute, TRUE);
445 pa_dbus_send_empty_reply(conn, msg);
448 static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
449 pa_dbusiface_stream *s = userdata;
450 dbus_uint64_t buffer_latency = 0;
456 if (s->type == STREAM_TYPE_PLAYBACK)
457 buffer_latency = pa_sink_input_get_latency(s->sink_input, NULL);
459 buffer_latency = pa_source_output_get_latency(s->source_output, NULL);
461 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &buffer_latency);
464 static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
465 pa_dbusiface_stream *s = userdata;
466 dbus_uint64_t device_latency = 0;
472 if (s->type == STREAM_TYPE_PLAYBACK)
473 pa_sink_input_get_latency(s->sink_input, &device_latency);
475 pa_source_output_get_latency(s->source_output, &device_latency);
477 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &device_latency);
480 static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata) {
481 pa_dbusiface_stream *s = userdata;
482 const char *resample_method = NULL;
488 if (s->type == STREAM_TYPE_PLAYBACK)
489 resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
491 resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
493 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &resample_method);
496 static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
497 pa_dbusiface_stream *s = userdata;
503 pa_dbus_send_proplist_variant_reply(conn, msg, s->proplist);
506 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
507 pa_dbusiface_stream *s = userdata;
508 DBusMessage *reply = NULL;
509 DBusMessageIter msg_iter;
510 DBusMessageIter dict_iter;
511 dbus_uint32_t idx = 0;
512 const char *driver = NULL;
513 pa_module *owner_module = NULL;
514 const char *owner_module_path = NULL;
515 pa_client *client = NULL;
516 const char *client_path = NULL;
517 const char *device = NULL;
518 dbus_uint32_t sample_format = 0;
519 pa_channel_map *channel_map = NULL;
520 dbus_uint32_t channels[PA_CHANNELS_MAX];
521 dbus_uint32_t volume[PA_CHANNELS_MAX];
522 dbus_uint64_t buffer_latency = 0;
523 dbus_uint64_t device_latency = 0;
524 const char *resample_method = NULL;
532 for (i = 0; i < s->volume.channels; ++i)
533 volume[i] = s->volume.values[i];
536 if (s->type == STREAM_TYPE_PLAYBACK) {
537 idx = s->sink_input->index;
538 driver = s->sink_input->driver;
539 owner_module = s->sink_input->module;
540 client = s->sink_input->client;
541 device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
542 sample_format = s->sink_input->sample_spec.format;
543 channel_map = &s->sink_input->channel_map;
544 buffer_latency = pa_sink_input_get_latency(s->sink_input, &device_latency);
545 resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
547 idx = s->source_output->index;
548 driver = s->source_output->driver;
549 owner_module = s->source_output->module;
550 client = s->source_output->client;
551 device = pa_dbusiface_core_get_source_path(s->core, s->source);
552 sample_format = s->source_output->sample_spec.format;
553 channel_map = &s->source_output->channel_map;
554 buffer_latency = pa_source_output_get_latency(s->source_output, &device_latency);
555 resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
558 owner_module_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
560 client_path = pa_dbusiface_core_get_client_path(s->core, client);
561 for (i = 0; i < channel_map->channels; ++i)
562 channels[i] = channel_map->map[i];
564 pa_assert_se((reply = dbus_message_new_method_return(msg)));
566 dbus_message_iter_init_append(reply, &msg_iter);
567 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
569 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
572 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &driver);
575 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module_path);
578 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CLIENT].property_name, DBUS_TYPE_OBJECT_PATH, &client_path);
580 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE].property_name, DBUS_TYPE_OBJECT_PATH, &device);
581 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format);
582 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &s->sample_rate);
583 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, channel_map->channels);
586 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, s->volume.channels);
587 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &s->mute);
590 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BUFFER_LATENCY].property_name, DBUS_TYPE_UINT64, &buffer_latency);
591 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE_LATENCY].property_name, DBUS_TYPE_UINT64, &device_latency);
592 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_RESAMPLE_METHOD].property_name, DBUS_TYPE_STRING, &resample_method);
593 pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, s->proplist);
595 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
596 pa_assert_se(dbus_connection_send(conn, reply, NULL));
597 dbus_message_unref(reply);
600 static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata) {
601 pa_dbusiface_stream *s = userdata;
602 const char *device = NULL;
608 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID));
610 if (s->type == STREAM_TYPE_PLAYBACK) {
611 pa_sink *sink = pa_dbusiface_core_get_sink(s->core, device);
614 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", device);
618 if (pa_sink_input_move_to(s->sink_input, sink, TRUE) < 0) {
619 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
620 "Moving playback stream %u to sink %s failed.", s->sink_input->index, sink->name);
624 pa_source *source = pa_dbusiface_core_get_source(s->core, device);
627 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", device);
631 if (pa_source_output_move_to(s->source_output, source, TRUE) < 0) {
632 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
633 "Moving record stream %u to source %s failed.", s->source_output->index, source->name);
638 pa_dbus_send_empty_reply(conn, msg);
641 static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata) {
642 pa_dbusiface_stream *s = userdata;
648 if (s->type == STREAM_TYPE_PLAYBACK)
649 pa_sink_input_kill(s->sink_input);
651 pa_source_output_kill(s->source_output);
653 pa_dbus_send_empty_reply(conn, msg);
656 static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
657 pa_dbusiface_stream *s = userdata;
658 DBusMessage *signal_msg = NULL;
659 const char *new_device_path = NULL;
660 uint32_t new_sample_rate = 0;
661 pa_proplist *new_proplist = NULL;
667 if ((s->type == STREAM_TYPE_PLAYBACK && idx != s->sink_input->index)
668 || (s->type == STREAM_TYPE_RECORD && idx != s->source_output->index))
671 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
674 pa_assert(((s->type == STREAM_TYPE_PLAYBACK)
675 && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT))
676 || ((s->type == STREAM_TYPE_RECORD)
677 && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT)));
679 if (s->type == STREAM_TYPE_PLAYBACK) {
680 pa_sink *new_sink = s->sink_input->sink;
682 if (s->sink != new_sink) {
683 pa_sink_unref(s->sink);
684 s->sink = pa_sink_ref(new_sink);
686 new_device_path = pa_dbusiface_core_get_sink_path(s->core, new_sink);
688 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
689 PA_DBUSIFACE_STREAM_INTERFACE,
690 signals[SIGNAL_DEVICE_UPDATED].name));
691 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
693 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
694 dbus_message_unref(signal_msg);
698 pa_source *new_source = s->source_output->source;
700 if (s->source != new_source) {
701 pa_source_unref(s->source);
702 s->source = pa_source_ref(new_source);
704 new_device_path = pa_dbusiface_core_get_source_path(s->core, new_source);
706 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
707 PA_DBUSIFACE_STREAM_INTERFACE,
708 signals[SIGNAL_DEVICE_UPDATED].name));
709 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
711 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
712 dbus_message_unref(signal_msg);
717 new_sample_rate = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->sample_spec.rate : s->source_output->sample_spec.rate;
719 if (s->sample_rate != new_sample_rate) {
720 s->sample_rate = new_sample_rate;
722 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
723 PA_DBUSIFACE_STREAM_INTERFACE,
724 signals[SIGNAL_SAMPLE_RATE_UPDATED].name));
725 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID));
727 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
728 dbus_message_unref(signal_msg);
732 if (s->type == STREAM_TYPE_PLAYBACK) {
733 pa_bool_t new_mute = FALSE;
736 pa_cvolume new_volume;
738 pa_sink_input_get_volume(s->sink_input, &new_volume, TRUE);
740 if (!pa_cvolume_equal(&s->volume, &new_volume)) {
741 dbus_uint32_t volume[PA_CHANNELS_MAX];
742 dbus_uint32_t *volume_ptr = volume;
744 s->volume = new_volume;
746 for (i = 0; i < s->volume.channels; ++i)
747 volume[i] = s->volume.values[i];
749 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
750 PA_DBUSIFACE_STREAM_INTERFACE,
751 signals[SIGNAL_VOLUME_UPDATED].name));
752 pa_assert_se(dbus_message_append_args(signal_msg,
753 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
756 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
757 dbus_message_unref(signal_msg);
762 new_mute = pa_sink_input_get_mute(s->sink_input);
764 if (s->mute != new_mute) {
767 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
768 PA_DBUSIFACE_STREAM_INTERFACE,
769 signals[SIGNAL_MUTE_UPDATED].name));
770 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &s->mute, DBUS_TYPE_INVALID));
772 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
773 dbus_message_unref(signal_msg);
778 new_proplist = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->proplist : s->source_output->proplist;
780 if (!pa_proplist_equal(s->proplist, new_proplist)) {
781 DBusMessageIter msg_iter;
783 pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist);
785 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
786 PA_DBUSIFACE_STREAM_INTERFACE,
787 signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
788 dbus_message_iter_init_append(signal_msg, &msg_iter);
789 pa_dbus_append_proplist(&msg_iter, s->proplist);
791 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
792 dbus_message_unref(signal_msg);
797 static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *slot_data) {
798 pa_dbusiface_stream *s = slot_data;
799 DBusMessage *signal_msg = NULL;
800 DBusMessageIter msg_iter;
801 const char *name = NULL;
802 pa_proplist *property_list = NULL;
804 pa_assert(call_data);
807 if (s->type == STREAM_TYPE_PLAYBACK) {
808 pa_sink_input_send_event_hook_data *data = call_data;
810 if (data->sink_input != s->sink_input)
814 property_list = data->data;
816 pa_source_output_send_event_hook_data *data = call_data;
818 if (data->source_output != s->source_output)
822 property_list = data->data;
825 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
826 PA_DBUSIFACE_STREAM_INTERFACE,
827 signals[SIGNAL_STREAM_EVENT].name));
828 dbus_message_iter_init_append(signal_msg, &msg_iter);
829 pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name));
830 pa_dbus_append_proplist(&msg_iter, property_list);
832 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
833 dbus_message_unref(signal_msg);
838 pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, pa_sink_input *sink_input) {
839 pa_dbusiface_stream *s;
842 pa_assert(sink_input);
844 s = pa_xnew(pa_dbusiface_stream, 1);
846 s->sink_input = pa_sink_input_ref(sink_input);
847 s->type = STREAM_TYPE_PLAYBACK;
848 s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, PLAYBACK_OBJECT_NAME, sink_input->index);
849 s->sink = pa_sink_ref(sink_input->sink);
850 s->sample_rate = sink_input->sample_spec.rate;
851 s->has_volume = pa_sink_input_is_volume_readable(sink_input);
852 s->read_only_volume = s->has_volume ? !pa_sink_input_is_volume_writable(sink_input) : FALSE;
855 pa_sink_input_get_volume(sink_input, &s->volume, TRUE);
857 pa_cvolume_init(&s->volume);
859 s->mute = pa_sink_input_get_mute(sink_input);
860 s->proplist = pa_proplist_copy(sink_input->proplist);
861 s->dbus_protocol = pa_dbus_protocol_get(sink_input->core);
862 s->subscription = pa_subscription_new(sink_input->core, PA_SUBSCRIPTION_MASK_SINK_INPUT, subscription_cb, s);
863 s->send_event_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT],
868 pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
873 pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_source_output *source_output) {
874 pa_dbusiface_stream *s;
877 pa_assert(source_output);
879 s = pa_xnew(pa_dbusiface_stream, 1);
881 s->source_output = pa_source_output_ref(source_output);
882 s->type = STREAM_TYPE_RECORD;
883 s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, RECORD_OBJECT_NAME, source_output->index);
884 s->source = pa_source_ref(source_output->source);
885 s->sample_rate = source_output->sample_spec.rate;
886 pa_cvolume_init(&s->volume);
888 s->proplist = pa_proplist_copy(source_output->proplist);
889 s->has_volume = FALSE;
890 s->read_only_volume = FALSE;
891 s->dbus_protocol = pa_dbus_protocol_get(source_output->core);
892 s->subscription = pa_subscription_new(source_output->core, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscription_cb, s);
893 s->send_event_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT],
898 pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
903 void pa_dbusiface_stream_free(pa_dbusiface_stream *s) {
906 pa_assert_se(pa_dbus_protocol_remove_interface(s->dbus_protocol, s->path, stream_interface_info.name) >= 0);
908 if (s->type == STREAM_TYPE_PLAYBACK) {
909 pa_sink_input_unref(s->sink_input);
910 pa_sink_unref(s->sink);
912 pa_source_output_unref(s->source_output);
913 pa_source_unref(s->source);
916 pa_proplist_free(s->proplist);
917 pa_dbus_protocol_unref(s->dbus_protocol);
918 pa_subscription_free(s->subscription);
919 pa_hook_slot_free(s->send_event_slot);
925 const char *pa_dbusiface_stream_get_path(pa_dbusiface_stream *s) {