Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : : Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 : :
7 : : PulseAudio is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU Lesser General Public License as
9 : : published by the Free Software Foundation; either version 2.1 of the
10 : : License, or (at your option) any later version.
11 : :
12 : : PulseAudio is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : Lesser General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU Lesser General Public
18 : : License along with PulseAudio; if not, write to the Free Software
19 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 : : USA.
21 : : ***/
22 : :
23 : : #ifdef HAVE_CONFIG_H
24 : : #include <config.h>
25 : : #endif
26 : :
27 : : #include <stdio.h>
28 : : #include <stdlib.h>
29 : :
30 : : #include <pulse/rtclock.h>
31 : : #include <pulse/timeval.h>
32 : : #include <pulse/xmalloc.h>
33 : :
34 : : #include <pulsecore/native-common.h>
35 : : #include <pulsecore/llist.h>
36 : : #include <pulsecore/log.h>
37 : : #include <pulsecore/core-util.h>
38 : : #include <pulsecore/macro.h>
39 : : #include <pulsecore/refcnt.h>
40 : : #include <pulsecore/flist.h>
41 : : #include <pulsecore/core-rtclock.h>
42 : :
43 : : #include "pdispatch.h"
44 : :
45 : : /* #define DEBUG_OPCODES */
46 : :
47 : : #ifdef DEBUG_OPCODES
48 : :
49 : : static const char *command_names[PA_COMMAND_MAX] = {
50 : : /* Generic commands */
51 : : [PA_COMMAND_ERROR] = "ERROR",
52 : : [PA_COMMAND_TIMEOUT] = "TIMEOUT",
53 : : [PA_COMMAND_REPLY] = "REPLY",
54 : :
55 : : /* CLIENT->SERVER */
56 : : [PA_COMMAND_CREATE_PLAYBACK_STREAM] = "CREATE_PLAYBACK_STREAM",
57 : : [PA_COMMAND_DELETE_PLAYBACK_STREAM] = "DELETE_PLAYBACK_STREAM",
58 : : [PA_COMMAND_CREATE_RECORD_STREAM] = "CREATE_RECORD_STREAM",
59 : : [PA_COMMAND_DELETE_RECORD_STREAM] = "DELETE_RECORD_STREAM",
60 : : [PA_COMMAND_AUTH] = "AUTH",
61 : : [PA_COMMAND_EXIT] = "EXIT",
62 : : [PA_COMMAND_SET_CLIENT_NAME] = "SET_CLIENT_NAME",
63 : : [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK",
64 : : [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE",
65 : : [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM",
66 : : [PA_COMMAND_STAT] = "STAT",
67 : : [PA_COMMAND_GET_PLAYBACK_LATENCY] = "GET_PLAYBACK_LATENCY",
68 : : [PA_COMMAND_CREATE_UPLOAD_STREAM] = "CREATE_UPLOAD_STREAM",
69 : : [PA_COMMAND_DELETE_UPLOAD_STREAM] = "DELETE_UPLOAD_STREAM",
70 : : [PA_COMMAND_FINISH_UPLOAD_STREAM] = "FINISH_UPLOAD_STREAM",
71 : : [PA_COMMAND_PLAY_SAMPLE] = "PLAY_SAMPLE",
72 : : [PA_COMMAND_REMOVE_SAMPLE] = "REMOVE_SAMPLE",
73 : :
74 : : [PA_COMMAND_GET_SERVER_INFO] = "GET_SERVER_INFO",
75 : : [PA_COMMAND_GET_SINK_INFO] = "GET_SINK_INFO",
76 : : [PA_COMMAND_GET_SINK_INFO_LIST] = "GET_SINK_INFO_LIST",
77 : : [PA_COMMAND_GET_SOURCE_INFO] = "GET_SOURCE_INFO",
78 : : [PA_COMMAND_GET_SOURCE_INFO_LIST] = "GET_SOURCE_INFO_LIST",
79 : : [PA_COMMAND_GET_MODULE_INFO] = "GET_MODULE_INFO",
80 : : [PA_COMMAND_GET_MODULE_INFO_LIST] = "GET_MODULE_INFO_LIST",
81 : : [PA_COMMAND_GET_CLIENT_INFO] = "GET_CLIENT_INFO",
82 : : [PA_COMMAND_GET_CLIENT_INFO_LIST] = "GET_CLIENT_INFO_LIST",
83 : : [PA_COMMAND_GET_SAMPLE_INFO] = "GET_SAMPLE_INFO",
84 : : [PA_COMMAND_GET_SAMPLE_INFO_LIST] = "GET_SAMPLE_INFO_LIST",
85 : : [PA_COMMAND_GET_SINK_INPUT_INFO] = "GET_SINK_INPUT_INFO",
86 : : [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = "GET_SINK_INPUT_INFO_LIST",
87 : : [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = "GET_SOURCE_OUTPUT_INFO",
88 : : [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = "GET_SOURCE_OUTPUT_INFO_LIST",
89 : : [PA_COMMAND_SUBSCRIBE] = "SUBSCRIBE",
90 : :
91 : : [PA_COMMAND_SET_SINK_VOLUME] = "SET_SINK_VOLUME",
92 : : [PA_COMMAND_SET_SINK_INPUT_VOLUME] = "SET_SINK_INPUT_VOLUME",
93 : : [PA_COMMAND_SET_SOURCE_VOLUME] = "SET_SOURCE_VOLUME",
94 : :
95 : : [PA_COMMAND_SET_SINK_MUTE] = "SET_SINK_MUTE",
96 : : [PA_COMMAND_SET_SOURCE_MUTE] = "SET_SOURCE_MUTE",
97 : :
98 : : [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM",
99 : : [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM",
100 : : [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM",
101 : :
102 : : [PA_COMMAND_SET_DEFAULT_SINK] = "SET_DEFAULT_SINK",
103 : : [PA_COMMAND_SET_DEFAULT_SOURCE] = "SET_DEFAULT_SOURCE",
104 : :
105 : : [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = "SET_PLAYBACK_STREAM_NAME",
106 : : [PA_COMMAND_SET_RECORD_STREAM_NAME] = "SET_RECORD_STREAM_NAME",
107 : :
108 : : [PA_COMMAND_KILL_CLIENT] = "KILL_CLIENT",
109 : : [PA_COMMAND_KILL_SINK_INPUT] = "KILL_SINK_INPUT",
110 : : [PA_COMMAND_KILL_SOURCE_OUTPUT] = "SOURCE_OUTPUT",
111 : :
112 : : [PA_COMMAND_LOAD_MODULE] = "LOAD_MODULE",
113 : : [PA_COMMAND_UNLOAD_MODULE] = "UNLOAD_MODULE",
114 : :
115 : : [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = "ADD_AUTOLOAD (obsolete)",
116 : : [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = "REMOVE_AUTOLOAD (obsolete)",
117 : : [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = "GET_AUTOLOAD_INFO (obsolete)",
118 : : [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = "GET_AUTOLOAD_INFO_LIST (obsolete)",
119 : :
120 : : [PA_COMMAND_GET_RECORD_LATENCY] = "GET_RECORD_LATENCY",
121 : : [PA_COMMAND_CORK_RECORD_STREAM] = "CORK_RECORD_STREAM",
122 : : [PA_COMMAND_FLUSH_RECORD_STREAM] = "FLUSH_RECORD_STREAM",
123 : : [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = "PREBUF_PLAYBACK_STREAM",
124 : :
125 : : /* SERVER->CLIENT */
126 : : [PA_COMMAND_REQUEST] = "REQUEST",
127 : : [PA_COMMAND_OVERFLOW] = "OVERFLOW",
128 : : [PA_COMMAND_UNDERFLOW] = "UNDERFLOW",
129 : : [PA_COMMAND_PLAYBACK_STREAM_KILLED] = "PLAYBACK_STREAM_KILLED",
130 : : [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED",
131 : : [PA_COMMAND_SUBSCRIBE_EVENT] = "SUBSCRIBE_EVENT",
132 : :
133 : : /* A few more client->server commands */
134 : :
135 : : /* Supported since protocol v10 (0.9.5) */
136 : : [PA_COMMAND_MOVE_SINK_INPUT] = "MOVE_SINK_INPUT",
137 : : [PA_COMMAND_MOVE_SOURCE_OUTPUT] = "MOVE_SOURCE_OUTPUT",
138 : :
139 : : /* Supported since protocol v11 (0.9.7) */
140 : : [PA_COMMAND_SET_SINK_INPUT_MUTE] = "SET_SINK_INPUT_MUTE",
141 : :
142 : : [PA_COMMAND_SUSPEND_SINK] = "SUSPEND_SINK",
143 : : [PA_COMMAND_SUSPEND_SOURCE] = "SUSPEND_SOURCE",
144 : :
145 : : /* Supported since protocol v12 (0.9.8) */
146 : : [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = "SET_PLAYBACK_STREAM_BUFFER_ATTR",
147 : : [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = "SET_RECORD_STREAM_BUFFER_ATTR",
148 : :
149 : : [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = "UPDATE_PLAYBACK_STREAM_SAMPLE_RATE",
150 : : [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = "UPDATE_RECORD_STREAM_SAMPLE_RATE",
151 : :
152 : : /* SERVER->CLIENT */
153 : : [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = "PLAYBACK_STREAM_SUSPENDED",
154 : : [PA_COMMAND_RECORD_STREAM_SUSPENDED] = "RECORD_STREAM_SUSPENDED",
155 : : [PA_COMMAND_PLAYBACK_STREAM_MOVED] = "PLAYBACK_STREAM_MOVED",
156 : : [PA_COMMAND_RECORD_STREAM_MOVED] = "RECORD_STREAM_MOVED",
157 : :
158 : : /* Supported since protocol v13 (0.9.11) */
159 : : [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = "UPDATE_RECORD_STREAM_PROPLIST",
160 : : [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = "UPDATE_RECORD_STREAM_PROPLIST",
161 : : [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = "UPDATE_CLIENT_PROPLIST",
162 : : [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = "REMOVE_RECORD_STREAM_PROPLIST",
163 : : [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = "REMOVE_PLAYBACK_STREAM_PROPLIST",
164 : : [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = "REMOVE_CLIENT_PROPLIST",
165 : :
166 : : /* SERVER->CLIENT */
167 : : [PA_COMMAND_STARTED] = "STARTED",
168 : :
169 : : /* Supported since protocol v14 (0.9.12) */
170 : : [PA_COMMAND_EXTENSION] = "EXTENSION",
171 : :
172 : : /* Supported since protocol v15 (0.9.15) */
173 : : [PA_COMMAND_GET_CARD_INFO] = "GET_CARD_INFO",
174 : : [PA_COMMAND_GET_CARD_INFO_LIST] = "GET_CARD_INFO_LIST",
175 : : [PA_COMMAND_SET_CARD_PROFILE] = "SET_CARD_PROFILE",
176 : :
177 : : [PA_COMMAND_CLIENT_EVENT] = "GET_CLIENT_EVENT",
178 : : [PA_COMMAND_PLAYBACK_STREAM_EVENT] = "PLAYBACK_STREAM_EVENT",
179 : : [PA_COMMAND_RECORD_STREAM_EVENT] = "RECORD_STREAM_EVENT",
180 : :
181 : : /* SERVER->CLIENT */
182 : : [PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = "PLAYBACK_BUFFER_ATTR_CHANGED",
183 : : [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = "RECORD_BUFFER_ATTR_CHANGED",
184 : :
185 : : /* Supported since protocol v16 (0.9.16) */
186 : : [PA_COMMAND_SET_SINK_PORT] = "SET_SINK_PORT",
187 : : [PA_COMMAND_SET_SOURCE_PORT] = "SET_SOURCE_PORT",
188 : :
189 : : /* Supported since protocol v22 (1.0) */
190 : : [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = "SET_SOURCE_OUTPUT_VOLUME",
191 : : [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = "SET_SOURCE_OUTPUT_MUTE",
192 : :
193 : : };
194 : :
195 : : #endif
196 : :
197 [ - + ][ # # ]: 27 : PA_STATIC_FLIST_DECLARE(reply_infos, 0, pa_xfree);
198 : :
199 : : struct reply_info {
200 : : pa_pdispatch *pdispatch;
201 : : PA_LLIST_FIELDS(struct reply_info);
202 : : pa_pdispatch_cb_t callback;
203 : : void *userdata;
204 : : pa_free_cb_t free_cb;
205 : : uint32_t tag;
206 : : pa_time_event *time_event;
207 : : };
208 : :
209 : : struct pa_pdispatch {
210 : : PA_REFCNT_DECLARE;
211 : : pa_mainloop_api *mainloop;
212 : : const pa_pdispatch_cb_t *callback_table;
213 : : unsigned n_commands;
214 : : PA_LLIST_HEAD(struct reply_info, replies);
215 : : pa_pdispatch_drain_cb_t drain_callback;
216 : : void *drain_userdata;
217 : : const pa_creds *creds;
218 : : pa_bool_t use_rtclock;
219 : : };
220 : :
221 : 0 : static void reply_info_free(struct reply_info *r) {
222 [ # # ]: 0 : pa_assert(r);
223 [ # # ]: 0 : pa_assert(r->pdispatch);
224 [ # # ]: 0 : pa_assert(r->pdispatch->mainloop);
225 : :
226 [ # # ]: 0 : if (r->time_event)
227 : 0 : r->pdispatch->mainloop->time_free(r->time_event);
228 : :
229 [ # # ][ # # ]: 0 : PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r);
[ # # ][ # # ]
230 : :
231 [ # # ]: 0 : if (pa_flist_push(PA_STATIC_FLIST_GET(reply_infos), r) < 0)
232 : 0 : pa_xfree(r);
233 : 0 : }
234 : :
235 : 0 : pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, pa_bool_t use_rtclock, const pa_pdispatch_cb_t *table, unsigned entries) {
236 : : pa_pdispatch *pd;
237 : :
238 [ # # ]: 0 : pa_assert(mainloop);
239 [ # # ][ # # ]: 0 : pa_assert((entries && table) || (!entries && !table));
240 : :
241 : 0 : pd = pa_xnew0(pa_pdispatch, 1);
242 : 0 : PA_REFCNT_INIT(pd);
243 : 0 : pd->mainloop = mainloop;
244 : 0 : pd->callback_table = table;
245 : 0 : pd->n_commands = entries;
246 : 0 : PA_LLIST_HEAD_INIT(struct reply_info, pd->replies);
247 : 0 : pd->use_rtclock = use_rtclock;
248 : :
249 : 0 : return pd;
250 : : }
251 : :
252 : : static void pdispatch_free(pa_pdispatch *pd) {
253 [ # # ]: 0 : pa_assert(pd);
254 : :
255 [ # # ]: 0 : while (pd->replies) {
256 [ # # ]: 0 : if (pd->replies->free_cb)
257 : 0 : pd->replies->free_cb(pd->replies->userdata);
258 : :
259 : 0 : reply_info_free(pd->replies);
260 : : }
261 : :
262 : 0 : pa_xfree(pd);
263 : : }
264 : :
265 : 0 : static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) {
266 : : pa_pdispatch_cb_t callback;
267 : : void *userdata;
268 : : uint32_t tag;
269 [ # # ]: 0 : pa_assert(r);
270 : :
271 : 0 : pa_pdispatch_ref(pd);
272 : :
273 : 0 : callback = r->callback;
274 : 0 : userdata = r->userdata;
275 : 0 : tag = r->tag;
276 : :
277 : 0 : reply_info_free(r);
278 : :
279 : 0 : callback(pd, command, tag, ts, userdata);
280 : :
281 [ # # ][ # # ]: 0 : if (pd->drain_callback && !pa_pdispatch_is_pending(pd))
282 : 0 : pd->drain_callback(pd, pd->drain_userdata);
283 : :
284 : 0 : pa_pdispatch_unref(pd);
285 : 0 : }
286 : :
287 : 0 : int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, void *userdata) {
288 : : uint32_t tag, command;
289 : 0 : pa_tagstruct *ts = NULL;
290 : 0 : int ret = -1;
291 : :
292 [ # # ]: 0 : pa_assert(pd);
293 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(pd) >= 1);
294 [ # # ]: 0 : pa_assert(packet);
295 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(packet) >= 1);
296 [ # # ]: 0 : pa_assert(packet->data);
297 : :
298 : 0 : pa_pdispatch_ref(pd);
299 : :
300 [ # # ]: 0 : if (packet->length <= 8)
301 : : goto finish;
302 : :
303 : 0 : ts = pa_tagstruct_new(packet->data, packet->length);
304 : :
305 [ # # # # ]: 0 : if (pa_tagstruct_getu32(ts, &command) < 0 ||
306 : 0 : pa_tagstruct_getu32(ts, &tag) < 0)
307 : : goto finish;
308 : :
309 : : #ifdef DEBUG_OPCODES
310 : : {
311 : : char t[256];
312 : : char const *p = NULL;
313 : :
314 : : if (command >= PA_COMMAND_MAX || !(p = command_names[command]))
315 : : pa_snprintf((char*) (p = t), sizeof(t), "%u", command);
316 : :
317 : : pa_log("[%p] Received opcode <%s>", pd, p);
318 : : }
319 : : #endif
320 : :
321 : 0 : pd->creds = creds;
322 : :
323 [ # # ]: 0 : if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) {
324 : : struct reply_info *r;
325 : :
326 [ # # ]: 0 : PA_LLIST_FOREACH(r, pd->replies)
327 [ # # ]: 0 : if (r->tag == tag)
328 : : break;
329 : :
330 [ # # ]: 0 : if (r)
331 : 0 : run_action(pd, r, command, ts);
332 : :
333 [ # # ][ # # ]: 0 : } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) {
[ # # ]
334 : 0 : const pa_pdispatch_cb_t *cb = pd->callback_table+command;
335 : :
336 : 0 : (*cb)(pd, command, tag, ts, userdata);
337 : : } else {
338 : 0 : pa_log("Received unsupported command %u", command);
339 : 0 : goto finish;
340 : : }
341 : :
342 : : ret = 0;
343 : :
344 : : finish:
345 : 0 : pd->creds = NULL;
346 : :
347 [ # # ]: 0 : if (ts)
348 : 0 : pa_tagstruct_free(ts);
349 : :
350 : 0 : pa_pdispatch_unref(pd);
351 : :
352 : 0 : return ret;
353 : : }
354 : :
355 : 0 : static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, const struct timeval *t, void *userdata) {
356 : 0 : struct reply_info*r = userdata;
357 : :
358 [ # # ]: 0 : pa_assert(r);
359 [ # # ]: 0 : pa_assert(r->time_event == e);
360 [ # # ]: 0 : pa_assert(r->pdispatch);
361 [ # # ]: 0 : pa_assert(r->pdispatch->mainloop == m);
362 [ # # ]: 0 : pa_assert(r->callback);
363 : :
364 : 0 : run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL);
365 : 0 : }
366 : :
367 : 0 : void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t cb, void *userdata, pa_free_cb_t free_cb) {
368 : : struct reply_info *r;
369 : : struct timeval tv;
370 : :
371 [ # # ]: 0 : pa_assert(pd);
372 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(pd) >= 1);
373 [ # # ]: 0 : pa_assert(cb);
374 : :
375 [ # # ]: 0 : if (!(r = pa_flist_pop(PA_STATIC_FLIST_GET(reply_infos))))
376 : 0 : r = pa_xnew(struct reply_info, 1);
377 : :
378 : 0 : r->pdispatch = pd;
379 : 0 : r->callback = cb;
380 : 0 : r->userdata = userdata;
381 : 0 : r->free_cb = free_cb;
382 : 0 : r->tag = tag;
383 : :
384 [ # # ]: 0 : pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop,
385 : : pa_timeval_rtstore(&tv, pa_rtclock_now() + timeout * PA_USEC_PER_SEC, pd->use_rtclock),
386 : : timeout_callback, r));
387 : :
388 [ # # ][ # # ]: 0 : PA_LLIST_PREPEND(struct reply_info, pd->replies, r);
389 : 0 : }
390 : :
391 : 0 : int pa_pdispatch_is_pending(pa_pdispatch *pd) {
392 [ # # ]: 0 : pa_assert(pd);
393 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(pd) >= 1);
394 : :
395 : 0 : return !!pd->replies;
396 : : }
397 : :
398 : 0 : void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_cb_t cb, void *userdata) {
399 [ # # ]: 0 : pa_assert(pd);
400 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(pd) >= 1);
401 [ # # ][ # # ]: 0 : pa_assert(!cb || pa_pdispatch_is_pending(pd));
402 : :
403 : 0 : pd->drain_callback = cb;
404 : 0 : pd->drain_userdata = userdata;
405 : 0 : }
406 : :
407 : 0 : void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) {
408 : : struct reply_info *r, *n;
409 : :
410 [ # # ]: 0 : pa_assert(pd);
411 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(pd) >= 1);
412 : :
413 [ # # ]: 0 : PA_LLIST_FOREACH_SAFE(r, n, pd->replies)
414 [ # # ]: 0 : if (r->userdata == userdata)
415 : 0 : reply_info_free(r);
416 : 0 : }
417 : :
418 : 0 : void pa_pdispatch_unref(pa_pdispatch *pd) {
419 [ # # ]: 0 : pa_assert(pd);
420 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(pd) >= 1);
421 : :
422 [ # # ]: 0 : if (PA_REFCNT_DEC(pd) <= 0)
423 : : pdispatch_free(pd);
424 : 0 : }
425 : :
426 : 0 : pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) {
427 [ # # ]: 0 : pa_assert(pd);
428 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(pd) >= 1);
429 : :
430 : 0 : PA_REFCNT_INC(pd);
431 : 0 : return pd;
432 : : }
433 : :
434 : 0 : const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) {
435 [ # # ]: 0 : pa_assert(pd);
436 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(pd) >= 1);
437 : :
438 : 0 : return pd->creds;
439 : : }
|