1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2009 Tanu Kaskinen
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <ctype.h>
25
26 #include <dbus/dbus.h>
27
28 #include <pulse/utf8.h>
29 #include <pulse/xmalloc.h>
30
31 #include <pulsecore/core-util.h>
32 #include <pulsecore/dbus-util.h>
33 #include <pulsecore/macro.h>
34 #include <pulsecore/namereg.h>
35 #include <pulsecore/protocol-dbus.h>
36 #include <pulsecore/socket-util.h>
37 #include <pulsecore/strbuf.h>
38
39 #include "iface-card.h"
40 #include "iface-client.h"
41 #include "iface-device.h"
42 #include "iface-memstats.h"
43 #include "iface-module.h"
44 #include "iface-sample.h"
45 #include "iface-stream.h"
46
47 #include "iface-core.h"
48
49 #define INTERFACE_REVISION 0
50
51 static void handle_get_interface_revision(DBusConnection *conn, DBusMessage *msg, void *userdata);
52 static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
53 static void handle_get_version(DBusConnection *conn, DBusMessage *msg, void *userdata);
54 static void handle_get_is_local(DBusConnection *conn, DBusMessage *msg, void *userdata);
55 static void handle_get_username(DBusConnection *conn, DBusMessage *msg, void *userdata);
56 static void handle_get_hostname(DBusConnection *conn, DBusMessage *msg, void *userdata);
57 static void handle_get_default_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);
58 static void handle_set_default_channels(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
59 static void handle_get_default_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
60 static void handle_set_default_sample_format(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
61 static void handle_get_default_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
62 static void handle_set_default_sample_rate(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
63 static void handle_get_alternate_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
64 static void handle_set_alternate_sample_rate(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
65 static void handle_get_cards(DBusConnection *conn, DBusMessage *msg, void *userdata);
66 static void handle_get_sinks(DBusConnection *conn, DBusMessage *msg, void *userdata);
67 static void handle_get_fallback_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
68 static void handle_set_fallback_sink(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
69 static void handle_get_sources(DBusConnection *conn, DBusMessage *msg, void *userdata);
70 static void handle_get_fallback_source(DBusConnection *conn, DBusMessage *msg, void *userdata);
71 static void handle_set_fallback_source(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
72 static void handle_get_playback_streams(DBusConnection *conn, DBusMessage *msg, void *userdata);
73 static void handle_get_record_streams(DBusConnection *conn, DBusMessage *msg, void *userdata);
74 static void handle_get_samples(DBusConnection *conn, DBusMessage *msg, void *userdata);
75 static void handle_get_modules(DBusConnection *conn, DBusMessage *msg, void *userdata);
76 static void handle_get_clients(DBusConnection *conn, DBusMessage *msg, void *userdata);
77 static void handle_get_my_client(DBusConnection *conn, DBusMessage *msg, void *userdata);
78 static void handle_get_extensions(DBusConnection *conn, DBusMessage *msg, void *userdata);
79
80 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
81
82 static void handle_get_card_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
83 static void handle_get_sink_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
84 static void handle_get_source_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
85 static void handle_get_sample_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
86 static void handle_upload_sample(DBusConnection *conn, DBusMessage *msg, void *userdata);
87 static void handle_load_module(DBusConnection *conn, DBusMessage *msg, void *userdata);
88 static void handle_exit(DBusConnection *conn, DBusMessage *msg, void *userdata);
89 static void handle_listen_for_signal(DBusConnection *conn, DBusMessage *msg, void *userdata);
90 static void handle_stop_listening_for_signal(DBusConnection *conn, DBusMessage *msg, void *userdata);
91
92 struct pa_dbusiface_core {
93 pa_core *core;
94
95 pa_dbus_protocol *dbus_protocol;
96
97 pa_hashmap *cards;
98 pa_hashmap *sinks_by_index;
99 pa_hashmap *sinks_by_path;
100 pa_hashmap *sources_by_index;
101 pa_hashmap *sources_by_path;
102 pa_hashmap *playback_streams;
103 pa_hashmap *record_streams;
104 pa_hashmap *samples;
105 pa_hashmap *modules;
106 pa_hashmap *clients;
107
108 pa_sink *fallback_sink;
109 pa_source *fallback_source;
110
111 pa_hook_slot *module_new_slot;
112 pa_hook_slot *module_removed_slot;
113 pa_hook_slot *default_sink_changed_slot;
114 pa_hook_slot *default_source_changed_slot;
115 pa_hook_slot *sample_cache_new_slot;
116 pa_hook_slot *sample_cache_removed_slot;
117 pa_hook_slot *card_put_slot;
118 pa_hook_slot *card_unlink_slot;
119 pa_hook_slot *sink_input_put_slot;
120 pa_hook_slot *sink_input_unlink_slot;
121 pa_hook_slot *source_output_put_slot;
122 pa_hook_slot *source_output_unlink_slot;
123 pa_hook_slot *client_put_slot;
124 pa_hook_slot *client_unlink_slot;
125 pa_hook_slot *sink_put_slot;
126 pa_hook_slot *sink_unlink_slot;
127 pa_hook_slot *source_put_slot;
128 pa_hook_slot *source_unlink_slot;
129 pa_hook_slot *extension_registered_slot;
130 pa_hook_slot *extension_unregistered_slot;
131
132 pa_dbusiface_memstats *memstats;
133 };
134
135 enum property_handler_index {
136 PROPERTY_HANDLER_INTERFACE_REVISION,
137 PROPERTY_HANDLER_NAME,
138 PROPERTY_HANDLER_VERSION,
139 PROPERTY_HANDLER_IS_LOCAL,
140 PROPERTY_HANDLER_USERNAME,
141 PROPERTY_HANDLER_HOSTNAME,
142 PROPERTY_HANDLER_DEFAULT_CHANNELS,
143 PROPERTY_HANDLER_DEFAULT_SAMPLE_FORMAT,
144 PROPERTY_HANDLER_DEFAULT_SAMPLE_RATE,
145 PROPERTY_HANDLER_ALTERNATE_SAMPLE_RATE,
146 PROPERTY_HANDLER_CARDS,
147 PROPERTY_HANDLER_SINKS,
148 PROPERTY_HANDLER_FALLBACK_SINK,
149 PROPERTY_HANDLER_SOURCES,
150 PROPERTY_HANDLER_FALLBACK_SOURCE,
151 PROPERTY_HANDLER_PLAYBACK_STREAMS,
152 PROPERTY_HANDLER_RECORD_STREAMS,
153 PROPERTY_HANDLER_SAMPLES,
154 PROPERTY_HANDLER_MODULES,
155 PROPERTY_HANDLER_CLIENTS,
156 PROPERTY_HANDLER_MY_CLIENT,
157 PROPERTY_HANDLER_EXTENSIONS,
158 PROPERTY_HANDLER_MAX
159 };
160
161 static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
162 [PROPERTY_HANDLER_INTERFACE_REVISION] = { .property_name = "InterfaceRevision", .type = "u", .get_cb = handle_get_interface_revision, .set_cb = NULL },
163 [PROPERTY_HANDLER_NAME] = { .property_name = "Name", .type = "s", .get_cb = handle_get_name, .set_cb = NULL },
164 [PROPERTY_HANDLER_VERSION] = { .property_name = "Version", .type = "s", .get_cb = handle_get_version, .set_cb = NULL },
165 [PROPERTY_HANDLER_IS_LOCAL] = { .property_name = "IsLocal", .type = "b", .get_cb = handle_get_is_local, .set_cb = NULL },
166 [PROPERTY_HANDLER_USERNAME] = { .property_name = "Username", .type = "s", .get_cb = handle_get_username, .set_cb = NULL },
167 [PROPERTY_HANDLER_HOSTNAME] = { .property_name = "Hostname", .type = "s", .get_cb = handle_get_hostname, .set_cb = NULL },
168 [PROPERTY_HANDLER_DEFAULT_CHANNELS] = { .property_name = "DefaultChannels", .type = "au", .get_cb = handle_get_default_channels, .set_cb = handle_set_default_channels },
169 [PROPERTY_HANDLER_DEFAULT_SAMPLE_FORMAT] = { .property_name = "DefaultSampleFormat", .type = "u", .get_cb = handle_get_default_sample_format, .set_cb = handle_set_default_sample_format },
170 [PROPERTY_HANDLER_DEFAULT_SAMPLE_RATE] = { .property_name = "DefaultSampleRate", .type = "u", .get_cb = handle_get_default_sample_rate, .set_cb = handle_set_default_sample_rate },
171 [PROPERTY_HANDLER_ALTERNATE_SAMPLE_RATE] = { .property_name = "AlternateSampleRate", .type = "u", .get_cb = handle_get_alternate_sample_rate, .set_cb = handle_set_alternate_sample_rate },
172 [PROPERTY_HANDLER_CARDS] = { .property_name = "Cards", .type = "ao", .get_cb = handle_get_cards, .set_cb = NULL },
173 [PROPERTY_HANDLER_SINKS] = { .property_name = "Sinks", .type = "ao", .get_cb = handle_get_sinks, .set_cb = NULL },
174 [PROPERTY_HANDLER_FALLBACK_SINK] = { .property_name = "FallbackSink", .type = "o", .get_cb = handle_get_fallback_sink, .set_cb = handle_set_fallback_sink },
175 [PROPERTY_HANDLER_SOURCES] = { .property_name = "Sources", .type = "ao", .get_cb = handle_get_sources, .set_cb = NULL },
176 [PROPERTY_HANDLER_FALLBACK_SOURCE] = { .property_name = "FallbackSource", .type = "o", .get_cb = handle_get_fallback_source, .set_cb = handle_set_fallback_source },
177 [PROPERTY_HANDLER_PLAYBACK_STREAMS] = { .property_name = "PlaybackStreams", .type = "ao", .get_cb = handle_get_playback_streams, .set_cb = NULL },
178 [PROPERTY_HANDLER_RECORD_STREAMS] = { .property_name = "RecordStreams", .type = "ao", .get_cb = handle_get_record_streams, .set_cb = NULL },
179 [PROPERTY_HANDLER_SAMPLES] = { .property_name = "Samples", .type = "ao", .get_cb = handle_get_samples, .set_cb = NULL },
180 [PROPERTY_HANDLER_MODULES] = { .property_name = "Modules", .type = "ao", .get_cb = handle_get_modules, .set_cb = NULL },
181 [PROPERTY_HANDLER_CLIENTS] = { .property_name = "Clients", .type = "ao", .get_cb = handle_get_clients, .set_cb = NULL },
182 [PROPERTY_HANDLER_MY_CLIENT] = { .property_name = "MyClient", .type = "o", .get_cb = handle_get_my_client, .set_cb = NULL },
183 [PROPERTY_HANDLER_EXTENSIONS] = { .property_name = "Extensions", .type = "as", .get_cb = handle_get_extensions, .set_cb = NULL }
184 };
185
186 enum method_handler_index {
187 METHOD_HANDLER_GET_CARD_BY_NAME,
188 METHOD_HANDLER_GET_SINK_BY_NAME,
189 METHOD_HANDLER_GET_SOURCE_BY_NAME,
190 METHOD_HANDLER_GET_SAMPLE_BY_NAME,
191 METHOD_HANDLER_UPLOAD_SAMPLE,
192 METHOD_HANDLER_LOAD_MODULE,
193 METHOD_HANDLER_EXIT,
194 METHOD_HANDLER_LISTEN_FOR_SIGNAL,
195 METHOD_HANDLER_STOP_LISTENING_FOR_SIGNAL,
196 METHOD_HANDLER_MAX
197 };
198
199 static pa_dbus_arg_info get_card_by_name_args[] = { { "name", "s", "in" }, { "card", "o", "out" } };
200 static pa_dbus_arg_info get_sink_by_name_args[] = { { "name", "s", "in" }, { "sink", "o", "out" } };
201 static pa_dbus_arg_info get_source_by_name_args[] = { { "name", "s", "in" }, { "source", "o", "out" } };
202 static pa_dbus_arg_info get_sample_by_name_args[] = { { "name", "s", "in" }, { "sample", "o", "out" } };
203 static pa_dbus_arg_info upload_sample_args[] = { { "name", "s", "in" },
204 { "sample_format", "u", "in" },
205 { "sample_rate", "u", "in" },
206 { "channels", "au", "in" },
207 { "default_volume", "au", "in" },
208 { "property_list", "a{say}", "in" },
209 { "data", "ay", "in" },
210 { "sample", "o", "out" } };
211 static pa_dbus_arg_info load_module_args[] = { { "name", "s", "in" }, { "arguments", "a{ss}", "in" }, { "module", "o", "out" } };
212 static pa_dbus_arg_info listen_for_signal_args[] = { { "signal", "s", "in" }, { "objects", "ao", "in" } };
213 static pa_dbus_arg_info stop_listening_for_signal_args[] = { { "signal", "s", "in" } };
214
215 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
216 [METHOD_HANDLER_GET_CARD_BY_NAME] = {
217 .method_name = "GetCardByName",
218 .arguments = get_card_by_name_args,
219 .n_arguments = sizeof(get_card_by_name_args) / sizeof(pa_dbus_arg_info),
220 .receive_cb = handle_get_card_by_name },
221 [METHOD_HANDLER_GET_SINK_BY_NAME] = {
222 .method_name = "GetSinkByName",
223 .arguments = get_sink_by_name_args,
224 .n_arguments = sizeof(get_sink_by_name_args) / sizeof(pa_dbus_arg_info),
225 .receive_cb = handle_get_sink_by_name },
226 [METHOD_HANDLER_GET_SOURCE_BY_NAME] = {
227 .method_name = "GetSourceByName",
228 .arguments = get_source_by_name_args,
229 .n_arguments = sizeof(get_source_by_name_args) / sizeof(pa_dbus_arg_info),
230 .receive_cb = handle_get_source_by_name },
231 [METHOD_HANDLER_GET_SAMPLE_BY_NAME] = {
232 .method_name = "GetSampleByName",
233 .arguments = get_sample_by_name_args,
234 .n_arguments = sizeof(get_sample_by_name_args) / sizeof(pa_dbus_arg_info),
235 .receive_cb = handle_get_sample_by_name },
236 [METHOD_HANDLER_UPLOAD_SAMPLE] = {
237 .method_name = "UploadSample",
238 .arguments = upload_sample_args,
239 .n_arguments = sizeof(upload_sample_args) / sizeof(pa_dbus_arg_info),
240 .receive_cb = handle_upload_sample },
241 [METHOD_HANDLER_LOAD_MODULE] = {
242 .method_name = "LoadModule",
243 .arguments = load_module_args,
244 .n_arguments = sizeof(load_module_args) / sizeof(pa_dbus_arg_info),
245 .receive_cb = handle_load_module },
246 [METHOD_HANDLER_EXIT] = {
247 .method_name = "Exit",
248 .arguments = NULL,
249 .n_arguments = 0,
250 .receive_cb = handle_exit },
251 [METHOD_HANDLER_LISTEN_FOR_SIGNAL] = {
252 .method_name = "ListenForSignal",
253 .arguments = listen_for_signal_args,
254 .n_arguments = sizeof(listen_for_signal_args) / sizeof(pa_dbus_arg_info),
255 .receive_cb = handle_listen_for_signal },
256 [METHOD_HANDLER_STOP_LISTENING_FOR_SIGNAL] = {
257 .method_name = "StopListeningForSignal",
258 .arguments = stop_listening_for_signal_args,
259 .n_arguments = sizeof(stop_listening_for_signal_args) / sizeof(pa_dbus_arg_info),
260 .receive_cb = handle_stop_listening_for_signal }
261 };
262
263 enum signal_index {
264 SIGNAL_NEW_CARD,
265 SIGNAL_CARD_REMOVED,
266 SIGNAL_NEW_SINK,
267 SIGNAL_SINK_REMOVED,
268 SIGNAL_FALLBACK_SINK_UPDATED,
269 SIGNAL_FALLBACK_SINK_UNSET,
270 SIGNAL_NEW_SOURCE,
271 SIGNAL_SOURCE_REMOVED,
272 SIGNAL_FALLBACK_SOURCE_UPDATED,
273 SIGNAL_FALLBACK_SOURCE_UNSET,
274 SIGNAL_NEW_PLAYBACK_STREAM,
275 SIGNAL_PLAYBACK_STREAM_REMOVED,
276 SIGNAL_NEW_RECORD_STREAM,
277 SIGNAL_RECORD_STREAM_REMOVED,
278 SIGNAL_NEW_SAMPLE,
279 SIGNAL_SAMPLE_REMOVED,
280 SIGNAL_NEW_MODULE,
281 SIGNAL_MODULE_REMOVED,
282 SIGNAL_NEW_CLIENT,
283 SIGNAL_CLIENT_REMOVED,
284 SIGNAL_NEW_EXTENSION,
285 SIGNAL_EXTENSION_REMOVED,
286 SIGNAL_MAX
287 };
288
289 static pa_dbus_arg_info new_card_args[] = { { "card", "o", NULL } };
290 static pa_dbus_arg_info card_removed_args[] = { { "card", "o", NULL } };
291 static pa_dbus_arg_info new_sink_args[] = { { "sink", "o", NULL } };
292 static pa_dbus_arg_info sink_removed_args[] = { { "sink", "o", NULL } };
293 static pa_dbus_arg_info fallback_sink_updated_args[] = { { "sink", "o", NULL } };
294 static pa_dbus_arg_info new_source_args[] = { { "source", "o", NULL } };
295 static pa_dbus_arg_info source_removed_args[] = { { "source", "o", NULL } };
296 static pa_dbus_arg_info fallback_source_updated_args[] = { { "source", "o", NULL } };
297 static pa_dbus_arg_info new_playback_stream_args[] = { { "playback_stream", "o", NULL } };
298 static pa_dbus_arg_info playback_stream_removed_args[] = { { "playback_stream", "o", NULL } };
299 static pa_dbus_arg_info new_record_stream_args[] = { { "record_stream", "o", NULL } };
300 static pa_dbus_arg_info record_stream_removed_args[] = { { "record_stream", "o", NULL } };
301 static pa_dbus_arg_info new_sample_args[] = { { "sample", "o", NULL } };
302 static pa_dbus_arg_info sample_removed_args[] = { { "sample", "o", NULL } };
303 static pa_dbus_arg_info new_module_args[] = { { "module", "o", NULL } };
304 static pa_dbus_arg_info module_removed_args[] = { { "module", "o", NULL } };
305 static pa_dbus_arg_info new_client_args[] = { { "client", "o", NULL } };
306 static pa_dbus_arg_info client_removed_args[] = { { "client", "o", NULL } };
307 static pa_dbus_arg_info new_extension_args[] = { { "extension", "s", NULL } };
308 static pa_dbus_arg_info extension_removed_args[] = { { "extension", "s", NULL } };
309
310 static pa_dbus_signal_info signals[SIGNAL_MAX] = {
311 [SIGNAL_NEW_CARD] = { .name = "NewCard", .arguments = new_card_args, .n_arguments = 1 },
312 [SIGNAL_CARD_REMOVED] = { .name = "CardRemoved", .arguments = card_removed_args, .n_arguments = 1 },
313 [SIGNAL_NEW_SINK] = { .name = "NewSink", .arguments = new_sink_args, .n_arguments = 1 },
314 [SIGNAL_SINK_REMOVED] = { .name = "SinkRemoved", .arguments = sink_removed_args, .n_arguments = 1 },
315 [SIGNAL_FALLBACK_SINK_UPDATED] = { .name = "FallbackSinkUpdated", .arguments = fallback_sink_updated_args, .n_arguments = 1 },
316 [SIGNAL_FALLBACK_SINK_UNSET] = { .name = "FallbackSinkUnset", .arguments = NULL, .n_arguments = 0 },
317 [SIGNAL_NEW_SOURCE] = { .name = "NewSource", .arguments = new_source_args, .n_arguments = 1 },
318 [SIGNAL_SOURCE_REMOVED] = { .name = "SourceRemoved", .arguments = source_removed_args, .n_arguments = 1 },
319 [SIGNAL_FALLBACK_SOURCE_UPDATED] = { .name = "FallbackSourceUpdated", .arguments = fallback_source_updated_args, .n_arguments = 1 },
320 [SIGNAL_FALLBACK_SOURCE_UNSET] = { .name = "FallbackSourceUnset", .arguments = NULL, .n_arguments = 0 },
321 [SIGNAL_NEW_PLAYBACK_STREAM] = { .name = "NewPlaybackStream", .arguments = new_playback_stream_args, .n_arguments = 1 },
322 [SIGNAL_PLAYBACK_STREAM_REMOVED] = { .name = "PlaybackStreamRemoved", .arguments = playback_stream_removed_args, .n_arguments = 1 },
323 [SIGNAL_NEW_RECORD_STREAM] = { .name = "NewRecordStream", .arguments = new_record_stream_args, .n_arguments = 1 },
324 [SIGNAL_RECORD_STREAM_REMOVED] = { .name = "RecordStreamRemoved", .arguments = record_stream_removed_args, .n_arguments = 1 },
325 [SIGNAL_NEW_SAMPLE] = { .name = "NewSample", .arguments = new_sample_args, .n_arguments = 1 },
326 [SIGNAL_SAMPLE_REMOVED] = { .name = "SampleRemoved", .arguments = sample_removed_args, .n_arguments = 1 },
327 [SIGNAL_NEW_MODULE] = { .name = "NewModule", .arguments = new_module_args, .n_arguments = 1 },
328 [SIGNAL_MODULE_REMOVED] = { .name = "ModuleRemoved", .arguments = module_removed_args, .n_arguments = 1 },
329 [SIGNAL_NEW_CLIENT] = { .name = "NewClient", .arguments = new_client_args, .n_arguments = 1 },
330 [SIGNAL_CLIENT_REMOVED] = { .name = "ClientRemoved", .arguments = client_removed_args, .n_arguments = 1 },
331 [SIGNAL_NEW_EXTENSION] = { .name = "NewExtension", .arguments = new_extension_args, .n_arguments = 1 },
332 [SIGNAL_EXTENSION_REMOVED] = { .name = "ExtensionRemoved", .arguments = extension_removed_args, .n_arguments = 1 }
333 };
334
335 static pa_dbus_interface_info core_interface_info = {
336 .name = PA_DBUS_CORE_INTERFACE,
337 .method_handlers = method_handlers,
338 .n_method_handlers = METHOD_HANDLER_MAX,
339 .property_handlers = property_handlers,
340 .n_property_handlers = PROPERTY_HANDLER_MAX,
341 .get_all_properties_cb = handle_get_all,
342 .signals = signals,
343 .n_signals = SIGNAL_MAX
344 };
345
handle_get_interface_revision(DBusConnection * conn,DBusMessage * msg,void * userdata)346 static void handle_get_interface_revision(DBusConnection *conn, DBusMessage *msg, void *userdata) {
347 dbus_uint32_t interface_revision = INTERFACE_REVISION;
348
349 pa_assert(conn);
350 pa_assert(msg);
351
352 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &interface_revision);
353 }
354
handle_get_name(DBusConnection * conn,DBusMessage * msg,void * userdata)355 static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
356 const char *server_name = PACKAGE_NAME;
357
358 pa_assert(conn);
359 pa_assert(msg);
360
361 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &server_name);
362 }
363
handle_get_version(DBusConnection * conn,DBusMessage * msg,void * userdata)364 static void handle_get_version(DBusConnection *conn, DBusMessage *msg, void *userdata) {
365 const char *version = PACKAGE_VERSION;
366
367 pa_assert(conn);
368 pa_assert(msg);
369
370 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &version);
371 }
372
get_is_local(DBusConnection * conn)373 static dbus_bool_t get_is_local(DBusConnection *conn) {
374 int conn_fd;
375
376 pa_assert(conn);
377
378 if (!dbus_connection_get_socket(conn, &conn_fd))
379 return FALSE;
380
381 return pa_socket_is_local(conn_fd);
382 }
383
handle_get_is_local(DBusConnection * conn,DBusMessage * msg,void * userdata)384 static void handle_get_is_local(DBusConnection *conn, DBusMessage *msg, void *userdata) {
385 dbus_bool_t is_local;
386
387 pa_assert(conn);
388 pa_assert(msg);
389
390 is_local = get_is_local(conn);
391
392 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_local);
393 }
394
handle_get_username(DBusConnection * conn,DBusMessage * msg,void * userdata)395 static void handle_get_username(DBusConnection *conn, DBusMessage *msg, void *userdata) {
396 char *username = NULL;
397
398 pa_assert(conn);
399 pa_assert(msg);
400
401 username = pa_get_user_name_malloc();
402
403 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &username);
404
405 pa_xfree(username);
406 }
407
handle_get_hostname(DBusConnection * conn,DBusMessage * msg,void * userdata)408 static void handle_get_hostname(DBusConnection *conn, DBusMessage *msg, void *userdata) {
409 char *hostname = NULL;
410
411 pa_assert(conn);
412 pa_assert(msg);
413
414 hostname = pa_get_host_name_malloc();
415
416 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &hostname);
417
418 pa_xfree(hostname);
419 }
420
421 /* Caller frees the returned array. */
get_default_channels(pa_dbusiface_core * c,unsigned * n)422 static dbus_uint32_t *get_default_channels(pa_dbusiface_core *c, unsigned *n) {
423 dbus_uint32_t *default_channels = NULL;
424 unsigned i;
425
426 pa_assert(c);
427 pa_assert(n);
428
429 *n = c->core->default_channel_map.channels;
430 default_channels = pa_xnew(dbus_uint32_t, *n);
431
432 for (i = 0; i < *n; ++i)
433 default_channels[i] = c->core->default_channel_map.map[i];
434
435 return default_channels;
436 }
437
handle_get_default_channels(DBusConnection * conn,DBusMessage * msg,void * userdata)438 static void handle_get_default_channels(DBusConnection *conn, DBusMessage *msg, void *userdata) {
439 pa_dbusiface_core *c = userdata;
440 dbus_uint32_t *default_channels = NULL;
441 unsigned n;
442
443 pa_assert(conn);
444 pa_assert(msg);
445 pa_assert(c);
446
447 default_channels = get_default_channels(c, &n);
448
449 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, default_channels, n);
450
451 pa_xfree(default_channels);
452 }
453
handle_set_default_channels(DBusConnection * conn,DBusMessage * msg,DBusMessageIter * iter,void * userdata)454 static void handle_set_default_channels(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
455 pa_dbusiface_core *c = userdata;
456 DBusMessageIter array_iter;
457 pa_channel_map new_channel_map;
458 const dbus_uint32_t *default_channels;
459 int n_channels;
460 unsigned i;
461
462 pa_assert(conn);
463 pa_assert(msg);
464 pa_assert(iter);
465 pa_assert(c);
466
467 pa_channel_map_init(&new_channel_map);
468
469 dbus_message_iter_recurse(iter, &array_iter);
470 dbus_message_iter_get_fixed_array(&array_iter, &default_channels, &n_channels);
471
472 if (n_channels <= 0) {
473 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Empty channel array.");
474 return;
475 }
476
477 if (n_channels > (int) PA_CHANNELS_MAX) {
478 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
479 "Too many channels: %i. The maximum number of channels is %u.", n_channels, PA_CHANNELS_MAX);
480 return;
481 }
482
483 new_channel_map.channels = n_channels;
484
485 for (i = 0; i < new_channel_map.channels; ++i) {
486 if (default_channels[i] >= PA_CHANNEL_POSITION_MAX) {
487 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid channel position: %u.", default_channels[i]);
488 return;
489 }
490
491 new_channel_map.map[i] = default_channels[i];
492 }
493
494 c->core->default_channel_map = new_channel_map;
495 c->core->default_sample_spec.channels = n_channels;
496
497 pa_dbus_send_empty_reply(conn, msg);
498 }
499
handle_get_default_sample_format(DBusConnection * conn,DBusMessage * msg,void * userdata)500 static void handle_get_default_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
501 pa_dbusiface_core *c = userdata;
502 dbus_uint32_t default_sample_format;
503
504 pa_assert(conn);
505 pa_assert(msg);
506 pa_assert(c);
507
508 default_sample_format = c->core->default_sample_spec.format;
509
510 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &default_sample_format);
511 }
512
handle_set_default_sample_format(DBusConnection * conn,DBusMessage * msg,DBusMessageIter * iter,void * userdata)513 static void handle_set_default_sample_format(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
514 pa_dbusiface_core *c = userdata;
515 dbus_uint32_t default_sample_format;
516
517 pa_assert(conn);
518 pa_assert(msg);
519 pa_assert(iter);
520 pa_assert(c);
521
522 dbus_message_iter_get_basic(iter, &default_sample_format);
523
524 if (!pa_sample_format_valid(default_sample_format)) {
525 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid sample format.");
526 return;
527 }
528
529 c->core->default_sample_spec.format = default_sample_format;
530
531 pa_dbus_send_empty_reply(conn, msg);
532 }
533
handle_get_default_sample_rate(DBusConnection * conn,DBusMessage * msg,void * userdata)534 static void handle_get_default_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
535 pa_dbusiface_core *c = userdata;
536 dbus_uint32_t default_sample_rate;
537
538 pa_assert(conn);
539 pa_assert(msg);
540 pa_assert(c);
541
542 default_sample_rate = c->core->default_sample_spec.rate;
543
544 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &default_sample_rate);
545 }
546
handle_set_default_sample_rate(DBusConnection * conn,DBusMessage * msg,DBusMessageIter * iter,void * userdata)547 static void handle_set_default_sample_rate(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
548 pa_dbusiface_core *c = userdata;
549 dbus_uint32_t default_sample_rate;
550
551 pa_assert(conn);
552 pa_assert(msg);
553 pa_assert(iter);
554 pa_assert(c);
555
556 dbus_message_iter_get_basic(iter, &default_sample_rate);
557
558 if (!pa_sample_rate_valid(default_sample_rate)) {
559 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid sample rate.");
560 return;
561 }
562
563 c->core->default_sample_spec.rate = default_sample_rate;
564
565 pa_dbus_send_empty_reply(conn, msg);
566 }
567
handle_get_alternate_sample_rate(DBusConnection * conn,DBusMessage * msg,void * userdata)568 static void handle_get_alternate_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
569 pa_dbusiface_core *c = userdata;
570 dbus_uint32_t alternate_sample_rate;
571
572 pa_assert(conn);
573 pa_assert(msg);
574 pa_assert(c);
575
576 alternate_sample_rate = c->core->alternate_sample_rate;
577
578 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &alternate_sample_rate);
579 }
580
handle_set_alternate_sample_rate(DBusConnection * conn,DBusMessage * msg,DBusMessageIter * iter,void * userdata)581 static void handle_set_alternate_sample_rate(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
582 pa_dbusiface_core *c = userdata;
583 dbus_uint32_t alternate_sample_rate;
584
585 pa_assert(conn);
586 pa_assert(msg);
587 pa_assert(iter);
588 pa_assert(c);
589
590 dbus_message_iter_get_basic(iter, &alternate_sample_rate);
591
592 if (!pa_sample_rate_valid(alternate_sample_rate)) {
593 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid sample rate.");
594 return;
595 }
596
597 c->core->alternate_sample_rate = alternate_sample_rate;
598
599 pa_dbus_send_empty_reply(conn, msg);
600 }
601
602 /* The caller frees the array, but not the strings. */
get_cards(pa_dbusiface_core * c,unsigned * n)603 static const char **get_cards(pa_dbusiface_core *c, unsigned *n) {
604 const char **cards;
605 unsigned i = 0;
606 void *state = NULL;
607 pa_dbusiface_card *card;
608
609 pa_assert(c);
610 pa_assert(n);
611
612 *n = pa_hashmap_size(c->cards);
613
614 if (*n == 0)
615 return NULL;
616
617 cards = pa_xnew(const char *, *n);
618
619 PA_HASHMAP_FOREACH(card, c->cards, state)
620 cards[i++] = pa_dbusiface_card_get_path(card);
621
622 return cards;
623 }
624
handle_get_cards(DBusConnection * conn,DBusMessage * msg,void * userdata)625 static void handle_get_cards(DBusConnection *conn, DBusMessage *msg, void *userdata) {
626 pa_dbusiface_core *c = userdata;
627 const char **cards;
628 unsigned n;
629
630 pa_assert(conn);
631 pa_assert(msg);
632 pa_assert(c);
633
634 cards = get_cards(c, &n);
635
636 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, cards, n);
637
638 pa_xfree(cards);
639 }
640
641 /* The caller frees the array, but not the strings. */
get_sinks(pa_dbusiface_core * c,unsigned * n)642 static const char **get_sinks(pa_dbusiface_core *c, unsigned *n) {
643 const char **sinks;
644 unsigned i = 0;
645 void *state = NULL;
646 pa_dbusiface_device *sink;
647
648 pa_assert(c);
649 pa_assert(n);
650
651 *n = pa_hashmap_size(c->sinks_by_index);
652
653 if (*n == 0)
654 return NULL;
655
656 sinks = pa_xnew(const char *, *n);
657
658 PA_HASHMAP_FOREACH(sink, c->sinks_by_index, state)
659 sinks[i++] = pa_dbusiface_device_get_path(sink);
660
661 return sinks;
662 }
663
handle_get_sinks(DBusConnection * conn,DBusMessage * msg,void * userdata)664 static void handle_get_sinks(DBusConnection *conn, DBusMessage *msg, void *userdata) {
665 pa_dbusiface_core *c = userdata;
666 const char **sinks;
667 unsigned n;
668
669 pa_assert(conn);
670 pa_assert(msg);
671 pa_assert(c);
672
673 sinks = get_sinks(c, &n);
674
675 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, sinks, n);
676
677 pa_xfree(sinks);
678 }
679
handle_get_fallback_sink(DBusConnection * conn,DBusMessage * msg,void * userdata)680 static void handle_get_fallback_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
681 pa_dbusiface_core *c = userdata;
682 pa_dbusiface_device *fallback_sink;
683 const char *object_path;
684
685 pa_assert(conn);
686 pa_assert(msg);
687 pa_assert(c);
688
689 if (!c->fallback_sink) {
690 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
691 "There are no sinks, and therefore no fallback sink either.");
692 return;
693 }
694
695 pa_assert_se((fallback_sink = pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(c->fallback_sink->index))));
696 object_path = pa_dbusiface_device_get_path(fallback_sink);
697
698 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
699 }
700
handle_set_fallback_sink(DBusConnection * conn,DBusMessage * msg,DBusMessageIter * iter,void * userdata)701 static void handle_set_fallback_sink(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
702 pa_dbusiface_core *c = userdata;
703 pa_dbusiface_device *fallback_sink;
704 const char *object_path;
705
706 pa_assert(conn);
707 pa_assert(msg);
708 pa_assert(iter);
709 pa_assert(c);
710
711 if (!c->fallback_sink) {
712 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
713 "There are no sinks, and therefore no fallback sink either.");
714 return;
715 }
716
717 dbus_message_iter_get_basic(iter, &object_path);
718
719 if (!(fallback_sink = pa_hashmap_get(c->sinks_by_path, object_path))) {
720 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", object_path);
721 return;
722 }
723
724 pa_core_set_configured_default_sink(c->core, pa_dbusiface_device_get_sink(fallback_sink)->name);
725
726 pa_dbus_send_empty_reply(conn, msg);
727 }
728
729 /* The caller frees the array, but not the strings. */
get_sources(pa_dbusiface_core * c,unsigned * n)730 static const char **get_sources(pa_dbusiface_core *c, unsigned *n) {
731 const char **sources;
732 unsigned i = 0;
733 void *state = NULL;
734 pa_dbusiface_device *source;
735
736 pa_assert(c);
737 pa_assert(n);
738
739 *n = pa_hashmap_size(c->sources_by_index);
740
741 if (*n == 0)
742 return NULL;
743
744 sources = pa_xnew(const char *, *n);
745
746 PA_HASHMAP_FOREACH(source, c->sources_by_index, state)
747 sources[i++] = pa_dbusiface_device_get_path(source);
748
749 return sources;
750 }
751
handle_get_sources(DBusConnection * conn,DBusMessage * msg,void * userdata)752 static void handle_get_sources(DBusConnection *conn, DBusMessage *msg, void *userdata) {
753 pa_dbusiface_core *c = userdata;
754 const char **sources;
755 unsigned n;
756
757 pa_assert(conn);
758 pa_assert(msg);
759 pa_assert(c);
760
761 sources = get_sources(c, &n);
762
763 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, sources, n);
764
765 pa_xfree(sources);
766 }
767
handle_get_fallback_source(DBusConnection * conn,DBusMessage * msg,void * userdata)768 static void handle_get_fallback_source(DBusConnection *conn, DBusMessage *msg, void *userdata) {
769 pa_dbusiface_core *c = userdata;
770 pa_dbusiface_device *fallback_source;
771 const char *object_path;
772
773 pa_assert(conn);
774 pa_assert(msg);
775 pa_assert(c);
776
777 if (!c->fallback_source) {
778 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
779 "There are no sources, and therefore no fallback source either.");
780 return;
781 }
782
783 pa_assert_se((fallback_source = pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(c->fallback_source->index))));
784 object_path = pa_dbusiface_device_get_path(fallback_source);
785
786 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
787 }
788
handle_set_fallback_source(DBusConnection * conn,DBusMessage * msg,DBusMessageIter * iter,void * userdata)789 static void handle_set_fallback_source(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
790 pa_dbusiface_core *c = userdata;
791 pa_dbusiface_device *fallback_source;
792 const char *object_path;
793
794 pa_assert(conn);
795 pa_assert(msg);
796 pa_assert(iter);
797 pa_assert(c);
798
799 if (!c->fallback_source) {
800 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
801 "There are no sources, and therefore no fallback source either.");
802 return;
803 }
804
805 dbus_message_iter_get_basic(iter, &object_path);
806
807 if (!(fallback_source = pa_hashmap_get(c->sources_by_path, object_path))) {
808 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", object_path);
809 return;
810 }
811
812 pa_core_set_configured_default_source(c->core, pa_dbusiface_device_get_source(fallback_source)->name);
813
814 pa_dbus_send_empty_reply(conn, msg);
815 }
816
817 /* The caller frees the array, but not the strings. */
get_playback_streams(pa_dbusiface_core * c,unsigned * n)818 static const char **get_playback_streams(pa_dbusiface_core *c, unsigned *n) {
819 const char **streams;
820 unsigned i = 0;
821 void *state = NULL;
822 pa_dbusiface_stream *stream;
823
824 pa_assert(c);
825 pa_assert(n);
826
827 *n = pa_hashmap_size(c->playback_streams);
828
829 if (*n == 0)
830 return NULL;
831
832 streams = pa_xnew(const char *, *n);
833
834 PA_HASHMAP_FOREACH(stream, c->playback_streams, state)
835 streams[i++] = pa_dbusiface_stream_get_path(stream);
836
837 return streams;
838 }
839
handle_get_playback_streams(DBusConnection * conn,DBusMessage * msg,void * userdata)840 static void handle_get_playback_streams(DBusConnection *conn, DBusMessage *msg, void *userdata) {
841 pa_dbusiface_core *c = userdata;
842 const char **playback_streams;
843 unsigned n;
844
845 pa_assert(conn);
846 pa_assert(msg);
847 pa_assert(c);
848
849 playback_streams = get_playback_streams(c, &n);
850
851 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, playback_streams, n);
852
853 pa_xfree(playback_streams);
854 }
855
856 /* The caller frees the array, but not the strings. */
get_record_streams(pa_dbusiface_core * c,unsigned * n)857 static const char **get_record_streams(pa_dbusiface_core *c, unsigned *n) {
858 const char **streams;
859 unsigned i = 0;
860 void *state = NULL;
861 pa_dbusiface_stream *stream;
862
863 pa_assert(c);
864 pa_assert(n);
865
866 *n = pa_hashmap_size(c->record_streams);
867
868 if (*n == 0)
869 return NULL;
870
871 streams = pa_xnew(const char *, *n);
872
873 PA_HASHMAP_FOREACH(stream, c->record_streams, state)
874 streams[i++] = pa_dbusiface_stream_get_path(stream);
875
876 return streams;
877 }
878
handle_get_record_streams(DBusConnection * conn,DBusMessage * msg,void * userdata)879 static void handle_get_record_streams(DBusConnection *conn, DBusMessage *msg, void *userdata) {
880 pa_dbusiface_core *c = userdata;
881 const char **record_streams;
882 unsigned n;
883
884 pa_assert(conn);
885 pa_assert(msg);
886 pa_assert(c);
887
888 record_streams = get_record_streams(c, &n);
889
890 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, record_streams, n);
891
892 pa_xfree(record_streams);
893 }
894
895 /* The caller frees the array, but not the strings. */
get_samples(pa_dbusiface_core * c,unsigned * n)896 static const char **get_samples(pa_dbusiface_core *c, unsigned *n) {
897 const char **samples;
898 unsigned i = 0;
899 void *state = NULL;
900 pa_dbusiface_sample *sample;
901
902 pa_assert(c);
903 pa_assert(n);
904
905 *n = pa_hashmap_size(c->samples);
906
907 if (*n == 0)
908 return NULL;
909
910 samples = pa_xnew(const char *, *n);
911
912 PA_HASHMAP_FOREACH(sample, c->samples, state)
913 samples[i++] = pa_dbusiface_sample_get_path(sample);
914
915 return samples;
916 }
917
handle_get_samples(DBusConnection * conn,DBusMessage * msg,void * userdata)918 static void handle_get_samples(DBusConnection *conn, DBusMessage *msg, void *userdata) {
919 pa_dbusiface_core *c = userdata;
920 const char **samples;
921 unsigned n;
922
923 pa_assert(conn);
924 pa_assert(msg);
925 pa_assert(c);
926
927 samples = get_samples(c, &n);
928
929 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, samples, n);
930
931 pa_xfree(samples);
932 }
933
934 /* The caller frees the array, but not the strings. */
get_modules(pa_dbusiface_core * c,unsigned * n)935 static const char **get_modules(pa_dbusiface_core *c, unsigned *n) {
936 const char **modules;
937 unsigned i = 0;
938 void *state = NULL;
939 pa_dbusiface_module *module;
940
941 pa_assert(c);
942 pa_assert(n);
943
944 *n = pa_hashmap_size(c->modules);
945
946 if (*n == 0)
947 return NULL;
948
949 modules = pa_xnew(const char *, *n);
950
951 PA_HASHMAP_FOREACH(module, c->modules, state)
952 modules[i++] = pa_dbusiface_module_get_path(module);
953
954 return modules;
955 }
956
handle_get_modules(DBusConnection * conn,DBusMessage * msg,void * userdata)957 static void handle_get_modules(DBusConnection *conn, DBusMessage *msg, void *userdata) {
958 pa_dbusiface_core *c = userdata;
959 const char **modules;
960 unsigned n;
961
962 pa_assert(conn);
963 pa_assert(msg);
964 pa_assert(c);
965
966 modules = get_modules(c, &n);
967
968 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, modules, n);
969
970 pa_xfree(modules);
971 }
972
973 /* The caller frees the array, but not the strings. */
get_clients(pa_dbusiface_core * c,unsigned * n)974 static const char **get_clients(pa_dbusiface_core *c, unsigned *n) {
975 const char **clients;
976 unsigned i = 0;
977 void *state = NULL;
978 pa_dbusiface_client *client;
979
980 pa_assert(c);
981 pa_assert(n);
982
983 *n = pa_hashmap_size(c->clients);
984
985 if (*n == 0)
986 return NULL;
987
988 clients = pa_xnew(const char *, *n);
989
990 PA_HASHMAP_FOREACH(client, c->clients, state)
991 clients[i++] = pa_dbusiface_client_get_path(client);
992
993 return clients;
994 }
995
handle_get_clients(DBusConnection * conn,DBusMessage * msg,void * userdata)996 static void handle_get_clients(DBusConnection *conn, DBusMessage *msg, void *userdata) {
997 pa_dbusiface_core *c = userdata;
998 const char **clients;
999 unsigned n;
1000
1001 pa_assert(conn);
1002 pa_assert(msg);
1003 pa_assert(c);
1004
1005 clients = get_clients(c, &n);
1006
1007 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, clients, n);
1008
1009 pa_xfree(clients);
1010 }
1011
get_my_client(pa_dbusiface_core * c,DBusConnection * conn)1012 static const char *get_my_client(pa_dbusiface_core *c, DBusConnection *conn) {
1013 pa_client *my_client;
1014
1015 pa_assert(c);
1016 pa_assert(conn);
1017
1018 pa_assert_se((my_client = pa_dbus_protocol_get_client(c->dbus_protocol, conn)));
1019
1020 return pa_dbusiface_client_get_path(pa_hashmap_get(c->clients, PA_UINT32_TO_PTR(my_client->index)));
1021 }
1022
handle_get_my_client(DBusConnection * conn,DBusMessage * msg,void * userdata)1023 static void handle_get_my_client(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1024 pa_dbusiface_core *c = userdata;
1025 const char *my_client;
1026
1027 pa_assert(conn);
1028 pa_assert(msg);
1029 pa_assert(c);
1030
1031 my_client = get_my_client(c, conn);
1032
1033 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &my_client);
1034 }
1035
handle_get_extensions(DBusConnection * conn,DBusMessage * msg,void * userdata)1036 static void handle_get_extensions(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1037 pa_dbusiface_core *c = userdata;
1038 const char **extensions;
1039 unsigned n;
1040
1041 pa_assert(conn);
1042 pa_assert(msg);
1043 pa_assert(c);
1044
1045 extensions = pa_dbus_protocol_get_extensions(c->dbus_protocol, &n);
1046
1047 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_STRING, extensions, n);
1048
1049 pa_xfree(extensions);
1050 }
1051
handle_get_all(DBusConnection * conn,DBusMessage * msg,void * userdata)1052 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1053 pa_dbusiface_core *c = userdata;
1054 DBusMessage *reply = NULL;
1055 DBusMessageIter msg_iter;
1056 DBusMessageIter dict_iter;
1057 dbus_uint32_t interface_revision;
1058 const char *server_name;
1059 const char *version;
1060 dbus_bool_t is_local;
1061 char *username;
1062 char *hostname;
1063 dbus_uint32_t *default_channels;
1064 unsigned n_default_channels;
1065 dbus_uint32_t default_sample_format;
1066 dbus_uint32_t default_sample_rate;
1067 dbus_uint32_t alternate_sample_rate;
1068 const char **cards;
1069 unsigned n_cards;
1070 const char **sinks;
1071 unsigned n_sinks;
1072 const char *fallback_sink;
1073 const char **sources;
1074 unsigned n_sources;
1075 const char *fallback_source;
1076 const char **playback_streams;
1077 unsigned n_playback_streams;
1078 const char **record_streams;
1079 unsigned n_record_streams;
1080 const char **samples;
1081 unsigned n_samples;
1082 const char **modules;
1083 unsigned n_modules;
1084 const char **clients;
1085 unsigned n_clients;
1086 const char *my_client;
1087 const char **extensions;
1088 unsigned n_extensions;
1089
1090 pa_assert(conn);
1091 pa_assert(msg);
1092 pa_assert(c);
1093
1094 interface_revision = INTERFACE_REVISION;
1095 server_name = PACKAGE_NAME;
1096 version = PACKAGE_VERSION;
1097 is_local = get_is_local(conn);
1098 username = pa_get_user_name_malloc();
1099 hostname = pa_get_host_name_malloc();
1100 default_channels = get_default_channels(c, &n_default_channels);
1101 default_sample_format = c->core->default_sample_spec.format;
1102 default_sample_rate = c->core->default_sample_spec.rate;
1103 alternate_sample_rate = c->core->alternate_sample_rate;
1104 cards = get_cards(c, &n_cards);
1105 sinks = get_sinks(c, &n_sinks);
1106 fallback_sink = c->fallback_sink
1107 ? pa_dbusiface_device_get_path(pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(c->fallback_sink->index)))
1108 : NULL;
1109 sources = get_sources(c, &n_sources);
1110 fallback_source = c->fallback_source
1111 ? pa_dbusiface_device_get_path(pa_hashmap_get(c->sources_by_index,
1112 PA_UINT32_TO_PTR(c->fallback_source->index)))
1113 : NULL;
1114 playback_streams = get_playback_streams(c, &n_playback_streams);
1115 record_streams = get_record_streams(c, &n_record_streams);
1116 samples = get_samples(c, &n_samples);
1117 modules = get_modules(c, &n_modules);
1118 clients = get_clients(c, &n_clients);
1119 my_client = get_my_client(c, conn);
1120 extensions = pa_dbus_protocol_get_extensions(c->dbus_protocol, &n_extensions);
1121
1122 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1123
1124 dbus_message_iter_init_append(reply, &msg_iter);
1125 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
1126
1127 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INTERFACE_REVISION].property_name, DBUS_TYPE_UINT32, &interface_revision);
1128 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &server_name);
1129 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VERSION].property_name, DBUS_TYPE_STRING, &version);
1130 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_IS_LOCAL].property_name, DBUS_TYPE_BOOLEAN, &is_local);
1131 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_USERNAME].property_name, DBUS_TYPE_STRING, &username);
1132 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_HOSTNAME].property_name, DBUS_TYPE_STRING, &hostname);
1133 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEFAULT_CHANNELS].property_name, DBUS_TYPE_UINT32, default_channels, n_default_channels);
1134 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEFAULT_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &default_sample_format);
1135 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEFAULT_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &default_sample_rate);
1136 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_ALTERNATE_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &alternate_sample_rate);
1137 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CARDS].property_name, DBUS_TYPE_OBJECT_PATH, cards, n_cards);
1138 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SINKS].property_name, DBUS_TYPE_OBJECT_PATH, sinks, n_sinks);
1139
1140 if (fallback_sink)
1141 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_FALLBACK_SINK].property_name, DBUS_TYPE_OBJECT_PATH, &fallback_sink);
1142
1143 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SOURCES].property_name, DBUS_TYPE_OBJECT_PATH, sources, n_sources);
1144
1145 if (fallback_source)
1146 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_FALLBACK_SOURCE].property_name, DBUS_TYPE_OBJECT_PATH, &fallback_source);
1147
1148 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PLAYBACK_STREAMS].property_name, DBUS_TYPE_OBJECT_PATH, playback_streams, n_playback_streams);
1149 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_RECORD_STREAMS].property_name, DBUS_TYPE_OBJECT_PATH, record_streams, n_record_streams);
1150 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLES].property_name, DBUS_TYPE_OBJECT_PATH, samples, n_samples);
1151 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MODULES].property_name, DBUS_TYPE_OBJECT_PATH, modules, n_modules);
1152 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CLIENTS].property_name, DBUS_TYPE_OBJECT_PATH, clients, n_clients);
1153 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MY_CLIENT].property_name, DBUS_TYPE_OBJECT_PATH, &my_client);
1154 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_EXTENSIONS].property_name, DBUS_TYPE_STRING, extensions, n_extensions);
1155
1156 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
1157
1158 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1159
1160 dbus_message_unref(reply);
1161
1162 pa_xfree(username);
1163 pa_xfree(hostname);
1164 pa_xfree(default_channels);
1165 pa_xfree(cards);
1166 pa_xfree(sinks);
1167 pa_xfree(sources);
1168 pa_xfree(playback_streams);
1169 pa_xfree(record_streams);
1170 pa_xfree(samples);
1171 pa_xfree(modules);
1172 pa_xfree(clients);
1173 pa_xfree(extensions);
1174 }
1175
handle_get_card_by_name(DBusConnection * conn,DBusMessage * msg,void * userdata)1176 static void handle_get_card_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1177 pa_dbusiface_core *c = userdata;
1178 char *card_name;
1179 pa_card *card;
1180 pa_dbusiface_card *dbus_card;
1181 const char *object_path;
1182
1183 pa_assert(conn);
1184 pa_assert(msg);
1185 pa_assert(c);
1186
1187 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &card_name, DBUS_TYPE_INVALID));
1188
1189 if (!(card = pa_namereg_get(c->core, card_name, PA_NAMEREG_CARD))) {
1190 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "No such card.");
1191 return;
1192 }
1193
1194 pa_assert_se((dbus_card = pa_hashmap_get(c->cards, PA_UINT32_TO_PTR(card->index))));
1195
1196 object_path = pa_dbusiface_card_get_path(dbus_card);
1197
1198 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
1199 }
1200
handle_get_sink_by_name(DBusConnection * conn,DBusMessage * msg,void * userdata)1201 static void handle_get_sink_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1202 pa_dbusiface_core *c = userdata;
1203 char *sink_name;
1204 pa_sink *sink;
1205 pa_dbusiface_device *dbus_sink;
1206 const char *object_path;
1207
1208 pa_assert(conn);
1209 pa_assert(msg);
1210 pa_assert(c);
1211
1212 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &sink_name, DBUS_TYPE_INVALID));
1213
1214 if (!(sink = pa_namereg_get(c->core, sink_name, PA_NAMEREG_SINK))) {
1215 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", sink_name);
1216 return;
1217 }
1218
1219 pa_assert_se((dbus_sink = pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(sink->index))));
1220
1221 object_path = pa_dbusiface_device_get_path(dbus_sink);
1222
1223 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
1224 }
1225
handle_get_source_by_name(DBusConnection * conn,DBusMessage * msg,void * userdata)1226 static void handle_get_source_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1227 pa_dbusiface_core *c = userdata;
1228 char *source_name;
1229 pa_source *source;
1230 pa_dbusiface_device *dbus_source;
1231 const char *object_path;
1232
1233 pa_assert(conn);
1234 pa_assert(msg);
1235 pa_assert(c);
1236
1237 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &source_name, DBUS_TYPE_INVALID));
1238
1239 if (!(source = pa_namereg_get(c->core, source_name, PA_NAMEREG_SOURCE))) {
1240 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", source_name);
1241 return;
1242 }
1243
1244 pa_assert_se((dbus_source = pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(source->index))));
1245
1246 object_path = pa_dbusiface_device_get_path(dbus_source);
1247
1248 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
1249 }
1250
handle_get_sample_by_name(DBusConnection * conn,DBusMessage * msg,void * userdata)1251 static void handle_get_sample_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1252 pa_dbusiface_core *c = userdata;
1253 char *sample_name;
1254 pa_scache_entry *sample;
1255 pa_dbusiface_sample *dbus_sample;
1256 const char *object_path;
1257
1258 pa_assert(conn);
1259 pa_assert(msg);
1260 pa_assert(c);
1261
1262 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &sample_name, DBUS_TYPE_INVALID));
1263
1264 if (!(sample = pa_namereg_get(c->core, sample_name, PA_NAMEREG_SAMPLE))) {
1265 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "No such sample.");
1266 return;
1267 }
1268
1269 pa_assert_se((dbus_sample = pa_hashmap_get(c->samples, PA_UINT32_TO_PTR(sample->index))));
1270
1271 object_path = pa_dbusiface_sample_get_path(dbus_sample);
1272
1273 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
1274 }
1275
handle_upload_sample(DBusConnection * conn,DBusMessage * msg,void * userdata)1276 static void handle_upload_sample(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1277 pa_dbusiface_core *c = userdata;
1278 DBusMessageIter msg_iter;
1279 DBusMessageIter array_iter;
1280 const char *name;
1281 dbus_uint32_t sample_format;
1282 dbus_uint32_t sample_rate;
1283 const dbus_uint32_t *channels;
1284 int n_channels;
1285 const dbus_uint32_t *default_volume;
1286 int n_volume_entries;
1287 pa_proplist *property_list;
1288 const uint8_t *data;
1289 int data_length;
1290 int i;
1291 pa_sample_spec ss;
1292 pa_channel_map map;
1293 pa_memchunk chunk;
1294 uint32_t idx;
1295 pa_dbusiface_sample *dbus_sample = NULL;
1296 pa_scache_entry *sample = NULL;
1297 const char *object_path;
1298
1299 pa_assert(conn);
1300 pa_assert(msg);
1301 pa_assert(c);
1302
1303 chunk.memblock = NULL;
1304
1305 pa_assert_se(dbus_message_iter_init(msg, &msg_iter));
1306 dbus_message_iter_get_basic(&msg_iter, &name);
1307
1308 pa_assert_se(dbus_message_iter_next(&msg_iter));
1309 dbus_message_iter_get_basic(&msg_iter, &sample_format);
1310
1311 pa_assert_se(dbus_message_iter_next(&msg_iter));
1312 dbus_message_iter_get_basic(&msg_iter, &sample_rate);
1313
1314 pa_assert_se(dbus_message_iter_next(&msg_iter));
1315 dbus_message_iter_recurse(&msg_iter, &array_iter);
1316 dbus_message_iter_get_fixed_array(&array_iter, &channels, &n_channels);
1317
1318 pa_assert_se(dbus_message_iter_next(&msg_iter));
1319 dbus_message_iter_recurse(&msg_iter, &array_iter);
1320 dbus_message_iter_get_fixed_array(&array_iter, &default_volume, &n_volume_entries);
1321
1322 pa_assert_se(dbus_message_iter_next(&msg_iter));
1323 if (!(property_list = pa_dbus_get_proplist_arg(conn, msg, &msg_iter)))
1324 return;
1325
1326 dbus_message_iter_recurse(&msg_iter, &array_iter);
1327 dbus_message_iter_get_fixed_array(&array_iter, &data, &data_length);
1328
1329 if (!pa_sample_format_valid(sample_format)) {
1330 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid sample format.");
1331 goto finish;
1332 }
1333
1334 if (!pa_sample_rate_valid(sample_rate)) {
1335 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid sample rate.");
1336 goto finish;
1337 }
1338
1339 if (n_channels <= 0) {
1340 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Empty channel map.");
1341 goto finish;
1342 }
1343
1344 if (n_channels > (int) PA_CHANNELS_MAX) {
1345 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
1346 "Too many channels: %i. The maximum is %u.", n_channels, PA_CHANNELS_MAX);
1347 goto finish;
1348 }
1349
1350 for (i = 0; i < n_channels; ++i) {
1351 if (channels[i] >= PA_CHANNEL_POSITION_MAX) {
1352 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid channel position.");
1353 goto finish;
1354 }
1355 }
1356
1357 if (n_volume_entries != 0 && n_volume_entries != n_channels) {
1358 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
1359 "The channels and default_volume arguments have different number of elements (%i and %i, resp).",
1360 n_channels, n_volume_entries);
1361 goto finish;
1362 }
1363
1364 for (i = 0; i < n_volume_entries; ++i) {
1365 if (!PA_VOLUME_IS_VALID(default_volume[i])) {
1366 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume: %u.", default_volume[i]);
1367 goto finish;
1368 }
1369 }
1370
1371 if (data_length == 0) {
1372 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Empty data.");
1373 goto finish;
1374 }
1375
1376 if (data_length > PA_SCACHE_ENTRY_SIZE_MAX) {
1377 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
1378 "Too big sample: %i bytes. The maximum sample length is %u bytes.",
1379 data_length, PA_SCACHE_ENTRY_SIZE_MAX);
1380 goto finish;
1381 }
1382
1383 ss.format = sample_format;
1384 ss.rate = sample_rate;
1385 ss.channels = n_channels;
1386
1387 pa_assert(pa_sample_spec_valid(&ss));
1388
1389 if (!pa_frame_aligned(data_length, &ss)) {
1390 char buf[PA_SAMPLE_SPEC_SNPRINT_MAX];
1391 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
1392 "The sample length (%i bytes) doesn't align with the sample format and channels (%s).",
1393 data_length, pa_sample_spec_snprint(buf, sizeof(buf), &ss));
1394 goto finish;
1395 }
1396
1397 map.channels = n_channels;
1398 for (i = 0; i < n_channels; ++i)
1399 map.map[i] = channels[i];
1400
1401 chunk.memblock = pa_memblock_new(c->core->mempool, data_length);
1402 chunk.index = 0;
1403 chunk.length = data_length;
1404
1405 memcpy(pa_memblock_acquire(chunk.memblock), data, data_length);
1406 pa_memblock_release(chunk.memblock);
1407
1408 if (pa_scache_add_item(c->core, name, &ss, &map, &chunk, property_list, &idx) < 0) {
1409 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Adding the sample failed.");
1410 goto finish;
1411 }
1412
1413 pa_assert_se(sample = pa_idxset_get_by_index(c->core->scache, idx));
1414
1415 if (n_volume_entries > 0) {
1416 sample->volume.channels = n_channels;
1417 for (i = 0; i < n_volume_entries; ++i)
1418 sample->volume.values[i] = default_volume[i];
1419 sample->volume_is_set = true;
1420 } else {
1421 sample->volume_is_set = false;
1422 }
1423
1424 dbus_sample = pa_dbusiface_sample_new(c, sample);
1425 pa_hashmap_put(c->samples, PA_UINT32_TO_PTR(idx), dbus_sample);
1426
1427 object_path = pa_dbusiface_sample_get_path(dbus_sample);
1428
1429 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
1430
1431 finish:
1432 if (property_list)
1433 pa_proplist_free(property_list);
1434
1435 if (chunk.memblock)
1436 pa_memblock_unref(chunk.memblock);
1437 }
1438
contains_space(const char * string)1439 static bool contains_space(const char *string) {
1440 const char *p;
1441
1442 pa_assert(string);
1443
1444 for (p = string; *p; ++p) {
1445 if (isspace((unsigned char)*p))
1446 return true;
1447 }
1448
1449 return false;
1450 }
1451
handle_load_module(DBusConnection * conn,DBusMessage * msg,void * userdata)1452 static void handle_load_module(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1453 pa_dbusiface_core *c = userdata;
1454 DBusMessageIter msg_iter;
1455 DBusMessageIter dict_iter;
1456 DBusMessageIter dict_entry_iter;
1457 char *name = NULL;
1458 const char *key = NULL;
1459 const char *value = NULL;
1460 char *escaped_value = NULL;
1461 pa_strbuf *arg_buffer = NULL;
1462 char *arg_string = NULL;
1463 pa_module *module = NULL;
1464 pa_dbusiface_module *dbus_module = NULL;
1465 const char *object_path = NULL;
1466
1467 pa_assert(conn);
1468 pa_assert(msg);
1469 pa_assert(c);
1470
1471 if (c->core->disallow_module_loading) {
1472 pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "The server is configured to disallow module loading.");
1473 return;
1474 }
1475
1476 pa_assert_se(dbus_message_iter_init(msg, &msg_iter));
1477 dbus_message_iter_get_basic(&msg_iter, &name);
1478
1479 arg_buffer = pa_strbuf_new();
1480
1481 pa_assert_se(dbus_message_iter_next(&msg_iter));
1482 dbus_message_iter_recurse(&msg_iter, &dict_iter);
1483
1484 while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
1485 if (!pa_strbuf_isempty(arg_buffer))
1486 pa_strbuf_putc(arg_buffer, ' ');
1487
1488 dbus_message_iter_recurse(&dict_iter, &dict_entry_iter);
1489
1490 dbus_message_iter_get_basic(&dict_entry_iter, &key);
1491
1492 if (strlen(key) <= 0 || !pa_ascii_valid(key) || contains_space(key)) {
1493 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid module argument name: %s", key);
1494 goto finish;
1495 }
1496
1497 pa_assert_se(dbus_message_iter_next(&dict_entry_iter));
1498 dbus_message_iter_get_basic(&dict_entry_iter, &value);
1499
1500 escaped_value = pa_escape(value, "\"");
1501 pa_strbuf_printf(arg_buffer, "%s=\"%s\"", key, escaped_value);
1502 pa_xfree(escaped_value);
1503
1504 dbus_message_iter_next(&dict_iter);
1505 }
1506
1507 arg_string = pa_strbuf_to_string(arg_buffer);
1508
1509 if (pa_module_load(&module, c->core, name, arg_string) < 0) {
1510 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Failed to load module.");
1511 goto finish;
1512 }
1513
1514 /* This is created during module loading in module_new_cb() */
1515 dbus_module = pa_hashmap_get(c->modules, PA_UINT32_TO_PTR(module->index));
1516 object_path = pa_dbusiface_module_get_path(dbus_module);
1517
1518 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
1519
1520 finish:
1521 if (arg_buffer)
1522 pa_strbuf_free(arg_buffer);
1523
1524 pa_xfree(arg_string);
1525 }
1526
handle_exit(DBusConnection * conn,DBusMessage * msg,void * userdata)1527 static void handle_exit(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1528 pa_dbusiface_core *c = userdata;
1529
1530 pa_assert(conn);
1531 pa_assert(msg);
1532 pa_assert(c);
1533
1534 if (c->core->disallow_exit) {
1535 pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "The server is configured to disallow exiting.");
1536 return;
1537 }
1538
1539 pa_dbus_send_empty_reply(conn, msg);
1540
1541 pa_core_exit(c->core, false, 0);
1542 }
1543
handle_listen_for_signal(DBusConnection * conn,DBusMessage * msg,void * userdata)1544 static void handle_listen_for_signal(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1545 pa_dbusiface_core *c = userdata;
1546 const char *signal_str;
1547 char **objects = NULL;
1548 int n_objects;
1549
1550 pa_assert(conn);
1551 pa_assert(msg);
1552 pa_assert(c);
1553
1554 pa_assert_se(dbus_message_get_args(msg, NULL,
1555 DBUS_TYPE_STRING, &signal_str,
1556 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &objects, &n_objects,
1557 DBUS_TYPE_INVALID));
1558
1559 pa_dbus_protocol_add_signal_listener(c->dbus_protocol, conn, *signal_str ? signal_str : NULL, objects, n_objects);
1560
1561 pa_dbus_send_empty_reply(conn, msg);
1562
1563 dbus_free_string_array(objects);
1564 }
1565
handle_stop_listening_for_signal(DBusConnection * conn,DBusMessage * msg,void * userdata)1566 static void handle_stop_listening_for_signal(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1567 pa_dbusiface_core *c = userdata;
1568 const char *signal_str;
1569
1570 pa_assert(conn);
1571 pa_assert(msg);
1572 pa_assert(c);
1573
1574 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &signal_str, DBUS_TYPE_INVALID));
1575
1576 pa_dbus_protocol_remove_signal_listener(c->dbus_protocol, conn, *signal_str ? signal_str : NULL);
1577
1578 pa_dbus_send_empty_reply(conn, msg);
1579 }
1580
module_new_cb(void * hook_data,void * call_data,void * slot_data)1581 static pa_hook_result_t module_new_cb(void *hook_data, void *call_data, void *slot_data) {
1582 pa_dbusiface_core *c = slot_data;
1583 pa_module * module = call_data;
1584 pa_dbusiface_module *module_iface;
1585 const char *object_path;
1586 DBusMessage *signal_msg = NULL;
1587
1588 pa_assert(c);
1589 pa_assert(module);
1590
1591 if (pa_streq(module->name, "module-dbus-protocol")) {
1592 /* module-dbus-protocol can only be loaded once, and will be accounted
1593 * for while iterating core->modules in pa_dbusiface_core_new(). As it
1594 * happens, we will also see it here when the hook is called after the
1595 * module is initialised, so we ignore it. */
1596 return PA_HOOK_OK;
1597 }
1598
1599 module_iface = pa_dbusiface_module_new(module);
1600 pa_assert_se(pa_hashmap_put(c->modules, PA_UINT32_TO_PTR(module->index), module_iface) >= 0);
1601
1602 object_path = pa_dbusiface_module_get_path(module_iface);
1603
1604 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1605 PA_DBUS_CORE_INTERFACE,
1606 signals[SIGNAL_NEW_MODULE].name)));
1607 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1608
1609 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1610 dbus_message_unref(signal_msg);
1611
1612 return PA_HOOK_OK;
1613 }
1614
module_removed_cb(void * hook_data,void * call_data,void * slot_data)1615 static pa_hook_result_t module_removed_cb(void *hook_data, void *call_data, void *slot_data) {
1616 pa_dbusiface_core *c = slot_data;
1617 pa_module * module = call_data;
1618 pa_dbusiface_module *module_iface;
1619 const char *object_path;
1620 DBusMessage *signal_msg = NULL;
1621
1622 pa_assert(c);
1623 pa_assert(module);
1624
1625 pa_assert_se((module_iface = pa_hashmap_remove(c->modules, PA_UINT32_TO_PTR(module->index))));
1626
1627 object_path = pa_dbusiface_module_get_path(module_iface);
1628
1629 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1630 PA_DBUS_CORE_INTERFACE,
1631 signals[SIGNAL_MODULE_REMOVED].name)));
1632 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1633
1634 pa_dbusiface_module_free(module_iface);
1635
1636 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1637 dbus_message_unref(signal_msg);
1638
1639 return PA_HOOK_OK;
1640 }
1641
sample_cache_new_cb(void * hook_data,void * call_data,void * slot_data)1642 static pa_hook_result_t sample_cache_new_cb(void *hook_data, void *call_data, void *slot_data) {
1643 pa_dbusiface_core *c = slot_data;
1644 pa_scache_entry *sample = call_data;
1645 pa_dbusiface_sample *sample_iface;
1646 const char *object_path;
1647 DBusMessage *signal_msg = NULL;
1648
1649 pa_assert(c);
1650 pa_assert(sample);
1651
1652 sample_iface = pa_dbusiface_sample_new(c, sample);
1653 pa_assert_se(pa_hashmap_put(c->samples, PA_UINT32_TO_PTR(sample->index), sample_iface) >= 0);
1654
1655 object_path = pa_dbusiface_sample_get_path(sample_iface);
1656
1657 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1658 PA_DBUS_CORE_INTERFACE,
1659 signals[SIGNAL_NEW_SAMPLE].name)));
1660 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1661
1662 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1663 dbus_message_unref(signal_msg);
1664
1665 return PA_HOOK_OK;
1666 }
1667
sample_cache_removed_cb(void * hook_data,void * call_data,void * slot_data)1668 static pa_hook_result_t sample_cache_removed_cb(void *hook_data, void *call_data, void *slot_data) {
1669 pa_dbusiface_core *c = slot_data;
1670 pa_scache_entry *sample = call_data;
1671 pa_dbusiface_sample *sample_iface;
1672 const char *object_path;
1673 DBusMessage *signal_msg = NULL;
1674
1675 pa_assert(c);
1676 pa_assert(sample);
1677
1678 pa_assert_se((sample_iface = pa_hashmap_remove(c->samples, PA_UINT32_TO_PTR(sample->index))));
1679
1680 object_path = pa_dbusiface_sample_get_path(sample_iface);
1681
1682 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1683 PA_DBUS_CORE_INTERFACE,
1684 signals[SIGNAL_SAMPLE_REMOVED].name)));
1685 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1686
1687 pa_dbusiface_sample_free(sample_iface);
1688
1689 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1690 dbus_message_unref(signal_msg);
1691
1692 return PA_HOOK_OK;
1693 }
1694
create_dbus_object_for_sink(pa_dbusiface_core * c,pa_sink * s)1695 static pa_dbusiface_device *create_dbus_object_for_sink(pa_dbusiface_core *c, pa_sink *s) {
1696 pa_dbusiface_device *d;
1697 const char *object_path;
1698 DBusMessage *signal_msg;
1699
1700 d = pa_dbusiface_device_new_sink(c, s);
1701 object_path = pa_dbusiface_device_get_path(d);
1702
1703 pa_assert_se(pa_hashmap_put(c->sinks_by_index, PA_UINT32_TO_PTR(s->index), d) >= 0);
1704 pa_assert_se(pa_hashmap_put(c->sinks_by_path, (char *) object_path, d) >= 0);
1705
1706 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1707 PA_DBUS_CORE_INTERFACE,
1708 signals[SIGNAL_NEW_SINK].name)));
1709 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1710
1711 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1712 dbus_message_unref(signal_msg);
1713
1714 return d;
1715 }
1716
default_sink_changed_cb(void * hook_data,void * call_data,void * slot_data)1717 static pa_hook_result_t default_sink_changed_cb(void *hook_data, void *call_data, void *slot_data) {
1718 pa_dbusiface_core *c = slot_data;
1719 pa_sink *new_fallback_sink = call_data;
1720 pa_dbusiface_device *device_iface;
1721 const char *object_path;
1722 DBusMessage *signal_msg = NULL;
1723
1724 pa_assert(c);
1725
1726 if (c->fallback_sink != new_fallback_sink) {
1727 if (c->fallback_sink)
1728 pa_sink_unref(c->fallback_sink);
1729 c->fallback_sink = new_fallback_sink ? pa_sink_ref(new_fallback_sink) : NULL;
1730
1731 if (c->fallback_sink) {
1732 device_iface = pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(c->fallback_sink->index));
1733
1734 /* It's possible that we haven't created a dbus object for the
1735 * source yet, because if a new source immediately becomes the
1736 * default source, the default source change hook is fired before
1737 * the put hook. */
1738 if (!device_iface)
1739 device_iface = create_dbus_object_for_sink(c, c->fallback_sink);
1740
1741 object_path = pa_dbusiface_device_get_path(device_iface);
1742
1743 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1744 PA_DBUS_CORE_INTERFACE,
1745 signals[SIGNAL_FALLBACK_SINK_UPDATED].name)));
1746 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1747
1748 } else {
1749 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1750 PA_DBUS_CORE_INTERFACE,
1751 signals[SIGNAL_FALLBACK_SINK_UNSET].name)));
1752 }
1753 }
1754
1755 if (signal_msg) {
1756 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1757 dbus_message_unref(signal_msg);
1758 }
1759
1760 return PA_HOOK_OK;
1761 }
1762
create_dbus_object_for_source(pa_dbusiface_core * c,pa_source * s)1763 static pa_dbusiface_device *create_dbus_object_for_source(pa_dbusiface_core *c, pa_source *s) {
1764 pa_dbusiface_device *d;
1765 const char *object_path;
1766 DBusMessage *signal_msg;
1767
1768 d = pa_dbusiface_device_new_source(c, s);
1769 object_path = pa_dbusiface_device_get_path(d);
1770
1771 pa_assert_se(pa_hashmap_put(c->sources_by_index, PA_UINT32_TO_PTR(s->index), d) >= 0);
1772 pa_assert_se(pa_hashmap_put(c->sources_by_path, (char *) object_path, d) >= 0);
1773
1774 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1775 PA_DBUS_CORE_INTERFACE,
1776 signals[SIGNAL_NEW_SOURCE].name)));
1777 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1778
1779 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1780 dbus_message_unref(signal_msg);
1781
1782 return d;
1783 }
1784
default_source_changed_cb(void * hook_data,void * call_data,void * slot_data)1785 static pa_hook_result_t default_source_changed_cb(void *hook_data, void *call_data, void *slot_data) {
1786 pa_dbusiface_core *c = slot_data;
1787 pa_source *new_fallback_source = call_data;
1788 pa_dbusiface_device *device_iface;
1789 const char *object_path;
1790 DBusMessage *signal_msg = NULL;
1791
1792 pa_assert(c);
1793
1794 if (c->fallback_source != new_fallback_source) {
1795 if (c->fallback_source)
1796 pa_source_unref(c->fallback_source);
1797 c->fallback_source = new_fallback_source ? pa_source_ref(new_fallback_source) : NULL;
1798
1799 if (c->fallback_source) {
1800 device_iface = pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(c->fallback_source->index));
1801
1802 /* It's possible that we haven't created a dbus object for the
1803 * source yet, because if a new source immediately becomes the
1804 * default source, the default source change hook is fired before
1805 * the put hook. */
1806 if (!device_iface)
1807 device_iface = create_dbus_object_for_source(c, c->fallback_source);
1808
1809 object_path = pa_dbusiface_device_get_path(device_iface);
1810
1811 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1812 PA_DBUS_CORE_INTERFACE,
1813 signals[SIGNAL_FALLBACK_SOURCE_UPDATED].name)));
1814 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1815
1816 } else {
1817 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1818 PA_DBUS_CORE_INTERFACE,
1819 signals[SIGNAL_FALLBACK_SOURCE_UNSET].name)));
1820 }
1821 }
1822
1823 if (signal_msg) {
1824 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1825 dbus_message_unref(signal_msg);
1826 }
1827
1828 return PA_HOOK_OK;
1829 }
1830
card_put_cb(void * hook_data,void * call_data,void * slot_data)1831 static pa_hook_result_t card_put_cb(void *hook_data, void *call_data, void *slot_data) {
1832 pa_dbusiface_core *c = slot_data;
1833 pa_card *card = call_data;
1834 pa_dbusiface_card *card_iface = NULL;
1835 const char *object_path;
1836 DBusMessage *signal_msg;
1837
1838 pa_assert(c);
1839 pa_assert(card);
1840
1841 card_iface = pa_dbusiface_card_new(c, card);
1842 pa_assert_se(pa_hashmap_put(c->cards, PA_UINT32_TO_PTR(card->index), card_iface) >= 0);
1843
1844 object_path = pa_dbusiface_card_get_path(card_iface);
1845
1846 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1847 PA_DBUS_CORE_INTERFACE,
1848 signals[SIGNAL_NEW_CARD].name)));
1849 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1850
1851 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1852 dbus_message_unref(signal_msg);
1853
1854 return PA_HOOK_OK;
1855 }
1856
card_unlink_cb(void * hook_data,void * call_data,void * slot_data)1857 static pa_hook_result_t card_unlink_cb(void *hook_data, void *call_data, void *slot_data) {
1858 pa_dbusiface_core *c = slot_data;
1859 pa_card *card = call_data;
1860 pa_dbusiface_card *card_iface;
1861 const char *object_path;
1862 DBusMessage *signal_msg;
1863
1864 pa_assert(c);
1865 pa_assert(card);
1866
1867 pa_assert_se((card_iface = pa_hashmap_remove(c->cards, PA_UINT32_TO_PTR(card->index))));
1868
1869 object_path = pa_dbusiface_card_get_path(card_iface);
1870
1871 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1872 PA_DBUS_CORE_INTERFACE,
1873 signals[SIGNAL_CARD_REMOVED].name)));
1874 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1875
1876 pa_dbusiface_card_free(card_iface);
1877
1878 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1879 dbus_message_unref(signal_msg);
1880
1881 return PA_HOOK_OK;
1882 }
1883
sink_input_put_cb(void * hook_data,void * call_data,void * slot_data)1884 static pa_hook_result_t sink_input_put_cb(void *hook_data, void *call_data, void *slot_data) {
1885 pa_dbusiface_core *c = slot_data;
1886 pa_sink_input *sink_input = call_data;
1887 pa_dbusiface_stream *stream_iface;
1888 const char *object_path;
1889 DBusMessage *signal_msg;
1890
1891 pa_assert(c);
1892 pa_assert(sink_input);
1893
1894 stream_iface = pa_dbusiface_stream_new_playback(c, sink_input);
1895 pa_assert_se(pa_hashmap_put(c->playback_streams, PA_UINT32_TO_PTR(sink_input->index), stream_iface) >= 0);
1896
1897 object_path = pa_dbusiface_stream_get_path(stream_iface);
1898
1899 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1900 PA_DBUS_CORE_INTERFACE,
1901 signals[SIGNAL_NEW_PLAYBACK_STREAM].name)));
1902 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1903
1904 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1905 dbus_message_unref(signal_msg);
1906
1907 return PA_HOOK_OK;
1908 }
1909
sink_input_unlink_cb(void * hook_data,void * call_data,void * slot_data)1910 static pa_hook_result_t sink_input_unlink_cb(void *hook_data, void *call_data, void *slot_data) {
1911 pa_dbusiface_core *c = slot_data;
1912 pa_sink_input *sink_input = call_data;
1913 pa_dbusiface_stream *stream_iface;
1914 const char *object_path;
1915 DBusMessage *signal_msg;
1916
1917 pa_assert(c);
1918 pa_assert(sink_input);
1919
1920 pa_assert_se((stream_iface = pa_hashmap_remove(c->playback_streams, PA_UINT32_TO_PTR(sink_input->index))));
1921
1922 object_path = pa_dbusiface_stream_get_path(stream_iface);
1923
1924 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1925 PA_DBUS_CORE_INTERFACE,
1926 signals[SIGNAL_PLAYBACK_STREAM_REMOVED].name)));
1927 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1928
1929 pa_dbusiface_stream_free(stream_iface);
1930
1931 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1932 dbus_message_unref(signal_msg);
1933
1934 return PA_HOOK_OK;
1935 }
1936
source_output_put_cb(void * hook_data,void * call_data,void * slot_data)1937 static pa_hook_result_t source_output_put_cb(void *hook_data, void *call_data, void *slot_data) {
1938 pa_dbusiface_core *c = slot_data;
1939 pa_source_output *source_output = call_data;
1940 pa_dbusiface_stream *stream_iface;
1941 const char *object_path;
1942 DBusMessage *signal_msg;
1943
1944 pa_assert(c);
1945 pa_assert(source_output);
1946
1947 stream_iface = pa_dbusiface_stream_new_record(c, source_output);
1948 pa_assert_se(pa_hashmap_put(c->record_streams, PA_UINT32_TO_PTR(source_output->index), stream_iface) >= 0);
1949
1950 object_path = pa_dbusiface_stream_get_path(stream_iface);
1951
1952 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1953 PA_DBUS_CORE_INTERFACE,
1954 signals[SIGNAL_NEW_RECORD_STREAM].name)));
1955 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1956
1957 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1958 dbus_message_unref(signal_msg);
1959
1960 return PA_HOOK_OK;
1961 }
1962
source_output_unlink_cb(void * hook_data,void * call_data,void * slot_data)1963 static pa_hook_result_t source_output_unlink_cb(void *hook_data, void *call_data, void *slot_data) {
1964 pa_dbusiface_core *c = slot_data;
1965 pa_source_output *source_output = call_data;
1966 pa_dbusiface_stream *stream_iface;
1967 const char *object_path;
1968 DBusMessage *signal_msg;
1969
1970 pa_assert(c);
1971 pa_assert(source_output);
1972
1973 pa_assert_se((stream_iface = pa_hashmap_remove(c->record_streams, PA_UINT32_TO_PTR(source_output->index))));
1974
1975 object_path = pa_dbusiface_stream_get_path(stream_iface);
1976
1977 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
1978 PA_DBUS_CORE_INTERFACE,
1979 signals[SIGNAL_RECORD_STREAM_REMOVED].name)));
1980 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
1981
1982 pa_dbusiface_stream_free(stream_iface);
1983
1984 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
1985 dbus_message_unref(signal_msg);
1986
1987 return PA_HOOK_OK;
1988 }
1989
client_put_cb(void * hook_data,void * call_data,void * slot_data)1990 static pa_hook_result_t client_put_cb(void *hook_data, void *call_data, void *slot_data) {
1991 pa_dbusiface_core *c = slot_data;
1992 pa_client *client = call_data;
1993 pa_dbusiface_client *client_iface;
1994 const char *object_path;
1995 DBusMessage *signal_msg;
1996
1997 pa_assert(c);
1998 pa_assert(client);
1999
2000 client_iface = pa_dbusiface_client_new(c, client);
2001 pa_assert_se(pa_hashmap_put(c->clients, PA_UINT32_TO_PTR(client->index), client_iface) >= 0);
2002
2003 object_path = pa_dbusiface_client_get_path(client_iface);
2004
2005 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
2006 PA_DBUS_CORE_INTERFACE,
2007 signals[SIGNAL_NEW_CLIENT].name)));
2008 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
2009
2010 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
2011 dbus_message_unref(signal_msg);
2012
2013 return PA_HOOK_OK;
2014 }
2015
client_unlink_cb(void * hook_data,void * call_data,void * slot_data)2016 static pa_hook_result_t client_unlink_cb(void *hook_data, void *call_data, void *slot_data) {
2017 pa_dbusiface_core *c = slot_data;
2018 pa_client *client = call_data;
2019 pa_dbusiface_client *client_iface;
2020 const char *object_path;
2021 DBusMessage *signal_msg;
2022
2023 pa_assert(c);
2024 pa_assert(client);
2025
2026 pa_assert_se((client_iface = pa_hashmap_remove(c->clients, PA_UINT32_TO_PTR(client->index))));
2027
2028 object_path = pa_dbusiface_client_get_path(client_iface);
2029
2030 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
2031 PA_DBUS_CORE_INTERFACE,
2032 signals[SIGNAL_CLIENT_REMOVED].name)));
2033 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
2034
2035 pa_dbusiface_client_free(client_iface);
2036
2037 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
2038 dbus_message_unref(signal_msg);
2039
2040 return PA_HOOK_OK;
2041 }
2042
sink_put_cb(void * hook_data,void * call_data,void * slot_data)2043 static pa_hook_result_t sink_put_cb(void *hook_data, void *call_data, void *slot_data) {
2044 pa_dbusiface_core *c = slot_data;
2045 pa_sink *s = call_data;
2046
2047 pa_assert(c);
2048 pa_assert(s);
2049
2050 /* We may have alredy encountered this sink, because if the new sink was
2051 * chosen as the default sink, the default sink change hook was fired
2052 * first, and we saw the sink in default_sink_changed_cb(). */
2053 if (pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(s->index)))
2054 return PA_HOOK_OK;
2055
2056 create_dbus_object_for_sink(c, s);
2057
2058 return PA_HOOK_OK;
2059 }
2060
sink_unlink_cb(void * hook_data,void * call_data,void * slot_data)2061 static pa_hook_result_t sink_unlink_cb(void *hook_data, void *call_data, void *slot_data) {
2062 pa_dbusiface_core *c = slot_data;
2063 pa_sink *s = call_data;
2064 pa_dbusiface_device *d = NULL;
2065 const char *object_path = NULL;
2066 DBusMessage *signal_msg = NULL;
2067
2068 pa_assert(c);
2069 pa_assert(s);
2070
2071 pa_assert_se(d = pa_hashmap_remove(c->sinks_by_index, PA_UINT32_TO_PTR(s->index)));
2072 object_path = pa_dbusiface_device_get_path(d);
2073 pa_assert_se(pa_hashmap_remove(c->sinks_by_path, object_path));
2074
2075 pa_assert_se(signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
2076 PA_DBUS_CORE_INTERFACE,
2077 signals[SIGNAL_SINK_REMOVED].name));
2078 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
2079
2080 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
2081 dbus_message_unref(signal_msg);
2082
2083 pa_dbusiface_device_free(d);
2084
2085 return PA_HOOK_OK;
2086 }
2087
source_put_cb(void * hook_data,void * call_data,void * slot_data)2088 static pa_hook_result_t source_put_cb(void *hook_data, void *call_data, void *slot_data) {
2089 pa_dbusiface_core *c = slot_data;
2090 pa_source *s = call_data;
2091
2092 pa_assert(c);
2093 pa_assert(s);
2094
2095 /* We may have alredy encountered this source, because if the new source
2096 * was chosen as the default source, the default source change hook was
2097 * fired first, and we saw the source in default_source_changed_cb(). */
2098 if (pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(s->index)))
2099 return PA_HOOK_OK;
2100
2101 create_dbus_object_for_source(c, s);
2102
2103 return PA_HOOK_OK;
2104 }
2105
source_unlink_cb(void * hook_data,void * call_data,void * slot_data)2106 static pa_hook_result_t source_unlink_cb(void *hook_data, void *call_data, void *slot_data) {
2107 pa_dbusiface_core *c = slot_data;
2108 pa_source *s = call_data;
2109 pa_dbusiface_device *d = NULL;
2110 const char *object_path = NULL;
2111 DBusMessage *signal_msg = NULL;
2112
2113 pa_assert(c);
2114 pa_assert(s);
2115
2116 pa_assert_se(d = pa_hashmap_remove(c->sources_by_index, PA_UINT32_TO_PTR(s->index)));
2117 object_path = pa_dbusiface_device_get_path(d);
2118 pa_assert_se(pa_hashmap_remove(c->sources_by_path, object_path));
2119
2120 pa_assert_se(signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
2121 PA_DBUS_CORE_INTERFACE,
2122 signals[SIGNAL_SOURCE_REMOVED].name));
2123 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
2124
2125 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
2126 dbus_message_unref(signal_msg);
2127
2128 pa_dbusiface_device_free(d);
2129
2130 return PA_HOOK_OK;
2131 }
2132
extension_registered_cb(void * hook_data,void * call_data,void * slot_data)2133 static pa_hook_result_t extension_registered_cb(void *hook_data, void *call_data, void *slot_data) {
2134 pa_dbusiface_core *c = slot_data;
2135 const char *ext_name = call_data;
2136 DBusMessage *signal_msg = NULL;
2137
2138 pa_assert(c);
2139 pa_assert(ext_name);
2140
2141 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
2142 PA_DBUS_CORE_INTERFACE,
2143 signals[SIGNAL_NEW_EXTENSION].name)));
2144 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_STRING, &ext_name, DBUS_TYPE_INVALID));
2145
2146 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
2147 dbus_message_unref(signal_msg);
2148
2149 return PA_HOOK_OK;
2150 }
2151
extension_unregistered_cb(void * hook_data,void * call_data,void * slot_data)2152 static pa_hook_result_t extension_unregistered_cb(void *hook_data, void *call_data, void *slot_data) {
2153 pa_dbusiface_core *c = slot_data;
2154 const char *ext_name = call_data;
2155 DBusMessage *signal_msg = NULL;
2156
2157 pa_assert(c);
2158 pa_assert(ext_name);
2159
2160 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
2161 PA_DBUS_CORE_INTERFACE,
2162 signals[SIGNAL_EXTENSION_REMOVED].name)));
2163 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_STRING, &ext_name, DBUS_TYPE_INVALID));
2164
2165 pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
2166 dbus_message_unref(signal_msg);
2167
2168 return PA_HOOK_OK;
2169 }
2170
pa_dbusiface_core_new(pa_core * core)2171 pa_dbusiface_core *pa_dbusiface_core_new(pa_core *core) {
2172 pa_dbusiface_core *c;
2173 pa_card *card;
2174 pa_sink *sink;
2175 pa_source *source;
2176 pa_dbusiface_device *device;
2177 pa_sink_input *sink_input;
2178 pa_source_output *source_output;
2179 pa_scache_entry *sample;
2180 pa_module *module;
2181 pa_client *client;
2182 uint32_t idx;
2183
2184 pa_assert(core);
2185
2186 c = pa_xnew(pa_dbusiface_core, 1);
2187 c->core = core;
2188 c->dbus_protocol = pa_dbus_protocol_get(core);
2189 c->cards = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t) pa_dbusiface_card_free);
2190 c->sinks_by_index = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL,
2191 (pa_free_cb_t) pa_dbusiface_device_free);
2192 c->sinks_by_path = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2193 c->sources_by_index = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL,
2194 (pa_free_cb_t) pa_dbusiface_device_free);
2195 c->sources_by_path = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2196 c->playback_streams = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL,
2197 (pa_free_cb_t) pa_dbusiface_stream_free);
2198 c->record_streams = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL,
2199 (pa_free_cb_t) pa_dbusiface_stream_free);
2200 c->samples = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t) pa_dbusiface_sample_free);
2201 c->modules = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t) pa_dbusiface_module_free);
2202 c->clients = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t) pa_dbusiface_client_free);
2203 c->fallback_sink = core->default_sink;
2204 c->fallback_source = core->default_source;
2205 c->default_sink_changed_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_DEFAULT_SINK_CHANGED],
2206 PA_HOOK_NORMAL, default_sink_changed_cb, c);
2207 c->default_source_changed_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED],
2208 PA_HOOK_NORMAL, default_source_changed_cb, c);
2209 c->module_new_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_MODULE_NEW],
2210 PA_HOOK_NORMAL, module_new_cb, c);
2211 c->module_removed_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_MODULE_UNLINK],
2212 PA_HOOK_NORMAL, module_removed_cb, c);
2213 c->sample_cache_new_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SAMPLE_CACHE_NEW],
2214 PA_HOOK_NORMAL, sample_cache_new_cb, c);
2215 c->sample_cache_removed_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SAMPLE_CACHE_UNLINK],
2216 PA_HOOK_NORMAL, sample_cache_removed_cb, c);
2217 c->card_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_CARD_PUT],
2218 PA_HOOK_NORMAL, card_put_cb, c);
2219 c->card_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_CARD_UNLINK],
2220 PA_HOOK_NORMAL, card_unlink_cb, c);
2221 c->sink_input_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT],
2222 PA_HOOK_NORMAL, sink_input_put_cb, c);
2223 c->sink_input_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK],
2224 PA_HOOK_NORMAL, sink_input_unlink_cb, c);
2225 c->source_output_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT],
2226 PA_HOOK_NORMAL, source_output_put_cb, c);
2227 c->source_output_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK],
2228 PA_HOOK_NORMAL, source_output_unlink_cb, c);
2229 c->client_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_CLIENT_PUT],
2230 PA_HOOK_NORMAL, client_put_cb, c);
2231 c->client_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_CLIENT_UNLINK],
2232 PA_HOOK_NORMAL, client_unlink_cb, c);
2233 c->sink_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL, sink_put_cb, c);
2234 c->sink_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_NORMAL, sink_unlink_cb, c);
2235 c->source_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_NORMAL, source_put_cb, c);
2236 c->source_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_NORMAL, source_unlink_cb, c);
2237 c->extension_registered_slot = pa_dbus_protocol_hook_connect(c->dbus_protocol,
2238 PA_DBUS_PROTOCOL_HOOK_EXTENSION_REGISTERED,
2239 PA_HOOK_NORMAL,
2240 extension_registered_cb,
2241 c);
2242 c->extension_unregistered_slot = pa_dbus_protocol_hook_connect(c->dbus_protocol,
2243 PA_DBUS_PROTOCOL_HOOK_EXTENSION_UNREGISTERED,
2244 PA_HOOK_NORMAL,
2245 extension_unregistered_cb,
2246 c);
2247 c->memstats = pa_dbusiface_memstats_new(c, core);
2248
2249 if (c->fallback_sink)
2250 pa_sink_ref(c->fallback_sink);
2251 if (c->fallback_source)
2252 pa_source_ref(c->fallback_source);
2253
2254 PA_IDXSET_FOREACH(card, core->cards, idx)
2255 pa_hashmap_put(c->cards, PA_UINT32_TO_PTR(idx), pa_dbusiface_card_new(c, card));
2256
2257 PA_IDXSET_FOREACH(sink, core->sinks, idx) {
2258 device = pa_dbusiface_device_new_sink(c, sink);
2259 pa_hashmap_put(c->sinks_by_index, PA_UINT32_TO_PTR(idx), device);
2260 pa_hashmap_put(c->sinks_by_path, (char *) pa_dbusiface_device_get_path(device), device);
2261 }
2262
2263 PA_IDXSET_FOREACH(source, core->sources, idx) {
2264 device = pa_dbusiface_device_new_source(c, source);
2265 pa_hashmap_put(c->sources_by_index, PA_UINT32_TO_PTR(idx), device);
2266 pa_hashmap_put(c->sources_by_path, (char *) pa_dbusiface_device_get_path(device), device);
2267 }
2268
2269 PA_IDXSET_FOREACH(sink_input, core->sink_inputs, idx)
2270 pa_hashmap_put(c->playback_streams, PA_UINT32_TO_PTR(idx), pa_dbusiface_stream_new_playback(c, sink_input));
2271
2272 PA_IDXSET_FOREACH(source_output, core->source_outputs, idx)
2273 pa_hashmap_put(c->record_streams, PA_UINT32_TO_PTR(idx), pa_dbusiface_stream_new_record(c, source_output));
2274
2275 PA_IDXSET_FOREACH(sample, core->scache, idx)
2276 pa_hashmap_put(c->samples, PA_UINT32_TO_PTR(idx), pa_dbusiface_sample_new(c, sample));
2277
2278 PA_IDXSET_FOREACH(module, core->modules, idx)
2279 pa_hashmap_put(c->modules, PA_UINT32_TO_PTR(idx), pa_dbusiface_module_new(module));
2280
2281 PA_IDXSET_FOREACH(client, core->clients, idx)
2282 pa_hashmap_put(c->clients, PA_UINT32_TO_PTR(idx), pa_dbusiface_client_new(c, client));
2283
2284 pa_assert_se(pa_dbus_protocol_add_interface(c->dbus_protocol, PA_DBUS_CORE_OBJECT_PATH, &core_interface_info, c) >= 0);
2285
2286 return c;
2287 }
2288
pa_dbusiface_core_free(pa_dbusiface_core * c)2289 void pa_dbusiface_core_free(pa_dbusiface_core *c) {
2290 pa_assert(c);
2291
2292 pa_assert_se(pa_dbus_protocol_remove_interface(c->dbus_protocol, PA_DBUS_CORE_OBJECT_PATH, core_interface_info.name) >= 0);
2293
2294 /* Note that the order of freeing is important below.
2295 * Do not change it for the sake of tidiness without checking! */
2296 pa_hashmap_free(c->cards);
2297 pa_hashmap_free(c->sinks_by_path);
2298 pa_hashmap_free(c->sinks_by_index);
2299 pa_hashmap_free(c->sources_by_path);
2300 pa_hashmap_free(c->sources_by_index);
2301 pa_hashmap_free(c->playback_streams);
2302 pa_hashmap_free(c->record_streams);
2303 pa_hashmap_free(c->samples);
2304 pa_hashmap_free(c->modules);
2305 pa_hashmap_free(c->clients);
2306 pa_hook_slot_free(c->module_new_slot);
2307 pa_hook_slot_free(c->module_removed_slot);
2308 pa_hook_slot_free(c->default_sink_changed_slot);
2309 pa_hook_slot_free(c->default_source_changed_slot);
2310 pa_hook_slot_free(c->sample_cache_new_slot);
2311 pa_hook_slot_free(c->sample_cache_removed_slot);
2312 pa_hook_slot_free(c->card_put_slot);
2313 pa_hook_slot_free(c->card_unlink_slot);
2314 pa_hook_slot_free(c->sink_input_put_slot);
2315 pa_hook_slot_free(c->sink_input_unlink_slot);
2316 pa_hook_slot_free(c->source_output_put_slot);
2317 pa_hook_slot_free(c->source_output_unlink_slot);
2318 pa_hook_slot_free(c->client_put_slot);
2319 pa_hook_slot_free(c->client_unlink_slot);
2320 pa_hook_slot_free(c->sink_put_slot);
2321 pa_hook_slot_free(c->sink_unlink_slot);
2322 pa_hook_slot_free(c->source_put_slot);
2323 pa_hook_slot_free(c->source_unlink_slot);
2324 pa_hook_slot_free(c->extension_registered_slot);
2325 pa_hook_slot_free(c->extension_unregistered_slot);
2326 pa_dbusiface_memstats_free(c->memstats);
2327
2328 if (c->fallback_sink)
2329 pa_sink_unref(c->fallback_sink);
2330 if (c->fallback_source)
2331 pa_source_unref(c->fallback_source);
2332
2333 pa_dbus_protocol_unref(c->dbus_protocol);
2334
2335 pa_xfree(c);
2336 }
2337
pa_dbusiface_core_get_card_path(pa_dbusiface_core * c,const pa_card * card)2338 const char *pa_dbusiface_core_get_card_path(pa_dbusiface_core *c, const pa_card *card) {
2339 pa_assert(c);
2340 pa_assert(card);
2341
2342 return pa_dbusiface_card_get_path(pa_hashmap_get(c->cards, PA_UINT32_TO_PTR(card->index)));
2343 }
2344
pa_dbusiface_core_get_sink_path(pa_dbusiface_core * c,const pa_sink * sink)2345 const char *pa_dbusiface_core_get_sink_path(pa_dbusiface_core *c, const pa_sink *sink) {
2346 pa_assert(c);
2347 pa_assert(sink);
2348
2349 return pa_dbusiface_device_get_path(pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(sink->index)));
2350 }
2351
pa_dbusiface_core_get_source_path(pa_dbusiface_core * c,const pa_source * source)2352 const char *pa_dbusiface_core_get_source_path(pa_dbusiface_core *c, const pa_source *source) {
2353 pa_assert(c);
2354 pa_assert(source);
2355
2356 return pa_dbusiface_device_get_path(pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(source->index)));
2357 }
2358
pa_dbusiface_core_get_playback_stream_path(pa_dbusiface_core * c,const pa_sink_input * sink_input)2359 const char *pa_dbusiface_core_get_playback_stream_path(pa_dbusiface_core *c, const pa_sink_input *sink_input) {
2360 pa_assert(c);
2361 pa_assert(sink_input);
2362
2363 return pa_dbusiface_stream_get_path(pa_hashmap_get(c->playback_streams, PA_UINT32_TO_PTR(sink_input->index)));
2364 }
2365
pa_dbusiface_core_get_record_stream_path(pa_dbusiface_core * c,const pa_source_output * source_output)2366 const char *pa_dbusiface_core_get_record_stream_path(pa_dbusiface_core *c, const pa_source_output *source_output) {
2367 pa_assert(c);
2368 pa_assert(source_output);
2369
2370 return pa_dbusiface_stream_get_path(pa_hashmap_get(c->record_streams, PA_UINT32_TO_PTR(source_output->index)));
2371 }
2372
pa_dbusiface_core_get_module_path(pa_dbusiface_core * c,const pa_module * module)2373 const char *pa_dbusiface_core_get_module_path(pa_dbusiface_core *c, const pa_module *module) {
2374 pa_assert(c);
2375 pa_assert(module);
2376
2377 return pa_dbusiface_module_get_path(pa_hashmap_get(c->modules, PA_UINT32_TO_PTR(module->index)));
2378 }
2379
pa_dbusiface_core_get_client_path(pa_dbusiface_core * c,const pa_client * client)2380 const char *pa_dbusiface_core_get_client_path(pa_dbusiface_core *c, const pa_client *client) {
2381 pa_assert(c);
2382 pa_assert(client);
2383
2384 return pa_dbusiface_client_get_path(pa_hashmap_get(c->clients, PA_UINT32_TO_PTR(client->index)));
2385 }
2386
pa_dbusiface_core_get_sink(pa_dbusiface_core * c,const char * object_path)2387 pa_sink *pa_dbusiface_core_get_sink(pa_dbusiface_core *c, const char *object_path) {
2388 pa_dbusiface_device *device = NULL;
2389
2390 pa_assert(c);
2391 pa_assert(object_path);
2392
2393 device = pa_hashmap_get(c->sinks_by_path, object_path);
2394
2395 if (device)
2396 return pa_dbusiface_device_get_sink(device);
2397 else
2398 return NULL;
2399 }
2400
pa_dbusiface_core_get_source(pa_dbusiface_core * c,const char * object_path)2401 pa_source *pa_dbusiface_core_get_source(pa_dbusiface_core *c, const char *object_path) {
2402 pa_dbusiface_device *device = NULL;
2403
2404 pa_assert(c);
2405 pa_assert(object_path);
2406
2407 device = pa_hashmap_get(c->sources_by_path, object_path);
2408
2409 if (device)
2410 return pa_dbusiface_device_get_source(device);
2411 else
2412 return NULL;
2413 }
2414