• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, see <http://www.gnu.org/licenses/>.
19 ***/
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 
28 #include <pulse/rtclock.h>
29 #include <pulse/timeval.h>
30 #include <pulse/xmalloc.h>
31 
32 #include <pulsecore/native-common.h>
33 #include <pulsecore/llist.h>
34 #include <pulsecore/log.h>
35 #include <pulsecore/core-util.h>
36 #include <pulsecore/macro.h>
37 #include <pulsecore/refcnt.h>
38 #include <pulsecore/flist.h>
39 #include <pulsecore/core-rtclock.h>
40 
41 #include "pdispatch.h"
42 
43 #include "log/audio_log.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] = "KILL_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_PLAYBACK_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] = "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     /* Supported since protocol v27 (3.0) */
194     [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = "SET_PORT_LATENCY_OFFSET",
195 
196     /* Supported since protocol v30 (6.0) */
197     /* BOTH DIRECTIONS */
198     [PA_COMMAND_ENABLE_SRBCHANNEL] = "ENABLE_SRBCHANNEL",
199     [PA_COMMAND_DISABLE_SRBCHANNEL] = "DISABLE_SRBCHANNEL",
200 
201     /* Supported since protocol v31 (9.0) */
202     /* BOTH DIRECTIONS */
203     [PA_COMMAND_REGISTER_MEMFD_SHMID] = "REGISTER_MEMFD_SHMID",
204 
205     /* Supported since protocol v35 (15.0) */
206     [PA_COMMAND_SEND_OBJECT_MESSAGE] = "SEND_OBJECT_MESSAGE",
207 
208     [PA_COMMAND_UNDERFLOW_OHOS] = "UNDERFLOW_OHOS",
209 };
210 
211 #endif
212 
213 PA_STATIC_FLIST_DECLARE(reply_infos, 0, pa_xfree);
214 
215 struct reply_info {
216     pa_pdispatch *pdispatch;
217     PA_LLIST_FIELDS(struct reply_info);
218     pa_pdispatch_cb_t callback;
219     void *userdata;
220     pa_free_cb_t free_cb;
221     uint32_t tag;
222     pa_time_event *time_event;
223 };
224 
225 struct pa_pdispatch {
226     PA_REFCNT_DECLARE;
227     pa_mainloop_api *mainloop;
228     const pa_pdispatch_cb_t *callback_table;
229     unsigned n_commands;
230     PA_LLIST_HEAD(struct reply_info, replies);
231     pa_pdispatch_drain_cb_t drain_callback;
232     void *drain_userdata;
233     pa_cmsg_ancil_data *ancil_data;
234     bool use_rtclock;
235 };
236 
reply_info_free(struct reply_info * r)237 static void reply_info_free(struct reply_info *r) {
238     pa_assert(r);
239     pa_assert(r->pdispatch);
240     pa_assert(r->pdispatch->mainloop);
241 
242     if (r->time_event)
243         r->pdispatch->mainloop->time_free(r->time_event);
244 
245     PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r);
246 
247     if (pa_flist_push(PA_STATIC_FLIST_GET(reply_infos), r) < 0)
248         pa_xfree(r);
249 }
250 
pa_pdispatch_new(pa_mainloop_api * mainloop,bool use_rtclock,const pa_pdispatch_cb_t * table,unsigned entries)251 pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, bool use_rtclock, const pa_pdispatch_cb_t *table, unsigned entries) {
252     pa_pdispatch *pd;
253 
254     pa_assert(mainloop);
255     pa_assert((entries && table) || (!entries && !table));
256 
257     pd = pa_xnew0(pa_pdispatch, 1);
258     PA_REFCNT_INIT(pd);
259     pd->mainloop = mainloop;
260     pd->callback_table = table;
261     pd->n_commands = entries;
262     PA_LLIST_HEAD_INIT(struct reply_info, pd->replies);
263     pd->use_rtclock = use_rtclock;
264 
265     return pd;
266 }
267 
pdispatch_free(pa_pdispatch * pd)268 static void pdispatch_free(pa_pdispatch *pd) {
269     pa_assert(pd);
270 
271     while (pd->replies) {
272         if (pd->replies->free_cb)
273             pd->replies->free_cb(pd->replies->userdata);
274 
275         reply_info_free(pd->replies);
276     }
277 
278     pa_xfree(pd);
279 }
280 
run_action(pa_pdispatch * pd,struct reply_info * r,uint32_t command,pa_tagstruct * ts)281 static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) {
282     pa_pdispatch_cb_t callback;
283     void *userdata;
284     uint32_t tag;
285     pa_assert(r);
286 
287     pa_pdispatch_ref(pd);
288 
289     callback = r->callback;
290     userdata = r->userdata;
291     tag = r->tag;
292 
293     reply_info_free(r);
294 
295     callback(pd, command, tag, ts, userdata);
296 
297     if (pd->drain_callback && !pa_pdispatch_is_pending(pd))
298         pd->drain_callback(pd, pd->drain_userdata);
299 
300     pa_pdispatch_unref(pd);
301 }
302 
pa_pdispatch_run(pa_pdispatch * pd,pa_packet * packet,pa_cmsg_ancil_data * ancil_data,void * userdata)303 int pa_pdispatch_run(pa_pdispatch *pd, pa_packet *packet, pa_cmsg_ancil_data *ancil_data, void *userdata) {
304     uint32_t tag, command;
305     pa_tagstruct *ts = NULL;
306     int ret = -1;
307     const void *pdata;
308     size_t plen;
309 
310     pa_assert(pd);
311     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
312     pa_assert(packet);
313 
314     pa_pdispatch_ref(pd);
315 
316     pdata = pa_packet_data(packet, &plen);
317     if (plen <= 8)
318         goto finish;
319 
320     ts = pa_tagstruct_new_fixed(pdata, plen);
321 
322     if (pa_tagstruct_getu32(ts, &command) < 0 ||
323         pa_tagstruct_getu32(ts, &tag) < 0)
324         goto finish;
325 
326     char const *p = NULL;
327 #ifdef DEBUG_OPCODES
328 {
329     char t[256];
330 
331     if (command >= PA_COMMAND_MAX || !(p = command_names[command]))
332         pa_snprintf((char*) (p = t), sizeof(t), "%u", command);
333 
334     // pa_log("[%p] Received opcode <%s>", pd, p);
335 }
336 #endif
337     char oht[256] = {0};  // PA CMD 256bytes max
338     pa_snprintf(oht, sizeof(oht), "PA_RECV_CMD[%u] <%s>", command, p);
339     CallStart(oht);
340 
341     pd->ancil_data = ancil_data;
342 
343     if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) {
344         struct reply_info *r;
345 
346         PA_LLIST_FOREACH(r, pd->replies)
347             if (r->tag == tag)
348                 break;
349 
350         if (r)
351             run_action(pd, r, command, ts);
352 
353     } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) {
354         const pa_pdispatch_cb_t *cb = pd->callback_table+command;
355 
356         pa_usec_t startTime = pa_rtclock_now();
357         (*cb)(pd, command, tag, ts, userdata);
358         pa_usec_t executionTime = pa_rtclock_now() - startTime;
359         if (executionTime > OH_DAEMON_TIMEOUT_THRESHOLD_ON_US) {  // too long block of daemon thread, dangerous
360             AUDIO_WARNING_LOG("execution time of this command is too long: CMD[%{public}s] (%{public}" PRIu64 "ms)",
361                 p, executionTime / PA_USEC_PER_MSEC);
362         }
363     } else {
364         pa_log("Received unsupported command %u", command);
365         CallEnd();
366         goto finish;
367     }
368     CallEnd();
369 
370     ret = 0;
371 
372 finish:
373     pd->ancil_data = NULL;
374 
375     if (ts)
376         pa_tagstruct_free(ts);
377 
378     pa_pdispatch_unref(pd);
379 
380     return ret;
381 }
382 
timeout_callback(pa_mainloop_api * m,pa_time_event * e,const struct timeval * t,void * userdata)383 static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, const struct timeval *t, void *userdata) {
384     struct reply_info*r = userdata;
385 
386     pa_assert(r);
387     pa_assert(r->time_event == e);
388     pa_assert(r->pdispatch);
389     pa_assert(r->pdispatch->mainloop == m);
390     pa_assert(r->callback);
391 
392     run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL);
393 }
394 
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)395 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) {
396     struct reply_info *r;
397     struct timeval tv;
398 
399     pa_assert(pd);
400     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
401     pa_assert(cb);
402 
403     if (!(r = pa_flist_pop(PA_STATIC_FLIST_GET(reply_infos))))
404         r = pa_xnew(struct reply_info, 1);
405 
406     r->pdispatch = pd;
407     r->callback = cb;
408     r->userdata = userdata;
409     r->free_cb = free_cb;
410     r->tag = tag;
411 
412     pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop,
413                                                         pa_timeval_rtstore(&tv, pa_rtclock_now() + timeout * PA_USEC_PER_SEC, pd->use_rtclock),
414                                                         timeout_callback, r));
415 
416     PA_LLIST_PREPEND(struct reply_info, pd->replies, r);
417 }
418 
pa_pdispatch_is_pending(pa_pdispatch * pd)419 int pa_pdispatch_is_pending(pa_pdispatch *pd) {
420     pa_assert(pd);
421     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
422 
423     return !!pd->replies;
424 }
425 
pa_pdispatch_set_drain_callback(pa_pdispatch * pd,pa_pdispatch_drain_cb_t cb,void * userdata)426 void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_cb_t cb, void *userdata) {
427     pa_assert(pd);
428     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
429     pa_assert(!cb || pa_pdispatch_is_pending(pd));
430 
431     pd->drain_callback = cb;
432     pd->drain_userdata = userdata;
433 }
434 
pa_pdispatch_unregister_reply(pa_pdispatch * pd,void * userdata)435 void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) {
436     struct reply_info *r, *n;
437 
438     pa_assert(pd);
439     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
440 
441     PA_LLIST_FOREACH_SAFE(r, n, pd->replies)
442         if (r->userdata == userdata)
443             reply_info_free(r);
444 }
445 
pa_pdispatch_unref(pa_pdispatch * pd)446 void pa_pdispatch_unref(pa_pdispatch *pd) {
447     pa_assert(pd);
448     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
449 
450     if (PA_REFCNT_DEC(pd) <= 0)
451         pdispatch_free(pd);
452 }
453 
pa_pdispatch_ref(pa_pdispatch * pd)454 pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) {
455     pa_assert(pd);
456     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
457 
458     PA_REFCNT_INC(pd);
459     return pd;
460 }
461 
462 #ifdef HAVE_CREDS
463 
pa_pdispatch_creds(pa_pdispatch * pd)464 const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) {
465     pa_assert(pd);
466     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
467 
468     if (pd->ancil_data && pd->ancil_data->creds_valid)
469          return &pd->ancil_data->creds;
470     return NULL;
471 }
472 
473 /* Should be called only once during the dispatcher lifetime
474  *
475  * If the returned ancillary data contains any fds, caller maintains sole
476  * responsibility of closing them down using pa_cmsg_ancil_data_close_fds() */
pa_pdispatch_take_ancil_data(pa_pdispatch * pd)477 pa_cmsg_ancil_data *pa_pdispatch_take_ancil_data(pa_pdispatch *pd) {
478     pa_cmsg_ancil_data *ancil;
479 
480     pa_assert(pd);
481     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
482 
483     ancil = pd->ancil_data;
484 
485     /* iochannel guarantees us that nfd will always be capped */
486     if (ancil)
487         pa_assert(ancil->nfd <= MAX_ANCIL_DATA_FDS);
488 
489     pd->ancil_data = NULL;
490     return ancil;
491 }
492 
493 #endif
494