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