dbusiface-device: Implement the Device and DevicePort D-Bus interfaces.
[profile/ivi/pulseaudio.git] / src / modules / dbus / iface-device.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2009 Tanu Kaskinen
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <pulsecore/core-util.h>
27 #include <pulsecore/dbus-util.h>
28 #include <pulsecore/protocol-dbus.h>
29
30 #include "iface-device-port.h"
31
32 #include "iface-device.h"
33
34 #define SINK_OBJECT_NAME "sink"
35 #define SOURCE_OBJECT_NAME "source"
36
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);
65
66 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
67
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);
70
71 static void handle_sink_get_monitor_source(DBusConnection *conn, DBusMessage *msg, void *userdata);
72
73 static void handle_sink_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
74
75 static void handle_source_get_monitor_of_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
76
77 static void handle_source_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
78
79 enum device_type {
80     DEVICE_TYPE_SINK,
81     DEVICE_TYPE_SOURCE
82 };
83
84 struct pa_dbusiface_device {
85     pa_dbusiface_core *core;
86
87     union {
88         pa_sink *sink;
89         pa_source *source;
90     };
91     enum device_type type;
92     char *path;
93     pa_cvolume volume;
94     pa_bool_t is_muted;
95     union {
96         pa_sink_state_t sink_state;
97         pa_source_state_t source_state;
98     };
99     pa_hashmap *ports;
100     uint32_t next_port_index;
101     pa_device_port *active_port;
102     pa_proplist *proplist;
103
104     pa_dbus_protocol *dbus_protocol;
105     pa_subscription *subscription;
106 };
107
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,
134     PROPERTY_HANDLER_MAX
135 };
136
137 enum sink_property_handler_index {
138     SINK_PROPERTY_HANDLER_MONITOR_SOURCE,
139     SINK_PROPERTY_HANDLER_MAX
140 };
141
142 enum source_property_handler_index {
143     SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK,
144     SOURCE_PROPERTY_HANDLER_MAX
145 };
146
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 }
173 };
174
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 }
177 };
178
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 }
181 };
182
183 enum method_handler_index {
184     METHOD_HANDLER_SUSPEND,
185     METHOD_HANDLER_GET_PORT_BY_NAME,
186     METHOD_HANDLER_MAX
187 };
188
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" } };
191
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 }
203 };
204
205 enum signal_index {
206     SIGNAL_VOLUME_UPDATED,
207     SIGNAL_MUTE_UPDATED,
208     SIGNAL_STATE_UPDATED,
209     SIGNAL_ACTIVE_PORT_UPDATED,
210     SIGNAL_PROPERTY_LIST_UPDATED,
211     SIGNAL_MAX
212 };
213
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 } };
219
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 }
226 };
227
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,
235     .signals = signals,
236     .n_signals = SIGNAL_MAX
237 };
238
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,
246     .signals = NULL,
247     .n_signals = 0
248 };
249
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,
257     .signals = NULL,
258     .n_signals = 0
259 };
260
261 static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
262     pa_dbusiface_device *d = userdata;
263     dbus_uint32_t idx = 0;
264
265     pa_assert(conn);
266     pa_assert(msg);
267     pa_assert(d);
268
269     idx = (d->type == DEVICE_TYPE_SINK) ? d->sink->index : d->source->index;
270
271     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
272 }
273
274 static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
275     pa_dbusiface_device *d = userdata;
276     const char *name = NULL;
277
278     pa_assert(conn);
279     pa_assert(msg);
280     pa_assert(d);
281
282     name = (d->type == DEVICE_TYPE_SINK) ? d->sink->name : d->source->name;
283
284     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &name);
285 }
286
287 static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) {
288     pa_dbusiface_device *d = userdata;
289     const char *driver = NULL;
290
291     pa_assert(conn);
292     pa_assert(msg);
293     pa_assert(d);
294
295     driver = (d->type == DEVICE_TYPE_SINK) ? d->sink->driver : d->source->driver;
296
297     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &driver);
298 }
299
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;
304
305     pa_assert(conn);
306     pa_assert(msg);
307     pa_assert(d);
308
309     owner_module = (d->type == DEVICE_TYPE_SINK) ? d->sink->module : d->source->module;
310
311     if (!owner_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);
314         else
315             pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Source %s doesn't have an owner module.", d->source->name);
316         return;
317     }
318
319     object_path = pa_dbusiface_core_get_module_path(d->core, owner_module);
320
321     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
322 }
323
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;
328
329     pa_assert(conn);
330     pa_assert(msg);
331     pa_assert(d);
332
333     card = (d->type == DEVICE_TYPE_SINK) ? d->sink->card : d->source->card;
334
335     if (!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);
338         else
339             pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Source %s doesn't belong to any card.", d->source->name);
340         return;
341     }
342
343     object_path = pa_dbusiface_core_get_card_path(d->core, card);
344
345     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
346 }
347
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;
351
352     pa_assert(conn);
353     pa_assert(msg);
354     pa_assert(d);
355
356     sample_format = (d->type == DEVICE_TYPE_SINK) ? d->sink->sample_spec.format : d->source->sample_spec.format;
357
358     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_format);
359 }
360
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;
364
365     pa_assert(conn);
366     pa_assert(msg);
367     pa_assert(d);
368
369     sample_rate = (d->type == DEVICE_TYPE_SINK) ? d->sink->sample_spec.rate : d->source->sample_spec.rate;
370
371     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_rate);
372 }
373
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];
378     unsigned i = 0;
379
380     pa_assert(conn);
381     pa_assert(msg);
382     pa_assert(d);
383
384     channel_map = (d->type == DEVICE_TYPE_SINK) ? &d->sink->channel_map : &d->source->channel_map;
385
386     for (i = 0; i < channel_map->channels; ++i)
387         channels[i] = channel_map->map[i];
388
389     pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, channels, channel_map->channels);
390 }
391
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];
395     unsigned i = 0;
396
397     pa_assert(conn);
398     pa_assert(msg);
399     pa_assert(d);
400
401     for (i = 0; i < d->volume.channels; ++i)
402         volume[i] = d->volume.values[i];
403
404     pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, volume, d->volume.channels);
405 }
406
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;
412     pa_cvolume new_vol;
413     unsigned i = 0;
414
415     pa_assert(conn);
416     pa_assert(msg);
417     pa_assert(d);
418
419     pa_cvolume_init(&new_vol);
420
421     device_channels = (d->type == DEVICE_TYPE_SINK) ? d->sink->channel_map.channels : d->source->channel_map.channels;
422
423     new_vol.channels = device_channels;
424
425     if (pa_dbus_get_fixed_array_set_property_arg(conn, msg, DBUS_TYPE_UINT32, &volume, &n_volume_entries) < 0)
426         return;
427
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);
430         return;
431     }
432
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]);
436             return;
437         }
438         new_vol.values[i] = volume[i];
439     }
440
441     if (d->type == DEVICE_TYPE_SINK)
442         pa_sink_set_volume(d->sink, &new_vol, TRUE, TRUE, TRUE, TRUE);
443     else
444         pa_source_set_volume(d->source, &new_vol, TRUE);
445
446     pa_dbus_send_empty_reply(conn, msg);
447 }
448
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;
452
453     pa_assert(conn);
454     pa_assert(msg);
455     pa_assert(d);
456
457     has_flat_volume = (d->type == DEVICE_TYPE_SINK) ? (d->sink->flags & PA_SINK_FLAT_VOLUME) : FALSE;
458
459     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_flat_volume);
460 }
461
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;
465
466     pa_assert(conn);
467     pa_assert(msg);
468     pa_assert(d);
469
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);
473
474     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_convertible_to_decibel_volume);
475 }
476
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;
480
481     pa_assert(conn);
482     pa_assert(msg);
483     pa_assert(d);
484
485     base_volume = (d->type == DEVICE_TYPE_SINK) ? d->sink->base_volume : d->source->base_volume;
486
487     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &base_volume);
488 }
489
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;
493
494     pa_assert(conn);
495     pa_assert(msg);
496     pa_assert(d);
497
498     volume_steps = (d->type == DEVICE_TYPE_SINK) ? d->sink->n_volume_steps : d->source->n_volume_steps;
499
500     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &volume_steps);
501 }
502
503 static void handle_get_is_muted(DBusConnection *conn, DBusMessage *msg, void *userdata) {
504     pa_dbusiface_device *d = userdata;
505
506     pa_assert(conn);
507     pa_assert(msg);
508     pa_assert(d);
509
510     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &d->is_muted);
511 }
512
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;
516
517     pa_assert(conn);
518     pa_assert(msg);
519     pa_assert(d);
520
521     if (pa_dbus_get_basic_set_property_arg(conn, msg, DBUS_TYPE_BOOLEAN, &is_muted) < 0)
522         return;
523
524     if (d->type == DEVICE_TYPE_SINK)
525         pa_sink_set_mute(d->sink, is_muted, TRUE);
526     else
527         pa_source_set_mute(d->source, is_muted, TRUE);
528
529     pa_dbus_send_empty_reply(conn, msg);
530 }
531
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;
535
536     pa_assert(conn);
537     pa_assert(msg);
538     pa_assert(d);
539
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);
543
544     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_hardware_volume);
545 }
546
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;
550
551     pa_assert(conn);
552     pa_assert(msg);
553     pa_assert(d);
554
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);
558
559     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_hardware_mute);
560 }
561
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;
565
566     pa_assert(conn);
567     pa_assert(msg);
568     pa_assert(d);
569
570     configured_latency = (d->type == DEVICE_TYPE_SINK)
571                          ? pa_sink_get_requested_latency(d->sink)
572                          : pa_source_get_requested_latency(d->source);
573
574     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &configured_latency);
575 }
576
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;
580
581     pa_assert(conn);
582     pa_assert(msg);
583     pa_assert(d);
584
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);
588
589     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &has_dynamic_latency);
590 }
591
592 static void handle_get_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
593     pa_dbusiface_device *d = userdata;
594     dbus_uint64_t latency = 0;
595
596     pa_assert(conn);
597     pa_assert(msg);
598     pa_assert(d);
599
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);
604     return;
605
606     latency = (d->type == DEVICE_TYPE_SINK) ? pa_sink_get_latency(d->sink) : pa_source_get_latency(d->source);
607
608     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &latency);
609 }
610
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;
614
615     pa_assert(conn);
616     pa_assert(msg);
617     pa_assert(d);
618
619     is_hardware_device = (d->type == DEVICE_TYPE_SINK)
620                          ? (d->sink->flags & PA_SINK_HARDWARE)
621                          : (d->source->flags & PA_SOURCE_HARDWARE);
622
623     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_hardware_device);
624 }
625
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;
629
630     pa_assert(conn);
631     pa_assert(msg);
632     pa_assert(d);
633
634     is_network_device = (d->type == DEVICE_TYPE_SINK)
635                         ? (d->sink->flags & PA_SINK_NETWORK)
636                         : (d->source->flags & PA_SOURCE_NETWORK);
637
638     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_network_device);
639 }
640
641 static void handle_get_state(DBusConnection *conn, DBusMessage *msg, void *userdata) {
642     pa_dbusiface_device *d = userdata;
643     dbus_uint32_t state;
644
645     pa_assert(conn);
646     pa_assert(msg);
647     pa_assert(d);
648
649     state = (d->type == DEVICE_TYPE_SINK) ? d->sink_state : d->source_state;
650
651     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &state);
652 }
653
654 /* The caller frees the array, but not the strings. */
655 static const char **get_ports(pa_dbusiface_device *d, unsigned *n) {
656     const char **ports;
657     unsigned i = 0;
658     void *state = NULL;
659     pa_dbusiface_device_port *port = NULL;
660
661     pa_assert(d);
662     pa_assert(n);
663
664     *n = pa_hashmap_size(d->ports);
665
666     if (*n == 0)
667         return NULL;
668
669     ports = pa_xnew(const char *, *n);
670
671     PA_HASHMAP_FOREACH(port, d->ports, state)
672         ports[i++] = pa_dbusiface_device_port_get_path(port);
673
674     return ports;
675 }
676
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;
681
682     pa_assert(conn);
683     pa_assert(msg);
684     pa_assert(d);
685
686     ports = get_ports(d, &n_ports);
687
688     pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, ports, n_ports);
689
690     pa_xfree(ports);
691 }
692
693 static void handle_get_active_port(DBusConnection *conn, DBusMessage *msg, void *userdata) {
694     pa_dbusiface_device *d = userdata;
695     const char *active_port;
696
697     pa_assert(conn);
698     pa_assert(msg);
699     pa_assert(d);
700
701     if (!d->active_port) {
702         pa_assert(pa_hashmap_isempty(d->ports));
703
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);
707         else
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);
710         return;
711     }
712
713     active_port = pa_dbusiface_device_port_get_path(pa_hashmap_get(d->ports, d->active_port->name));
714
715     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &active_port);
716 }
717
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;
722     int r;
723
724     pa_assert(conn);
725     pa_assert(msg);
726     pa_assert(d);
727
728     if (pa_dbus_get_basic_set_property_arg(conn, msg, DBUS_TYPE_OBJECT_PATH, &new_active_path) < 0)
729         return;
730
731     if (!d->active_port) {
732         pa_assert(pa_hashmap_isempty(d->ports));
733
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);
737         else
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);
740         return;
741     }
742
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);
745         return;
746     }
747
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);
752             return;
753         }
754     } else {
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);
758             return;
759         }
760     }
761
762     pa_dbus_send_empty_reply(conn, msg);
763 }
764
765 static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
766     pa_dbusiface_device *d = userdata;
767
768     pa_assert(conn);
769     pa_assert(msg);
770     pa_assert(d);
771
772     pa_dbus_send_proplist_variant_reply(conn, msg, d->proplist);
773 }
774
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;
807     unsigned i = 0;
808
809     pa_assert(conn);
810     pa_assert(msg);
811     pa_assert(d);
812
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;
817     if (owner_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;
820     if (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);
856     if (d->active_port)
857         active_port = pa_dbusiface_device_port_get_path(pa_hashmap_get(d->ports, d->active_port->name));
858
859     pa_assert_se((reply = dbus_message_new_method_return(msg)));
860
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));
863
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);
867
868     if (owner_module)
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);
870
871     if (card)
872         pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CARD].property_name, DBUS_TYPE_OBJECT_PATH, &card_path);
873
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);
892
893     if (active_port)
894         pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_ACTIVE_PORT].property_name, DBUS_TYPE_OBJECT_PATH, &active_port);
895
896     pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, d->proplist);
897
898     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
899
900     pa_assert_se(dbus_connection_send(conn, reply, NULL));
901
902     dbus_message_unref(reply);
903
904     pa_xfree(ports);
905 }
906
907 static void handle_suspend(DBusConnection *conn, DBusMessage *msg, void *userdata) {
908     pa_dbusiface_device *d = userdata;
909     dbus_bool_t suspend = FALSE;
910
911     pa_assert(conn);
912     pa_assert(msg);
913     pa_assert(d);
914
915     if (pa_dbus_get_basic_set_property_arg(conn, msg, DBUS_TYPE_BOOLEAN, &suspend) < 0)
916         return;
917
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.");
920         return;
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.");
923         return;
924     }
925
926     pa_dbus_send_empty_reply(conn, msg);
927 }
928
929 static void handle_get_port_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
930     pa_dbusiface_device *d = userdata;
931     DBusError error;
932     const char *port_name = NULL;
933     pa_dbusiface_device_port *port = NULL;
934     const char *port_path = NULL;
935
936     pa_assert(conn);
937     pa_assert(msg);
938     pa_assert(d);
939
940     dbus_error_init(&error);
941
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);
945         return;
946     }
947
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);
952         else
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);
955         return;
956     }
957
958     port_path = pa_dbusiface_device_port_get_path(port);
959
960     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &port_path);
961 }
962
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;
966
967     pa_assert(conn);
968     pa_assert(msg);
969     pa_assert(d);
970     pa_assert(d->type == DEVICE_TYPE_SINK);
971
972     monitor_source = pa_dbusiface_core_get_source_path(d->core, d->sink->monitor_source);
973
974     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &monitor_source);
975 }
976
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;
983
984     pa_assert(conn);
985     pa_assert(msg);
986     pa_assert(d);
987     pa_assert(d->type == DEVICE_TYPE_SINK);
988
989     monitor_source = pa_dbusiface_core_get_source_path(d->core, d->sink->monitor_source);
990
991     pa_assert_se((reply = dbus_message_new_method_return(msg)));
992
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));
995
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);
997
998     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
999
1000     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1001
1002     dbus_message_unref(reply);
1003 }
1004
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;
1008
1009     pa_assert(conn);
1010     pa_assert(msg);
1011     pa_assert(d);
1012     pa_assert(d->type == DEVICE_TYPE_SOURCE);
1013
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);
1016         return;
1017     }
1018
1019     monitor_of_sink = pa_dbusiface_core_get_sink_path(d->core, d->source->monitor_of);
1020
1021     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &monitor_of_sink);
1022 }
1023
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;
1030
1031     pa_assert(conn);
1032     pa_assert(msg);
1033     pa_assert(d);
1034     pa_assert(d->type == DEVICE_TYPE_SOURCE);
1035
1036     if (d->source->monitor_of)
1037         monitor_of_sink = pa_dbusiface_core_get_sink_path(d->core, d->source->monitor_of);
1038
1039     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1040
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));
1043
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);
1046
1047     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
1048
1049     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1050
1051     dbus_message_unref(reply);
1052 }
1053
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;
1056
1057     pa_assert(c);
1058     pa_assert(d);
1059
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;
1068         unsigned i = 0;
1069
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)));
1074
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);
1078
1079         if (!pa_cvolume_equal(&d->volume, new_volume)) {
1080             dbus_uint32_t volume[PA_CHANNELS_MAX];
1081             dbus_uint32_t *volume_ptr = volume;
1082
1083             d->volume = *new_volume;
1084
1085             for (i = 0; i < d->volume.channels; ++i)
1086                 volume[i] = d->volume.values[i];
1087
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));
1094
1095             pa_dbus_protocol_send_signal(d->dbus_protocol, signal);
1096             dbus_message_unref(signal);
1097             signal = NULL;
1098         }
1099
1100         new_muted = (d->type == DEVICE_TYPE_SINK) ? pa_sink_get_mute(d->sink, FALSE) : pa_source_get_mute(d->source, FALSE);
1101
1102         if (d->is_muted != new_muted) {
1103             d->is_muted = new_muted;
1104
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));
1109
1110             pa_dbus_protocol_send_signal(d->dbus_protocol, signal);
1111             dbus_message_unref(signal);
1112             signal = NULL;
1113         }
1114
1115         if (d->type == DEVICE_TYPE_SINK)
1116             new_sink_state = pa_sink_get_state(d->sink);
1117         else
1118             new_source_state = pa_source_get_state(d->source);
1119
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;
1123
1124             if (d->type == DEVICE_TYPE_SINK)
1125                 d->sink_state = new_sink_state;
1126             else
1127                 d->source_state = new_source_state;
1128
1129             state = (d->type == DEVICE_TYPE_SINK) ? d->sink_state : d->source_state;
1130
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));
1135
1136             pa_dbus_protocol_send_signal(d->dbus_protocol, signal);
1137             dbus_message_unref(signal);
1138             signal = NULL;
1139         }
1140
1141         new_active_port = (d->type == DEVICE_TYPE_SINK) ? d->sink->active_port : d->source->active_port;
1142
1143         if (d->active_port != new_active_port) {
1144             const char *object_path = NULL;
1145
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));
1148
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));
1153
1154             pa_dbus_protocol_send_signal(d->dbus_protocol, signal);
1155             dbus_message_unref(signal);
1156             signal = NULL;
1157         }
1158
1159         new_proplist = (d->type == DEVICE_TYPE_SINK) ? d->sink->proplist : d->source->proplist;
1160
1161         if (!pa_proplist_equal(d->proplist, new_proplist)) {
1162             DBusMessageIter msg_iter;
1163
1164             pa_proplist_update(d->proplist, PA_UPDATE_SET, new_proplist);
1165
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);
1171
1172             pa_dbus_protocol_send_signal(d->dbus_protocol, signal);
1173             dbus_message_unref(signal);
1174             signal = NULL;
1175         }
1176     }
1177 }
1178
1179 pa_dbusiface_device *pa_dbusiface_device_new_sink(pa_dbusiface_core *core, pa_sink *sink) {
1180     pa_dbusiface_device *d = NULL;
1181
1182     pa_assert(core);
1183     pa_assert(sink);
1184
1185     d = pa_xnew0(pa_dbusiface_device, 1);
1186     d->core = core;
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);
1199
1200     if (sink->ports) {
1201         pa_device_port *port;
1202         void *state = NULL;
1203
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);
1207         }
1208         pa_assert_se(d->active_port = sink->active_port);
1209     }
1210
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);
1213
1214     return d;
1215 }
1216
1217 pa_dbusiface_device *pa_dbusiface_device_new_source(pa_dbusiface_core *core, pa_source *source) {
1218     pa_dbusiface_device *d = NULL;
1219
1220     pa_assert(core);
1221     pa_assert(source);
1222
1223     d = pa_xnew0(pa_dbusiface_device, 1);
1224     d->core = core;
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);
1237
1238     if (source->ports) {
1239         pa_device_port *port;
1240         void *state = NULL;
1241
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);
1245         }
1246         pa_assert_se(d->active_port = source->active_port);
1247     }
1248
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);
1251
1252     return d;
1253 }
1254
1255 static void port_free_cb(void *p, void *userdata) {
1256     pa_dbusiface_device_port *port = p;
1257
1258     pa_assert(port);
1259
1260     pa_dbusiface_device_port_free(port);
1261 }
1262
1263 void pa_dbusiface_device_free(pa_dbusiface_device *d) {
1264     pa_assert(d);
1265
1266     pa_assert_se(pa_dbus_protocol_remove_interface(d->dbus_protocol, d->path, device_interface_info.name) >= 0);
1267
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);
1271
1272     } else {
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);
1275     }
1276     pa_hashmap_free(d->ports, port_free_cb, NULL);
1277     pa_dbus_protocol_unref(d->dbus_protocol);
1278     pa_subscription_free(d->subscription);
1279
1280     pa_xfree(d->path);
1281     pa_xfree(d);
1282 }
1283
1284 const char *pa_dbusiface_device_get_path(pa_dbusiface_device *d) {
1285     pa_assert(d);
1286
1287     return d->path;
1288 }
1289
1290 pa_sink *pa_dbusiface_device_get_sink(pa_dbusiface_device *d) {
1291     pa_assert(d);
1292     pa_assert(d->type == DEVICE_TYPE_SINK);
1293
1294     return d->sink;
1295 }
1296
1297 pa_source *pa_dbusiface_device_get_source(pa_dbusiface_device *d) {
1298     pa_assert(d);
1299     pa_assert(d->type == DEVICE_TYPE_SOURCE);
1300
1301     return d->source;
1302 }