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