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
);
79 struct pa_dbusiface_device
{
80 pa_dbusiface_core
*core
;
86 pa_device_type_t type
;
91 pa_sink_state_t sink_state
;
92 pa_source_state_t source_state
;
95 uint32_t next_port_index
;
96 pa_device_port
*active_port
;
97 pa_proplist
*proplist
;
99 pa_dbus_protocol
*dbus_protocol
;
100 pa_subscription
*subscription
;
103 enum property_handler_index
{
104 PROPERTY_HANDLER_INDEX
,
105 PROPERTY_HANDLER_NAME
,
106 PROPERTY_HANDLER_DRIVER
,
107 PROPERTY_HANDLER_OWNER_MODULE
,
108 PROPERTY_HANDLER_CARD
,
109 PROPERTY_HANDLER_SAMPLE_FORMAT
,
110 PROPERTY_HANDLER_SAMPLE_RATE
,
111 PROPERTY_HANDLER_CHANNELS
,
112 PROPERTY_HANDLER_VOLUME
,
113 PROPERTY_HANDLER_HAS_FLAT_VOLUME
,
114 PROPERTY_HANDLER_HAS_CONVERTIBLE_TO_DECIBEL_VOLUME
,
115 PROPERTY_HANDLER_BASE_VOLUME
,
116 PROPERTY_HANDLER_VOLUME_STEPS
,
117 PROPERTY_HANDLER_MUTE
,
118 PROPERTY_HANDLER_HAS_HARDWARE_VOLUME
,
119 PROPERTY_HANDLER_HAS_HARDWARE_MUTE
,
120 PROPERTY_HANDLER_CONFIGURED_LATENCY
,
121 PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY
,
122 PROPERTY_HANDLER_LATENCY
,
123 PROPERTY_HANDLER_IS_HARDWARE_DEVICE
,
124 PROPERTY_HANDLER_IS_NETWORK_DEVICE
,
125 PROPERTY_HANDLER_STATE
,
126 PROPERTY_HANDLER_PORTS
,
127 PROPERTY_HANDLER_ACTIVE_PORT
,
128 PROPERTY_HANDLER_PROPERTY_LIST
,
132 enum sink_property_handler_index
{
133 SINK_PROPERTY_HANDLER_MONITOR_SOURCE
,
134 SINK_PROPERTY_HANDLER_MAX
137 enum source_property_handler_index
{
138 SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK
,
139 SOURCE_PROPERTY_HANDLER_MAX
142 static pa_dbus_property_handler property_handlers
[PROPERTY_HANDLER_MAX
] = {
143 [PROPERTY_HANDLER_INDEX
] = { .property_name
= "Index", .type
= "u", .get_cb
= handle_get_index
, .set_cb
= NULL
},
144 [PROPERTY_HANDLER_NAME
] = { .property_name
= "Name", .type
= "s", .get_cb
= handle_get_name
, .set_cb
= NULL
},
145 [PROPERTY_HANDLER_DRIVER
] = { .property_name
= "Driver", .type
= "s", .get_cb
= handle_get_driver
, .set_cb
= NULL
},
146 [PROPERTY_HANDLER_OWNER_MODULE
] = { .property_name
= "OwnerModule", .type
= "o", .get_cb
= handle_get_owner_module
, .set_cb
= NULL
},
147 [PROPERTY_HANDLER_CARD
] = { .property_name
= "Card", .type
= "o", .get_cb
= handle_get_card
, .set_cb
= NULL
},
148 [PROPERTY_HANDLER_SAMPLE_FORMAT
] = { .property_name
= "SampleFormat", .type
= "u", .get_cb
= handle_get_sample_format
, .set_cb
= NULL
},
149 [PROPERTY_HANDLER_SAMPLE_RATE
] = { .property_name
= "SampleRate", .type
= "u", .get_cb
= handle_get_sample_rate
, .set_cb
= NULL
},
150 [PROPERTY_HANDLER_CHANNELS
] = { .property_name
= "Channels", .type
= "au", .get_cb
= handle_get_channels
, .set_cb
= NULL
},
151 [PROPERTY_HANDLER_VOLUME
] = { .property_name
= "Volume", .type
= "au", .get_cb
= handle_get_volume
, .set_cb
= handle_set_volume
},
152 [PROPERTY_HANDLER_HAS_FLAT_VOLUME
] = { .property_name
= "HasFlatVolume", .type
= "b", .get_cb
= handle_get_has_flat_volume
, .set_cb
= NULL
},
153 [PROPERTY_HANDLER_HAS_CONVERTIBLE_TO_DECIBEL_VOLUME
] = { .property_name
= "HasConvertibleToDecibelVolume", .type
= "b", .get_cb
= handle_get_has_convertible_to_decibel_volume
, .set_cb
= NULL
},
154 [PROPERTY_HANDLER_BASE_VOLUME
] = { .property_name
= "BaseVolume", .type
= "u", .get_cb
= handle_get_base_volume
, .set_cb
= NULL
},
155 [PROPERTY_HANDLER_VOLUME_STEPS
] = { .property_name
= "VolumeSteps", .type
= "u", .get_cb
= handle_get_volume_steps
, .set_cb
= NULL
},
156 [PROPERTY_HANDLER_MUTE
] = { .property_name
= "Mute", .type
= "b", .get_cb
= handle_get_mute
, .set_cb
= handle_set_mute
},
157 [PROPERTY_HANDLER_HAS_HARDWARE_VOLUME
] = { .property_name
= "HasHardwareVolume", .type
= "b", .get_cb
= handle_get_has_hardware_volume
, .set_cb
= NULL
},
158 [PROPERTY_HANDLER_HAS_HARDWARE_MUTE
] = { .property_name
= "HasHardwareMute", .type
= "b", .get_cb
= handle_get_has_hardware_mute
, .set_cb
= NULL
},
159 [PROPERTY_HANDLER_CONFIGURED_LATENCY
] = { .property_name
= "ConfiguredLatency", .type
= "t", .get_cb
= handle_get_configured_latency
, .set_cb
= NULL
},
160 [PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY
] = { .property_name
= "HasDynamicLatency", .type
= "b", .get_cb
= handle_get_has_dynamic_latency
, .set_cb
= NULL
},
161 [PROPERTY_HANDLER_LATENCY
] = { .property_name
= "Latency", .type
= "t", .get_cb
= handle_get_latency
, .set_cb
= NULL
},
162 [PROPERTY_HANDLER_IS_HARDWARE_DEVICE
] = { .property_name
= "IsHardwareDevice", .type
= "b", .get_cb
= handle_get_is_hardware_device
, .set_cb
= NULL
},
163 [PROPERTY_HANDLER_IS_NETWORK_DEVICE
] = { .property_name
= "IsNetworkDevice", .type
= "b", .get_cb
= handle_get_is_network_device
, .set_cb
= NULL
},
164 [PROPERTY_HANDLER_STATE
] = { .property_name
= "State", .type
= "u", .get_cb
= handle_get_state
, .set_cb
= NULL
},
165 [PROPERTY_HANDLER_PORTS
] = { .property_name
= "Ports", .type
= "ao", .get_cb
= handle_get_ports
, .set_cb
= NULL
},
166 [PROPERTY_HANDLER_ACTIVE_PORT
] = { .property_name
= "ActivePort", .type
= "o", .get_cb
= handle_get_active_port
, .set_cb
= handle_set_active_port
},
167 [PROPERTY_HANDLER_PROPERTY_LIST
] = { .property_name
= "PropertyList", .type
= "a{say}", .get_cb
= handle_get_property_list
, .set_cb
= NULL
}
170 static pa_dbus_property_handler sink_property_handlers
[SINK_PROPERTY_HANDLER_MAX
] = {
171 [SINK_PROPERTY_HANDLER_MONITOR_SOURCE
] = { .property_name
= "MonitorSource", .type
= "o", .get_cb
= handle_sink_get_monitor_source
, .set_cb
= NULL
}
174 static pa_dbus_property_handler source_property_handlers
[SOURCE_PROPERTY_HANDLER_MAX
] = {
175 [SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK
] = { .property_name
= "MonitorOfSink", .type
= "o", .get_cb
= handle_source_get_monitor_of_sink
, .set_cb
= NULL
}
178 enum method_handler_index
{
179 METHOD_HANDLER_SUSPEND
,
180 METHOD_HANDLER_GET_PORT_BY_NAME
,
184 static pa_dbus_arg_info suspend_args
[] = { { "suspend", "b", "in" } };
185 static pa_dbus_arg_info get_port_by_name_args
[] = { { "name", "s", "in" }, { "port", "o", "out" } };
187 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
188 [METHOD_HANDLER_SUSPEND
] = {
189 .method_name
= "Suspend",
190 .arguments
= suspend_args
,
191 .n_arguments
= sizeof(suspend_args
) / sizeof(pa_dbus_arg_info
),
192 .receive_cb
= handle_suspend
},
193 [METHOD_HANDLER_GET_PORT_BY_NAME
] = {
194 .method_name
= "GetPortByName",
195 .arguments
= get_port_by_name_args
,
196 .n_arguments
= sizeof(get_port_by_name_args
) / sizeof(pa_dbus_arg_info
),
197 .receive_cb
= handle_get_port_by_name
}
201 SIGNAL_VOLUME_UPDATED
,
203 SIGNAL_STATE_UPDATED
,
204 SIGNAL_ACTIVE_PORT_UPDATED
,
205 SIGNAL_PROPERTY_LIST_UPDATED
,
209 static pa_dbus_arg_info volume_updated_args
[] = { { "volume", "au", NULL
} };
210 static pa_dbus_arg_info mute_updated_args
[] = { { "muted", "b", NULL
} };
211 static pa_dbus_arg_info state_updated_args
[] = { { "state", "u", NULL
} };
212 static pa_dbus_arg_info active_port_updated_args
[] = { { "port", "o", NULL
} };
213 static pa_dbus_arg_info property_list_updated_args
[] = { { "property_list", "a{say}", NULL
} };
215 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
216 [SIGNAL_VOLUME_UPDATED
] = { .name
= "VolumeUpdated", .arguments
= volume_updated_args
, .n_arguments
= 1 },
217 [SIGNAL_MUTE_UPDATED
] = { .name
= "MuteUpdated", .arguments
= mute_updated_args
, .n_arguments
= 1 },
218 [SIGNAL_STATE_UPDATED
] = { .name
= "StateUpdated", .arguments
= state_updated_args
, .n_arguments
= 1 },
219 [SIGNAL_ACTIVE_PORT_UPDATED
] = { .name
= "ActivePortUpdated", .arguments
= active_port_updated_args
, .n_arguments
= 1 },
220 [SIGNAL_PROPERTY_LIST_UPDATED
] = { .name
= "PropertyListUpdated", .arguments
= property_list_updated_args
, .n_arguments
= 1 }
223 static pa_dbus_interface_info device_interface_info
= {
224 .name
= PA_DBUSIFACE_DEVICE_INTERFACE
,
225 .method_handlers
= method_handlers
,
226 .n_method_handlers
= METHOD_HANDLER_MAX
,
227 .property_handlers
= property_handlers
,
228 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
229 .get_all_properties_cb
= handle_get_all
,
231 .n_signals
= SIGNAL_MAX
234 static pa_dbus_interface_info sink_interface_info
= {
235 .name
= PA_DBUSIFACE_SINK_INTERFACE
,
236 .method_handlers
= NULL
,
237 .n_method_handlers
= 0,
238 .property_handlers
= sink_property_handlers
,
239 .n_property_handlers
= SINK_PROPERTY_HANDLER_MAX
,
240 .get_all_properties_cb
= handle_sink_get_all
,
245 static pa_dbus_interface_info source_interface_info
= {
246 .name
= PA_DBUSIFACE_SOURCE_INTERFACE
,
247 .method_handlers
= NULL
,
248 .n_method_handlers
= 0,
249 .property_handlers
= source_property_handlers
,
250 .n_property_handlers
= SOURCE_PROPERTY_HANDLER_MAX
,
251 .get_all_properties_cb
= handle_source_get_all
,
256 static void handle_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
257 pa_dbusiface_device
*d
= userdata
;
258 dbus_uint32_t idx
= 0;
264 idx
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->index
: d
->source
->index
;
266 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &idx
);
269 static void handle_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
270 pa_dbusiface_device
*d
= userdata
;
271 const char *name
= NULL
;
277 name
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->name
: d
->source
->name
;
279 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &name
);
282 static void handle_get_driver(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
283 pa_dbusiface_device
*d
= userdata
;
284 const char *driver
= NULL
;
290 driver
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->driver
: d
->source
->driver
;
292 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &driver
);
295 static void handle_get_owner_module(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
296 pa_dbusiface_device
*d
= userdata
;
297 pa_module
*owner_module
= NULL
;
298 const char *object_path
= NULL
;
304 owner_module
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->module
: d
->source
->module
;
307 if (d
->type
== PA_DEVICE_TYPE_SINK
)
308 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
309 "Sink %s doesn't have an owner module.", d
->sink
->name
);
311 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
312 "Source %s doesn't have an owner module.", d
->source
->name
);
316 object_path
= pa_dbusiface_core_get_module_path(d
->core
, owner_module
);
318 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &object_path
);
321 static void handle_get_card(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
322 pa_dbusiface_device
*d
= userdata
;
323 pa_card
*card
= NULL
;
324 const char *object_path
= NULL
;
330 card
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->card
: d
->source
->card
;
333 if (d
->type
== PA_DEVICE_TYPE_SINK
)
334 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
335 "Sink %s doesn't belong to any card.", d
->sink
->name
);
337 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
338 "Source %s doesn't belong to any card.", d
->source
->name
);
342 object_path
= pa_dbusiface_core_get_card_path(d
->core
, card
);
344 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &object_path
);
347 static void handle_get_sample_format(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
348 pa_dbusiface_device
*d
= userdata
;
349 dbus_uint32_t sample_format
= 0;
355 sample_format
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->sample_spec
.format
: d
->source
->sample_spec
.format
;
357 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &sample_format
);
360 static void handle_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
361 pa_dbusiface_device
*d
= userdata
;
362 dbus_uint32_t sample_rate
= 0;
368 sample_rate
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->sample_spec
.rate
: d
->source
->sample_spec
.rate
;
370 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &sample_rate
);
373 static void handle_get_channels(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
374 pa_dbusiface_device
*d
= userdata
;
375 pa_channel_map
*channel_map
= NULL
;
376 dbus_uint32_t channels
[PA_CHANNELS_MAX
];
383 channel_map
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? &d
->sink
->channel_map
: &d
->source
->channel_map
;
385 for (i
= 0; i
< channel_map
->channels
; ++i
)
386 channels
[i
] = channel_map
->map
[i
];
388 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, channels
, channel_map
->channels
);
391 static void handle_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
392 pa_dbusiface_device
*d
= userdata
;
393 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
400 for (i
= 0; i
< d
->volume
.channels
; ++i
)
401 volume
[i
] = d
->volume
.values
[i
];
403 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, volume
, d
->volume
.channels
);
406 static void handle_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
407 pa_dbusiface_device
*d
= userdata
;
408 DBusMessageIter array_iter
;
409 int device_channels
= 0;
410 dbus_uint32_t
*volume
= NULL
;
411 int n_volume_entries
= 0;
420 device_channels
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->channel_map
.channels
: d
->source
->channel_map
.channels
;
422 dbus_message_iter_recurse(iter
, &array_iter
);
423 dbus_message_iter_get_fixed_array(&array_iter
, &volume
, &n_volume_entries
);
425 if (n_volume_entries
!= device_channels
&& n_volume_entries
!= 1) {
426 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
,
427 "Expected %u volume entries, got %i.", device_channels
, n_volume_entries
);
431 pa_cvolume_init(&new_vol
);
432 new_vol
.channels
= n_volume_entries
;
434 for (i
= 0; i
< n_volume_entries
; ++i
) {
435 if (!PA_VOLUME_IS_VALID(volume
[i
])) {
436 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too large volume value: %u", volume
[i
]);
439 new_vol
.values
[i
] = volume
[i
];
442 if (d
->type
== PA_DEVICE_TYPE_SINK
)
443 pa_sink_set_volume(d
->sink
, &new_vol
, true, true);
445 pa_source_set_volume(d
->source
, &new_vol
, true, true);
447 pa_dbus_send_empty_reply(conn
, msg
);
450 static void handle_get_has_flat_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
451 pa_dbusiface_device
*d
= userdata
;
452 dbus_bool_t has_flat_volume
= FALSE
;
458 has_flat_volume
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? !!(d
->sink
->flags
& PA_SINK_FLAT_VOLUME
) : FALSE
;
460 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &has_flat_volume
);
463 static void handle_get_has_convertible_to_decibel_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
464 pa_dbusiface_device
*d
= userdata
;
465 dbus_bool_t has_convertible_to_decibel_volume
= FALSE
;
471 has_convertible_to_decibel_volume
= (d
->type
== PA_DEVICE_TYPE_SINK
)
472 ? !!(d
->sink
->flags
& PA_SINK_DECIBEL_VOLUME
)
473 : !!(d
->source
->flags
& PA_SOURCE_DECIBEL_VOLUME
);
475 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &has_convertible_to_decibel_volume
);
478 static void handle_get_base_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
479 pa_dbusiface_device
*d
= userdata
;
480 dbus_uint32_t base_volume
;
486 base_volume
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->base_volume
: d
->source
->base_volume
;
488 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &base_volume
);
491 static void handle_get_volume_steps(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
492 pa_dbusiface_device
*d
= userdata
;
493 dbus_uint32_t volume_steps
;
499 volume_steps
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->n_volume_steps
: d
->source
->n_volume_steps
;
501 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &volume_steps
);
504 static void handle_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
505 pa_dbusiface_device
*d
= userdata
;
511 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &d
->mute
);
514 static void handle_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
515 pa_dbusiface_device
*d
= userdata
;
516 dbus_bool_t mute
= FALSE
;
523 dbus_message_iter_get_basic(iter
, &mute
);
525 if (d
->type
== PA_DEVICE_TYPE_SINK
)
526 pa_sink_set_mute(d
->sink
, mute
, true);
528 pa_source_set_mute(d
->source
, mute
, true);
530 pa_dbus_send_empty_reply(conn
, msg
);
533 static void handle_get_has_hardware_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
534 pa_dbusiface_device
*d
= userdata
;
535 dbus_bool_t has_hardware_volume
= FALSE
;
541 has_hardware_volume
= (d
->type
== PA_DEVICE_TYPE_SINK
)
542 ? !!(d
->sink
->flags
& PA_SINK_HW_VOLUME_CTRL
)
543 : !!(d
->source
->flags
& PA_SOURCE_HW_VOLUME_CTRL
);
545 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &has_hardware_volume
);
548 static void handle_get_has_hardware_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
549 pa_dbusiface_device
*d
= userdata
;
550 dbus_bool_t has_hardware_mute
= FALSE
;
556 has_hardware_mute
= (d
->type
== PA_DEVICE_TYPE_SINK
)
557 ? !!(d
->sink
->flags
& PA_SINK_HW_MUTE_CTRL
)
558 : !!(d
->source
->flags
& PA_SOURCE_HW_MUTE_CTRL
);
560 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &has_hardware_mute
);
563 static void handle_get_configured_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
564 pa_dbusiface_device
*d
= userdata
;
565 dbus_uint64_t configured_latency
= 0;
571 configured_latency
= (d
->type
== PA_DEVICE_TYPE_SINK
)
572 ? pa_sink_get_requested_latency(d
->sink
)
573 : pa_source_get_requested_latency(d
->source
);
575 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT64
, &configured_latency
);
578 static void handle_get_has_dynamic_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
579 pa_dbusiface_device
*d
= userdata
;
580 dbus_bool_t has_dynamic_latency
= FALSE
;
586 has_dynamic_latency
= (d
->type
== PA_DEVICE_TYPE_SINK
)
587 ? !!(d
->sink
->flags
& PA_SINK_DYNAMIC_LATENCY
)
588 : !!(d
->source
->flags
& PA_SOURCE_DYNAMIC_LATENCY
);
590 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &has_dynamic_latency
);
593 static void handle_get_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
594 pa_dbusiface_device
*d
= userdata
;
595 dbus_uint64_t latency
= 0;
601 if (d
->type
== PA_DEVICE_TYPE_SINK
&& !(d
->sink
->flags
& PA_SINK_LATENCY
)) {
602 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
603 "Sink %s doesn't support latency querying.", d
->sink
->name
);
607 if (d
->type
== PA_DEVICE_TYPE_SOURCE
&& !(d
->source
->flags
& PA_SOURCE_LATENCY
)) {
608 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
609 "Source %s doesn't support latency querying.", d
->source
->name
);
613 latency
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? pa_sink_get_latency(d
->sink
) : pa_source_get_latency(d
->source
);
615 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT64
, &latency
);
618 static void handle_get_is_hardware_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
619 pa_dbusiface_device
*d
= userdata
;
620 dbus_bool_t is_hardware_device
= FALSE
;
626 is_hardware_device
= (d
->type
== PA_DEVICE_TYPE_SINK
)
627 ? !!(d
->sink
->flags
& PA_SINK_HARDWARE
)
628 : !!(d
->source
->flags
& PA_SOURCE_HARDWARE
);
630 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &is_hardware_device
);
633 static void handle_get_is_network_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
634 pa_dbusiface_device
*d
= userdata
;
635 dbus_bool_t is_network_device
= FALSE
;
641 is_network_device
= (d
->type
== PA_DEVICE_TYPE_SINK
)
642 ? !!(d
->sink
->flags
& PA_SINK_NETWORK
)
643 : !!(d
->source
->flags
& PA_SOURCE_NETWORK
);
645 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &is_network_device
);
648 static void handle_get_state(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
649 pa_dbusiface_device
*d
= userdata
;
656 state
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink_state
: d
->source_state
;
658 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &state
);
661 /* The caller frees the array, but not the strings. */
662 static const char **get_ports(pa_dbusiface_device
*d
, unsigned *n
) {
666 pa_dbusiface_device_port
*port
= NULL
;
671 *n
= pa_hashmap_size(d
->ports
);
676 ports
= pa_xnew(const char *, *n
);
678 PA_HASHMAP_FOREACH(port
, d
->ports
, state
)
679 ports
[i
++] = pa_dbusiface_device_port_get_path(port
);
684 static void handle_get_ports(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
685 pa_dbusiface_device
*d
= userdata
;
686 const char **ports
= NULL
;
687 unsigned n_ports
= 0;
693 ports
= get_ports(d
, &n_ports
);
695 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, ports
, n_ports
);
700 static void handle_get_active_port(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
701 pa_dbusiface_device
*d
= userdata
;
702 const char *active_port
;
708 if (!d
->active_port
) {
709 pa_assert(pa_hashmap_isempty(d
->ports
));
711 if (d
->type
== PA_DEVICE_TYPE_SINK
)
712 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
713 "The sink %s has no ports, and therefore there's no active port either.", d
->sink
->name
);
715 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
716 "The source %s has no ports, and therefore there's no active port either.", d
->source
->name
);
720 active_port
= pa_dbusiface_device_port_get_path(pa_hashmap_get(d
->ports
, d
->active_port
->name
));
722 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &active_port
);
725 static void handle_set_active_port(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
726 pa_dbusiface_device
*d
= userdata
;
727 const char *new_active_path
;
728 pa_dbusiface_device_port
*new_active
;
736 if (!d
->active_port
) {
737 pa_assert(pa_hashmap_isempty(d
->ports
));
739 if (d
->type
== PA_DEVICE_TYPE_SINK
)
740 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
741 "The sink %s has no ports, and therefore there's no active port either.", d
->sink
->name
);
743 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
744 "The source %s has no ports, and therefore there's no active port either.", d
->source
->name
);
748 dbus_message_iter_get_basic(iter
, &new_active_path
);
750 if (!(new_active
= pa_hashmap_get(d
->ports
, new_active_path
))) {
751 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "No such port: %s", new_active_path
);
755 if (d
->type
== PA_DEVICE_TYPE_SINK
) {
756 if ((r
= pa_sink_set_port(d
->sink
, pa_dbusiface_device_port_get_name(new_active
), true)) < 0) {
757 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
,
758 "Internal error in PulseAudio: pa_sink_set_port() failed with error code %i.", r
);
762 if ((r
= pa_source_set_port(d
->source
, pa_dbusiface_device_port_get_name(new_active
), true)) < 0) {
763 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
,
764 "Internal error in PulseAudio: pa_source_set_port() failed with error code %i.", r
);
769 pa_dbus_send_empty_reply(conn
, msg
);
772 static void handle_get_property_list(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
773 pa_dbusiface_device
*d
= userdata
;
779 pa_dbus_send_proplist_variant_reply(conn
, msg
, d
->proplist
);
782 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
783 pa_dbusiface_device
*d
= userdata
;
784 DBusMessage
*reply
= NULL
;
785 DBusMessageIter msg_iter
;
786 DBusMessageIter dict_iter
;
787 dbus_uint32_t idx
= 0;
788 const char *name
= NULL
;
789 const char *driver
= NULL
;
790 pa_module
*owner_module
= NULL
;
791 const char *owner_module_path
= NULL
;
792 pa_card
*card
= NULL
;
793 const char *card_path
= NULL
;
794 dbus_uint32_t sample_format
= 0;
795 dbus_uint32_t sample_rate
= 0;
796 pa_channel_map
*channel_map
= NULL
;
797 dbus_uint32_t channels
[PA_CHANNELS_MAX
];
798 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
799 dbus_bool_t has_flat_volume
= FALSE
;
800 dbus_bool_t has_convertible_to_decibel_volume
= FALSE
;
801 dbus_uint32_t base_volume
= 0;
802 dbus_uint32_t volume_steps
= 0;
803 dbus_bool_t has_hardware_volume
= FALSE
;
804 dbus_bool_t has_hardware_mute
= FALSE
;
805 dbus_uint64_t configured_latency
= 0;
806 dbus_bool_t has_dynamic_latency
= FALSE
;
807 dbus_uint64_t latency
= 0;
808 dbus_bool_t is_hardware_device
= FALSE
;
809 dbus_bool_t is_network_device
= FALSE
;
810 dbus_uint32_t state
= 0;
811 const char **ports
= NULL
;
812 unsigned n_ports
= 0;
813 const char *active_port
= NULL
;
820 if (d
->type
== PA_DEVICE_TYPE_SINK
) {
821 idx
= d
->sink
->index
;
822 name
= d
->sink
->name
;
823 driver
= d
->sink
->driver
;
824 owner_module
= d
->sink
->module
;
825 card
= d
->sink
->card
;
826 sample_format
= d
->sink
->sample_spec
.format
;
827 sample_rate
= d
->sink
->sample_spec
.rate
;
828 channel_map
= &d
->sink
->channel_map
;
829 has_flat_volume
= !!(d
->sink
->flags
& PA_SINK_FLAT_VOLUME
);
830 has_convertible_to_decibel_volume
= !!(d
->sink
->flags
& PA_SINK_DECIBEL_VOLUME
);
831 base_volume
= d
->sink
->base_volume
;
832 volume_steps
= d
->sink
->n_volume_steps
;
833 has_hardware_volume
= !!(d
->sink
->flags
& PA_SINK_HW_VOLUME_CTRL
);
834 has_hardware_mute
= !!(d
->sink
->flags
& PA_SINK_HW_MUTE_CTRL
);
835 configured_latency
= pa_sink_get_requested_latency(d
->sink
);
836 has_dynamic_latency
= !!(d
->sink
->flags
& PA_SINK_DYNAMIC_LATENCY
);
837 latency
= pa_sink_get_latency(d
->sink
);
838 is_hardware_device
= !!(d
->sink
->flags
& PA_SINK_HARDWARE
);
839 is_network_device
= !!(d
->sink
->flags
& PA_SINK_NETWORK
);
840 state
= pa_sink_get_state(d
->sink
);
842 idx
= d
->source
->index
;
843 name
= d
->source
->name
;
844 driver
= d
->source
->driver
;
845 owner_module
= d
->source
->module
;
846 card
= d
->source
->card
;
847 sample_format
= d
->source
->sample_spec
.format
;
848 sample_rate
= d
->source
->sample_spec
.rate
;
849 channel_map
= &d
->source
->channel_map
;
850 has_flat_volume
= FALSE
;
851 has_convertible_to_decibel_volume
= !!(d
->source
->flags
& PA_SOURCE_DECIBEL_VOLUME
);
852 base_volume
= d
->source
->base_volume
;
853 volume_steps
= d
->source
->n_volume_steps
;
854 has_hardware_volume
= !!(d
->source
->flags
& PA_SOURCE_HW_VOLUME_CTRL
);
855 has_hardware_mute
= !!(d
->source
->flags
& PA_SOURCE_HW_MUTE_CTRL
);
856 configured_latency
= pa_source_get_requested_latency(d
->source
);
857 has_dynamic_latency
= !!(d
->source
->flags
& PA_SOURCE_DYNAMIC_LATENCY
);
858 latency
= pa_source_get_latency(d
->source
);
859 is_hardware_device
= !!(d
->source
->flags
& PA_SOURCE_HARDWARE
);
860 is_network_device
= !!(d
->source
->flags
& PA_SOURCE_NETWORK
);
861 state
= pa_source_get_state(d
->source
);
864 owner_module_path
= pa_dbusiface_core_get_module_path(d
->core
, owner_module
);
866 card_path
= pa_dbusiface_core_get_card_path(d
->core
, card
);
867 for (i
= 0; i
< channel_map
->channels
; ++i
)
868 channels
[i
] = channel_map
->map
[i
];
869 for (i
= 0; i
< d
->volume
.channels
; ++i
)
870 volume
[i
] = d
->volume
.values
[i
];
871 ports
= get_ports(d
, &n_ports
);
873 active_port
= pa_dbusiface_device_port_get_path(pa_hashmap_get(d
->ports
, d
->active_port
->name
));
875 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
877 dbus_message_iter_init_append(reply
, &msg_iter
);
878 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
880 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &idx
);
881 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &name
);
882 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_DRIVER
].property_name
, DBUS_TYPE_STRING
, &driver
);
885 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_OWNER_MODULE
].property_name
, DBUS_TYPE_OBJECT_PATH
, &owner_module_path
);
888 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_CARD
].property_name
, DBUS_TYPE_OBJECT_PATH
, &card_path
);
890 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_SAMPLE_FORMAT
].property_name
, DBUS_TYPE_UINT32
, &sample_format
);
891 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_SAMPLE_RATE
].property_name
, DBUS_TYPE_UINT32
, &sample_rate
);
892 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_CHANNELS
].property_name
, DBUS_TYPE_UINT32
, channels
, channel_map
->channels
);
893 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_VOLUME
].property_name
, DBUS_TYPE_UINT32
, volume
, d
->volume
.channels
);
894 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_HAS_FLAT_VOLUME
].property_name
, DBUS_TYPE_BOOLEAN
, &has_flat_volume
);
895 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_HAS_CONVERTIBLE_TO_DECIBEL_VOLUME
].property_name
, DBUS_TYPE_BOOLEAN
, &has_convertible_to_decibel_volume
);
896 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_BASE_VOLUME
].property_name
, DBUS_TYPE_UINT32
, &base_volume
);
897 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_VOLUME_STEPS
].property_name
, DBUS_TYPE_UINT32
, &volume_steps
);
898 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &d
->mute
);
899 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_HAS_HARDWARE_VOLUME
].property_name
, DBUS_TYPE_BOOLEAN
, &has_hardware_volume
);
900 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_HAS_HARDWARE_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &has_hardware_mute
);
901 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_CONFIGURED_LATENCY
].property_name
, DBUS_TYPE_UINT64
, &configured_latency
);
902 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_HAS_DYNAMIC_LATENCY
].property_name
, DBUS_TYPE_BOOLEAN
, &has_dynamic_latency
);
903 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_LATENCY
].property_name
, DBUS_TYPE_UINT64
, &latency
);
904 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_IS_HARDWARE_DEVICE
].property_name
, DBUS_TYPE_BOOLEAN
, &is_hardware_device
);
905 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_IS_NETWORK_DEVICE
].property_name
, DBUS_TYPE_BOOLEAN
, &is_network_device
);
906 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_STATE
].property_name
, DBUS_TYPE_UINT32
, &state
);
907 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_PORTS
].property_name
, DBUS_TYPE_OBJECT_PATH
, ports
, n_ports
);
910 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ACTIVE_PORT
].property_name
, DBUS_TYPE_OBJECT_PATH
, &active_port
);
912 pa_dbus_append_proplist_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_PROPERTY_LIST
].property_name
, d
->proplist
);
914 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
916 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
918 dbus_message_unref(reply
);
923 static void handle_suspend(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
924 pa_dbusiface_device
*d
= userdata
;
925 dbus_bool_t suspend
= FALSE
;
932 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_BOOLEAN
, &suspend
, DBUS_TYPE_INVALID
));
933 pa_assert_se(client
= pa_dbus_protocol_get_client(d
->dbus_protocol
, conn
));
935 if (d
->type
== PA_DEVICE_TYPE_SINK
) {
936 pa_log_debug("%s sink %s requested by client %" PRIu32
".", suspend
? "Suspending" : "Resuming", d
->sink
->name
, client
->index
);
938 if (pa_sink_suspend(d
->sink
, suspend
, PA_SUSPEND_USER
) < 0) {
939 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
, "Internal error in PulseAudio: pa_sink_suspend() failed.");
944 pa_log_debug("%s source %s requested by client %" PRIu32
".", suspend
? "Suspending" : "Resuming", d
->source
->name
, client
->index
);
946 if (pa_source_suspend(d
->source
, suspend
, PA_SUSPEND_USER
) < 0) {
947 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
, "Internal error in PulseAudio: pa_source_suspend() failed.");
952 pa_dbus_send_empty_reply(conn
, msg
);
955 static void handle_get_port_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
956 pa_dbusiface_device
*d
= userdata
;
957 const char *port_name
= NULL
;
958 pa_dbusiface_device_port
*port
= NULL
;
959 const char *port_path
= NULL
;
965 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_STRING
, &port_name
, DBUS_TYPE_INVALID
));
967 if (!(port
= pa_hashmap_get(d
->ports
, port_name
))) {
968 if (d
->type
== PA_DEVICE_TYPE_SINK
)
969 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
,
970 "%s: No such port on sink %s.", port_name
, d
->sink
->name
);
972 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
,
973 "%s: No such port on source %s.", port_name
, d
->source
->name
);
977 port_path
= pa_dbusiface_device_port_get_path(port
);
979 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &port_path
);
982 static void handle_sink_get_monitor_source(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
983 pa_dbusiface_device
*d
= userdata
;
984 const char *monitor_source
= NULL
;
989 pa_assert(d
->type
== PA_DEVICE_TYPE_SINK
);
991 monitor_source
= pa_dbusiface_core_get_source_path(d
->core
, d
->sink
->monitor_source
);
993 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &monitor_source
);
996 static void handle_sink_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
997 pa_dbusiface_device
*d
= userdata
;
998 DBusMessage
*reply
= NULL
;
999 DBusMessageIter msg_iter
;
1000 DBusMessageIter dict_iter
;
1001 const char *monitor_source
= NULL
;
1006 pa_assert(d
->type
== PA_DEVICE_TYPE_SINK
);
1008 monitor_source
= pa_dbusiface_core_get_source_path(d
->core
, d
->sink
->monitor_source
);
1010 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1012 dbus_message_iter_init_append(reply
, &msg_iter
);
1013 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1015 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[SINK_PROPERTY_HANDLER_MONITOR_SOURCE
].property_name
, DBUS_TYPE_OBJECT_PATH
, &monitor_source
);
1017 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1019 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1021 dbus_message_unref(reply
);
1024 static void handle_source_get_monitor_of_sink(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
1025 pa_dbusiface_device
*d
= userdata
;
1026 const char *monitor_of_sink
= NULL
;
1031 pa_assert(d
->type
== PA_DEVICE_TYPE_SOURCE
);
1033 if (!d
->source
->monitor_of
) {
1034 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "Source %s is not a monitor source.", d
->source
->name
);
1038 monitor_of_sink
= pa_dbusiface_core_get_sink_path(d
->core
, d
->source
->monitor_of
);
1040 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &monitor_of_sink
);
1043 static void handle_source_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
1044 pa_dbusiface_device
*d
= userdata
;
1045 DBusMessage
*reply
= NULL
;
1046 DBusMessageIter msg_iter
;
1047 DBusMessageIter dict_iter
;
1048 const char *monitor_of_sink
= NULL
;
1053 pa_assert(d
->type
== PA_DEVICE_TYPE_SOURCE
);
1055 if (d
->source
->monitor_of
)
1056 monitor_of_sink
= pa_dbusiface_core_get_sink_path(d
->core
, d
->source
->monitor_of
);
1058 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1060 dbus_message_iter_init_append(reply
, &msg_iter
);
1061 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1063 if (monitor_of_sink
)
1064 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[SOURCE_PROPERTY_HANDLER_MONITOR_OF_SINK
].property_name
, DBUS_TYPE_OBJECT_PATH
, &monitor_of_sink
);
1066 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1068 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1070 dbus_message_unref(reply
);
1073 static void subscription_cb(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1074 pa_dbusiface_device
*d
= userdata
;
1075 DBusMessage
*signal_msg
= NULL
;
1076 const pa_cvolume
*new_volume
= NULL
;
1077 bool new_mute
= false;
1078 pa_sink_state_t new_sink_state
= 0;
1079 pa_source_state_t new_source_state
= 0;
1080 pa_device_port
*new_active_port
= NULL
;
1081 pa_proplist
*new_proplist
= NULL
;
1087 if ((d
->type
== PA_DEVICE_TYPE_SINK
&& idx
!= d
->sink
->index
) || (d
->type
== PA_DEVICE_TYPE_SOURCE
&& idx
!= d
->source
->index
))
1090 if ((t
& PA_SUBSCRIPTION_EVENT_TYPE_MASK
) != PA_SUBSCRIPTION_EVENT_CHANGE
)
1093 pa_assert(((d
->type
== PA_DEVICE_TYPE_SINK
)
1094 && ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK
))
1095 || ((d
->type
== PA_DEVICE_TYPE_SOURCE
)
1096 && ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE
)));
1098 new_volume
= (d
->type
== PA_DEVICE_TYPE_SINK
)
1099 ? pa_sink_get_volume(d
->sink
, false)
1100 : pa_source_get_volume(d
->source
, false);
1102 if (!pa_cvolume_equal(&d
->volume
, new_volume
)) {
1103 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
1104 dbus_uint32_t
*volume_ptr
= volume
;
1106 d
->volume
= *new_volume
;
1108 for (i
= 0; i
< d
->volume
.channels
; ++i
)
1109 volume
[i
] = d
->volume
.values
[i
];
1111 pa_assert_se(signal_msg
= dbus_message_new_signal(d
->path
,
1112 PA_DBUSIFACE_DEVICE_INTERFACE
,
1113 signals
[SIGNAL_VOLUME_UPDATED
].name
));
1114 pa_assert_se(dbus_message_append_args(signal_msg
,
1115 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &volume_ptr
, d
->volume
.channels
,
1116 DBUS_TYPE_INVALID
));
1118 pa_dbus_protocol_send_signal(d
->dbus_protocol
, signal_msg
);
1119 dbus_message_unref(signal_msg
);
1123 new_mute
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? pa_sink_get_mute(d
->sink
, false) : pa_source_get_mute(d
->source
, false);
1125 if (d
->mute
!= new_mute
) {
1128 pa_assert_se(signal_msg
= dbus_message_new_signal(d
->path
,
1129 PA_DBUSIFACE_DEVICE_INTERFACE
,
1130 signals
[SIGNAL_MUTE_UPDATED
].name
));
1131 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_BOOLEAN
, &d
->mute
, DBUS_TYPE_INVALID
));
1133 pa_dbus_protocol_send_signal(d
->dbus_protocol
, signal_msg
);
1134 dbus_message_unref(signal_msg
);
1138 if (d
->type
== PA_DEVICE_TYPE_SINK
)
1139 new_sink_state
= pa_sink_get_state(d
->sink
);
1141 new_source_state
= pa_source_get_state(d
->source
);
1143 if ((d
->type
== PA_DEVICE_TYPE_SINK
&& d
->sink_state
!= new_sink_state
)
1144 || (d
->type
== PA_DEVICE_TYPE_SOURCE
&& d
->source_state
!= new_source_state
)) {
1145 dbus_uint32_t state
= 0;
1147 if (d
->type
== PA_DEVICE_TYPE_SINK
)
1148 d
->sink_state
= new_sink_state
;
1150 d
->source_state
= new_source_state
;
1152 state
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink_state
: d
->source_state
;
1154 pa_assert_se(signal_msg
= dbus_message_new_signal(d
->path
,
1155 PA_DBUSIFACE_DEVICE_INTERFACE
,
1156 signals
[SIGNAL_STATE_UPDATED
].name
));
1157 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_UINT32
, &state
, DBUS_TYPE_INVALID
));
1159 pa_dbus_protocol_send_signal(d
->dbus_protocol
, signal_msg
);
1160 dbus_message_unref(signal_msg
);
1164 new_active_port
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->active_port
: d
->source
->active_port
;
1166 if (d
->active_port
!= new_active_port
) {
1167 const char *object_path
= NULL
;
1169 d
->active_port
= new_active_port
;
1170 object_path
= pa_dbusiface_device_port_get_path(pa_hashmap_get(d
->ports
, d
->active_port
->name
));
1172 pa_assert_se(signal_msg
= dbus_message_new_signal(d
->path
,
1173 PA_DBUSIFACE_DEVICE_INTERFACE
,
1174 signals
[SIGNAL_ACTIVE_PORT_UPDATED
].name
));
1175 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &object_path
, DBUS_TYPE_INVALID
));
1177 pa_dbus_protocol_send_signal(d
->dbus_protocol
, signal_msg
);
1178 dbus_message_unref(signal_msg
);
1182 new_proplist
= (d
->type
== PA_DEVICE_TYPE_SINK
) ? d
->sink
->proplist
: d
->source
->proplist
;
1184 if (!pa_proplist_equal(d
->proplist
, new_proplist
)) {
1185 DBusMessageIter msg_iter
;
1187 pa_proplist_update(d
->proplist
, PA_UPDATE_SET
, new_proplist
);
1189 pa_assert_se(signal_msg
= dbus_message_new_signal(d
->path
,
1190 PA_DBUSIFACE_DEVICE_INTERFACE
,
1191 signals
[SIGNAL_PROPERTY_LIST_UPDATED
].name
));
1192 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
1193 pa_dbus_append_proplist(&msg_iter
, d
->proplist
);
1195 pa_dbus_protocol_send_signal(d
->dbus_protocol
, signal_msg
);
1196 dbus_message_unref(signal_msg
);
1201 pa_dbusiface_device
*pa_dbusiface_device_new_sink(pa_dbusiface_core
*core
, pa_sink
*sink
) {
1202 pa_dbusiface_device
*d
= NULL
;
1203 pa_device_port
*port
;
1209 d
= pa_xnew0(pa_dbusiface_device
, 1);
1211 d
->sink
= pa_sink_ref(sink
);
1212 d
->type
= PA_DEVICE_TYPE_SINK
;
1213 d
->path
= pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH
, SINK_OBJECT_NAME
, sink
->index
);
1214 d
->volume
= *pa_sink_get_volume(sink
, false);
1215 d
->mute
= pa_sink_get_mute(sink
, false);
1216 d
->sink_state
= pa_sink_get_state(sink
);
1217 d
->ports
= pa_hashmap_new_full(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
, NULL
, (pa_free_cb_t
) pa_dbusiface_device_port_free
);
1218 d
->next_port_index
= 0;
1219 d
->active_port
= sink
->active_port
;
1220 d
->proplist
= pa_proplist_copy(sink
->proplist
);
1221 d
->dbus_protocol
= pa_dbus_protocol_get(sink
->core
);
1222 d
->subscription
= pa_subscription_new(sink
->core
, PA_SUBSCRIPTION_MASK_SINK
, subscription_cb
, d
);
1224 PA_HASHMAP_FOREACH(port
, sink
->ports
, state
) {
1225 pa_dbusiface_device_port
*p
= pa_dbusiface_device_port_new(d
, sink
->core
, port
, d
->next_port_index
++);
1226 pa_hashmap_put(d
->ports
, (char *) pa_dbusiface_device_port_get_name(p
), p
);
1229 pa_assert_se(pa_dbus_protocol_add_interface(d
->dbus_protocol
, d
->path
, &device_interface_info
, d
) >= 0);
1230 pa_assert_se(pa_dbus_protocol_add_interface(d
->dbus_protocol
, d
->path
, &sink_interface_info
, d
) >= 0);
1235 pa_dbusiface_device
*pa_dbusiface_device_new_source(pa_dbusiface_core
*core
, pa_source
*source
) {
1236 pa_dbusiface_device
*d
= NULL
;
1237 pa_device_port
*port
;
1243 d
= pa_xnew0(pa_dbusiface_device
, 1);
1245 d
->source
= pa_source_ref(source
);
1246 d
->type
= PA_DEVICE_TYPE_SOURCE
;
1247 d
->path
= pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH
, SOURCE_OBJECT_NAME
, source
->index
);
1248 d
->volume
= *pa_source_get_volume(source
, false);
1249 d
->mute
= pa_source_get_mute(source
, false);
1250 d
->source_state
= pa_source_get_state(source
);
1251 d
->ports
= pa_hashmap_new_full(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
, NULL
, (pa_free_cb_t
) pa_dbusiface_device_port_free
);
1252 d
->next_port_index
= 0;
1253 d
->active_port
= source
->active_port
;
1254 d
->proplist
= pa_proplist_copy(source
->proplist
);
1255 d
->dbus_protocol
= pa_dbus_protocol_get(source
->core
);
1256 d
->subscription
= pa_subscription_new(source
->core
, PA_SUBSCRIPTION_MASK_SOURCE
, subscription_cb
, d
);
1258 PA_HASHMAP_FOREACH(port
, source
->ports
, state
) {
1259 pa_dbusiface_device_port
*p
= pa_dbusiface_device_port_new(d
, source
->core
, port
, d
->next_port_index
++);
1260 pa_hashmap_put(d
->ports
, (char *) pa_dbusiface_device_port_get_name(p
), p
);
1263 pa_assert_se(pa_dbus_protocol_add_interface(d
->dbus_protocol
, d
->path
, &device_interface_info
, d
) >= 0);
1264 pa_assert_se(pa_dbus_protocol_add_interface(d
->dbus_protocol
, d
->path
, &source_interface_info
, d
) >= 0);
1269 void pa_dbusiface_device_free(pa_dbusiface_device
*d
) {
1272 pa_assert_se(pa_dbus_protocol_remove_interface(d
->dbus_protocol
, d
->path
, device_interface_info
.name
) >= 0);
1274 if (d
->type
== PA_DEVICE_TYPE_SINK
) {
1275 pa_assert_se(pa_dbus_protocol_remove_interface(d
->dbus_protocol
, d
->path
, sink_interface_info
.name
) >= 0);
1276 pa_sink_unref(d
->sink
);
1279 pa_assert_se(pa_dbus_protocol_remove_interface(d
->dbus_protocol
, d
->path
, source_interface_info
.name
) >= 0);
1280 pa_source_unref(d
->source
);
1282 pa_hashmap_free(d
->ports
);
1283 pa_proplist_free(d
->proplist
);
1284 pa_dbus_protocol_unref(d
->dbus_protocol
);
1285 pa_subscription_free(d
->subscription
);
1291 const char *pa_dbusiface_device_get_path(pa_dbusiface_device
*d
) {
1297 pa_sink
*pa_dbusiface_device_get_sink(pa_dbusiface_device
*d
) {
1299 pa_assert(d
->type
== PA_DEVICE_TYPE_SINK
);
1304 pa_source
*pa_dbusiface_device_get_source(pa_dbusiface_device
*d
) {
1306 pa_assert(d
->type
== PA_DEVICE_TYPE_SOURCE
);