2 This file is part of PulseAudio.
4 Copyright 2009 Tanu Kaskinen
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.
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.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 #include <pulsecore/core-util.h>
27 #include <pulsecore/dbus-util.h>
28 #include <pulsecore/protocol-dbus.h>
30 #include "iface-device-port.h"
32 #include "iface-device.h"
34 #define SINK_OBJECT_NAME "sink"
35 #define SOURCE_OBJECT_NAME "source"
37 static void handle_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
38 static void handle_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
39 static void handle_get_driver(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
40 static void handle_get_owner_module(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
41 static void handle_get_card(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
42 static void handle_get_sample_format(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
43 static void handle_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
44 static void handle_get_channels(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
45 static void handle_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
46 static void handle_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
47 static void handle_get_has_flat_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
48 static void handle_get_has_convertible_to_decibel_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
49 static void handle_get_base_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
50 static void handle_get_volume_steps(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
51 static void handle_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
52 static void handle_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
53 static void handle_get_has_hardware_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
54 static void handle_get_has_hardware_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
55 static void handle_get_configured_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
56 static void handle_get_has_dynamic_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
57 static void handle_get_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
58 static void handle_get_is_hardware_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
59 static void handle_get_is_network_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
60 static void handle_get_state(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
61 static void handle_get_ports(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
62 static void handle_get_active_port(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
63 static void handle_set_active_port(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
64 static void handle_get_property_list(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
66 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
68 static void handle_suspend(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
69 static void handle_get_port_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
71 static void handle_sink_get_monitor_source(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
73 static void handle_sink_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
75 static void handle_source_get_monitor_of_sink(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
77 static void handle_source_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
84 struct pa_dbusiface_device
{
85 pa_dbusiface_core
*core
;
91 enum device_type type
;
96 pa_sink_state_t sink_state
;
97 pa_source_state_t source_state
;
100 uint32_t next_port_index
;
101 pa_device_port
*active_port
;
102 pa_proplist
*proplist
;
104 pa_dbus_protocol
*dbus_protocol
;
105 pa_subscription
*subscription
;
108 enum property_handler_index
{
109 PROPERTY_HANDLER_INDEX
,
110 PROPERTY_HANDLER_NAME
,
111 PROPERTY_HANDLER_DRIVER
,
112 PROPERTY_HANDLER_OWNER_MODULE
,
113 PROPERTY_HANDLER_CARD
,
114 PROPERTY_HANDLER_SAMPLE_FORMAT
,
115 PROPERTY_HANDLER_SAMPLE_RATE
,
116 PROPERTY_HANDLER_CHANNELS
,
117 PROPERTY_HANDLER_VOLUME
,
118 PROPERTY_HANDLER_HAS_FLAT_VOLUME
,
119 PROPERTY_HANDLER_HAS_CONVERTIBLE_TO_DECIBEL_VOLUME
,
120 PROPERTY_HANDLER_BASE_VOLUME
,
121 PROPERTY_HANDLER_VOLUME_STEPS
,
122 PROPERTY_HANDLER_MUTE
,
123 PROPERTY_HANDLER_HAS_HARDWARE_VOLUME
,
124 PROPERTY_HANDLER_HAS_HARDWARE_MUTE
,
125 PROPERTY_HANDLER_CONFIGURED_LATENCY
,
126 PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY
,
127 PROPERTY_HANDLER_LATENCY
,
128 PROPERTY_HANDLER_IS_HARDWARE_DEVICE
,
129 PROPERTY_HANDLER_IS_NETWORK_DEVICE
,
130 PROPERTY_HANDLER_STATE
,
131 PROPERTY_HANDLER_PORTS
,
132 PROPERTY_HANDLER_ACTIVE_PORT
,
133 PROPERTY_HANDLER_PROPERTY_LIST
,
137 enum sink_property_handler_index
{
138 SINK_PROPERTY_HANDLER_MONITOR_SOURCE
,
139 SINK_PROPERTY_HANDLER_MAX
142 enum source_property_handler_index
{
143 SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK
,
144 SOURCE_PROPERTY_HANDLER_MAX
147 static pa_dbus_property_handler property_handlers
[PROPERTY_HANDLER_MAX
] = {
148 [PROPERTY_HANDLER_INDEX
] = { .property_name
= "Index", .type
= "u", .get_cb
= handle_get_index
, .set_cb
= NULL
},
149 [PROPERTY_HANDLER_NAME
] = { .property_name
= "Name", .type
= "s", .get_cb
= handle_get_name
, .set_cb
= NULL
},
150 [PROPERTY_HANDLER_DRIVER
] = { .property_name
= "Driver", .type
= "s", .get_cb
= handle_get_driver
, .set_cb
= NULL
},
151 [PROPERTY_HANDLER_OWNER_MODULE
] = { .property_name
= "OwnerModule", .type
= "o", .get_cb
= handle_get_owner_module
, .set_cb
= NULL
},
152 [PROPERTY_HANDLER_CARD
] = { .property_name
= "Card", .type
= "o", .get_cb
= handle_get_card
, .set_cb
= NULL
},
153 [PROPERTY_HANDLER_SAMPLE_FORMAT
] = { .property_name
= "SampleFormat", .type
= "u", .get_cb
= handle_get_sample_format
, .set_cb
= NULL
},
154 [PROPERTY_HANDLER_SAMPLE_RATE
] = { .property_name
= "SampleRate", .type
= "u", .get_cb
= handle_get_sample_rate
, .set_cb
= NULL
},
155 [PROPERTY_HANDLER_CHANNELS
] = { .property_name
= "Channels", .type
= "au", .get_cb
= handle_get_channels
, .set_cb
= NULL
},
156 [PROPERTY_HANDLER_VOLUME
] = { .property_name
= "Volume", .type
= "au", .get_cb
= handle_get_volume
, .set_cb
= handle_set_volume
},
157 [PROPERTY_HANDLER_HAS_FLAT_VOLUME
] = { .property_name
= "HasFlatVolume", .type
= "b", .get_cb
= handle_get_has_flat_volume
, .set_cb
= NULL
},
158 [PROPERTY_HANDLER_HAS_CONVERTIBLE_TO_DECIBEL_VOLUME
] = { .property_name
= "HasConvertibleToDecibelVolume", .type
= "b", .get_cb
= handle_get_has_convertible_to_decibel_volume
, .set_cb
= NULL
},
159 [PROPERTY_HANDLER_BASE_VOLUME
] = { .property_name
= "BaseVolume", .type
= "u", .get_cb
= handle_get_base_volume
, .set_cb
= NULL
},
160 [PROPERTY_HANDLER_VOLUME_STEPS
] = { .property_name
= "VolumeSteps", .type
= "u", .get_cb
= handle_get_volume_steps
, .set_cb
= NULL
},
161 [PROPERTY_HANDLER_MUTE
] = { .property_name
= "Mute", .type
= "b", .get_cb
= handle_get_mute
, .set_cb
= handle_set_mute
},
162 [PROPERTY_HANDLER_HAS_HARDWARE_VOLUME
] = { .property_name
= "HasHardwareVolume", .type
= "b", .get_cb
= handle_get_has_hardware_volume
, .set_cb
= NULL
},
163 [PROPERTY_HANDLER_HAS_HARDWARE_MUTE
] = { .property_name
= "HasHardwareMute", .type
= "b", .get_cb
= handle_get_has_hardware_mute
, .set_cb
= NULL
},
164 [PROPERTY_HANDLER_CONFIGURED_LATENCY
] = { .property_name
= "ConfiguredLatency", .type
= "t", .get_cb
= handle_get_configured_latency
, .set_cb
= NULL
},
165 [PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY
] = { .property_name
= "HasDynamicLatency", .type
= "b", .get_cb
= handle_get_has_dynamic_latency
, .set_cb
= NULL
},
166 [PROPERTY_HANDLER_LATENCY
] = { .property_name
= "Latency", .type
= "t", .get_cb
= handle_get_latency
, .set_cb
= NULL
},
167 [PROPERTY_HANDLER_IS_HARDWARE_DEVICE
] = { .property_name
= "IsHardwareDevice", .type
= "b", .get_cb
= handle_get_is_hardware_device
, .set_cb
= NULL
},
168 [PROPERTY_HANDLER_IS_NETWORK_DEVICE
] = { .property_name
= "IsNetworkDevice", .type
= "b", .get_cb
= handle_get_is_network_device
, .set_cb
= NULL
},
169 [PROPERTY_HANDLER_STATE
] = { .property_name
= "State", .type
= "u", .get_cb
= handle_get_state
, .set_cb
= NULL
},
170 [PROPERTY_HANDLER_PORTS
] = { .property_name
= "Ports", .type
= "ao", .get_cb
= handle_get_ports
, .set_cb
= NULL
},
171 [PROPERTY_HANDLER_ACTIVE_PORT
] = { .property_name
= "ActivePort", .type
= "o", .get_cb
= handle_get_active_port
, .set_cb
= handle_set_active_port
},
172 [PROPERTY_HANDLER_PROPERTY_LIST
] = { .property_name
= "PropertyList", .type
= "a{say}", .get_cb
= handle_get_property_list
, .set_cb
= NULL
}
175 static pa_dbus_property_handler sink_property_handlers
[SINK_PROPERTY_HANDLER_MAX
] = {
176 [SINK_PROPERTY_HANDLER_MONITOR_SOURCE
] = { .property_name
= "MonitorSource", .type
= "o", .get_cb
= handle_sink_get_monitor_source
, .set_cb
= NULL
}
179 static pa_dbus_property_handler source_property_handlers
[SOURCE_PROPERTY_HANDLER_MAX
] = {
180 [SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK
] = { .property_name
= "MonitorOfSink", .type
= "o", .get_cb
= handle_source_get_monitor_of_sink
, .set_cb
= NULL
}
183 enum method_handler_index
{
184 METHOD_HANDLER_SUSPEND
,
185 METHOD_HANDLER_GET_PORT_BY_NAME
,
189 static pa_dbus_arg_info suspend_args
[] = { { "suspend", "b", "in" } };
190 static pa_dbus_arg_info get_port_by_name_args
[] = { { "name", "s", "in" }, { "port", "o", "out" } };
192 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
193 [METHOD_HANDLER_SUSPEND
] = {
194 .method_name
= "Suspend",
195 .arguments
= suspend_args
,
196 .n_arguments
= sizeof(suspend_args
) / sizeof(pa_dbus_arg_info
),
197 .receive_cb
= handle_suspend
},
198 [METHOD_HANDLER_GET_PORT_BY_NAME
] = {
199 .method_name
= "GetPortByName",
200 .arguments
= get_port_by_name_args
,
201 .n_arguments
= sizeof(get_port_by_name_args
) / sizeof(pa_dbus_arg_info
),
202 .receive_cb
= handle_get_port_by_name
}
206 SIGNAL_VOLUME_UPDATED
,
208 SIGNAL_STATE_UPDATED
,
209 SIGNAL_ACTIVE_PORT_UPDATED
,
210 SIGNAL_PROPERTY_LIST_UPDATED
,
214 static pa_dbus_arg_info volume_updated_args
[] = { { "volume", "au", NULL
} };
215 static pa_dbus_arg_info mute_updated_args
[] = { { "muted", "b", NULL
} };
216 static pa_dbus_arg_info state_updated_args
[] = { { "state", "u", NULL
} };
217 static pa_dbus_arg_info active_port_updated_args
[] = { { "port", "o", NULL
} };
218 static pa_dbus_arg_info property_list_updated_args
[] = { { "property_list", "a{say}", NULL
} };
220 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
221 [SIGNAL_VOLUME_UPDATED
] = { .name
= "VolumeUpdated", .arguments
= volume_updated_args
, .n_arguments
= 1 },
222 [SIGNAL_MUTE_UPDATED
] = { .name
= "MuteUpdated", .arguments
= mute_updated_args
, .n_arguments
= 1 },
223 [SIGNAL_STATE_UPDATED
] = { .name
= "StateUpdated", .arguments
= state_updated_args
, .n_arguments
= 1 },
224 [SIGNAL_ACTIVE_PORT_UPDATED
] = { .name
= "ActivePortUpdated", .arguments
= active_port_updated_args
, .n_arguments
= 1 },
225 [SIGNAL_PROPERTY_LIST_UPDATED
] = { .name
= "PropertyListUpdated", .arguments
= property_list_updated_args
, .n_arguments
= 1 }
228 static pa_dbus_interface_info device_interface_info
= {
229 .name
= PA_DBUSIFACE_DEVICE_INTERFACE
,
230 .method_handlers
= method_handlers
,
231 .n_method_handlers
= METHOD_HANDLER_MAX
,
232 .property_handlers
= property_handlers
,
233 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
234 .get_all_properties_cb
= handle_get_all
,
236 .n_signals
= SIGNAL_MAX
239 static pa_dbus_interface_info sink_interface_info
= {
240 .name
= PA_DBUSIFACE_SINK_INTERFACE
,
241 .method_handlers
= NULL
,
242 .n_method_handlers
= 0,
243 .property_handlers
= sink_property_handlers
,
244 .n_property_handlers
= SINK_PROPERTY_HANDLER_MAX
,
245 .get_all_properties_cb
= handle_sink_get_all
,
250 static pa_dbus_interface_info source_interface_info
= {
251 .name
= PA_DBUSIFACE_SOURCE_INTERFACE
,
252 .method_handlers
= NULL
,
253 .n_method_handlers
= 0,
254 .property_handlers
= source_property_handlers
,
255 .n_property_handlers
= SOURCE_PROPERTY_HANDLER_MAX
,
256 .get_all_properties_cb
= handle_source_get_all
,
261 static void handle_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
262 pa_dbusiface_device
*d
= userdata
;
263 dbus_uint32_t idx
= 0;
269 idx
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->index
: d
->source
->index
;
271 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &idx
);
274 static void handle_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
275 pa_dbusiface_device
*d
= userdata
;
276 const char *name
= NULL
;
282 name
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->name
: d
->source
->name
;
284 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &name
);
287 static void handle_get_driver(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
288 pa_dbusiface_device
*d
= userdata
;
289 const char *driver
= NULL
;
295 driver
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->driver
: d
->source
->driver
;
297 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &driver
);
300 static void handle_get_owner_module(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
301 pa_dbusiface_device
*d
= userdata
;
302 pa_module
*owner_module
= NULL
;
303 const char *object_path
= NULL
;
309 owner_module
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->module
: d
->source
->module
;
312 if (d
->type
== DEVICE_TYPE_SINK
)
313 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
314 "Sink %s doesn't have an owner module.", d
->sink
->name
);
316 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
317 "Source %s doesn't have an owner module.", d
->source
->name
);
321 object_path
= pa_dbusiface_core_get_module_path(d
->core
, owner_module
);
323 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &object_path
);
326 static void handle_get_card(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
327 pa_dbusiface_device
*d
= userdata
;
328 pa_card
*card
= NULL
;
329 const char *object_path
= NULL
;
335 card
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->card
: d
->source
->card
;
338 if (d
->type
== DEVICE_TYPE_SINK
)
339 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
340 "Sink %s doesn't belong to any card.", d
->sink
->name
);
342 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
343 "Source %s doesn't belong to any card.", d
->source
->name
);
347 object_path
= pa_dbusiface_core_get_card_path(d
->core
, card
);
349 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &object_path
);
352 static void handle_get_sample_format(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
353 pa_dbusiface_device
*d
= userdata
;
354 dbus_uint32_t sample_format
= 0;
360 sample_format
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->sample_spec
.format
: d
->source
->sample_spec
.format
;
362 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &sample_format
);
365 static void handle_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
366 pa_dbusiface_device
*d
= userdata
;
367 dbus_uint32_t sample_rate
= 0;
373 sample_rate
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->sample_spec
.rate
: d
->source
->sample_spec
.rate
;
375 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &sample_rate
);
378 static void handle_get_channels(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
379 pa_dbusiface_device
*d
= userdata
;
380 pa_channel_map
*channel_map
= NULL
;
381 dbus_uint32_t channels
[PA_CHANNELS_MAX
];
388 channel_map
= (d
->type
== DEVICE_TYPE_SINK
) ? &d
->sink
->channel_map
: &d
->source
->channel_map
;
390 for (i
= 0; i
< channel_map
->channels
; ++i
)
391 channels
[i
] = channel_map
->map
[i
];
393 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, channels
, channel_map
->channels
);
396 static void handle_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
397 pa_dbusiface_device
*d
= userdata
;
398 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
405 for (i
= 0; i
< d
->volume
.channels
; ++i
)
406 volume
[i
] = d
->volume
.values
[i
];
408 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, volume
, d
->volume
.channels
);
411 static void handle_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
412 pa_dbusiface_device
*d
= userdata
;
413 DBusMessageIter array_iter
;
414 int device_channels
= 0;
415 dbus_uint32_t
*volume
= NULL
;
416 int n_volume_entries
= 0;
425 pa_cvolume_init(&new_vol
);
427 device_channels
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->channel_map
.channels
: d
->source
->channel_map
.channels
;
429 new_vol
.channels
= device_channels
;
431 dbus_message_iter_recurse(iter
, &array_iter
);
432 dbus_message_iter_get_fixed_array(&array_iter
, &volume
, &n_volume_entries
);
434 if (n_volume_entries
!= device_channels
) {
435 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
,
436 "Expected %u volume entries, got %i.", device_channels
, n_volume_entries
);
440 for (i
= 0; i
< n_volume_entries
; ++i
) {
441 if (volume
[i
] > PA_VOLUME_MAX
) {
442 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too large volume value: %u", volume
[i
]);
445 new_vol
.values
[i
] = volume
[i
];
448 if (d
->type
== DEVICE_TYPE_SINK
)
449 pa_sink_set_volume(d
->sink
, &new_vol
, TRUE
, TRUE
);
451 pa_source_set_volume(d
->source
, &new_vol
, TRUE
);
453 pa_dbus_send_empty_reply(conn
, msg
);
456 static void handle_get_has_flat_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
457 pa_dbusiface_device
*d
= userdata
;
458 dbus_bool_t has_flat_volume
= FALSE
;
464 has_flat_volume
= (d
->type
== DEVICE_TYPE_SINK
) ? (d
->sink
->flags
& PA_SINK_FLAT_VOLUME
) : FALSE
;
466 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &has_flat_volume
);
469 static void handle_get_has_convertible_to_decibel_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
470 pa_dbusiface_device
*d
= userdata
;
471 dbus_bool_t has_convertible_to_decibel_volume
= FALSE
;
477 has_convertible_to_decibel_volume
= (d
->type
== DEVICE_TYPE_SINK
)
478 ? (d
->sink
->flags
& PA_SINK_DECIBEL_VOLUME
)
479 : (d
->source
->flags
& PA_SOURCE_DECIBEL_VOLUME
);
481 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &has_convertible_to_decibel_volume
);
484 static void handle_get_base_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
485 pa_dbusiface_device
*d
= userdata
;
486 dbus_uint32_t base_volume
;
492 base_volume
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->base_volume
: d
->source
->base_volume
;
494 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &base_volume
);
497 static void handle_get_volume_steps(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
498 pa_dbusiface_device
*d
= userdata
;
499 dbus_uint32_t volume_steps
;
505 volume_steps
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->n_volume_steps
: d
->source
->n_volume_steps
;
507 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &volume_steps
);
510 static void handle_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
511 pa_dbusiface_device
*d
= userdata
;
517 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &d
->mute
);
520 static void handle_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
521 pa_dbusiface_device
*d
= userdata
;
522 dbus_bool_t mute
= FALSE
;
529 dbus_message_iter_get_basic(iter
, &mute
);
531 if (d
->type
== DEVICE_TYPE_SINK
)
532 pa_sink_set_mute(d
->sink
, mute
, TRUE
);
534 pa_source_set_mute(d
->source
, mute
, TRUE
);
536 pa_dbus_send_empty_reply(conn
, msg
);
539 static void handle_get_has_hardware_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
540 pa_dbusiface_device
*d
= userdata
;
541 dbus_bool_t has_hardware_volume
= FALSE
;
547 has_hardware_volume
= (d
->type
== DEVICE_TYPE_SINK
)
548 ? (d
->sink
->flags
& PA_SINK_HW_VOLUME_CTRL
)
549 : (d
->source
->flags
& PA_SOURCE_HW_VOLUME_CTRL
);
551 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &has_hardware_volume
);
554 static void handle_get_has_hardware_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
555 pa_dbusiface_device
*d
= userdata
;
556 dbus_bool_t has_hardware_mute
= FALSE
;
562 has_hardware_mute
= (d
->type
== DEVICE_TYPE_SINK
)
563 ? (d
->sink
->flags
& PA_SINK_HW_MUTE_CTRL
)
564 : (d
->source
->flags
& PA_SOURCE_HW_MUTE_CTRL
);
566 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &has_hardware_mute
);
569 static void handle_get_configured_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
570 pa_dbusiface_device
*d
= userdata
;
571 dbus_uint64_t configured_latency
= 0;
577 configured_latency
= (d
->type
== DEVICE_TYPE_SINK
)
578 ? pa_sink_get_requested_latency(d
->sink
)
579 : pa_source_get_requested_latency(d
->source
);
581 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT64
, &configured_latency
);
584 static void handle_get_has_dynamic_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
585 pa_dbusiface_device
*d
= userdata
;
586 dbus_bool_t has_dynamic_latency
= FALSE
;
592 has_dynamic_latency
= (d
->type
== DEVICE_TYPE_SINK
)
593 ? (d
->sink
->flags
& PA_SINK_DYNAMIC_LATENCY
)
594 : (d
->source
->flags
& PA_SOURCE_DYNAMIC_LATENCY
);
596 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &has_dynamic_latency
);
599 static void handle_get_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
600 pa_dbusiface_device
*d
= userdata
;
601 dbus_uint64_t latency
= 0;
607 if (d
->type
== DEVICE_TYPE_SINK
&& !(d
->sink
->flags
& PA_SINK_LATENCY
))
608 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
609 "Sink %s doesn't support latency querying.", d
->sink
->name
);
610 else if (d
->type
== 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
);
615 latency
= (d
->type
== DEVICE_TYPE_SINK
) ? pa_sink_get_latency(d
->sink
) : pa_source_get_latency(d
->source
);
617 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT64
, &latency
);
620 static void handle_get_is_hardware_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
621 pa_dbusiface_device
*d
= userdata
;
622 dbus_bool_t is_hardware_device
= FALSE
;
628 is_hardware_device
= (d
->type
== DEVICE_TYPE_SINK
)
629 ? (d
->sink
->flags
& PA_SINK_HARDWARE
)
630 : (d
->source
->flags
& PA_SOURCE_HARDWARE
);
632 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &is_hardware_device
);
635 static void handle_get_is_network_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
636 pa_dbusiface_device
*d
= userdata
;
637 dbus_bool_t is_network_device
= FALSE
;
643 is_network_device
= (d
->type
== DEVICE_TYPE_SINK
)
644 ? (d
->sink
->flags
& PA_SINK_NETWORK
)
645 : (d
->source
->flags
& PA_SOURCE_NETWORK
);
647 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &is_network_device
);
650 static void handle_get_state(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
651 pa_dbusiface_device
*d
= userdata
;
658 state
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink_state
: d
->source_state
;
660 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &state
);
663 /* The caller frees the array, but not the strings. */
664 static const char **get_ports(pa_dbusiface_device
*d
, unsigned *n
) {
668 pa_dbusiface_device_port
*port
= NULL
;
673 *n
= pa_hashmap_size(d
->ports
);
678 ports
= pa_xnew(const char *, *n
);
680 PA_HASHMAP_FOREACH(port
, d
->ports
, state
)
681 ports
[i
++] = pa_dbusiface_device_port_get_path(port
);
686 static void handle_get_ports(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
687 pa_dbusiface_device
*d
= userdata
;
688 const char **ports
= NULL
;
689 unsigned n_ports
= 0;
695 ports
= get_ports(d
, &n_ports
);
697 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, ports
, n_ports
);
702 static void handle_get_active_port(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
703 pa_dbusiface_device
*d
= userdata
;
704 const char *active_port
;
710 if (!d
->active_port
) {
711 pa_assert(pa_hashmap_isempty(d
->ports
));
713 if (d
->type
== DEVICE_TYPE_SINK
)
714 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
715 "The sink %s has no ports, and therefore there's no active port either.", d
->sink
->name
);
717 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
718 "The source %s has no ports, and therefore there's no active port either.", d
->source
->name
);
722 active_port
= pa_dbusiface_device_port_get_path(pa_hashmap_get(d
->ports
, d
->active_port
->name
));
724 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &active_port
);
727 static void handle_set_active_port(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
728 pa_dbusiface_device
*d
= userdata
;
729 const char *new_active_path
;
730 pa_dbusiface_device_port
*new_active
;
738 if (!d
->active_port
) {
739 pa_assert(pa_hashmap_isempty(d
->ports
));
741 if (d
->type
== DEVICE_TYPE_SINK
)
742 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
743 "The sink %s has no ports, and therefore there's no active port either.", d
->sink
->name
);
745 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
746 "The source %s has no ports, and therefore there's no active port either.", d
->source
->name
);
750 dbus_message_iter_get_basic(iter
, &new_active_path
);
752 if (!(new_active
= pa_hashmap_get(d
->ports
, new_active_path
))) {
753 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "No such port: %s", new_active_path
);
757 if (d
->type
== DEVICE_TYPE_SINK
) {
758 if ((r
= pa_sink_set_port(d
->sink
, pa_dbusiface_device_port_get_name(new_active
), TRUE
)) < 0) {
759 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
,
760 "Internal error in PulseAudio: pa_sink_set_port() failed with error code %i.", r
);
764 if ((r
= pa_source_set_port(d
->source
, pa_dbusiface_device_port_get_name(new_active
), TRUE
)) < 0) {
765 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
,
766 "Internal error in PulseAudio: pa_source_set_port() failed with error code %i.", r
);
771 pa_dbus_send_empty_reply(conn
, msg
);
774 static void handle_get_property_list(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
775 pa_dbusiface_device
*d
= userdata
;
781 pa_dbus_send_proplist_variant_reply(conn
, msg
, d
->proplist
);
784 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
785 pa_dbusiface_device
*d
= userdata
;
786 DBusMessage
*reply
= NULL
;
787 DBusMessageIter msg_iter
;
788 DBusMessageIter dict_iter
;
789 dbus_uint32_t idx
= 0;
790 const char *name
= NULL
;
791 const char *driver
= NULL
;
792 pa_module
*owner_module
= NULL
;
793 const char *owner_module_path
= NULL
;
794 pa_card
*card
= NULL
;
795 const char *card_path
= NULL
;
796 dbus_uint32_t sample_format
= 0;
797 dbus_uint32_t sample_rate
= 0;
798 pa_channel_map
*channel_map
= NULL
;
799 dbus_uint32_t channels
[PA_CHANNELS_MAX
];
800 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
801 dbus_bool_t has_flat_volume
= FALSE
;
802 dbus_bool_t has_convertible_to_decibel_volume
= FALSE
;
803 dbus_uint32_t base_volume
= 0;
804 dbus_uint32_t volume_steps
= 0;
805 dbus_bool_t has_hardware_volume
= FALSE
;
806 dbus_bool_t has_hardware_mute
= FALSE
;
807 dbus_uint64_t configured_latency
= 0;
808 dbus_bool_t has_dynamic_latency
= FALSE
;
809 dbus_uint64_t latency
= 0;
810 dbus_bool_t is_hardware_device
= FALSE
;
811 dbus_bool_t is_network_device
= FALSE
;
812 dbus_uint32_t state
= 0;
813 const char **ports
= NULL
;
814 unsigned n_ports
= 0;
815 const char *active_port
= NULL
;
822 if (d
->type
== DEVICE_TYPE_SINK
) {
823 idx
= d
->sink
->index
;
824 name
= d
->sink
->name
;
825 driver
= d
->sink
->driver
;
826 owner_module
= d
->sink
->module
;
827 card
= d
->sink
->card
;
828 sample_format
= d
->sink
->sample_spec
.format
;
829 sample_rate
= d
->sink
->sample_spec
.rate
;
830 channel_map
= &d
->sink
->channel_map
;
831 has_flat_volume
= d
->sink
->flags
& PA_SINK_FLAT_VOLUME
;
832 has_convertible_to_decibel_volume
= d
->sink
->flags
& PA_SINK_DECIBEL_VOLUME
;
833 base_volume
= d
->sink
->base_volume
;
834 volume_steps
= d
->sink
->n_volume_steps
;
835 has_hardware_volume
= d
->sink
->flags
& PA_SINK_HW_VOLUME_CTRL
;
836 has_hardware_mute
= d
->sink
->flags
& PA_SINK_HW_MUTE_CTRL
;
837 configured_latency
= pa_sink_get_requested_latency(d
->sink
);
838 has_dynamic_latency
= d
->sink
->flags
& PA_SINK_DYNAMIC_LATENCY
;
839 latency
= pa_sink_get_latency(d
->sink
);
840 is_hardware_device
= d
->sink
->flags
& PA_SINK_HARDWARE
;
841 is_network_device
= d
->sink
->flags
& PA_SINK_NETWORK
;
842 state
= pa_sink_get_state(d
->sink
);
844 idx
= d
->source
->index
;
845 name
= d
->source
->name
;
846 driver
= d
->source
->driver
;
847 owner_module
= d
->source
->module
;
848 card
= d
->source
->card
;
849 sample_format
= d
->source
->sample_spec
.format
;
850 sample_rate
= d
->source
->sample_spec
.rate
;
851 channel_map
= &d
->source
->channel_map
;
852 has_flat_volume
= FALSE
;
853 has_convertible_to_decibel_volume
= d
->source
->flags
& PA_SOURCE_DECIBEL_VOLUME
;
854 base_volume
= d
->source
->base_volume
;
855 volume_steps
= d
->source
->n_volume_steps
;
856 has_hardware_volume
= d
->source
->flags
& PA_SOURCE_HW_VOLUME_CTRL
;
857 has_hardware_mute
= d
->source
->flags
& PA_SOURCE_HW_MUTE_CTRL
;
858 configured_latency
= pa_source_get_requested_latency(d
->source
);
859 has_dynamic_latency
= d
->source
->flags
& PA_SOURCE_DYNAMIC_LATENCY
;
860 latency
= pa_source_get_latency(d
->source
);
861 is_hardware_device
= d
->source
->flags
& PA_SOURCE_HARDWARE
;
862 is_network_device
= d
->source
->flags
& PA_SOURCE_NETWORK
;
863 state
= pa_source_get_state(d
->source
);
866 owner_module_path
= pa_dbusiface_core_get_module_path(d
->core
, owner_module
);
868 card_path
= pa_dbusiface_core_get_card_path(d
->core
, card
);
869 for (i
= 0; i
< channel_map
->channels
; ++i
)
870 channels
[i
] = channel_map
->map
[i
];
871 for (i
= 0; i
< d
->volume
.channels
; ++i
)
872 volume
[i
] = d
->volume
.values
[i
];
873 ports
= get_ports(d
, &n_ports
);
875 active_port
= pa_dbusiface_device_port_get_path(pa_hashmap_get(d
->ports
, d
->active_port
->name
));
877 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
879 dbus_message_iter_init_append(reply
, &msg_iter
);
880 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
882 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &idx
);
883 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &name
);
884 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_DRIVER
].property_name
, DBUS_TYPE_STRING
, &driver
);
887 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_OWNER_MODULE
].property_name
, DBUS_TYPE_OBJECT_PATH
, &owner_module_path
);
890 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_CARD
].property_name
, DBUS_TYPE_OBJECT_PATH
, &card_path
);
892 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_SAMPLE_FORMAT
].property_name
, DBUS_TYPE_UINT32
, &sample_format
);
893 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_SAMPLE_RATE
].property_name
, DBUS_TYPE_UINT32
, &sample_rate
);
894 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_CHANNELS
].property_name
, DBUS_TYPE_UINT32
, channels
, channel_map
->channels
);
895 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_VOLUME
].property_name
, DBUS_TYPE_UINT32
, volume
, d
->volume
.channels
);
896 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_HAS_FLAT_VOLUME
].property_name
, DBUS_TYPE_BOOLEAN
, &has_flat_volume
);
897 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
);
898 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_BASE_VOLUME
].property_name
, DBUS_TYPE_UINT32
, &base_volume
);
899 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_VOLUME_STEPS
].property_name
, DBUS_TYPE_UINT32
, &volume_steps
);
900 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &d
->mute
);
901 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_HAS_HARDWARE_VOLUME
].property_name
, DBUS_TYPE_BOOLEAN
, &has_hardware_volume
);
902 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_HAS_HARDWARE_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &has_hardware_mute
);
903 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_CONFIGURED_LATENCY
].property_name
, DBUS_TYPE_UINT64
, &configured_latency
);
904 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY
].property_name
, DBUS_TYPE_BOOLEAN
, &has_dynamic_latency
);
905 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_LATENCY
].property_name
, DBUS_TYPE_UINT64
, &latency
);
906 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_IS_HARDWARE_DEVICE
].property_name
, DBUS_TYPE_BOOLEAN
, &is_hardware_device
);
907 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_IS_NETWORK_DEVICE
].property_name
, DBUS_TYPE_BOOLEAN
, &is_network_device
);
908 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_STATE
].property_name
, DBUS_TYPE_UINT32
, &state
);
909 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_PORTS
].property_name
, DBUS_TYPE_OBJECT_PATH
, ports
, n_ports
);
912 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ACTIVE_PORT
].property_name
, DBUS_TYPE_OBJECT_PATH
, &active_port
);
914 pa_dbus_append_proplist_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_PROPERTY_LIST
].property_name
, d
->proplist
);
916 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
918 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
920 dbus_message_unref(reply
);
925 static void handle_suspend(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
926 pa_dbusiface_device
*d
= userdata
;
927 dbus_bool_t suspend
= FALSE
;
933 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_BOOLEAN
, &suspend
, DBUS_TYPE_INVALID
));
935 if ((d
->type
== DEVICE_TYPE_SINK
) && (pa_sink_suspend(d
->sink
, suspend
, PA_SUSPEND_USER
) < 0)) {
936 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
, "Internal error in PulseAudio: pa_sink_suspend() failed.");
938 } else if ((d
->type
== DEVICE_TYPE_SOURCE
) && (pa_source_suspend(d
->source
, suspend
, PA_SUSPEND_USER
) < 0)) {
939 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
, "Internal error in PulseAudio: pa_source_suspend() failed.");
943 pa_dbus_send_empty_reply(conn
, msg
);
946 static void handle_get_port_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
947 pa_dbusiface_device
*d
= userdata
;
948 const char *port_name
= NULL
;
949 pa_dbusiface_device_port
*port
= NULL
;
950 const char *port_path
= NULL
;
956 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_STRING
, &port_name
, DBUS_TYPE_INVALID
));
958 if (!(port
= pa_hashmap_get(d
->ports
, port_name
))) {
959 if (d
->type
== DEVICE_TYPE_SINK
)
960 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
,
961 "%s: No such port on sink %s.", port_name
, d
->sink
->name
);
963 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
,
964 "%s: No such port on source %s.", port_name
, d
->source
->name
);
968 port_path
= pa_dbusiface_device_port_get_path(port
);
970 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &port_path
);
973 static void handle_sink_get_monitor_source(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
974 pa_dbusiface_device
*d
= userdata
;
975 const char *monitor_source
= NULL
;
980 pa_assert(d
->type
== DEVICE_TYPE_SINK
);
982 monitor_source
= pa_dbusiface_core_get_source_path(d
->core
, d
->sink
->monitor_source
);
984 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &monitor_source
);
987 static void handle_sink_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
988 pa_dbusiface_device
*d
= userdata
;
989 DBusMessage
*reply
= NULL
;
990 DBusMessageIter msg_iter
;
991 DBusMessageIter dict_iter
;
992 const char *monitor_source
= NULL
;
997 pa_assert(d
->type
== DEVICE_TYPE_SINK
);
999 monitor_source
= pa_dbusiface_core_get_source_path(d
->core
, d
->sink
->monitor_source
);
1001 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1003 dbus_message_iter_init_append(reply
, &msg_iter
);
1004 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1006 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[SINK_PROPERTY_HANDLER_MONITOR_SOURCE
].property_name
, DBUS_TYPE_OBJECT_PATH
, &monitor_source
);
1008 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1010 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1012 dbus_message_unref(reply
);
1015 static void handle_source_get_monitor_of_sink(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
1016 pa_dbusiface_device
*d
= userdata
;
1017 const char *monitor_of_sink
= NULL
;
1022 pa_assert(d
->type
== DEVICE_TYPE_SOURCE
);
1024 if (!d
->source
->monitor_of
) {
1025 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "Source %s is not a monitor source.", d
->source
->name
);
1029 monitor_of_sink
= pa_dbusiface_core_get_sink_path(d
->core
, d
->source
->monitor_of
);
1031 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &monitor_of_sink
);
1034 static void handle_source_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
1035 pa_dbusiface_device
*d
= userdata
;
1036 DBusMessage
*reply
= NULL
;
1037 DBusMessageIter msg_iter
;
1038 DBusMessageIter dict_iter
;
1039 const char *monitor_of_sink
= NULL
;
1044 pa_assert(d
->type
== DEVICE_TYPE_SOURCE
);
1046 if (d
->source
->monitor_of
)
1047 monitor_of_sink
= pa_dbusiface_core_get_sink_path(d
->core
, d
->source
->monitor_of
);
1049 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1051 dbus_message_iter_init_append(reply
, &msg_iter
);
1052 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1054 if (monitor_of_sink
)
1055 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
);
1057 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1059 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1061 dbus_message_unref(reply
);
1064 static void subscription_cb(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1065 pa_dbusiface_device
*d
= userdata
;
1066 DBusMessage
*signal_msg
= NULL
;
1067 const pa_cvolume
*new_volume
= NULL
;
1068 pa_bool_t new_mute
= FALSE
;
1069 pa_sink_state_t new_sink_state
= 0;
1070 pa_source_state_t new_source_state
= 0;
1071 pa_device_port
*new_active_port
= NULL
;
1072 pa_proplist
*new_proplist
= NULL
;
1078 if ((d
->type
== DEVICE_TYPE_SINK
&& idx
!= d
->sink
->index
) || (d
->type
== DEVICE_TYPE_SOURCE
&& idx
!= d
->source
->index
))
1081 if ((t
& PA_SUBSCRIPTION_EVENT_TYPE_MASK
) != PA_SUBSCRIPTION_EVENT_CHANGE
)
1084 pa_assert(((d
->type
== DEVICE_TYPE_SINK
)
1085 && ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK
))
1086 || ((d
->type
== DEVICE_TYPE_SOURCE
)
1087 && ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE
)));
1089 new_volume
= (d
->type
== DEVICE_TYPE_SINK
)
1090 ? pa_sink_get_volume(d
->sink
, FALSE
)
1091 : pa_source_get_volume(d
->source
, FALSE
);
1093 if (!pa_cvolume_equal(&d
->volume
, new_volume
)) {
1094 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
1095 dbus_uint32_t
*volume_ptr
= volume
;
1097 d
->volume
= *new_volume
;
1099 for (i
= 0; i
< d
->volume
.channels
; ++i
)
1100 volume
[i
] = d
->volume
.values
[i
];
1102 pa_assert_se(signal_msg
= dbus_message_new_signal(d
->path
,
1103 PA_DBUSIFACE_DEVICE_INTERFACE
,
1104 signals
[SIGNAL_VOLUME_UPDATED
].name
));
1105 pa_assert_se(dbus_message_append_args(signal_msg
,
1106 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &volume_ptr
, d
->volume
.channels
,
1107 DBUS_TYPE_INVALID
));
1109 pa_dbus_protocol_send_signal(d
->dbus_protocol
, signal_msg
);
1110 dbus_message_unref(signal_msg
);
1114 new_mute
= (d
->type
== DEVICE_TYPE_SINK
) ? pa_sink_get_mute(d
->sink
, FALSE
) : pa_source_get_mute(d
->source
, FALSE
);
1116 if (d
->mute
!= new_mute
) {
1119 pa_assert_se(signal_msg
= dbus_message_new_signal(d
->path
,
1120 PA_DBUSIFACE_DEVICE_INTERFACE
,
1121 signals
[SIGNAL_MUTE_UPDATED
].name
));
1122 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_BOOLEAN
, &d
->mute
, DBUS_TYPE_INVALID
));
1124 pa_dbus_protocol_send_signal(d
->dbus_protocol
, signal_msg
);
1125 dbus_message_unref(signal_msg
);
1129 if (d
->type
== DEVICE_TYPE_SINK
)
1130 new_sink_state
= pa_sink_get_state(d
->sink
);
1132 new_source_state
= pa_source_get_state(d
->source
);
1134 if ((d
->type
== DEVICE_TYPE_SINK
&& d
->sink_state
!= new_sink_state
)
1135 || (d
->type
== DEVICE_TYPE_SOURCE
&& d
->source_state
!= new_source_state
)) {
1136 dbus_uint32_t state
= 0;
1138 if (d
->type
== DEVICE_TYPE_SINK
)
1139 d
->sink_state
= new_sink_state
;
1141 d
->source_state
= new_source_state
;
1143 state
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink_state
: d
->source_state
;
1145 pa_assert_se(signal_msg
= dbus_message_new_signal(d
->path
,
1146 PA_DBUSIFACE_DEVICE_INTERFACE
,
1147 signals
[SIGNAL_STATE_UPDATED
].name
));
1148 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_UINT32
, &state
, DBUS_TYPE_INVALID
));
1150 pa_dbus_protocol_send_signal(d
->dbus_protocol
, signal_msg
);
1151 dbus_message_unref(signal_msg
);
1155 new_active_port
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->active_port
: d
->source
->active_port
;
1157 if (d
->active_port
!= new_active_port
) {
1158 const char *object_path
= NULL
;
1160 d
->active_port
= new_active_port
;
1161 object_path
= pa_dbusiface_device_port_get_path(pa_hashmap_get(d
->ports
, d
->active_port
->name
));
1163 pa_assert_se(signal_msg
= dbus_message_new_signal(d
->path
,
1164 PA_DBUSIFACE_DEVICE_INTERFACE
,
1165 signals
[SIGNAL_ACTIVE_PORT_UPDATED
].name
));
1166 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &object_path
, DBUS_TYPE_INVALID
));
1168 pa_dbus_protocol_send_signal(d
->dbus_protocol
, signal_msg
);
1169 dbus_message_unref(signal_msg
);
1173 new_proplist
= (d
->type
== DEVICE_TYPE_SINK
) ? d
->sink
->proplist
: d
->source
->proplist
;
1175 if (!pa_proplist_equal(d
->proplist
, new_proplist
)) {
1176 DBusMessageIter msg_iter
;
1178 pa_proplist_update(d
->proplist
, PA_UPDATE_SET
, new_proplist
);
1180 pa_assert_se(signal_msg
= dbus_message_new_signal(d
->path
,
1181 PA_DBUSIFACE_DEVICE_INTERFACE
,
1182 signals
[SIGNAL_PROPERTY_LIST_UPDATED
].name
));
1183 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
1184 pa_dbus_append_proplist(&msg_iter
, d
->proplist
);
1186 pa_dbus_protocol_send_signal(d
->dbus_protocol
, signal_msg
);
1187 dbus_message_unref(signal_msg
);
1192 pa_dbusiface_device
*pa_dbusiface_device_new_sink(pa_dbusiface_core
*core
, pa_sink
*sink
) {
1193 pa_dbusiface_device
*d
= NULL
;
1198 d
= pa_xnew0(pa_dbusiface_device
, 1);
1200 d
->sink
= pa_sink_ref(sink
);
1201 d
->type
= DEVICE_TYPE_SINK
;
1202 d
->path
= pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH
, SINK_OBJECT_NAME
, sink
->index
);
1203 d
->volume
= *pa_sink_get_volume(sink
, FALSE
);
1204 d
->mute
= pa_sink_get_mute(sink
, FALSE
);
1205 d
->sink_state
= pa_sink_get_state(sink
);
1206 d
->ports
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
1207 d
->next_port_index
= 0;
1208 d
->active_port
= NULL
;
1209 d
->proplist
= pa_proplist_copy(sink
->proplist
);
1210 d
->dbus_protocol
= pa_dbus_protocol_get(sink
->core
);
1211 d
->subscription
= pa_subscription_new(sink
->core
, PA_SUBSCRIPTION_MASK_SINK
, subscription_cb
, d
);
1214 pa_device_port
*port
;
1217 PA_HASHMAP_FOREACH(port
, sink
->ports
, state
) {
1218 pa_dbusiface_device_port
*p
= pa_dbusiface_device_port_new(d
, sink
->core
, port
, d
->next_port_index
++);
1219 pa_hashmap_put(d
->ports
, pa_dbusiface_device_port_get_name(p
), p
);
1221 pa_assert_se(d
->active_port
= sink
->active_port
);
1224 pa_assert_se(pa_dbus_protocol_add_interface(d
->dbus_protocol
, d
->path
, &device_interface_info
, d
) >= 0);
1225 pa_assert_se(pa_dbus_protocol_add_interface(d
->dbus_protocol
, d
->path
, &sink_interface_info
, d
) >= 0);
1230 pa_dbusiface_device
*pa_dbusiface_device_new_source(pa_dbusiface_core
*core
, pa_source
*source
) {
1231 pa_dbusiface_device
*d
= NULL
;
1236 d
= pa_xnew0(pa_dbusiface_device
, 1);
1238 d
->source
= pa_source_ref(source
);
1239 d
->type
= DEVICE_TYPE_SOURCE
;
1240 d
->path
= pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH
, SOURCE_OBJECT_NAME
, source
->index
);
1241 d
->volume
= *pa_source_get_volume(source
, FALSE
);
1242 d
->mute
= pa_source_get_mute(source
, FALSE
);
1243 d
->source_state
= pa_source_get_state(source
);
1244 d
->ports
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
1245 d
->next_port_index
= 0;
1246 d
->active_port
= NULL
;
1247 d
->proplist
= pa_proplist_copy(source
->proplist
);
1248 d
->dbus_protocol
= pa_dbus_protocol_get(source
->core
);
1249 d
->subscription
= pa_subscription_new(source
->core
, PA_SUBSCRIPTION_MASK_SOURCE
, subscription_cb
, d
);
1251 if (source
->ports
) {
1252 pa_device_port
*port
;
1255 PA_HASHMAP_FOREACH(port
, source
->ports
, state
) {
1256 pa_dbusiface_device_port
*p
= pa_dbusiface_device_port_new(d
, source
->core
, port
, d
->next_port_index
++);
1257 pa_hashmap_put(d
->ports
, pa_dbusiface_device_port_get_name(p
), p
);
1259 pa_assert_se(d
->active_port
= source
->active_port
);
1262 pa_assert_se(pa_dbus_protocol_add_interface(d
->dbus_protocol
, d
->path
, &device_interface_info
, d
) >= 0);
1263 pa_assert_se(pa_dbus_protocol_add_interface(d
->dbus_protocol
, d
->path
, &source_interface_info
, d
) >= 0);
1268 static void port_free_cb(void *p
, void *userdata
) {
1269 pa_dbusiface_device_port
*port
= p
;
1273 pa_dbusiface_device_port_free(port
);
1276 void pa_dbusiface_device_free(pa_dbusiface_device
*d
) {
1279 pa_assert_se(pa_dbus_protocol_remove_interface(d
->dbus_protocol
, d
->path
, device_interface_info
.name
) >= 0);
1281 if (d
->type
== DEVICE_TYPE_SINK
) {
1282 pa_assert_se(pa_dbus_protocol_remove_interface(d
->dbus_protocol
, d
->path
, sink_interface_info
.name
) >= 0);
1283 pa_sink_unref(d
->sink
);
1286 pa_assert_se(pa_dbus_protocol_remove_interface(d
->dbus_protocol
, d
->path
, source_interface_info
.name
) >= 0);
1287 pa_source_unref(d
->source
);
1289 pa_hashmap_free(d
->ports
, port_free_cb
, NULL
);
1290 pa_proplist_free(d
->proplist
);
1291 pa_dbus_protocol_unref(d
->dbus_protocol
);
1292 pa_subscription_free(d
->subscription
);
1298 const char *pa_dbusiface_device_get_path(pa_dbusiface_device
*d
) {
1304 pa_sink
*pa_dbusiface_device_get_sink(pa_dbusiface_device
*d
) {
1306 pa_assert(d
->type
== DEVICE_TYPE_SINK
);
1311 pa_source
*pa_dbusiface_device_get_source(pa_dbusiface_device
*d
) {
1313 pa_assert(d
->type
== DEVICE_TYPE_SOURCE
);