2 This file is part of PulseAudio.
4 Copyright 2009 Tanu Kaskinen
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 #include <pulsecore/core-util.h>
27 #include <pulsecore/dbus-util.h>
28 #include <pulsecore/protocol-dbus.h>
30 #include "iface-device-port.h"
32 #include "iface-device.h"
34 #define SINK_OBJECT_NAME "sink"
35 #define SOURCE_OBJECT_NAME "source"
37 static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
38 static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
39 static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata);
40 static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata);
41 static void handle_get_card(DBusConnection *conn, DBusMessage *msg, void *userdata);
42 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
43 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
44 static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);
45 static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
46 static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
47 static void handle_get_has_flat_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
48 static void handle_get_has_convertible_to_decibel_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
49 static void handle_get_base_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
50 static void handle_get_volume_steps(DBusConnection *conn, DBusMessage *msg, void *userdata);
51 static void handle_get_is_muted(DBusConnection *conn, DBusMessage *msg, void *userdata);
52 static void handle_set_is_muted(DBusConnection *conn, DBusMessage *msg, void *userdata);
53 static void handle_get_has_hardware_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
54 static void handle_get_has_hardware_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
55 static void handle_get_configured_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
56 static void handle_get_has_dynamic_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
57 static void handle_get_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
58 static void handle_get_is_hardware_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
59 static void handle_get_is_network_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
60 static void handle_get_state(DBusConnection *conn, DBusMessage *msg, void *userdata);
61 static void handle_get_ports(DBusConnection *conn, DBusMessage *msg, void *userdata);
62 static void handle_get_active_port(DBusConnection *conn, DBusMessage *msg, void *userdata);
63 static void handle_set_active_port(DBusConnection *conn, DBusMessage *msg, void *userdata);
64 static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
66 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
68 static void handle_suspend(DBusConnection *conn, DBusMessage *msg, void *userdata);
69 static void handle_get_port_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
71 static void handle_sink_get_monitor_source(DBusConnection *conn, DBusMessage *msg, void *userdata);
73 static void handle_sink_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
75 static void handle_source_get_monitor_of_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
77 static void handle_source_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
84 struct pa_dbusiface_device {
85 pa_dbusiface_core *core;
91 enum device_type type;
96 pa_sink_state_t sink_state;
97 pa_source_state_t source_state;
100 uint32_t next_port_index;
101 pa_device_port *active_port;
102 pa_proplist *proplist;
104 pa_dbus_protocol *dbus_protocol;
105 pa_subscription *subscription;
108 enum property_handler_index {
109 PROPERTY_HANDLER_INDEX,
110 PROPERTY_HANDLER_NAME,
111 PROPERTY_HANDLER_DRIVER,
112 PROPERTY_HANDLER_OWNER_MODULE,
113 PROPERTY_HANDLER_CARD,
114 PROPERTY_HANDLER_SAMPLE_FORMAT,
115 PROPERTY_HANDLER_SAMPLE_RATE,
116 PROPERTY_HANDLER_CHANNELS,
117 PROPERTY_HANDLER_VOLUME,
118 PROPERTY_HANDLER_HAS_FLAT_VOLUME,
119 PROPERTY_HANDLER_HAS_CONVERTIBLE_TO_DECIBEL_VOLUME,
120 PROPERTY_HANDLER_BASE_VOLUME,
121 PROPERTY_HANDLER_VOLUME_STEPS,
122 PROPERTY_HANDLER_IS_MUTED,
123 PROPERTY_HANDLER_HAS_HARDWARE_VOLUME,
124 PROPERTY_HANDLER_HAS_HARDWARE_MUTE,
125 PROPERTY_HANDLER_CONFIGURED_LATENCY,
126 PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY,
127 PROPERTY_HANDLER_LATENCY,
128 PROPERTY_HANDLER_IS_HARDWARE_DEVICE,
129 PROPERTY_HANDLER_IS_NETWORK_DEVICE,
130 PROPERTY_HANDLER_STATE,
131 PROPERTY_HANDLER_PORTS,
132 PROPERTY_HANDLER_ACTIVE_PORT,
133 PROPERTY_HANDLER_PROPERTY_LIST,
137 enum sink_property_handler_index {
138 SINK_PROPERTY_HANDLER_MONITOR_SOURCE,
139 SINK_PROPERTY_HANDLER_MAX
142 enum source_property_handler_index {
143 SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK,
144 SOURCE_PROPERTY_HANDLER_MAX
147 static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
148 [PROPERTY_HANDLER_INDEX] = { .property_name = "Index", .type = "u", .get_cb = handle_get_index, .set_cb = NULL },
149 [PROPERTY_HANDLER_NAME] = { .property_name = "Name", .type = "s", .get_cb = handle_get_name, .set_cb = NULL },
150 [PROPERTY_HANDLER_DRIVER] = { .property_name = "Driver", .type = "s", .get_cb = handle_get_driver, .set_cb = NULL },
151 [PROPERTY_HANDLER_OWNER_MODULE] = { .property_name = "OwnerModule", .type = "o", .get_cb = handle_get_owner_module, .set_cb = NULL },
152 [PROPERTY_HANDLER_CARD] = { .property_name = "Card", .type = "o", .get_cb = handle_get_card, .set_cb = NULL },
153 [PROPERTY_HANDLER_SAMPLE_FORMAT] = { .property_name = "SampleFormat", .type = "u", .get_cb = handle_get_sample_format, .set_cb = NULL },
154 [PROPERTY_HANDLER_SAMPLE_RATE] = { .property_name = "SampleRate", .type = "u", .get_cb = handle_get_sample_rate, .set_cb = NULL },
155 [PROPERTY_HANDLER_CHANNELS] = { .property_name = "Channels", .type = "au", .get_cb = handle_get_channels, .set_cb = NULL },
156 [PROPERTY_HANDLER_VOLUME] = { .property_name = "Volume", .type = "au", .get_cb = handle_get_volume, .set_cb = handle_set_volume },
157 [PROPERTY_HANDLER_HAS_FLAT_VOLUME] = { .property_name = "HasFlatVolume", .type = "b", .get_cb = handle_get_has_flat_volume, .set_cb = NULL },
158 [PROPERTY_HANDLER_HAS_CONVERTIBLE_TO_DECIBEL_VOLUME] = { .property_name = "HasConvertibleToDecibelVolume", .type = "b", .get_cb = handle_get_has_convertible_to_decibel_volume, .set_cb = NULL },
159 [PROPERTY_HANDLER_BASE_VOLUME] = { .property_name = "BaseVolume", .type = "u", .get_cb = handle_get_base_volume, .set_cb = NULL },
160 [PROPERTY_HANDLER_VOLUME_STEPS] = { .property_name = "VolumeSteps", .type = "u", .get_cb = handle_get_volume_steps, .set_cb = NULL },
161 [PROPERTY_HANDLER_IS_MUTED] = { .property_name = "IsMuted", .type = "b", .get_cb = handle_get_is_muted, .set_cb = handle_set_is_muted },
162 [PROPERTY_HANDLER_HAS_HARDWARE_VOLUME] = { .property_name = "HasHardwareVolume", .type = "b", .get_cb = handle_get_has_hardware_volume, .set_cb = NULL },
163 [PROPERTY_HANDLER_HAS_HARDWARE_MUTE] = { .property_name = "HasHardwareMute", .type = "b", .get_cb = handle_get_has_hardware_mute, .set_cb = NULL },
164 [PROPERTY_HANDLER_CONFIGURED_LATENCY] = { .property_name = "ConfiguredLatency", .type = "t", .get_cb = handle_get_configured_latency, .set_cb = NULL },
165 [PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY] = { .property_name = "HasDynamicLatency", .type = "b", .get_cb = handle_get_has_dynamic_latency, .set_cb = NULL },
166 [PROPERTY_HANDLER_LATENCY] = { .property_name = "Latency", .type = "t", .get_cb = handle_get_latency, .set_cb = NULL },
167 [PROPERTY_HANDLER_IS_HARDWARE_DEVICE] = { .property_name = "IsHardwareDevice", .type = "b", .get_cb = handle_get_is_hardware_device, .set_cb = NULL },
168 [PROPERTY_HANDLER_IS_NETWORK_DEVICE] = { .property_name = "IsNetworkDevice", .type = "b", .get_cb = handle_get_is_network_device, .set_cb = NULL },
169 [PROPERTY_HANDLER_STATE] = { .property_name = "State", .type = "u", .get_cb = handle_get_state, .set_cb = NULL },
170 [PROPERTY_HANDLER_PORTS] = { .property_name = "Ports", .type = "ao", .get_cb = handle_get_ports, .set_cb = NULL },
171 [PROPERTY_HANDLER_ACTIVE_PORT] = { .property_name = "ActivePort", .type = "o", .get_cb = handle_get_active_port, .set_cb = handle_set_active_port },
172 [PROPERTY_HANDLER_PROPERTY_LIST] = { .property_name = "PropertyList", .type = "a{say}", .get_cb = handle_get_property_list, .set_cb = NULL }
175 static pa_dbus_property_handler sink_property_handlers[SINK_PROPERTY_HANDLER_MAX] = {
176 [SINK_PROPERTY_HANDLER_MONITOR_SOURCE] = { .property_name = "MonitorSource", .type = "o", .get_cb = handle_sink_get_monitor_source, .set_cb = NULL }
179 static pa_dbus_property_handler source_property_handlers[SOURCE_PROPERTY_HANDLER_MAX] = {
180 [SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK] = { .property_name = "MonitorOfSink", .type = "o", .get_cb = handle_source_get_monitor_of_sink, .set_cb = NULL }
183 enum method_handler_index {
184 METHOD_HANDLER_SUSPEND,
185 METHOD_HANDLER_GET_PORT_BY_NAME,
189 static pa_dbus_arg_info suspend_args[] = { { "suspend", "b", "in" } };
190 static pa_dbus_arg_info get_port_by_name_args[] = { { "name", "s", "in" }, { "port", "o", "out" } };
192 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
193 [METHOD_HANDLER_SUSPEND] = {
194 .method_name = "Suspend",
195 .arguments = suspend_args,
196 .n_arguments = sizeof(suspend_args) / sizeof(pa_dbus_arg_info),
197 .receive_cb = handle_suspend },
198 [METHOD_HANDLER_GET_PORT_BY_NAME] = {
199 .method_name = "GetPortByName",
200 .arguments = get_port_by_name_args,
201 .n_arguments = sizeof(get_port_by_name_args) / sizeof(pa_dbus_arg_info),
202 .receive_cb = handle_get_port_by_name }
206 SIGNAL_VOLUME_UPDATED,
208 SIGNAL_STATE_UPDATED,
209 SIGNAL_ACTIVE_PORT_UPDATED,
210 SIGNAL_PROPERTY_LIST_UPDATED,
214 static pa_dbus_arg_info volume_updated_args[] = { { "volume", "au", NULL } };
215 static pa_dbus_arg_info mute_updated_args[] = { { "muted", "b", NULL } };
216 static pa_dbus_arg_info state_updated_args[] = { { "state", "u", NULL } };
217 static pa_dbus_arg_info active_port_updated_args[] = { { "port", "o", NULL } };
218 static pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } };
220 static pa_dbus_signal_info signals[SIGNAL_MAX] = {
221 [SIGNAL_VOLUME_UPDATED] = { .name = "VolumeUpdated", .arguments = volume_updated_args, .n_arguments = 1 },
222 [SIGNAL_MUTE_UPDATED] = { .name = "MuteUpdated", .arguments = mute_updated_args, .n_arguments = 1 },
223 [SIGNAL_STATE_UPDATED] = { .name = "StateUpdated", .arguments = state_updated_args, .n_arguments = 1 },
224 [SIGNAL_ACTIVE_PORT_UPDATED] = { .name = "ActivePortUpdated", .arguments = active_port_updated_args, .n_arguments = 1 },
225 [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 }
228 static pa_dbus_interface_info device_interface_info = {
229 .name = PA_DBUSIFACE_DEVICE_INTERFACE,
230 .method_handlers = method_handlers,
231 .n_method_handlers = METHOD_HANDLER_MAX,
232 .property_handlers = property_handlers,
233 .n_property_handlers = PROPERTY_HANDLER_MAX,
234 .get_all_properties_cb = handle_get_all,
236 .n_signals = SIGNAL_MAX
239 static pa_dbus_interface_info sink_interface_info = {
240 .name = PA_DBUSIFACE_SINK_INTERFACE,
241 .method_handlers = NULL,
242 .n_method_handlers = 0,
243 .property_handlers = sink_property_handlers,
244 .n_property_handlers = SINK_PROPERTY_HANDLER_MAX,
245 .get_all_properties_cb = handle_sink_get_all,
250 static pa_dbus_interface_info source_interface_info = {
251 .name = PA_DBUSIFACE_SOURCE_INTERFACE,
252 .method_handlers = NULL,
253 .n_method_handlers = 0,
254 .property_handlers = source_property_handlers,
255 .n_property_handlers = SOURCE_PROPERTY_HANDLER_MAX,
256 .get_all_properties_cb = handle_source_get_all,
261 static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
262 pa_dbusiface_device *d = userdata;
263 dbus_uint32_t idx = 0;
269 idx = (d->type == DEVICE_TYPE_SINK) ? d->sink->index : d->source->index;
271 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
274 static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
275 pa_dbusiface_device *d = userdata;
276 const char *name = NULL;
282 name = (d->type == DEVICE_TYPE_SINK) ? d->sink->name : d->source->name;
284 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &name);
287 static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) {
288 pa_dbusiface_device *d = userdata;
289 const char *driver = NULL;
295 driver = (d->type == DEVICE_TYPE_SINK) ? d->sink->driver : d->source->driver;
297 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &driver);
300 static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata) {
301 pa_dbusiface_device *d = userdata;
302 pa_module *owner_module = NULL;
303 const char *object_path = NULL;
309 owner_module = (d->type == DEVICE_TYPE_SINK) ? d->sink->module : d->source->module;
312 if (d->type == DEVICE_TYPE_SINK)
313 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Sink %s doesn't have an owner module.", d->sink->name);
315 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Source %s doesn't have an owner module.", d->source->name);
319 object_path = pa_dbusiface_core_get_module_path(d->core, owner_module);
321 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
324 static 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;
333 card = (d->type == DEVICE_TYPE_SINK) ? d->sink->card : d->source->card;
336 if (d->type == DEVICE_TYPE_SINK)
337 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Sink %s doesn't belong to any card.", d->sink->name);
339 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Source %s doesn't belong to any card.", d->source->name);
343 object_path = pa_dbusiface_core_get_card_path(d->core, card);
345 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
348 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
349 pa_dbusiface_device *d = userdata;
350 dbus_uint32_t sample_format = 0;
356 sample_format = (d->type == DEVICE_TYPE_SINK) ? d->sink->sample_spec.format : d->source->sample_spec.format;
358 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_format);
361 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
362 pa_dbusiface_device *d = userdata;
363 dbus_uint32_t sample_rate = 0;
369 sample_rate = (d->type == DEVICE_TYPE_SINK) ? d->sink->sample_spec.rate : d->source->sample_spec.rate;
371 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_rate);
374 static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata) {
375 pa_dbusiface_device *d = userdata;
376 pa_channel_map *channel_map = NULL;
377 dbus_uint32_t channels[PA_CHANNELS_MAX];
384 channel_map = (d->type == DEVICE_TYPE_SINK) ? &d->sink->channel_map : &d->source->channel_map;
386 for (i = 0; i < channel_map->channels; ++i)
387 channels[i] = channel_map->map[i];
389 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, channels, channel_map->channels);
392 static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
393 pa_dbusiface_device *d = userdata;
394 dbus_uint32_t volume[PA_CHANNELS_MAX];
401 for (i = 0; i < d->volume.channels; ++i)
402 volume[i] = d->volume.values[i];
404 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, volume, d->volume.channels);
407 static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
408 pa_dbusiface_device *d = userdata;
409 unsigned device_channels = 0;
410 dbus_uint32_t *volume = NULL;
411 unsigned n_volume_entries = 0;
419 pa_cvolume_init(&new_vol);
421 device_channels = (d->type == DEVICE_TYPE_SINK) ? d->sink->channel_map.channels : d->source->channel_map.channels;
423 new_vol.channels = device_channels;
425 if (pa_dbus_get_fixed_array_set_property_arg(conn, msg, DBUS_TYPE_UINT32, &volume, &n_volume_entries) < 0)
428 if (n_volume_entries != device_channels) {
429 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Expected %u volume entries, got %u.", device_channels, n_volume_entries);
433 for (i = 0; i < n_volume_entries; ++i) {
434 if (volume[i] > PA_VOLUME_MAX) {
435 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Too large volume value: %u", volume[i]);
438 new_vol.values[i] = volume[i];
441 if (d->type == DEVICE_TYPE_SINK)
442 pa_sink_set_volume(d->sink, &new_vol, TRUE, TRUE, TRUE, TRUE);
444 pa_source_set_volume(d->source, &new_vol, TRUE);
446 pa_dbus_send_empty_reply(conn, msg);
449 static void handle_get_has_flat_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
450 pa_dbusiface_device *d = userdata;
451 dbus_bool_t has_flat_volume = FALSE;
457 has_flat_volume = (d->type == DEVICE_TYPE_SINK) ? (d->sink->flags & PA_SINK_FLAT_VOLUME) : FALSE;
459 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_flat_volume);
462 static void handle_get_has_convertible_to_decibel_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
463 pa_dbusiface_device *d = userdata;
464 dbus_bool_t has_convertible_to_decibel_volume = FALSE;
470 has_convertible_to_decibel_volume = (d->type == DEVICE_TYPE_SINK)
471 ? (d->sink->flags & PA_SINK_DECIBEL_VOLUME)
472 : (d->source->flags & PA_SOURCE_DECIBEL_VOLUME);
474 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_convertible_to_decibel_volume);
477 static void handle_get_base_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
478 pa_dbusiface_device *d = userdata;
479 dbus_uint32_t base_volume;
485 base_volume = (d->type == DEVICE_TYPE_SINK) ? d->sink->base_volume : d->source->base_volume;
487 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &base_volume);
490 static void handle_get_volume_steps(DBusConnection *conn, DBusMessage *msg, void *userdata) {
491 pa_dbusiface_device *d = userdata;
492 dbus_uint32_t volume_steps;
498 volume_steps = (d->type == DEVICE_TYPE_SINK) ? d->sink->n_volume_steps : d->source->n_volume_steps;
500 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &volume_steps);
503 static void handle_get_is_muted(DBusConnection *conn, DBusMessage *msg, void *userdata) {
504 pa_dbusiface_device *d = userdata;
510 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &d->is_muted);
513 static void handle_set_is_muted(DBusConnection *conn, DBusMessage *msg, void *userdata) {
514 pa_dbusiface_device *d = userdata;
515 dbus_bool_t is_muted = FALSE;
521 if (pa_dbus_get_basic_set_property_arg(conn, msg, DBUS_TYPE_BOOLEAN, &is_muted) < 0)
524 if (d->type == DEVICE_TYPE_SINK)
525 pa_sink_set_mute(d->sink, is_muted, TRUE);
527 pa_source_set_mute(d->source, is_muted, TRUE);
529 pa_dbus_send_empty_reply(conn, msg);
532 static void handle_get_has_hardware_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
533 pa_dbusiface_device *d = userdata;
534 dbus_bool_t has_hardware_volume = FALSE;
540 has_hardware_volume = (d->type == DEVICE_TYPE_SINK)
541 ? (d->sink->flags & PA_SINK_HW_VOLUME_CTRL)
542 : (d->source->flags & PA_SOURCE_HW_VOLUME_CTRL);
544 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_hardware_volume);
547 static void handle_get_has_hardware_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
548 pa_dbusiface_device *d = userdata;
549 dbus_bool_t has_hardware_mute = FALSE;
555 has_hardware_mute = (d->type == DEVICE_TYPE_SINK)
556 ? (d->sink->flags & PA_SINK_HW_MUTE_CTRL)
557 : (d->source->flags & PA_SOURCE_HW_MUTE_CTRL);
559 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_hardware_mute);
562 static void handle_get_configured_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
563 pa_dbusiface_device *d = userdata;
564 dbus_uint64_t configured_latency = 0;
570 configured_latency = (d->type == DEVICE_TYPE_SINK)
571 ? pa_sink_get_requested_latency(d->sink)
572 : pa_source_get_requested_latency(d->source);
574 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &configured_latency);
577 static void handle_get_has_dynamic_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
578 pa_dbusiface_device *d = userdata;
579 dbus_bool_t has_dynamic_latency = FALSE;
585 has_dynamic_latency = (d->type == DEVICE_TYPE_SINK)
586 ? (d->sink->flags & PA_SINK_DYNAMIC_LATENCY)
587 : (d->source->flags & PA_SOURCE_DYNAMIC_LATENCY);
589 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_dynamic_latency);
592 static void handle_get_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
593 pa_dbusiface_device *d = userdata;
594 dbus_uint64_t latency = 0;
600 if (d->type == DEVICE_TYPE_SINK && !(d->sink->flags & PA_SINK_LATENCY))
601 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Sink %s doesn't support latency querying.", d->sink->name);
602 else if (d->type == DEVICE_TYPE_SOURCE && !(d->source->flags & PA_SOURCE_LATENCY))
603 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Source %s doesn't support latency querying.", d->source->name);
606 latency = (d->type == DEVICE_TYPE_SINK) ? pa_sink_get_latency(d->sink) : pa_source_get_latency(d->source);
608 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &latency);
611 static void handle_get_is_hardware_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
612 pa_dbusiface_device *d = userdata;
613 dbus_bool_t is_hardware_device = FALSE;
619 is_hardware_device = (d->type == DEVICE_TYPE_SINK)
620 ? (d->sink->flags & PA_SINK_HARDWARE)
621 : (d->source->flags & PA_SOURCE_HARDWARE);
623 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_hardware_device);
626 static void handle_get_is_network_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
627 pa_dbusiface_device *d = userdata;
628 dbus_bool_t is_network_device = FALSE;
634 is_network_device = (d->type == DEVICE_TYPE_SINK)
635 ? (d->sink->flags & PA_SINK_NETWORK)
636 : (d->source->flags & PA_SOURCE_NETWORK);
638 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_network_device);
641 static void handle_get_state(DBusConnection *conn, DBusMessage *msg, void *userdata) {
642 pa_dbusiface_device *d = userdata;
649 state = (d->type == DEVICE_TYPE_SINK) ? d->sink_state : d->source_state;
651 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &state);
654 /* The caller frees the array, but not the strings. */
655 static const char **get_ports(pa_dbusiface_device *d, unsigned *n) {
659 pa_dbusiface_device_port *port = NULL;
664 *n = pa_hashmap_size(d->ports);
669 ports = pa_xnew(const char *, *n);
671 PA_HASHMAP_FOREACH(port, d->ports, state)
672 ports[i++] = pa_dbusiface_device_port_get_path(port);
677 static void handle_get_ports(DBusConnection *conn, DBusMessage *msg, void *userdata) {
678 pa_dbusiface_device *d = userdata;
679 const char **ports = NULL;
680 unsigned n_ports = 0;
686 ports = get_ports(d, &n_ports);
688 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, ports, n_ports);
693 static void handle_get_active_port(DBusConnection *conn, DBusMessage *msg, void *userdata) {
694 pa_dbusiface_device *d = userdata;
695 const char *active_port;
701 if (!d->active_port) {
702 pa_assert(pa_hashmap_isempty(d->ports));
704 if (d->type == DEVICE_TYPE_SINK)
705 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
706 "The sink %s has no ports, and therefore there's no active port either.", d->sink->name);
708 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
709 "The source %s has no ports, and therefore there's no active port either.", d->source->name);
713 active_port = pa_dbusiface_device_port_get_path(pa_hashmap_get(d->ports, d->active_port->name));
715 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &active_port);
718 static void handle_set_active_port(DBusConnection *conn, DBusMessage *msg, void *userdata) {
719 pa_dbusiface_device *d = userdata;
720 const char *new_active_path;
721 pa_dbusiface_device_port *new_active;
728 if (pa_dbus_get_basic_set_property_arg(conn, msg, DBUS_TYPE_OBJECT_PATH, &new_active_path) < 0)
731 if (!d->active_port) {
732 pa_assert(pa_hashmap_isempty(d->ports));
734 if (d->type == DEVICE_TYPE_SINK)
735 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
736 "The sink %s has no ports, and therefore there's no active port either.", d->sink->name);
738 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
739 "The source %s has no ports, and therefore there's no active port either.", d->source->name);
743 if (!(new_active = pa_hashmap_get(d->ports, new_active_path))) {
744 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such port.", new_active_path);
748 if (d->type == DEVICE_TYPE_SINK) {
749 if ((r = pa_sink_set_port(d->sink, pa_dbusiface_device_port_get_name(new_active), TRUE)) < 0) {
750 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
751 "Internal error in PulseAudio: pa_sink_set_port() failed with error code %i.", r);
755 if ((r = pa_source_set_port(d->source, pa_dbusiface_device_port_get_name(new_active), TRUE)) < 0) {
756 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
757 "Internal error in PulseAudio: pa_source_set_port() failed with error code %i.", r);
762 pa_dbus_send_empty_reply(conn, msg);
765 static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
766 pa_dbusiface_device *d = userdata;
772 pa_dbus_send_proplist_variant_reply(conn, msg, d->proplist);
775 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
776 pa_dbusiface_device *d = userdata;
777 DBusMessage *reply = NULL;
778 DBusMessageIter msg_iter;
779 DBusMessageIter dict_iter;
780 dbus_uint32_t idx = 0;
781 const char *name = NULL;
782 const char *driver = NULL;
783 pa_module *owner_module = NULL;
784 const char *owner_module_path = NULL;
785 pa_card *card = NULL;
786 const char *card_path = NULL;
787 dbus_uint32_t sample_format = 0;
788 dbus_uint32_t sample_rate = 0;
789 pa_channel_map *channel_map = NULL;
790 dbus_uint32_t channels[PA_CHANNELS_MAX];
791 dbus_uint32_t volume[PA_CHANNELS_MAX];
792 dbus_bool_t has_flat_volume = FALSE;
793 dbus_bool_t has_convertible_to_decibel_volume = FALSE;
794 dbus_uint32_t base_volume = 0;
795 dbus_uint32_t volume_steps = 0;
796 dbus_bool_t has_hardware_volume = FALSE;
797 dbus_bool_t has_hardware_mute = FALSE;
798 dbus_uint64_t configured_latency = 0;
799 dbus_bool_t has_dynamic_latency = FALSE;
800 dbus_uint64_t latency = 0;
801 dbus_bool_t is_hardware_device = FALSE;
802 dbus_bool_t is_network_device = FALSE;
803 dbus_uint32_t state = 0;
804 const char **ports = NULL;
805 unsigned n_ports = 0;
806 const char *active_port = NULL;
813 idx = (d->type == DEVICE_TYPE_SINK) ? d->sink->index : d->source->index;
814 name = (d->type == DEVICE_TYPE_SINK) ? d->sink->name : d->source->name;
815 driver = (d->type == DEVICE_TYPE_SINK) ? d->sink->driver : d->source->driver;
816 owner_module = (d->type == DEVICE_TYPE_SINK) ? d->sink->module : d->source->module;
818 owner_module_path = pa_dbusiface_core_get_module_path(d->core, owner_module);
819 card = (d->type == DEVICE_TYPE_SINK) ? d->sink->card : d->source->card;
821 card_path = pa_dbusiface_core_get_card_path(d->core, card);
822 sample_format = (d->type == DEVICE_TYPE_SINK) ? d->sink->sample_spec.format : d->source->sample_spec.format;
823 sample_rate = (d->type == DEVICE_TYPE_SINK) ? d->sink->sample_spec.rate : d->source->sample_spec.rate;
824 channel_map = (d->type == DEVICE_TYPE_SINK) ? &d->sink->channel_map : &d->source->channel_map;
825 for (i = 0; i < channel_map->channels; ++i)
826 channels[i] = channel_map->map[i];
827 for (i = 0; i < d->volume.channels; ++i)
828 volume[i] = d->volume.values[i];
829 has_flat_volume = (d->type == DEVICE_TYPE_SINK) ? (d->sink->flags & PA_SINK_FLAT_VOLUME) : FALSE;
830 has_convertible_to_decibel_volume = (d->type == DEVICE_TYPE_SINK)
831 ? (d->sink->flags & PA_SINK_DECIBEL_VOLUME)
832 : (d->source->flags & PA_SOURCE_DECIBEL_VOLUME);
833 base_volume = (d->type == DEVICE_TYPE_SINK) ? d->sink->base_volume : d->source->base_volume;
834 volume_steps = (d->type == DEVICE_TYPE_SINK) ? d->sink->n_volume_steps : d->source->n_volume_steps;
835 has_hardware_volume = (d->type == DEVICE_TYPE_SINK)
836 ? (d->sink->flags & PA_SINK_HW_VOLUME_CTRL)
837 : (d->source->flags & PA_SOURCE_HW_VOLUME_CTRL);
838 has_hardware_mute = (d->type == DEVICE_TYPE_SINK)
839 ? (d->sink->flags & PA_SINK_HW_MUTE_CTRL)
840 : (d->source->flags & PA_SOURCE_HW_MUTE_CTRL);
841 configured_latency = (d->type == DEVICE_TYPE_SINK)
842 ? pa_sink_get_requested_latency(d->sink)
843 : pa_source_get_requested_latency(d->source);
844 has_dynamic_latency = (d->type == DEVICE_TYPE_SINK)
845 ? (d->sink->flags & PA_SINK_DYNAMIC_LATENCY)
846 : (d->source->flags & PA_SOURCE_DYNAMIC_LATENCY);
847 latency = (d->type == DEVICE_TYPE_SINK) ? pa_sink_get_latency(d->sink) : pa_source_get_latency(d->source);
848 is_hardware_device = (d->type == DEVICE_TYPE_SINK)
849 ? (d->sink->flags & PA_SINK_HARDWARE)
850 : (d->source->flags & PA_SOURCE_HARDWARE);
851 is_network_device = (d->type == DEVICE_TYPE_SINK)
852 ? (d->sink->flags & PA_SINK_NETWORK)
853 : (d->source->flags & PA_SOURCE_NETWORK);
854 state = (d->type == DEVICE_TYPE_SINK) ? pa_sink_get_state(d->sink) : pa_source_get_state(d->source);
855 ports = get_ports(d, &n_ports);
857 active_port = pa_dbusiface_device_port_get_path(pa_hashmap_get(d->ports, d->active_port->name));
859 pa_assert_se((reply = dbus_message_new_method_return(msg)));
861 dbus_message_iter_init_append(reply, &msg_iter);
862 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
864 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
865 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &name);
866 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &driver);
869 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module_path);
872 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CARD].property_name, DBUS_TYPE_OBJECT_PATH, &card_path);
874 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format);
875 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &sample_rate);
876 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, channel_map->channels);
877 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, d->volume.channels);
878 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_HAS_FLAT_VOLUME].property_name, DBUS_TYPE_BOOLEAN, &has_flat_volume);
879 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);
880 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BASE_VOLUME].property_name, DBUS_TYPE_UINT32, &base_volume);
881 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME_STEPS].property_name, DBUS_TYPE_UINT32, &volume_steps);
882 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_IS_MUTED].property_name, DBUS_TYPE_BOOLEAN, &d->is_muted);
883 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_HAS_HARDWARE_VOLUME].property_name, DBUS_TYPE_BOOLEAN, &has_hardware_volume);
884 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_HAS_HARDWARE_MUTE].property_name, DBUS_TYPE_BOOLEAN, &has_hardware_mute);
885 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CONFIGURED_LATENCY].property_name, DBUS_TYPE_UINT64, &configured_latency);
886 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY].property_name, DBUS_TYPE_BOOLEAN, &has_dynamic_latency);
887 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_LATENCY].property_name, DBUS_TYPE_UINT64, &latency);
888 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_IS_HARDWARE_DEVICE].property_name, DBUS_TYPE_BOOLEAN, &is_hardware_device);
889 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_IS_NETWORK_DEVICE].property_name, DBUS_TYPE_BOOLEAN, &is_network_device);
890 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_STATE].property_name, DBUS_TYPE_UINT32, &state);
891 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PORTS].property_name, DBUS_TYPE_OBJECT_PATH, ports, n_ports);
894 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_ACTIVE_PORT].property_name, DBUS_TYPE_OBJECT_PATH, &active_port);
896 pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, d->proplist);
898 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
900 pa_assert_se(dbus_connection_send(conn, reply, NULL));
902 dbus_message_unref(reply);
907 static void handle_suspend(DBusConnection *conn, DBusMessage *msg, void *userdata) {
908 pa_dbusiface_device *d = userdata;
909 dbus_bool_t suspend = FALSE;
915 if (pa_dbus_get_basic_set_property_arg(conn, msg, DBUS_TYPE_BOOLEAN, &suspend) < 0)
918 if ((d->type == DEVICE_TYPE_SINK) && (pa_sink_suspend(d->sink, suspend, PA_SUSPEND_USER) < 0)) {
919 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Internal error in PulseAudio: pa_sink_suspend() failed.");
921 } else if ((d->type == DEVICE_TYPE_SOURCE) && (pa_source_suspend(d->source, suspend, PA_SUSPEND_USER) < 0)) {
922 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Internal error in PulseAudio: pa_source_suspend() failed.");
926 pa_dbus_send_empty_reply(conn, msg);
929 static void handle_get_port_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
930 pa_dbusiface_device *d = userdata;
932 const char *port_name = NULL;
933 pa_dbusiface_device_port *port = NULL;
934 const char *port_path = NULL;
940 dbus_error_init(&error);
942 if (!dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &port_name, DBUS_TYPE_INVALID)) {
943 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
944 dbus_error_free(&error);
948 if (!(port = pa_hashmap_get(d->ports, port_name))) {
949 if (d->type == DEVICE_TYPE_SINK)
950 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND,
951 "%s: No such port on sink %s.", port_name, d->sink->name);
953 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND,
954 "%s: No such port on source %s.", port_name, d->source->name);
958 port_path = pa_dbusiface_device_port_get_path(port);
960 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &port_path);
963 static void handle_sink_get_monitor_source(DBusConnection *conn, DBusMessage *msg, void *userdata) {
964 pa_dbusiface_device *d = userdata;
965 const char *monitor_source = NULL;
970 pa_assert(d->type == DEVICE_TYPE_SINK);
972 monitor_source = pa_dbusiface_core_get_source_path(d->core, d->sink->monitor_source);
974 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &monitor_source);
977 static void handle_sink_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
978 pa_dbusiface_device *d = userdata;
979 DBusMessage *reply = NULL;
980 DBusMessageIter msg_iter;
981 DBusMessageIter dict_iter;
982 const char *monitor_source = NULL;
987 pa_assert(d->type == DEVICE_TYPE_SINK);
989 monitor_source = pa_dbusiface_core_get_source_path(d->core, d->sink->monitor_source);
991 pa_assert_se((reply = dbus_message_new_method_return(msg)));
993 dbus_message_iter_init_append(reply, &msg_iter);
994 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
996 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[SINK_PROPERTY_HANDLER_MONITOR_SOURCE].property_name, DBUS_TYPE_OBJECT_PATH, &monitor_source);
998 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
1000 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1002 dbus_message_unref(reply);
1005 static void handle_source_get_monitor_of_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1006 pa_dbusiface_device *d = userdata;
1007 const char *monitor_of_sink = NULL;
1012 pa_assert(d->type == DEVICE_TYPE_SOURCE);
1014 if (!d->source->monitor_of) {
1015 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Source %s is not a monitor source.", d->source->name);
1019 monitor_of_sink = pa_dbusiface_core_get_sink_path(d->core, d->source->monitor_of);
1021 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &monitor_of_sink);
1024 static void handle_source_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1025 pa_dbusiface_device *d = userdata;
1026 DBusMessage *reply = NULL;
1027 DBusMessageIter msg_iter;
1028 DBusMessageIter dict_iter;
1029 const char *monitor_of_sink = NULL;
1034 pa_assert(d->type == DEVICE_TYPE_SOURCE);
1036 if (d->source->monitor_of)
1037 monitor_of_sink = pa_dbusiface_core_get_sink_path(d->core, d->source->monitor_of);
1039 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1041 dbus_message_iter_init_append(reply, &msg_iter);
1042 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
1044 if (monitor_of_sink)
1045 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);
1047 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
1049 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1051 dbus_message_unref(reply);
1054 static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
1055 pa_dbusiface_device *d = userdata;
1060 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE) {
1061 DBusMessage *signal = NULL;
1062 const pa_cvolume *new_volume = NULL;
1063 pa_bool_t new_muted = FALSE;
1064 pa_sink_state_t new_sink_state = 0;
1065 pa_source_state_t new_source_state = 0;
1066 pa_device_port *new_active_port = NULL;
1067 pa_proplist *new_proplist = NULL;
1070 pa_assert(((d->type == DEVICE_TYPE_SINK)
1071 && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK))
1072 || ((d->type == DEVICE_TYPE_SOURCE)
1073 && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE)));
1075 new_volume = (d->type == DEVICE_TYPE_SINK)
1076 ? pa_sink_get_volume(d->sink, FALSE, FALSE)
1077 : pa_source_get_volume(d->source, FALSE);
1079 if (!pa_cvolume_equal(&d->volume, new_volume)) {
1080 dbus_uint32_t volume[PA_CHANNELS_MAX];
1081 dbus_uint32_t *volume_ptr = volume;
1083 d->volume = *new_volume;
1085 for (i = 0; i < d->volume.channels; ++i)
1086 volume[i] = d->volume.values[i];
1088 pa_assert_se(signal = dbus_message_new_signal(d->path,
1089 PA_DBUSIFACE_DEVICE_INTERFACE,
1090 signals[SIGNAL_VOLUME_UPDATED].name));
1091 pa_assert_se(dbus_message_append_args(signal,
1092 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, d->volume.channels,
1093 DBUS_TYPE_INVALID));
1095 pa_dbus_protocol_send_signal(d->dbus_protocol, signal);
1096 dbus_message_unref(signal);
1100 new_muted = (d->type == DEVICE_TYPE_SINK) ? pa_sink_get_mute(d->sink, FALSE) : pa_source_get_mute(d->source, FALSE);
1102 if (d->is_muted != new_muted) {
1103 d->is_muted = new_muted;
1105 pa_assert_se(signal = dbus_message_new_signal(d->path,
1106 PA_DBUSIFACE_DEVICE_INTERFACE,
1107 signals[SIGNAL_MUTE_UPDATED].name));
1108 pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_BOOLEAN, &d->is_muted, DBUS_TYPE_INVALID));
1110 pa_dbus_protocol_send_signal(d->dbus_protocol, signal);
1111 dbus_message_unref(signal);
1115 if (d->type == DEVICE_TYPE_SINK)
1116 new_sink_state = pa_sink_get_state(d->sink);
1118 new_source_state = pa_source_get_state(d->source);
1120 if ((d->type == DEVICE_TYPE_SINK && d->sink_state != new_sink_state)
1121 || (d->type == DEVICE_TYPE_SOURCE && d->source_state != new_source_state)) {
1122 dbus_uint32_t state = 0;
1124 if (d->type == DEVICE_TYPE_SINK)
1125 d->sink_state = new_sink_state;
1127 d->source_state = new_source_state;
1129 state = (d->type == DEVICE_TYPE_SINK) ? d->sink_state : d->source_state;
1131 pa_assert_se(signal = dbus_message_new_signal(d->path,
1132 PA_DBUSIFACE_DEVICE_INTERFACE,
1133 signals[SIGNAL_STATE_UPDATED].name));
1134 pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID));
1136 pa_dbus_protocol_send_signal(d->dbus_protocol, signal);
1137 dbus_message_unref(signal);
1141 new_active_port = (d->type == DEVICE_TYPE_SINK) ? d->sink->active_port : d->source->active_port;
1143 if (d->active_port != new_active_port) {
1144 const char *object_path = NULL;
1146 d->active_port = new_active_port;
1147 object_path = pa_dbusiface_device_port_get_path(pa_hashmap_get(d->ports, d->active_port->name));
1149 pa_assert_se(signal = dbus_message_new_signal(d->path,
1150 PA_DBUSIFACE_DEVICE_INTERFACE,
1151 signals[SIGNAL_ACTIVE_PORT_UPDATED].name));
1152 pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1154 pa_dbus_protocol_send_signal(d->dbus_protocol, signal);
1155 dbus_message_unref(signal);
1159 new_proplist = (d->type == DEVICE_TYPE_SINK) ? d->sink->proplist : d->source->proplist;
1161 if (!pa_proplist_equal(d->proplist, new_proplist)) {
1162 DBusMessageIter msg_iter;
1164 pa_proplist_update(d->proplist, PA_UPDATE_SET, new_proplist);
1166 pa_assert_se(signal = dbus_message_new_signal(d->path,
1167 PA_DBUSIFACE_DEVICE_INTERFACE,
1168 signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
1169 dbus_message_iter_init_append(signal, &msg_iter);
1170 pa_dbus_append_proplist(&msg_iter, d->proplist);
1172 pa_dbus_protocol_send_signal(d->dbus_protocol, signal);
1173 dbus_message_unref(signal);
1179 pa_dbusiface_device *pa_dbusiface_device_new_sink(pa_dbusiface_core *core, pa_sink *sink) {
1180 pa_dbusiface_device *d = NULL;
1185 d = pa_xnew0(pa_dbusiface_device, 1);
1187 d->sink = pa_sink_ref(sink);
1188 d->type = DEVICE_TYPE_SINK;
1189 d->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, SINK_OBJECT_NAME, sink->index);
1190 d->volume = *pa_sink_get_volume(sink, FALSE, FALSE);
1191 d->is_muted = pa_sink_get_mute(sink, FALSE);
1192 d->sink_state = pa_sink_get_state(sink);
1193 d->ports = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1194 d->next_port_index = 0;
1195 d->active_port = NULL;
1196 d->proplist = pa_proplist_copy(sink->proplist);
1197 d->dbus_protocol = pa_dbus_protocol_get(sink->core);
1198 d->subscription = pa_subscription_new(sink->core, PA_SUBSCRIPTION_MASK_SINK, subscription_cb, d);
1201 pa_device_port *port;
1204 PA_HASHMAP_FOREACH(port, sink->ports, state) {
1205 pa_dbusiface_device_port *p = pa_dbusiface_device_port_new(d, sink->core, port, d->next_port_index++);
1206 pa_hashmap_put(d->ports, pa_dbusiface_device_port_get_name(p), p);
1208 pa_assert_se(d->active_port = sink->active_port);
1211 pa_assert_se(pa_dbus_protocol_add_interface(d->dbus_protocol, d->path, &device_interface_info, d) >= 0);
1212 pa_assert_se(pa_dbus_protocol_add_interface(d->dbus_protocol, d->path, &sink_interface_info, d) >= 0);
1217 pa_dbusiface_device *pa_dbusiface_device_new_source(pa_dbusiface_core *core, pa_source *source) {
1218 pa_dbusiface_device *d = NULL;
1223 d = pa_xnew0(pa_dbusiface_device, 1);
1225 d->source = pa_source_ref(source);
1226 d->type = DEVICE_TYPE_SOURCE;
1227 d->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, SOURCE_OBJECT_NAME, source->index);
1228 d->volume = *pa_source_get_volume(source, FALSE);
1229 d->is_muted = pa_source_get_mute(source, FALSE);
1230 d->source_state = pa_source_get_state(source);
1231 d->ports = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1232 d->next_port_index = 0;
1233 d->active_port = NULL;
1234 d->proplist = pa_proplist_copy(source->proplist);
1235 d->dbus_protocol = pa_dbus_protocol_get(source->core);
1236 d->subscription = pa_subscription_new(source->core, PA_SUBSCRIPTION_MASK_SOURCE, subscription_cb, d);
1238 if (source->ports) {
1239 pa_device_port *port;
1242 PA_HASHMAP_FOREACH(port, source->ports, state) {
1243 pa_dbusiface_device_port *p = pa_dbusiface_device_port_new(d, source->core, port, d->next_port_index++);
1244 pa_hashmap_put(d->ports, pa_dbusiface_device_port_get_name(p), p);
1246 pa_assert_se(d->active_port = source->active_port);
1249 pa_assert_se(pa_dbus_protocol_add_interface(d->dbus_protocol, d->path, &device_interface_info, d) >= 0);
1250 pa_assert_se(pa_dbus_protocol_add_interface(d->dbus_protocol, d->path, &source_interface_info, d) >= 0);
1255 static void port_free_cb(void *p, void *userdata) {
1256 pa_dbusiface_device_port *port = p;
1260 pa_dbusiface_device_port_free(port);
1263 void pa_dbusiface_device_free(pa_dbusiface_device *d) {
1266 pa_assert_se(pa_dbus_protocol_remove_interface(d->dbus_protocol, d->path, device_interface_info.name) >= 0);
1268 if (d->type == DEVICE_TYPE_SINK) {
1269 pa_assert_se(pa_dbus_protocol_remove_interface(d->dbus_protocol, d->path, sink_interface_info.name) >= 0);
1270 pa_sink_unref(d->sink);
1273 pa_assert_se(pa_dbus_protocol_remove_interface(d->dbus_protocol, d->path, source_interface_info.name) >= 0);
1274 pa_source_unref(d->source);
1276 pa_hashmap_free(d->ports, port_free_cb, NULL);
1277 pa_dbus_protocol_unref(d->dbus_protocol);
1278 pa_subscription_free(d->subscription);
1284 const char *pa_dbusiface_device_get_path(pa_dbusiface_device *d) {
1290 pa_sink *pa_dbusiface_device_get_sink(pa_dbusiface_device *d) {
1292 pa_assert(d->type == DEVICE_TYPE_SINK);
1297 pa_source *pa_dbusiface_device_get_source(pa_dbusiface_device *d) {
1299 pa_assert(d->type == DEVICE_TYPE_SOURCE);