• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
35 static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
36 static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
37 static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata);
38 static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata);
39 static void handle_get_card(DBusConnection *conn, DBusMessage *msg, void *userdata);
40 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
41 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
42 static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);
43 static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
44 static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
45 static void handle_get_has_flat_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
46 static void handle_get_has_convertible_to_decibel_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
47 static void handle_get_base_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
48 static void handle_get_volume_steps(DBusConnection *conn, DBusMessage *msg, void *userdata);
49 static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
50 static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
51 static void handle_get_has_hardware_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
52 static void handle_get_has_hardware_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
53 static void handle_get_configured_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
54 static void handle_get_has_dynamic_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
55 static void handle_get_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
56 static void handle_get_is_hardware_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
57 static void handle_get_is_network_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
58 static void handle_get_state(DBusConnection *conn, DBusMessage *msg, void *userdata);
59 static void handle_get_ports(DBusConnection *conn, DBusMessage *msg, void *userdata);
60 static void handle_get_active_port(DBusConnection *conn, DBusMessage *msg, void *userdata);
61 static void handle_set_active_port(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
62 static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
63 
64 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
65 
66 static void handle_suspend(DBusConnection *conn, DBusMessage *msg, void *userdata);
67 static void handle_get_port_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
68 
69 static void handle_sink_get_monitor_source(DBusConnection *conn, DBusMessage *msg, void *userdata);
70 
71 static void handle_sink_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
72 
73 static void handle_source_get_monitor_of_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
74 
75 static void handle_source_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
76 
77 struct 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 
106 enum 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 
135 enum sink_property_handler_index {
136     SINK_PROPERTY_HANDLER_MONITOR_SOURCE,
137     SINK_PROPERTY_HANDLER_MAX
138 };
139 
140 enum source_property_handler_index {
141     SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK,
142     SOURCE_PROPERTY_HANDLER_MAX
143 };
144 
145 static 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 
173 static 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 
177 static 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 
181 enum method_handler_index {
182     METHOD_HANDLER_SUSPEND,
183     METHOD_HANDLER_GET_PORT_BY_NAME,
184     METHOD_HANDLER_MAX
185 };
186 
187 static pa_dbus_arg_info suspend_args[] = { { "suspend", "b", "in" } };
188 static pa_dbus_arg_info get_port_by_name_args[] = { { "name", "s", "in" }, { "port", "o", "out" } };
189 
190 static 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 
203 enum 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 
212 static pa_dbus_arg_info volume_updated_args[]        = { { "volume",        "au",     NULL } };
213 static pa_dbus_arg_info mute_updated_args[]          = { { "muted",         "b",      NULL } };
214 static pa_dbus_arg_info state_updated_args[]         = { { "state",         "u",      NULL } };
215 static pa_dbus_arg_info active_port_updated_args[]   = { { "port",          "o",      NULL } };
216 static pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } };
217 
218 static 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 
226 static 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 
237 static 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 
248 static 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 
handle_get_index(DBusConnection * conn,DBusMessage * msg,void * userdata)259 static 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 
handle_get_name(DBusConnection * conn,DBusMessage * msg,void * userdata)272 static 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 
handle_get_driver(DBusConnection * conn,DBusMessage * msg,void * userdata)285 static 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 
handle_get_owner_module(DBusConnection * conn,DBusMessage * msg,void * userdata)298 static 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 
handle_get_card(DBusConnection * conn,DBusMessage * msg,void * userdata)324 static void handle_get_card(DBusConnection *conn, DBusMessage *msg, void *userdata) {
325     pa_dbusiface_device *d = userdata;
326     pa_card *card = NULL;
327     const char *object_path = NULL;
328 
329     pa_assert(conn);
330     pa_assert(msg);
331     pa_assert(d);
332 
333     card = (d->type == 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 
handle_get_sample_format(DBusConnection * conn,DBusMessage * msg,void * userdata)350 static 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 
handle_get_sample_rate(DBusConnection * conn,DBusMessage * msg,void * userdata)363 static 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 
handle_get_channels(DBusConnection * conn,DBusMessage * msg,void * userdata)376 static 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 
handle_get_volume(DBusConnection * conn,DBusMessage * msg,void * userdata)394 static 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 
handle_set_volume(DBusConnection * conn,DBusMessage * msg,DBusMessageIter * iter,void * userdata)409 static 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 
handle_get_has_flat_volume(DBusConnection * conn,DBusMessage * msg,void * userdata)453 static 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 
handle_get_has_convertible_to_decibel_volume(DBusConnection * conn,DBusMessage * msg,void * userdata)466 static 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 
handle_get_base_volume(DBusConnection * conn,DBusMessage * msg,void * userdata)481 static 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 
handle_get_volume_steps(DBusConnection * conn,DBusMessage * msg,void * userdata)494 static 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 
handle_get_mute(DBusConnection * conn,DBusMessage * msg,void * userdata)507 static 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 
handle_set_mute(DBusConnection * conn,DBusMessage * msg,DBusMessageIter * iter,void * userdata)517 static 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 
handle_get_has_hardware_volume(DBusConnection * conn,DBusMessage * msg,void * userdata)536 static 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 
handle_get_has_hardware_mute(DBusConnection * conn,DBusMessage * msg,void * userdata)551 static 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 
handle_get_configured_latency(DBusConnection * conn,DBusMessage * msg,void * userdata)566 static 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 
handle_get_has_dynamic_latency(DBusConnection * conn,DBusMessage * msg,void * userdata)581 static 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 
handle_get_latency(DBusConnection * conn,DBusMessage * msg,void * userdata)596 static 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 
handle_get_is_hardware_device(DBusConnection * conn,DBusMessage * msg,void * userdata)621 static 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 
handle_get_is_network_device(DBusConnection * conn,DBusMessage * msg,void * userdata)636 static 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 
handle_get_state(DBusConnection * conn,DBusMessage * msg,void * userdata)651 static 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. */
get_ports(pa_dbusiface_device * d,unsigned * n)665 static 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 
handle_get_ports(DBusConnection * conn,DBusMessage * msg,void * userdata)687 static 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 
handle_get_active_port(DBusConnection * conn,DBusMessage * msg,void * userdata)703 static 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 
handle_set_active_port(DBusConnection * conn,DBusMessage * msg,DBusMessageIter * iter,void * userdata)728 static 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 
handle_get_property_list(DBusConnection * conn,DBusMessage * msg,void * userdata)784 static 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 
handle_get_all(DBusConnection * conn,DBusMessage * msg,void * userdata)794 static 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 
handle_suspend(DBusConnection * conn,DBusMessage * msg,void * userdata)935 static 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 
handle_get_port_by_name(DBusConnection * conn,DBusMessage * msg,void * userdata)967 static 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 
handle_sink_get_monitor_source(DBusConnection * conn,DBusMessage * msg,void * userdata)994 static 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 
handle_sink_get_all(DBusConnection * conn,DBusMessage * msg,void * userdata)1008 static 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 
handle_source_get_monitor_of_sink(DBusConnection * conn,DBusMessage * msg,void * userdata)1036 static 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 
handle_source_get_all(DBusConnection * conn,DBusMessage * msg,void * userdata)1055 static 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 
volume_changed_cb(void * hook_data,void * call_data,void * slot_data)1085 static 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 
mute_changed_cb(void * hook_data,void * call_data,void * slot_data)1122 static 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 
state_changed_cb(void * hook_data,void * call_data,void * slot_data)1150 static 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 
port_changed_cb(void * hook_data,void * call_data,void * slot_data)1188 static 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 
proplist_changed_cb(void * hook_data,void * call_data,void * slot_data)1217 static 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 
pa_dbusiface_device_new_sink(pa_dbusiface_core * core,pa_sink * sink)1246 pa_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 
pa_dbusiface_device_new_source(pa_dbusiface_core * core,pa_source * source)1289 pa_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 
pa_dbusiface_device_free(pa_dbusiface_device * d)1332 void 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 
pa_dbusiface_device_get_path(pa_dbusiface_device * d)1359 const char *pa_dbusiface_device_get_path(pa_dbusiface_device *d) {
1360     pa_assert(d);
1361 
1362     return d->path;
1363 }
1364 
pa_dbusiface_device_get_sink(pa_dbusiface_device * d)1365 pa_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 
pa_dbusiface_device_get_source(pa_dbusiface_device * d)1372 pa_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