Add default-monitor-time-sec
[platform/upstream/pulseaudio.git] / src / pulsecore / pdispatch.c
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 /* #define DEBUG_OPCODES */
44
45 #ifdef DEBUG_OPCODES
46
47 static const char *command_names[PA_COMMAND_MAX] = {
48     /* Generic commands */
49     [PA_COMMAND_ERROR] = "ERROR",
50     [PA_COMMAND_TIMEOUT] = "TIMEOUT",
51     [PA_COMMAND_REPLY] = "REPLY",
52
53     /* CLIENT->SERVER */
54     [PA_COMMAND_CREATE_PLAYBACK_STREAM] = "CREATE_PLAYBACK_STREAM",
55     [PA_COMMAND_DELETE_PLAYBACK_STREAM] = "DELETE_PLAYBACK_STREAM",
56     [PA_COMMAND_CREATE_RECORD_STREAM] = "CREATE_RECORD_STREAM",
57     [PA_COMMAND_DELETE_RECORD_STREAM] = "DELETE_RECORD_STREAM",
58     [PA_COMMAND_AUTH] = "AUTH",
59     [PA_COMMAND_EXIT] = "EXIT",
60     [PA_COMMAND_SET_CLIENT_NAME] = "SET_CLIENT_NAME",
61     [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK",
62     [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE",
63     [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM",
64     [PA_COMMAND_STAT] = "STAT",
65     [PA_COMMAND_GET_PLAYBACK_LATENCY] = "GET_PLAYBACK_LATENCY",
66     [PA_COMMAND_CREATE_UPLOAD_STREAM] = "CREATE_UPLOAD_STREAM",
67     [PA_COMMAND_DELETE_UPLOAD_STREAM] = "DELETE_UPLOAD_STREAM",
68     [PA_COMMAND_FINISH_UPLOAD_STREAM] = "FINISH_UPLOAD_STREAM",
69     [PA_COMMAND_PLAY_SAMPLE] = "PLAY_SAMPLE",
70     [PA_COMMAND_REMOVE_SAMPLE] = "REMOVE_SAMPLE",
71
72     [PA_COMMAND_GET_SERVER_INFO] = "GET_SERVER_INFO",
73     [PA_COMMAND_GET_SINK_INFO] = "GET_SINK_INFO",
74     [PA_COMMAND_GET_SINK_INFO_LIST] = "GET_SINK_INFO_LIST",
75     [PA_COMMAND_GET_SOURCE_INFO] = "GET_SOURCE_INFO",
76     [PA_COMMAND_GET_SOURCE_INFO_LIST] = "GET_SOURCE_INFO_LIST",
77     [PA_COMMAND_GET_MODULE_INFO] = "GET_MODULE_INFO",
78     [PA_COMMAND_GET_MODULE_INFO_LIST] = "GET_MODULE_INFO_LIST",
79     [PA_COMMAND_GET_CLIENT_INFO] = "GET_CLIENT_INFO",
80     [PA_COMMAND_GET_CLIENT_INFO_LIST] = "GET_CLIENT_INFO_LIST",
81     [PA_COMMAND_GET_SAMPLE_INFO] = "GET_SAMPLE_INFO",
82     [PA_COMMAND_GET_SAMPLE_INFO_LIST] = "GET_SAMPLE_INFO_LIST",
83     [PA_COMMAND_GET_SINK_INPUT_INFO] = "GET_SINK_INPUT_INFO",
84     [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = "GET_SINK_INPUT_INFO_LIST",
85     [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = "GET_SOURCE_OUTPUT_INFO",
86     [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = "GET_SOURCE_OUTPUT_INFO_LIST",
87     [PA_COMMAND_SUBSCRIBE] = "SUBSCRIBE",
88
89     [PA_COMMAND_SET_SINK_VOLUME] = "SET_SINK_VOLUME",
90     [PA_COMMAND_SET_SINK_INPUT_VOLUME] = "SET_SINK_INPUT_VOLUME",
91     [PA_COMMAND_SET_SOURCE_VOLUME] = "SET_SOURCE_VOLUME",
92
93     [PA_COMMAND_SET_SINK_MUTE] = "SET_SINK_MUTE",
94     [PA_COMMAND_SET_SOURCE_MUTE] = "SET_SOURCE_MUTE",
95
96     [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM",
97     [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM",
98     [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM",
99
100     [PA_COMMAND_SET_DEFAULT_SINK] = "SET_DEFAULT_SINK",
101     [PA_COMMAND_SET_DEFAULT_SOURCE] = "SET_DEFAULT_SOURCE",
102
103     [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = "SET_PLAYBACK_STREAM_NAME",
104     [PA_COMMAND_SET_RECORD_STREAM_NAME] = "SET_RECORD_STREAM_NAME",
105
106     [PA_COMMAND_KILL_CLIENT] = "KILL_CLIENT",
107     [PA_COMMAND_KILL_SINK_INPUT] = "KILL_SINK_INPUT",
108     [PA_COMMAND_KILL_SOURCE_OUTPUT] = "KILL_SOURCE_OUTPUT",
109
110     [PA_COMMAND_LOAD_MODULE] = "LOAD_MODULE",
111     [PA_COMMAND_UNLOAD_MODULE] = "UNLOAD_MODULE",
112
113     [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = "ADD_AUTOLOAD (obsolete)",
114     [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = "REMOVE_AUTOLOAD (obsolete)",
115     [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = "GET_AUTOLOAD_INFO (obsolete)",
116     [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = "GET_AUTOLOAD_INFO_LIST (obsolete)",
117
118     [PA_COMMAND_GET_RECORD_LATENCY] = "GET_RECORD_LATENCY",
119     [PA_COMMAND_CORK_RECORD_STREAM] = "CORK_RECORD_STREAM",
120     [PA_COMMAND_FLUSH_RECORD_STREAM] = "FLUSH_RECORD_STREAM",
121     [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = "PREBUF_PLAYBACK_STREAM",
122
123     /* SERVER->CLIENT */
124     [PA_COMMAND_REQUEST] = "REQUEST",
125     [PA_COMMAND_OVERFLOW] = "OVERFLOW",
126     [PA_COMMAND_UNDERFLOW] = "UNDERFLOW",
127     [PA_COMMAND_PLAYBACK_STREAM_KILLED] = "PLAYBACK_STREAM_KILLED",
128     [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED",
129     [PA_COMMAND_SUBSCRIBE_EVENT] = "SUBSCRIBE_EVENT",
130
131     /* A few more client->server commands */
132
133     /* Supported since protocol v10 (0.9.5) */
134     [PA_COMMAND_MOVE_SINK_INPUT] = "MOVE_SINK_INPUT",
135     [PA_COMMAND_MOVE_SOURCE_OUTPUT] = "MOVE_SOURCE_OUTPUT",
136
137     /* Supported since protocol v11 (0.9.7) */
138     [PA_COMMAND_SET_SINK_INPUT_MUTE] = "SET_SINK_INPUT_MUTE",
139
140     [PA_COMMAND_SUSPEND_SINK] = "SUSPEND_SINK",
141     [PA_COMMAND_SUSPEND_SOURCE] = "SUSPEND_SOURCE",
142
143     /* Supported since protocol v12 (0.9.8) */
144     [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = "SET_PLAYBACK_STREAM_BUFFER_ATTR",
145     [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = "SET_RECORD_STREAM_BUFFER_ATTR",
146
147     [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = "UPDATE_PLAYBACK_STREAM_SAMPLE_RATE",
148     [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = "UPDATE_RECORD_STREAM_SAMPLE_RATE",
149
150     /* SERVER->CLIENT */
151     [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = "PLAYBACK_STREAM_SUSPENDED",
152     [PA_COMMAND_RECORD_STREAM_SUSPENDED] = "RECORD_STREAM_SUSPENDED",
153     [PA_COMMAND_PLAYBACK_STREAM_MOVED] = "PLAYBACK_STREAM_MOVED",
154     [PA_COMMAND_RECORD_STREAM_MOVED] = "RECORD_STREAM_MOVED",
155
156     /* Supported since protocol v13 (0.9.11) */
157     [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = "UPDATE_RECORD_STREAM_PROPLIST",
158     [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = "UPDATE_PLAYBACK_STREAM_PROPLIST",
159     [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = "UPDATE_CLIENT_PROPLIST",
160     [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = "REMOVE_RECORD_STREAM_PROPLIST",
161     [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = "REMOVE_PLAYBACK_STREAM_PROPLIST",
162     [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = "REMOVE_CLIENT_PROPLIST",
163
164     /* SERVER->CLIENT */
165     [PA_COMMAND_STARTED] = "STARTED",
166
167     /* Supported since protocol v14 (0.9.12) */
168     [PA_COMMAND_EXTENSION] = "EXTENSION",
169
170     /* Supported since protocol v15 (0.9.15) */
171     [PA_COMMAND_GET_CARD_INFO] = "GET_CARD_INFO",
172     [PA_COMMAND_GET_CARD_INFO_LIST] = "GET_CARD_INFO_LIST",
173     [PA_COMMAND_SET_CARD_PROFILE] = "SET_CARD_PROFILE",
174
175     [PA_COMMAND_CLIENT_EVENT] = "CLIENT_EVENT",
176     [PA_COMMAND_PLAYBACK_STREAM_EVENT] = "PLAYBACK_STREAM_EVENT",
177     [PA_COMMAND_RECORD_STREAM_EVENT] = "RECORD_STREAM_EVENT",
178
179     /* SERVER->CLIENT */
180     [PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = "PLAYBACK_BUFFER_ATTR_CHANGED",
181     [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = "RECORD_BUFFER_ATTR_CHANGED",
182
183     /* Supported since protocol v16 (0.9.16) */
184     [PA_COMMAND_SET_SINK_PORT] = "SET_SINK_PORT",
185     [PA_COMMAND_SET_SOURCE_PORT] = "SET_SOURCE_PORT",
186
187     /* Supported since protocol v22 (1.0) */
188     [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = "SET_SOURCE_OUTPUT_VOLUME",
189     [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = "SET_SOURCE_OUTPUT_MUTE",
190
191     /* Supported since protocol v27 (3.0) */
192     [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = "SET_PORT_LATENCY_OFFSET",
193
194     /* Supported since protocol v30 (6.0) */
195     /* BOTH DIRECTIONS */
196     [PA_COMMAND_ENABLE_SRBCHANNEL] = "ENABLE_SRBCHANNEL",
197     [PA_COMMAND_DISABLE_SRBCHANNEL] = "DISABLE_SRBCHANNEL",
198
199     /* Supported since protocol v31 (9.0) */
200     /* BOTH DIRECTIONS */
201     [PA_COMMAND_REGISTER_MEMFD_SHMID] = "REGISTER_MEMFD_SHMID",
202
203     /* Supported since protocol v35 (15.0) */
204     [PA_COMMAND_SEND_OBJECT_MESSAGE] = "SEND_OBJECT_MESSAGE",
205 };
206
207 #endif
208
209 PA_STATIC_FLIST_DECLARE(reply_infos, 0, pa_xfree);
210
211 struct reply_info {
212     pa_pdispatch *pdispatch;
213     PA_LLIST_FIELDS(struct reply_info);
214     pa_pdispatch_cb_t callback;
215     void *userdata;
216     pa_free_cb_t free_cb;
217     uint32_t tag;
218     pa_time_event *time_event;
219 };
220
221 struct pa_pdispatch {
222     PA_REFCNT_DECLARE;
223     pa_mainloop_api *mainloop;
224     const pa_pdispatch_cb_t *callback_table;
225     unsigned n_commands;
226     PA_LLIST_HEAD(struct reply_info, replies);
227     pa_pdispatch_drain_cb_t drain_callback;
228     void *drain_userdata;
229     pa_cmsg_ancil_data *ancil_data;
230     bool use_rtclock;
231 };
232
233 static void reply_info_free(struct reply_info *r) {
234     pa_assert(r);
235     pa_assert(r->pdispatch);
236     pa_assert(r->pdispatch->mainloop);
237
238     if (r->time_event)
239         r->pdispatch->mainloop->time_free(r->time_event);
240
241     PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r);
242
243     if (pa_flist_push(PA_STATIC_FLIST_GET(reply_infos), r) < 0)
244         pa_xfree(r);
245 }
246
247 pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, bool use_rtclock, const pa_pdispatch_cb_t *table, unsigned entries) {
248     pa_pdispatch *pd;
249
250     pa_assert(mainloop);
251     pa_assert((entries && table) || (!entries && !table));
252
253     pd = pa_xnew0(pa_pdispatch, 1);
254     PA_REFCNT_INIT(pd);
255     pd->mainloop = mainloop;
256     pd->callback_table = table;
257     pd->n_commands = entries;
258     PA_LLIST_HEAD_INIT(struct reply_info, pd->replies);
259     pd->use_rtclock = use_rtclock;
260
261     return pd;
262 }
263
264 static void pdispatch_free(pa_pdispatch *pd) {
265     pa_assert(pd);
266
267     while (pd->replies) {
268         if (pd->replies->free_cb)
269             pd->replies->free_cb(pd->replies->userdata);
270
271         reply_info_free(pd->replies);
272     }
273
274     pa_xfree(pd);
275 }
276
277 static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) {
278     pa_pdispatch_cb_t callback;
279     void *userdata;
280     uint32_t tag;
281     pa_assert(r);
282
283     pa_pdispatch_ref(pd);
284
285     callback = r->callback;
286     userdata = r->userdata;
287     tag = r->tag;
288
289     reply_info_free(r);
290
291     callback(pd, command, tag, ts, userdata);
292
293     if (pd->drain_callback && !pa_pdispatch_is_pending(pd))
294         pd->drain_callback(pd, pd->drain_userdata);
295
296     pa_pdispatch_unref(pd);
297 }
298
299 int pa_pdispatch_run(pa_pdispatch *pd, pa_packet *packet, pa_cmsg_ancil_data *ancil_data, void *userdata) {
300     uint32_t tag, command;
301     pa_tagstruct *ts = NULL;
302     int ret = -1;
303     const void *pdata;
304     size_t plen;
305
306     pa_assert(pd);
307     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
308     pa_assert(packet);
309
310     pa_pdispatch_ref(pd);
311
312     pdata = pa_packet_data(packet, &plen);
313     if (plen <= 8)
314         goto finish;
315
316     ts = pa_tagstruct_new_fixed(pdata, plen);
317
318     if (pa_tagstruct_getu32(ts, &command) < 0 ||
319         pa_tagstruct_getu32(ts, &tag) < 0)
320         goto finish;
321
322 #ifdef DEBUG_OPCODES
323 {
324     char t[256];
325     char const *p = NULL;
326
327     if (command >= PA_COMMAND_MAX || !(p = command_names[command]))
328         pa_snprintf((char*) (p = t), sizeof(t), "%u", command);
329
330     pa_log("[%p] Received opcode <%s>", pd, p);
331 }
332 #endif
333
334     pd->ancil_data = ancil_data;
335
336     if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) {
337         struct reply_info *r;
338
339         PA_LLIST_FOREACH(r, pd->replies)
340             if (r->tag == tag)
341                 break;
342
343         if (r)
344             run_action(pd, r, command, ts);
345
346     } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) {
347         const pa_pdispatch_cb_t *cb = pd->callback_table+command;
348
349         (*cb)(pd, command, tag, ts, userdata);
350     } else {
351         pa_log("Received unsupported command %u", command);
352         goto finish;
353     }
354
355     ret = 0;
356
357 finish:
358     pd->ancil_data = NULL;
359
360     if (ts)
361         pa_tagstruct_free(ts);
362
363     pa_pdispatch_unref(pd);
364
365     return ret;
366 }
367
368 static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, const struct timeval *t, void *userdata) {
369     struct reply_info*r = userdata;
370
371     pa_assert(r);
372     pa_assert(r->time_event == e);
373     pa_assert(r->pdispatch);
374     pa_assert(r->pdispatch->mainloop == m);
375     pa_assert(r->callback);
376
377     run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL);
378 }
379
380 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) {
381     struct reply_info *r;
382     struct timeval tv;
383
384     pa_assert(pd);
385     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
386     pa_assert(cb);
387
388     if (!(r = pa_flist_pop(PA_STATIC_FLIST_GET(reply_infos))))
389         r = pa_xnew(struct reply_info, 1);
390
391     r->pdispatch = pd;
392     r->callback = cb;
393     r->userdata = userdata;
394     r->free_cb = free_cb;
395     r->tag = tag;
396
397     pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop,
398                                                         pa_timeval_rtstore(&tv, pa_rtclock_now() + timeout * PA_USEC_PER_SEC, pd->use_rtclock),
399                                                         timeout_callback, r));
400
401     PA_LLIST_PREPEND(struct reply_info, pd->replies, r);
402 }
403
404 int pa_pdispatch_is_pending(pa_pdispatch *pd) {
405     pa_assert(pd);
406     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
407
408     return !!pd->replies;
409 }
410
411 void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_cb_t cb, void *userdata) {
412     pa_assert(pd);
413     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
414     pa_assert(!cb || pa_pdispatch_is_pending(pd));
415
416     pd->drain_callback = cb;
417     pd->drain_userdata = userdata;
418 }
419
420 void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) {
421     struct reply_info *r, *n;
422
423     pa_assert(pd);
424     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
425
426     PA_LLIST_FOREACH_SAFE(r, n, pd->replies)
427         if (r->userdata == userdata)
428             reply_info_free(r);
429 }
430
431 void pa_pdispatch_unref(pa_pdispatch *pd) {
432     pa_assert(pd);
433     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
434
435     if (PA_REFCNT_DEC(pd) <= 0)
436         pdispatch_free(pd);
437 }
438
439 pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) {
440     pa_assert(pd);
441     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
442
443     PA_REFCNT_INC(pd);
444     return pd;
445 }
446
447 #ifdef HAVE_CREDS
448
449 const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) {
450     pa_assert(pd);
451     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
452
453     if (pd->ancil_data && pd->ancil_data->creds_valid)
454          return &pd->ancil_data->creds;
455     return NULL;
456 }
457
458 /* Should be called only once during the dispatcher lifetime
459  *
460  * If the returned ancillary data contains any fds, caller maintains sole
461  * responsibility of closing them down using pa_cmsg_ancil_data_close_fds() */
462 pa_cmsg_ancil_data *pa_pdispatch_take_ancil_data(pa_pdispatch *pd) {
463     pa_cmsg_ancil_data *ancil;
464
465     pa_assert(pd);
466     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
467
468     ancil = pd->ancil_data;
469
470     /* iochannel guarantees us that nfd will always be capped */
471     if (ancil)
472         pa_assert(ancil->nfd <= MAX_ANCIL_DATA_FDS);
473
474     pd->ancil_data = NULL;
475     return ancil;
476 }
477
478 #endif