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