]> code.delx.au - pulseaudio/blob - src/pulsecore/pdispatch.c
core: add missing SET_PORT_LATENCY_OFFSET to dispatcher opcode string table
[pulseaudio] / 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, 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] = "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
197 #endif
198
199 PA_STATIC_FLIST_DECLARE(reply_infos, 0, pa_xfree);
200
201 struct reply_info {
202 pa_pdispatch *pdispatch;
203 PA_LLIST_FIELDS(struct reply_info);
204 pa_pdispatch_cb_t callback;
205 void *userdata;
206 pa_free_cb_t free_cb;
207 uint32_t tag;
208 pa_time_event *time_event;
209 };
210
211 struct pa_pdispatch {
212 PA_REFCNT_DECLARE;
213 pa_mainloop_api *mainloop;
214 const pa_pdispatch_cb_t *callback_table;
215 unsigned n_commands;
216 PA_LLIST_HEAD(struct reply_info, replies);
217 pa_pdispatch_drain_cb_t drain_callback;
218 void *drain_userdata;
219 const pa_creds *creds;
220 bool use_rtclock;
221 };
222
223 static void reply_info_free(struct reply_info *r) {
224 pa_assert(r);
225 pa_assert(r->pdispatch);
226 pa_assert(r->pdispatch->mainloop);
227
228 if (r->time_event)
229 r->pdispatch->mainloop->time_free(r->time_event);
230
231 PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r);
232
233 if (pa_flist_push(PA_STATIC_FLIST_GET(reply_infos), r) < 0)
234 pa_xfree(r);
235 }
236
237 pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, bool use_rtclock, const pa_pdispatch_cb_t *table, unsigned entries) {
238 pa_pdispatch *pd;
239
240 pa_assert(mainloop);
241 pa_assert((entries && table) || (!entries && !table));
242
243 pd = pa_xnew0(pa_pdispatch, 1);
244 PA_REFCNT_INIT(pd);
245 pd->mainloop = mainloop;
246 pd->callback_table = table;
247 pd->n_commands = entries;
248 PA_LLIST_HEAD_INIT(struct reply_info, pd->replies);
249 pd->use_rtclock = use_rtclock;
250
251 return pd;
252 }
253
254 static void pdispatch_free(pa_pdispatch *pd) {
255 pa_assert(pd);
256
257 while (pd->replies) {
258 if (pd->replies->free_cb)
259 pd->replies->free_cb(pd->replies->userdata);
260
261 reply_info_free(pd->replies);
262 }
263
264 pa_xfree(pd);
265 }
266
267 static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) {
268 pa_pdispatch_cb_t callback;
269 void *userdata;
270 uint32_t tag;
271 pa_assert(r);
272
273 pa_pdispatch_ref(pd);
274
275 callback = r->callback;
276 userdata = r->userdata;
277 tag = r->tag;
278
279 reply_info_free(r);
280
281 callback(pd, command, tag, ts, userdata);
282
283 if (pd->drain_callback && !pa_pdispatch_is_pending(pd))
284 pd->drain_callback(pd, pd->drain_userdata);
285
286 pa_pdispatch_unref(pd);
287 }
288
289 int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, void *userdata) {
290 uint32_t tag, command;
291 pa_tagstruct *ts = NULL;
292 int ret = -1;
293
294 pa_assert(pd);
295 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
296 pa_assert(packet);
297 pa_assert(PA_REFCNT_VALUE(packet) >= 1);
298 pa_assert(packet->data);
299
300 pa_pdispatch_ref(pd);
301
302 if (packet->length <= 8)
303 goto finish;
304
305 ts = pa_tagstruct_new(packet->data, packet->length);
306
307 if (pa_tagstruct_getu32(ts, &command) < 0 ||
308 pa_tagstruct_getu32(ts, &tag) < 0)
309 goto finish;
310
311 #ifdef DEBUG_OPCODES
312 {
313 char t[256];
314 char const *p = NULL;
315
316 if (command >= PA_COMMAND_MAX || !(p = command_names[command]))
317 pa_snprintf((char*) (p = t), sizeof(t), "%u", command);
318
319 pa_log("[%p] Received opcode <%s>", pd, p);
320 }
321 #endif
322
323 pd->creds = creds;
324
325 if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) {
326 struct reply_info *r;
327
328 PA_LLIST_FOREACH(r, pd->replies)
329 if (r->tag == tag)
330 break;
331
332 if (r)
333 run_action(pd, r, command, ts);
334
335 } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) {
336 const pa_pdispatch_cb_t *cb = pd->callback_table+command;
337
338 (*cb)(pd, command, tag, ts, userdata);
339 } else {
340 pa_log("Received unsupported command %u", command);
341 goto finish;
342 }
343
344 ret = 0;
345
346 finish:
347 pd->creds = NULL;
348
349 if (ts)
350 pa_tagstruct_free(ts);
351
352 pa_pdispatch_unref(pd);
353
354 return ret;
355 }
356
357 static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, const struct timeval *t, void *userdata) {
358 struct reply_info*r = userdata;
359
360 pa_assert(r);
361 pa_assert(r->time_event == e);
362 pa_assert(r->pdispatch);
363 pa_assert(r->pdispatch->mainloop == m);
364 pa_assert(r->callback);
365
366 run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL);
367 }
368
369 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) {
370 struct reply_info *r;
371 struct timeval tv;
372
373 pa_assert(pd);
374 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
375 pa_assert(cb);
376
377 if (!(r = pa_flist_pop(PA_STATIC_FLIST_GET(reply_infos))))
378 r = pa_xnew(struct reply_info, 1);
379
380 r->pdispatch = pd;
381 r->callback = cb;
382 r->userdata = userdata;
383 r->free_cb = free_cb;
384 r->tag = tag;
385
386 pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop,
387 pa_timeval_rtstore(&tv, pa_rtclock_now() + timeout * PA_USEC_PER_SEC, pd->use_rtclock),
388 timeout_callback, r));
389
390 PA_LLIST_PREPEND(struct reply_info, pd->replies, r);
391 }
392
393 int pa_pdispatch_is_pending(pa_pdispatch *pd) {
394 pa_assert(pd);
395 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
396
397 return !!pd->replies;
398 }
399
400 void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_cb_t cb, void *userdata) {
401 pa_assert(pd);
402 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
403 pa_assert(!cb || pa_pdispatch_is_pending(pd));
404
405 pd->drain_callback = cb;
406 pd->drain_userdata = userdata;
407 }
408
409 void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) {
410 struct reply_info *r, *n;
411
412 pa_assert(pd);
413 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
414
415 PA_LLIST_FOREACH_SAFE(r, n, pd->replies)
416 if (r->userdata == userdata)
417 reply_info_free(r);
418 }
419
420 void pa_pdispatch_unref(pa_pdispatch *pd) {
421 pa_assert(pd);
422 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
423
424 if (PA_REFCNT_DEC(pd) <= 0)
425 pdispatch_free(pd);
426 }
427
428 pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) {
429 pa_assert(pd);
430 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
431
432 PA_REFCNT_INC(pd);
433 return pd;
434 }
435
436 const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) {
437 pa_assert(pd);
438 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
439
440 return pd->creds;
441 }