]> code.delx.au - pulseaudio/blob - src/pulsecore/protocol-native.c
fix packet formatting for a few commands
[pulseaudio] / src / pulsecore / protocol-native.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
13
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33
34 #include <pulse/timeval.h>
35 #include <pulse/version.h>
36 #include <pulse/utf8.h>
37 #include <pulse/util.h>
38 #include <pulse/xmalloc.h>
39
40 #include <pulsecore/native-common.h>
41 #include <pulsecore/packet.h>
42 #include <pulsecore/client.h>
43 #include <pulsecore/source-output.h>
44 #include <pulsecore/sink-input.h>
45 #include <pulsecore/pstream.h>
46 #include <pulsecore/tagstruct.h>
47 #include <pulsecore/pdispatch.h>
48 #include <pulsecore/pstream-util.h>
49 #include <pulsecore/authkey.h>
50 #include <pulsecore/namereg.h>
51 #include <pulsecore/core-scache.h>
52 #include <pulsecore/core-subscribe.h>
53 #include <pulsecore/log.h>
54 #include <pulsecore/autoload.h>
55 #include <pulsecore/authkey-prop.h>
56 #include <pulsecore/strlist.h>
57 #include <pulsecore/props.h>
58 #include <pulsecore/sample-util.h>
59 #include <pulsecore/llist.h>
60 #include <pulsecore/creds.h>
61 #include <pulsecore/core-util.h>
62 #include <pulsecore/ipacl.h>
63 #include <pulsecore/thread-mq.h>
64
65 #include "protocol-native.h"
66
67 /* Kick a client if it doesn't authenticate within this time */
68 #define AUTH_TIMEOUT 60
69
70 /* Don't accept more connection than this */
71 #define MAX_CONNECTIONS 64
72
73 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
74 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
75 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
76
77 typedef struct connection connection;
78 struct pa_protocol_native;
79
80 typedef struct record_stream {
81 pa_msgobject parent;
82
83 connection *connection;
84 uint32_t index;
85
86 pa_source_output *source_output;
87 pa_memblockq *memblockq;
88 size_t fragment_size;
89 pa_usec_t source_latency;
90 } record_stream;
91
92 typedef struct output_stream {
93 pa_msgobject parent;
94 } output_stream;
95
96 typedef struct playback_stream {
97 output_stream parent;
98
99 connection *connection;
100 uint32_t index;
101
102 pa_sink_input *sink_input;
103 pa_memblockq *memblockq;
104 pa_bool_t drain_request;
105 uint32_t drain_tag;
106 uint32_t syncid;
107 pa_bool_t underrun;
108
109 pa_atomic_t missing;
110 size_t minreq;
111 pa_usec_t sink_latency;
112
113 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
114 int64_t read_index, write_index;
115 size_t render_memblockq_length;
116 } playback_stream;
117
118 typedef struct upload_stream {
119 output_stream parent;
120
121 connection *connection;
122 uint32_t index;
123
124 pa_memchunk memchunk;
125 size_t length;
126 char *name;
127 pa_sample_spec sample_spec;
128 pa_channel_map channel_map;
129 pa_proplist *proplist;
130 } upload_stream;
131
132 struct connection {
133 pa_msgobject parent;
134
135 pa_bool_t authorized;
136 uint32_t version;
137 pa_protocol_native *protocol;
138 pa_client *client;
139 pa_pstream *pstream;
140 pa_pdispatch *pdispatch;
141 pa_idxset *record_streams, *output_streams;
142 uint32_t rrobin_index;
143 pa_subscription *subscription;
144 pa_time_event *auth_timeout_event;
145 };
146
147 PA_DECLARE_CLASS(record_stream);
148 #define RECORD_STREAM(o) (record_stream_cast(o))
149 static PA_DEFINE_CHECK_TYPE(record_stream, pa_msgobject);
150
151 PA_DECLARE_CLASS(output_stream);
152 #define OUTPUT_STREAM(o) (output_stream_cast(o))
153 static PA_DEFINE_CHECK_TYPE(output_stream, pa_msgobject);
154
155 PA_DECLARE_CLASS(playback_stream);
156 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
157 static PA_DEFINE_CHECK_TYPE(playback_stream, output_stream);
158
159 PA_DECLARE_CLASS(upload_stream);
160 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
161 static PA_DEFINE_CHECK_TYPE(upload_stream, output_stream);
162
163 PA_DECLARE_CLASS(connection);
164 #define CONNECTION(o) (connection_cast(o))
165 static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
166
167 struct pa_protocol_native {
168 pa_module *module;
169 pa_core *core;
170 pa_bool_t public;
171 pa_socket_server *server;
172 pa_idxset *connections;
173 uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
174 pa_bool_t auth_cookie_in_property;
175 #ifdef HAVE_CREDS
176 char *auth_group;
177 #endif
178 pa_ip_acl *auth_ip_acl;
179 };
180
181 enum {
182 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
183 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
184 SINK_INPUT_MESSAGE_FLUSH,
185 SINK_INPUT_MESSAGE_TRIGGER,
186 SINK_INPUT_MESSAGE_SEEK,
187 SINK_INPUT_MESSAGE_PREBUF_FORCE,
188 SINK_INPUT_MESSAGE_UPDATE_LATENCY
189 };
190
191 enum {
192 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
193 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
194 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
195 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
196 };
197
198 enum {
199 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
200 };
201
202 enum {
203 CONNECTION_MESSAGE_RELEASE,
204 CONNECTION_MESSAGE_REVOKE
205 };
206
207 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
208 static void sink_input_kill_cb(pa_sink_input *i);
209 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
210 static void sink_input_moved_cb(pa_sink_input *i);
211
212 static void send_memblock(connection *c);
213 static void request_bytes(struct playback_stream*s);
214
215 static void source_output_kill_cb(pa_source_output *o);
216 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
217 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend);
218 static void source_output_moved_cb(pa_source_output *o);
219 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
220
221 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
222
223 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
224 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
225 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
226 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
227 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
228 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
229 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
230 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
231 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
232 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
233 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
234 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
235 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
236 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
237 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
238 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
239 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
240 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
241 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
242 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
243 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
244 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
245 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
246 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
247 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
248 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
249 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
250 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
251 static void command_add_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
252 static void command_remove_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
253 static void command_get_autoload_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
254 static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
255 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
256 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
257 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
258 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
259 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
260 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
261 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
262 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
263
264 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
265 [PA_COMMAND_ERROR] = NULL,
266 [PA_COMMAND_TIMEOUT] = NULL,
267 [PA_COMMAND_REPLY] = NULL,
268 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
269 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
270 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
271 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
272 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
273 [PA_COMMAND_AUTH] = command_auth,
274 [PA_COMMAND_REQUEST] = NULL,
275 [PA_COMMAND_EXIT] = command_exit,
276 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
277 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
278 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
279 [PA_COMMAND_STAT] = command_stat,
280 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
281 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
282 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
283 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
284 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
285 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
286 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
287 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
288 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
289 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
290 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
291 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
292 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
293 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
294 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
295 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
296 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
297 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
298 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
299 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
300 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
301 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
302 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
303
304 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
305 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
306 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
307
308 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
309 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
310 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
311
312 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
313 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
314
315 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
316 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
317 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
318 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
319
320 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
321 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
322
323 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
324 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
325 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
326 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
327 [PA_COMMAND_KILL_CLIENT] = command_kill,
328 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
329 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
330 [PA_COMMAND_LOAD_MODULE] = command_load_module,
331 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
332 [PA_COMMAND_GET_AUTOLOAD_INFO] = command_get_autoload_info,
333 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = command_get_autoload_info_list,
334 [PA_COMMAND_ADD_AUTOLOAD] = command_add_autoload,
335 [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload,
336
337 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
338 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
339
340 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
341 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
342
343 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
344 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
345
346 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
347 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
348 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
349
350 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
351 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
352 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
353 };
354
355 /* structure management */
356
357 static void upload_stream_unlink(upload_stream *s) {
358 pa_assert(s);
359
360 if (!s->connection)
361 return;
362
363 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
364 s->connection = NULL;
365 upload_stream_unref(s);
366 }
367
368 static void upload_stream_free(pa_object *o) {
369 upload_stream *s = UPLOAD_STREAM(o);
370 pa_assert(s);
371
372 upload_stream_unlink(s);
373
374 pa_xfree(s->name);
375
376 if (s->proplist)
377 pa_proplist_free(s->proplist);
378
379 if (s->memchunk.memblock)
380 pa_memblock_unref(s->memchunk.memblock);
381
382 pa_xfree(s);
383 }
384
385 static upload_stream* upload_stream_new(
386 connection *c,
387 const pa_sample_spec *ss,
388 const pa_channel_map *map,
389 const char *name,
390 size_t length,
391 pa_proplist *p) {
392
393 upload_stream *s;
394
395 pa_assert(c);
396 pa_assert(ss);
397 pa_assert(name);
398 pa_assert(length > 0);
399 pa_assert(p);
400
401 s = pa_msgobject_new(upload_stream);
402 s->parent.parent.parent.free = upload_stream_free;
403 s->connection = c;
404 s->sample_spec = *ss;
405 s->channel_map = *map;
406 s->name = pa_xstrdup(name);
407 pa_memchunk_reset(&s->memchunk);
408 s->length = length;
409 s->proplist = pa_proplist_copy(p);
410 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
411
412 pa_idxset_put(c->output_streams, s, &s->index);
413
414 return s;
415 }
416
417 static void record_stream_unlink(record_stream *s) {
418 pa_assert(s);
419
420 if (!s->connection)
421 return;
422
423 if (s->source_output) {
424 pa_source_output_unlink(s->source_output);
425 pa_source_output_unref(s->source_output);
426 s->source_output = NULL;
427 }
428
429 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
430 s->connection = NULL;
431 record_stream_unref(s);
432 }
433
434 static void record_stream_free(pa_object *o) {
435 record_stream *s = RECORD_STREAM(o);
436 pa_assert(s);
437
438 record_stream_unlink(s);
439
440 pa_memblockq_free(s->memblockq);
441 pa_xfree(s);
442 }
443
444 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
445 record_stream *s = RECORD_STREAM(o);
446 record_stream_assert_ref(s);
447
448 if (!s->connection)
449 return -1;
450
451 switch (code) {
452
453 case RECORD_STREAM_MESSAGE_POST_DATA:
454
455 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
456 /* pa_log_warn("Failed to push data into output queue."); */
457 return -1;
458 }
459
460 if (!pa_pstream_is_pending(s->connection->pstream))
461 send_memblock(s->connection);
462
463 break;
464 }
465
466 return 0;
467 }
468
469 static record_stream* record_stream_new(
470 connection *c,
471 pa_source *source,
472 pa_sample_spec *ss,
473 pa_channel_map *map,
474 const char *name,
475 uint32_t *maxlength,
476 uint32_t *fragsize,
477 pa_source_output_flags_t flags,
478 pa_proplist *p,
479 pa_bool_t adjust_latency) {
480
481 record_stream *s;
482 pa_source_output *source_output;
483 size_t base;
484 pa_source_output_new_data data;
485
486 pa_assert(c);
487 pa_assert(ss);
488 pa_assert(name);
489 pa_assert(maxlength);
490 pa_assert(p);
491
492 pa_source_output_new_data_init(&data);
493
494 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
495 pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
496 data.driver = __FILE__;
497 data.module = c->protocol->module;
498 data.client = c->client;
499 data.source = source;
500 pa_source_output_new_data_set_sample_spec(&data, ss);
501 pa_source_output_new_data_set_channel_map(&data, map);
502
503 source_output = pa_source_output_new(c->protocol->core, &data, flags);
504
505 pa_source_output_new_data_done(&data);
506
507 if (!source_output)
508 return NULL;
509
510 s = pa_msgobject_new(record_stream);
511 s->parent.parent.free = record_stream_free;
512 s->parent.process_msg = record_stream_process_msg;
513 s->connection = c;
514 s->source_output = source_output;
515
516 s->source_output->push = source_output_push_cb;
517 s->source_output->kill = source_output_kill_cb;
518 s->source_output->get_latency = source_output_get_latency_cb;
519 s->source_output->moved = source_output_moved_cb;
520 s->source_output->suspend = source_output_suspend_cb;
521 s->source_output->userdata = s;
522
523 if (*maxlength <= 0 || *maxlength > MAX_MEMBLOCKQ_LENGTH)
524 *maxlength = MAX_MEMBLOCKQ_LENGTH;
525 if (*fragsize <= 0)
526 *fragsize = pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*1000, &source_output->sample_spec);
527
528 if (adjust_latency) {
529 pa_usec_t fragsize_usec;
530
531 /* So, the user asked us to adjust the latency according to
532 * the what the source can provide. Half the latency will be
533 * spent on the hw buffer, half of it in the async buffer
534 * queue we maintain for each client. */
535
536 fragsize_usec = pa_bytes_to_usec(*fragsize, &source_output->sample_spec);
537
538 s->source_latency = pa_source_output_set_requested_latency(source_output, fragsize_usec/2);
539
540 if (fragsize_usec >= s->source_latency*2)
541 fragsize_usec -= s->source_latency;
542 else
543 fragsize_usec = s->source_latency;
544
545 *fragsize = pa_usec_to_bytes(fragsize_usec, &source_output->sample_spec);
546 }
547
548 s->memblockq = pa_memblockq_new(
549 0,
550 *maxlength,
551 0,
552 base = pa_frame_size(&source_output->sample_spec),
553 1,
554 0,
555 0,
556 NULL);
557
558 *maxlength = pa_memblockq_get_maxlength(s->memblockq);
559
560 s->fragment_size = (*fragsize/base)*base;
561 if (s->fragment_size <= 0)
562 s->fragment_size = base;
563
564 if (s->fragment_size > *maxlength)
565 s->fragment_size = *maxlength;
566
567 *fragsize = s->fragment_size;
568
569 *ss = s->source_output->sample_spec;
570 *map = s->source_output->channel_map;
571
572 pa_idxset_put(c->record_streams, s, &s->index);
573
574 pa_source_output_put(s->source_output);
575 return s;
576 }
577
578 static void playback_stream_unlink(playback_stream *s) {
579 pa_assert(s);
580
581 if (!s->connection)
582 return;
583
584 if (s->sink_input) {
585 pa_sink_input_unlink(s->sink_input);
586 pa_sink_input_unref(s->sink_input);
587 s->sink_input = NULL;
588 }
589
590 if (s->drain_request)
591 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
592
593 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
594 s->connection = NULL;
595 playback_stream_unref(s);
596 }
597
598 static void playback_stream_free(pa_object* o) {
599 playback_stream *s = PLAYBACK_STREAM(o);
600 pa_assert(s);
601
602 playback_stream_unlink(s);
603
604 pa_memblockq_free(s->memblockq);
605 pa_xfree(s);
606 }
607
608 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
609 playback_stream *s = PLAYBACK_STREAM(o);
610 playback_stream_assert_ref(s);
611
612 if (!s->connection)
613 return -1;
614
615 switch (code) {
616 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
617 pa_tagstruct *t;
618 uint32_t l = 0;
619
620 for (;;) {
621 int32_t k;
622
623 if ((k = pa_atomic_load(&s->missing)) <= 0)
624 break;
625
626 l += k;
627
628 if (l < s->minreq)
629 break;
630
631 if (pa_atomic_sub(&s->missing, k) <= k)
632 break;
633 }
634
635 if (l < s->minreq)
636 break;
637
638 t = pa_tagstruct_new(NULL, 0);
639 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
640 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
641 pa_tagstruct_putu32(t, s->index);
642 pa_tagstruct_putu32(t, l);
643 pa_pstream_send_tagstruct(s->connection->pstream, t);
644
645 /* pa_log("Requesting %u bytes", l); */
646 break;
647 }
648
649 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
650 pa_tagstruct *t;
651
652 /* Report that we're empty */
653 t = pa_tagstruct_new(NULL, 0);
654 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
655 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
656 pa_tagstruct_putu32(t, s->index);
657 pa_pstream_send_tagstruct(s->connection->pstream, t);
658 break;
659 }
660
661 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
662 pa_tagstruct *t;
663
664 /* Notify the user we're overflowed*/
665 t = pa_tagstruct_new(NULL, 0);
666 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
667 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
668 pa_tagstruct_putu32(t, s->index);
669 pa_pstream_send_tagstruct(s->connection->pstream, t);
670 break;
671 }
672
673 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
674 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
675 break;
676
677 }
678
679 return 0;
680 }
681
682 static playback_stream* playback_stream_new(
683 connection *c,
684 pa_sink *sink,
685 pa_sample_spec *ss,
686 pa_channel_map *map,
687 const char *name,
688 uint32_t *maxlength,
689 uint32_t *tlength,
690 uint32_t *prebuf,
691 uint32_t *minreq,
692 pa_cvolume *volume,
693 pa_bool_t muted,
694 uint32_t syncid,
695 uint32_t *missing,
696 pa_sink_input_flags_t flags,
697 pa_proplist *p,
698 pa_bool_t adjust_latency) {
699
700 playback_stream *s, *ssync;
701 pa_sink_input *sink_input;
702 pa_memblock *silence;
703 uint32_t idx;
704 int64_t start_index;
705 pa_sink_input_new_data data;
706
707 pa_assert(c);
708 pa_assert(ss);
709 pa_assert(name);
710 pa_assert(maxlength);
711 pa_assert(tlength);
712 pa_assert(prebuf);
713 pa_assert(minreq);
714 pa_assert(volume);
715 pa_assert(missing);
716 pa_assert(p);
717
718 /* Find syncid group */
719 for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) {
720
721 if (!playback_stream_isinstance(ssync))
722 continue;
723
724 if (ssync->syncid == syncid)
725 break;
726 }
727
728 /* Synced streams must connect to the same sink */
729 if (ssync) {
730
731 if (!sink)
732 sink = ssync->sink_input->sink;
733 else if (sink != ssync->sink_input->sink)
734 return NULL;
735 }
736
737 pa_sink_input_new_data_init(&data);
738
739 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
740 pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
741 data.driver = __FILE__;
742 data.module = c->protocol->module;
743 data.client = c->client;
744 data.sink = sink;
745 pa_sink_input_new_data_set_sample_spec(&data, ss);
746 pa_sink_input_new_data_set_channel_map(&data, map);
747 pa_sink_input_new_data_set_volume(&data, volume);
748 pa_sink_input_new_data_set_muted(&data, muted);
749 data.sync_base = ssync ? ssync->sink_input : NULL;
750
751 sink_input = pa_sink_input_new(c->protocol->core, &data, flags);
752
753 pa_sink_input_new_data_done(&data);
754
755 if (!sink_input)
756 return NULL;
757
758 s = pa_msgobject_new(playback_stream);
759 s->parent.parent.parent.free = playback_stream_free;
760 s->parent.parent.process_msg = playback_stream_process_msg;
761 s->connection = c;
762 s->syncid = syncid;
763 s->sink_input = sink_input;
764 s->underrun = TRUE;
765
766 s->sink_input->parent.process_msg = sink_input_process_msg;
767 s->sink_input->pop = sink_input_pop_cb;
768 s->sink_input->kill = sink_input_kill_cb;
769 s->sink_input->moved = sink_input_moved_cb;
770 s->sink_input->suspend = sink_input_suspend_cb;
771 s->sink_input->userdata = s;
772
773 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
774
775 if (*maxlength <= 0 || *maxlength > MAX_MEMBLOCKQ_LENGTH)
776 *maxlength = MAX_MEMBLOCKQ_LENGTH;
777 if (*tlength <= 0)
778 *tlength = pa_usec_to_bytes(DEFAULT_TLENGTH_MSEC*1000, &sink_input->sample_spec);
779 if (*minreq <= 0)
780 *minreq = (*tlength*9)/10;
781 if (*prebuf <= 0)
782 *prebuf = *tlength;
783
784 if (adjust_latency) {
785 pa_usec_t tlength_usec, minreq_usec;
786
787 /* So, the user asked us to adjust the latency according to
788 * the what the sink can provide. Half the latency will be
789 * spent on the hw buffer, half of it in the async buffer
790 * queue we maintain for each client. */
791
792 tlength_usec = pa_bytes_to_usec(*tlength, &sink_input->sample_spec);
793 minreq_usec = pa_bytes_to_usec(*minreq, &sink_input->sample_spec);
794
795 s->sink_latency = pa_sink_input_set_requested_latency(sink_input, tlength_usec/2);
796
797 if (tlength_usec >= s->sink_latency*2)
798 tlength_usec -= s->sink_latency;
799 else
800 tlength_usec = s->sink_latency;
801
802 if (minreq_usec >= s->sink_latency*2)
803 minreq_usec -= s->sink_latency;
804 else
805 minreq_usec = s->sink_latency;
806
807 *tlength = pa_usec_to_bytes(tlength_usec, &sink_input->sample_spec);
808 *minreq = pa_usec_to_bytes(minreq_usec, &sink_input->sample_spec);
809 }
810
811 silence = pa_silence_memblock_new(c->protocol->core->mempool, &sink_input->sample_spec, 0);
812
813 s->memblockq = pa_memblockq_new(
814 start_index,
815 *maxlength,
816 *tlength,
817 pa_frame_size(&sink_input->sample_spec),
818 *prebuf,
819 *minreq,
820 0,
821 silence);
822
823 pa_memblock_unref(silence);
824
825 *maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq);
826 *tlength = (uint32_t) pa_memblockq_get_tlength(s->memblockq);
827 *prebuf = (uint32_t) pa_memblockq_get_prebuf(s->memblockq);
828 *minreq = (uint32_t) pa_memblockq_get_minreq(s->memblockq);
829 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
830
831 *ss = s->sink_input->sample_spec;
832 *map = s->sink_input->channel_map;
833
834 s->minreq = pa_memblockq_get_minreq(s->memblockq);
835 pa_atomic_store(&s->missing, 0);
836 s->drain_request = FALSE;
837
838 pa_idxset_put(c->output_streams, s, &s->index);
839
840 pa_sink_input_put(s->sink_input);
841 return s;
842 }
843
844 static int connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
845 connection *c = CONNECTION(o);
846 connection_assert_ref(c);
847
848 if (!c->protocol)
849 return -1;
850
851 switch (code) {
852
853 case CONNECTION_MESSAGE_REVOKE:
854 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
855 break;
856
857 case CONNECTION_MESSAGE_RELEASE:
858 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
859 break;
860 }
861
862 return 0;
863 }
864
865 static void connection_unlink(connection *c) {
866 record_stream *r;
867 output_stream *o;
868
869 pa_assert(c);
870
871 if (!c->protocol)
872 return;
873
874 while ((r = pa_idxset_first(c->record_streams, NULL)))
875 record_stream_unlink(r);
876
877 while ((o = pa_idxset_first(c->output_streams, NULL)))
878 if (playback_stream_isinstance(o))
879 playback_stream_unlink(PLAYBACK_STREAM(o));
880 else
881 upload_stream_unlink(UPLOAD_STREAM(o));
882
883 if (c->subscription)
884 pa_subscription_free(c->subscription);
885
886 if (c->pstream)
887 pa_pstream_unlink(c->pstream);
888
889 if (c->auth_timeout_event) {
890 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
891 c->auth_timeout_event = NULL;
892 }
893
894 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
895 c->protocol = NULL;
896 connection_unref(c);
897 }
898
899 static void connection_free(pa_object *o) {
900 connection *c = CONNECTION(o);
901
902 pa_assert(c);
903
904 connection_unlink(c);
905
906 pa_idxset_free(c->record_streams, NULL, NULL);
907 pa_idxset_free(c->output_streams, NULL, NULL);
908
909 pa_pdispatch_unref(c->pdispatch);
910 pa_pstream_unref(c->pstream);
911 pa_client_free(c->client);
912
913 pa_xfree(c);
914 }
915
916 /* Called from thread context */
917 static void request_bytes(playback_stream *s) {
918 size_t m, previous_missing;
919
920 playback_stream_assert_ref(s);
921
922 m = pa_memblockq_pop_missing(s->memblockq);
923
924 if (m <= 0)
925 return;
926
927 /* pa_log("request_bytes(%u)", m); */
928
929 previous_missing = pa_atomic_add(&s->missing, m);
930 if (previous_missing < s->minreq && previous_missing+m >= s->minreq) {
931 pa_assert(pa_thread_mq_get());
932 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
933 }
934 }
935
936 static void send_memblock(connection *c) {
937 uint32_t start;
938 record_stream *r;
939
940 start = PA_IDXSET_INVALID;
941 for (;;) {
942 pa_memchunk chunk;
943
944 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
945 return;
946
947 if (start == PA_IDXSET_INVALID)
948 start = c->rrobin_index;
949 else if (start == c->rrobin_index)
950 return;
951
952 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
953 pa_memchunk schunk = chunk;
954
955 if (schunk.length > r->fragment_size)
956 schunk.length = r->fragment_size;
957
958 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
959
960 pa_memblockq_drop(r->memblockq, schunk.length);
961 pa_memblock_unref(schunk.memblock);
962
963 return;
964 }
965 }
966 }
967
968 static void send_playback_stream_killed(playback_stream *p) {
969 pa_tagstruct *t;
970 playback_stream_assert_ref(p);
971
972 t = pa_tagstruct_new(NULL, 0);
973 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
974 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
975 pa_tagstruct_putu32(t, p->index);
976 pa_pstream_send_tagstruct(p->connection->pstream, t);
977 }
978
979 static void send_record_stream_killed(record_stream *r) {
980 pa_tagstruct *t;
981 record_stream_assert_ref(r);
982
983 t = pa_tagstruct_new(NULL, 0);
984 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
985 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
986 pa_tagstruct_putu32(t, r->index);
987 pa_pstream_send_tagstruct(r->connection->pstream, t);
988 }
989
990 /*** sink input callbacks ***/
991
992 /* Called from thread context */
993 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
994 pa_sink_input *i = PA_SINK_INPUT(o);
995 playback_stream *s;
996
997 pa_sink_input_assert_ref(i);
998 s = PLAYBACK_STREAM(i->userdata);
999 playback_stream_assert_ref(s);
1000
1001 switch (code) {
1002
1003 case SINK_INPUT_MESSAGE_SEEK:
1004 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata));
1005 request_bytes(s);
1006 return 0;
1007
1008 case SINK_INPUT_MESSAGE_POST_DATA: {
1009 pa_assert(chunk);
1010
1011 /* pa_log("sink input post: %u", chunk->length); */
1012
1013 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1014
1015 pa_log_warn("Failed to push data into queue");
1016 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1017 pa_memblockq_seek(s->memblockq, chunk->length, PA_SEEK_RELATIVE);
1018 }
1019
1020 request_bytes(s);
1021
1022 s->underrun = FALSE;
1023 return 0;
1024 }
1025
1026 case SINK_INPUT_MESSAGE_DRAIN: {
1027
1028 pa_memblockq_prebuf_disable(s->memblockq);
1029
1030 if (!pa_memblockq_is_readable(s->memblockq))
1031 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1032 else {
1033 s->drain_tag = PA_PTR_TO_UINT(userdata);
1034 s->drain_request = TRUE;
1035 }
1036 request_bytes(s);
1037
1038 return 0;
1039 }
1040
1041 case SINK_INPUT_MESSAGE_FLUSH:
1042 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1043 case SINK_INPUT_MESSAGE_TRIGGER: {
1044
1045 pa_sink_input *isync;
1046 void (*func)(pa_memblockq *bq);
1047
1048 switch (code) {
1049 case SINK_INPUT_MESSAGE_FLUSH:
1050 func = pa_memblockq_flush;
1051 break;
1052
1053 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1054 func = pa_memblockq_prebuf_force;
1055 break;
1056
1057 case SINK_INPUT_MESSAGE_TRIGGER:
1058 func = pa_memblockq_prebuf_disable;
1059 break;
1060
1061 default:
1062 pa_assert_not_reached();
1063 }
1064
1065 func(s->memblockq);
1066 s->underrun = FALSE;
1067 request_bytes(s);
1068
1069 /* Do the same for all other members in the sync group */
1070 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1071 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1072 func(ssync->memblockq);
1073 ssync->underrun = FALSE;
1074 request_bytes(ssync);
1075 }
1076
1077 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1078 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1079 func(ssync->memblockq);
1080 ssync->underrun = FALSE;
1081 request_bytes(ssync);
1082 }
1083
1084 return 0;
1085 }
1086
1087 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1088
1089 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1090 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1091 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1092 return 0;
1093
1094 case PA_SINK_INPUT_MESSAGE_SET_STATE:
1095
1096 pa_memblockq_prebuf_force(s->memblockq);
1097 request_bytes(s);
1098 break;
1099
1100 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1101 pa_usec_t *r = userdata;
1102
1103 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1104
1105 /* Fall through, the default handler will add in the extra
1106 * latency added by the resampler */
1107 break;
1108 }
1109 }
1110
1111 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1112 }
1113
1114 /* Called from thread context */
1115 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
1116 playback_stream *s;
1117
1118 pa_sink_input_assert_ref(i);
1119 s = PLAYBACK_STREAM(i->userdata);
1120 playback_stream_assert_ref(s);
1121 pa_assert(chunk);
1122
1123 if (pa_memblockq_peek(s->memblockq, chunk) < 0) {
1124
1125 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1126 s->drain_request = FALSE;
1127 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, PA_UINT_TO_PTR(s->drain_tag), 0, NULL, NULL);
1128 } else if (!s->underrun) {
1129 s->underrun = TRUE;
1130 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1131 }
1132
1133 return -1;
1134 }
1135
1136 pa_memblockq_drop(s->memblockq, chunk->length);
1137 request_bytes(s);
1138
1139 return 0;
1140 }
1141
1142 /* Called from main context */
1143 static void sink_input_kill_cb(pa_sink_input *i) {
1144 playback_stream *s;
1145
1146 pa_sink_input_assert_ref(i);
1147 s = PLAYBACK_STREAM(i->userdata);
1148 playback_stream_assert_ref(s);
1149
1150 send_playback_stream_killed(s);
1151 playback_stream_unlink(s);
1152 }
1153
1154 /* Called from main context */
1155 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1156 playback_stream *s;
1157 pa_tagstruct *t;
1158
1159 pa_sink_input_assert_ref(i);
1160 s = PLAYBACK_STREAM(i->userdata);
1161 playback_stream_assert_ref(s);
1162
1163 if (s->connection->version < 12)
1164 return;
1165
1166 t = pa_tagstruct_new(NULL, 0);
1167 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1168 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1169 pa_tagstruct_putu32(t, s->index);
1170 pa_tagstruct_put_boolean(t, suspend);
1171 pa_pstream_send_tagstruct(s->connection->pstream, t);
1172 }
1173
1174 /* Called from main context */
1175 static void sink_input_moved_cb(pa_sink_input *i) {
1176 playback_stream *s;
1177 pa_tagstruct *t;
1178
1179 pa_sink_input_assert_ref(i);
1180 s = PLAYBACK_STREAM(i->userdata);
1181 playback_stream_assert_ref(s);
1182
1183 if (s->connection->version < 12)
1184 return;
1185
1186 t = pa_tagstruct_new(NULL, 0);
1187 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1188 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1189 pa_tagstruct_putu32(t, s->index);
1190 pa_tagstruct_putu32(t, i->sink->index);
1191 pa_tagstruct_puts(t, i->sink->name);
1192 pa_tagstruct_put_boolean(t, pa_sink_get_state(i->sink) == PA_SINK_SUSPENDED);
1193 pa_pstream_send_tagstruct(s->connection->pstream, t);
1194 }
1195
1196 /*** source_output callbacks ***/
1197
1198 /* Called from thread context */
1199 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1200 record_stream *s;
1201
1202 pa_source_output_assert_ref(o);
1203 s = RECORD_STREAM(o->userdata);
1204 record_stream_assert_ref(s);
1205 pa_assert(chunk);
1206
1207 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1208 }
1209
1210 static void source_output_kill_cb(pa_source_output *o) {
1211 record_stream *s;
1212
1213 pa_source_output_assert_ref(o);
1214 s = RECORD_STREAM(o->userdata);
1215 record_stream_assert_ref(s);
1216
1217 send_record_stream_killed(s);
1218 record_stream_unlink(s);
1219 }
1220
1221 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1222 record_stream *s;
1223
1224 pa_source_output_assert_ref(o);
1225 s = RECORD_STREAM(o->userdata);
1226 record_stream_assert_ref(s);
1227
1228 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1229
1230 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1231 }
1232
1233 /* Called from main context */
1234 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1235 record_stream *s;
1236 pa_tagstruct *t;
1237
1238 pa_source_output_assert_ref(o);
1239 s = RECORD_STREAM(o->userdata);
1240 record_stream_assert_ref(s);
1241
1242 if (s->connection->version < 12)
1243 return;
1244
1245 t = pa_tagstruct_new(NULL, 0);
1246 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1247 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1248 pa_tagstruct_putu32(t, s->index);
1249 pa_tagstruct_put_boolean(t, suspend);
1250 pa_pstream_send_tagstruct(s->connection->pstream, t);
1251 }
1252
1253 /* Called from main context */
1254 static void source_output_moved_cb(pa_source_output *o) {
1255 record_stream *s;
1256 pa_tagstruct *t;
1257
1258 pa_source_output_assert_ref(o);
1259 s = RECORD_STREAM(o->userdata);
1260 record_stream_assert_ref(s);
1261
1262 if (s->connection->version < 12)
1263 return;
1264
1265 t = pa_tagstruct_new(NULL, 0);
1266 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1267 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1268 pa_tagstruct_putu32(t, s->index);
1269 pa_tagstruct_putu32(t, o->source->index);
1270 pa_tagstruct_puts(t, o->source->name);
1271 pa_tagstruct_put_boolean(t, pa_source_get_state(o->source) == PA_SOURCE_SUSPENDED);
1272 pa_pstream_send_tagstruct(s->connection->pstream, t);
1273 }
1274
1275 /*** pdispatch callbacks ***/
1276
1277 static void protocol_error(connection *c) {
1278 pa_log("protocol error, kicking client");
1279 connection_unlink(c);
1280 }
1281
1282 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1283 if (!(expression)) { \
1284 pa_pstream_send_error((pstream), (tag), (error)); \
1285 return; \
1286 } \
1287 } while(0);
1288
1289 static pa_tagstruct *reply_new(uint32_t tag) {
1290 pa_tagstruct *reply;
1291
1292 reply = pa_tagstruct_new(NULL, 0);
1293 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1294 pa_tagstruct_putu32(reply, tag);
1295 return reply;
1296 }
1297
1298 static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1299 connection *c = CONNECTION(userdata);
1300 playback_stream *s;
1301 uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid, missing;
1302 const char *name = NULL, *sink_name;
1303 pa_sample_spec ss;
1304 pa_channel_map map;
1305 pa_tagstruct *reply;
1306 pa_sink *sink = NULL;
1307 pa_cvolume volume;
1308 pa_bool_t
1309 corked = FALSE,
1310 no_remap = FALSE,
1311 no_remix = FALSE,
1312 fix_format = FALSE,
1313 fix_rate = FALSE,
1314 fix_channels = FALSE,
1315 no_move = FALSE,
1316 variable_rate = FALSE,
1317 muted = FALSE,
1318 adjust_latency = FALSE;
1319
1320 pa_sink_input_flags_t flags = 0;
1321 pa_proplist *p;
1322
1323 connection_assert_ref(c);
1324 pa_assert(t);
1325
1326 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1327 pa_tagstruct_get(
1328 t,
1329 PA_TAG_SAMPLE_SPEC, &ss,
1330 PA_TAG_CHANNEL_MAP, &map,
1331 PA_TAG_U32, &sink_index,
1332 PA_TAG_STRING, &sink_name,
1333 PA_TAG_U32, &maxlength,
1334 PA_TAG_BOOLEAN, &corked,
1335 PA_TAG_U32, &tlength,
1336 PA_TAG_U32, &prebuf,
1337 PA_TAG_U32, &minreq,
1338 PA_TAG_U32, &syncid,
1339 PA_TAG_CVOLUME, &volume,
1340 PA_TAG_INVALID) < 0) {
1341
1342 protocol_error(c);
1343 return;
1344 }
1345
1346 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1347 CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(sink_name)), tag, PA_ERR_INVALID);
1348 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
1349 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
1350 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
1351 CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID);
1352
1353 p = pa_proplist_new();
1354
1355 if (name)
1356 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1357
1358 if (c->version >= 12) {
1359 /* Since 0.9.8 the user can ask for a couple of additional flags */
1360
1361 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1362 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1363 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1364 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1365 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1366 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1367 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1368
1369 protocol_error(c);
1370 pa_proplist_free(p);
1371 return;
1372 }
1373 }
1374
1375 if (c->version >= 13) {
1376
1377 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1378 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1379 pa_tagstruct_get_proplist(t, p) < 0) {
1380 protocol_error(c);
1381 pa_proplist_free(p);
1382 return;
1383 }
1384 }
1385
1386 if (!pa_tagstruct_eof(t)) {
1387 protocol_error(c);
1388 pa_proplist_free(p);
1389 return;
1390 }
1391
1392 if (sink_index != PA_INVALID_INDEX) {
1393
1394 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
1395 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1396 pa_proplist_free(p);
1397 return;
1398 }
1399
1400 } else if (sink_name) {
1401
1402 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1))) {
1403 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1404 pa_proplist_free(p);
1405 return;
1406 }
1407 }
1408
1409 flags =
1410 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
1411 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
1412 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
1413 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
1414 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
1415 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
1416 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
1417 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0);
1418
1419 s = playback_stream_new(c, sink, &ss, &map, name, &maxlength, &tlength, &prebuf, &minreq, &volume, muted, syncid, &missing, flags, p, adjust_latency);
1420 pa_proplist_free(p);
1421
1422 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
1423
1424 reply = reply_new(tag);
1425 pa_tagstruct_putu32(reply, s->index);
1426 pa_assert(s->sink_input);
1427 pa_tagstruct_putu32(reply, s->sink_input->index);
1428 pa_tagstruct_putu32(reply, missing);
1429
1430 /* pa_log("initial request is %u", missing); */
1431
1432 if (c->version >= 9) {
1433 /* Since 0.9.0 we support sending the buffer metrics back to the client */
1434
1435 pa_tagstruct_putu32(reply, (uint32_t) maxlength);
1436 pa_tagstruct_putu32(reply, (uint32_t) tlength);
1437 pa_tagstruct_putu32(reply, (uint32_t) prebuf);
1438 pa_tagstruct_putu32(reply, (uint32_t) minreq);
1439 }
1440
1441 if (c->version >= 12) {
1442 /* Since 0.9.8 we support sending the chosen sample
1443 * spec/channel map/device/suspend status back to the
1444 * client */
1445
1446 pa_tagstruct_put_sample_spec(reply, &ss);
1447 pa_tagstruct_put_channel_map(reply, &map);
1448
1449 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
1450 pa_tagstruct_puts(reply, s->sink_input->sink->name);
1451
1452 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
1453 }
1454
1455 if (c->version >= 13)
1456 pa_tagstruct_put_usec(reply, s->sink_latency);
1457
1458 pa_pstream_send_tagstruct(c->pstream, reply);
1459 }
1460
1461 static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1462 connection *c = CONNECTION(userdata);
1463 uint32_t channel;
1464
1465 connection_assert_ref(c);
1466 pa_assert(t);
1467
1468 if (pa_tagstruct_getu32(t, &channel) < 0 ||
1469 !pa_tagstruct_eof(t)) {
1470 protocol_error(c);
1471 return;
1472 }
1473
1474 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1475
1476 switch (command) {
1477
1478 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
1479 playback_stream *s;
1480 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
1481 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
1482 return;
1483 }
1484
1485 playback_stream_unlink(s);
1486 break;
1487 }
1488
1489 case PA_COMMAND_DELETE_RECORD_STREAM: {
1490 record_stream *s;
1491 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
1492 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
1493 return;
1494 }
1495
1496 record_stream_unlink(s);
1497 break;
1498 }
1499
1500 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
1501 upload_stream *s;
1502
1503 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
1504 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
1505 return;
1506 }
1507
1508 upload_stream_unlink(s);
1509 break;
1510 }
1511
1512 default:
1513 pa_assert_not_reached();
1514 }
1515
1516 pa_pstream_send_simple_ack(c->pstream, tag);
1517 }
1518
1519 static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1520 connection *c = CONNECTION(userdata);
1521 record_stream *s;
1522 uint32_t maxlength, fragment_size;
1523 uint32_t source_index;
1524 const char *name, *source_name;
1525 pa_sample_spec ss;
1526 pa_channel_map map;
1527 pa_tagstruct *reply;
1528 pa_source *source = NULL;
1529 pa_bool_t
1530 corked = FALSE,
1531 no_remap = FALSE,
1532 no_remix = FALSE,
1533 fix_format = FALSE,
1534 fix_rate = FALSE,
1535 fix_channels = FALSE,
1536 no_move = FALSE,
1537 variable_rate = FALSE,
1538 adjust_latency = FALSE;
1539 pa_source_output_flags_t flags = 0;
1540 pa_proplist *p;
1541
1542 connection_assert_ref(c);
1543 pa_assert(t);
1544
1545 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1546 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
1547 pa_tagstruct_get_channel_map(t, &map) < 0 ||
1548 pa_tagstruct_getu32(t, &source_index) < 0 ||
1549 pa_tagstruct_gets(t, &source_name) < 0 ||
1550 pa_tagstruct_getu32(t, &maxlength) < 0 ||
1551 pa_tagstruct_get_boolean(t, &corked) < 0 ||
1552 pa_tagstruct_getu32(t, &fragment_size) < 0) {
1553 protocol_error(c);
1554 return;
1555 }
1556
1557 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1558 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
1559 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
1560 CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || (*source_name && pa_utf8_valid(source_name)), tag, PA_ERR_INVALID);
1561 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
1562
1563 p = pa_proplist_new();
1564
1565 if (name)
1566 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1567
1568 if (c->version >= 12) {
1569 /* Since 0.9.8 the user can ask for a couple of additional flags */
1570
1571 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1572 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1573 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1574 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1575 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1576 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1577 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1578
1579 protocol_error(c);
1580 pa_proplist_free(p);
1581 return;
1582 }
1583 }
1584
1585 if (c->version >= 13) {
1586
1587 if (pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1588 pa_tagstruct_get_proplist(t, p) < 0) {
1589 protocol_error(c);
1590 pa_proplist_free(p);
1591 return;
1592 }
1593 }
1594
1595 if (!pa_tagstruct_eof(t)) {
1596 protocol_error(c);
1597 pa_proplist_free(p);
1598 return;
1599 }
1600
1601 if (source_index != PA_INVALID_INDEX) {
1602
1603 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
1604 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1605 pa_proplist_free(p);
1606 return;
1607 }
1608
1609 } else if (source_name) {
1610
1611 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1))) {
1612 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1613 pa_proplist_free(p);
1614 return;
1615 }
1616 }
1617
1618 flags =
1619 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
1620 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
1621 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
1622 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
1623 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
1624 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
1625 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
1626 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0);
1627
1628 s = record_stream_new(c, source, &ss, &map, name, &maxlength, &fragment_size, flags, p, adjust_latency);
1629 pa_proplist_free(p);
1630
1631 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
1632
1633 reply = reply_new(tag);
1634 pa_tagstruct_putu32(reply, s->index);
1635 pa_assert(s->source_output);
1636 pa_tagstruct_putu32(reply, s->source_output->index);
1637
1638 if (c->version >= 9) {
1639 /* Since 0.9 we support sending the buffer metrics back to the client */
1640
1641 pa_tagstruct_putu32(reply, (uint32_t) maxlength);
1642 pa_tagstruct_putu32(reply, (uint32_t) fragment_size);
1643 }
1644
1645 if (c->version >= 12) {
1646 /* Since 0.9.8 we support sending the chosen sample
1647 * spec/channel map/device/suspend status back to the
1648 * client */
1649
1650 pa_tagstruct_put_sample_spec(reply, &ss);
1651 pa_tagstruct_put_channel_map(reply, &map);
1652
1653 pa_tagstruct_putu32(reply, s->source_output->source->index);
1654 pa_tagstruct_puts(reply, s->source_output->source->name);
1655
1656 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
1657 }
1658
1659 if (c->version >= 13)
1660 pa_tagstruct_put_usec(reply, s->source_latency);
1661
1662 pa_pstream_send_tagstruct(c->pstream, reply);
1663 }
1664
1665 static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1666 connection *c = CONNECTION(userdata);
1667
1668 connection_assert_ref(c);
1669 pa_assert(t);
1670
1671 if (!pa_tagstruct_eof(t)) {
1672 protocol_error(c);
1673 return;
1674 }
1675
1676 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1677
1678 c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0);
1679 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
1680 }
1681
1682 static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1683 connection *c = CONNECTION(userdata);
1684 const void*cookie;
1685 pa_tagstruct *reply;
1686 char tmp[16];
1687
1688 connection_assert_ref(c);
1689 pa_assert(t);
1690
1691 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
1692 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
1693 !pa_tagstruct_eof(t)) {
1694 protocol_error(c);
1695 return;
1696 }
1697
1698 /* Minimum supported version */
1699 if (c->version < 8) {
1700 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
1701 return;
1702 }
1703
1704 pa_snprintf(tmp, sizeof(tmp), "%u", c->version);
1705 pa_proplist_sets(c->client->proplist, "native-protocol.version", tmp);
1706
1707 if (!c->authorized) {
1708 int success = 0;
1709
1710 #ifdef HAVE_CREDS
1711 const pa_creds *creds;
1712
1713 if ((creds = pa_pdispatch_creds(pd))) {
1714 if (creds->uid == getuid())
1715 success = 1;
1716 else if (c->protocol->auth_group) {
1717 int r;
1718 gid_t gid;
1719
1720 if ((gid = pa_get_gid_of_group(c->protocol->auth_group)) == (gid_t) -1)
1721 pa_log_warn("failed to get GID of group '%s'", c->protocol->auth_group);
1722 else if (gid == creds->gid)
1723 success = 1;
1724
1725 if (!success) {
1726 if ((r = pa_uid_in_group(creds->uid, c->protocol->auth_group)) < 0)
1727 pa_log_warn("failed to check group membership.");
1728 else if (r > 0)
1729 success = 1;
1730 }
1731 }
1732
1733 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
1734 (unsigned long) creds->uid,
1735 (unsigned long) creds->gid,
1736 success);
1737
1738 if (c->version >= 10 &&
1739 pa_mempool_is_shared(c->protocol->core->mempool) &&
1740 creds->uid == getuid()) {
1741
1742 pa_pstream_use_shm(c->pstream, 1);
1743 pa_log_info("Enabled SHM for new connection");
1744 }
1745
1746 }
1747 #endif
1748
1749 if (!success && memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
1750 success = 1;
1751
1752 if (!success) {
1753 pa_log_warn("Denied access to client with invalid authorization data.");
1754 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
1755 return;
1756 }
1757
1758 c->authorized = TRUE;
1759 if (c->auth_timeout_event) {
1760 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1761 c->auth_timeout_event = NULL;
1762 }
1763 }
1764
1765 reply = reply_new(tag);
1766 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION);
1767
1768 #ifdef HAVE_CREDS
1769 {
1770 /* SHM support is only enabled after both sides made sure they are the same user. */
1771
1772 pa_creds ucred;
1773
1774 ucred.uid = getuid();
1775 ucred.gid = getgid();
1776
1777 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
1778 }
1779 #else
1780 pa_pstream_send_tagstruct(c->pstream, reply);
1781 #endif
1782 }
1783
1784 static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1785 connection *c = CONNECTION(userdata);
1786 const char *name = NULL;
1787 pa_proplist *p;
1788 pa_tagstruct *reply;
1789
1790 connection_assert_ref(c);
1791 pa_assert(t);
1792
1793 p = pa_proplist_new();
1794
1795 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
1796 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
1797 !pa_tagstruct_eof(t)) {
1798
1799 protocol_error(c);
1800 pa_proplist_free(p);
1801 return;
1802 }
1803
1804 if (name)
1805 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
1806 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
1807 pa_proplist_free(p);
1808 return;
1809 }
1810
1811 pa_proplist_update(c->client->proplist, PA_UPDATE_REPLACE, p);
1812 pa_proplist_free(p);
1813
1814 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
1815
1816 reply = reply_new(tag);
1817
1818 if (c->version >= 13)
1819 pa_tagstruct_putu32(reply, c->client->index);
1820
1821 pa_pstream_send_tagstruct(c->pstream, reply);
1822 }
1823
1824 static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1825 connection *c = CONNECTION(userdata);
1826 const char *name;
1827 uint32_t idx = PA_IDXSET_INVALID;
1828
1829 connection_assert_ref(c);
1830 pa_assert(t);
1831
1832 if (pa_tagstruct_gets(t, &name) < 0 ||
1833 !pa_tagstruct_eof(t)) {
1834 protocol_error(c);
1835 return;
1836 }
1837
1838 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1839 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
1840
1841 if (command == PA_COMMAND_LOOKUP_SINK) {
1842 pa_sink *sink;
1843 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1)))
1844 idx = sink->index;
1845 } else {
1846 pa_source *source;
1847 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
1848 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1)))
1849 idx = source->index;
1850 }
1851
1852 if (idx == PA_IDXSET_INVALID)
1853 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1854 else {
1855 pa_tagstruct *reply;
1856 reply = reply_new(tag);
1857 pa_tagstruct_putu32(reply, idx);
1858 pa_pstream_send_tagstruct(c->pstream, reply);
1859 }
1860 }
1861
1862 static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1863 connection *c = CONNECTION(userdata);
1864 uint32_t idx;
1865 playback_stream *s;
1866
1867 connection_assert_ref(c);
1868 pa_assert(t);
1869
1870 if (pa_tagstruct_getu32(t, &idx) < 0 ||
1871 !pa_tagstruct_eof(t)) {
1872 protocol_error(c);
1873 return;
1874 }
1875
1876 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1877 s = pa_idxset_get_by_index(c->output_streams, idx);
1878 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
1879 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
1880
1881 pa_asyncmsgq_post(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_DRAIN, PA_UINT_TO_PTR(tag), 0, NULL, NULL);
1882 }
1883
1884 static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1885 connection *c = CONNECTION(userdata);
1886 pa_tagstruct *reply;
1887 const pa_mempool_stat *stat;
1888
1889 connection_assert_ref(c);
1890 pa_assert(t);
1891
1892 if (!pa_tagstruct_eof(t)) {
1893 protocol_error(c);
1894 return;
1895 }
1896
1897 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1898
1899 stat = pa_mempool_get_stat(c->protocol->core->mempool);
1900
1901 reply = reply_new(tag);
1902 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
1903 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
1904 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
1905 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
1906 pa_tagstruct_putu32(reply, pa_scache_total_size(c->protocol->core));
1907 pa_pstream_send_tagstruct(c->pstream, reply);
1908 }
1909
1910 static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1911 connection *c = CONNECTION(userdata);
1912 pa_tagstruct *reply;
1913 playback_stream *s;
1914 struct timeval tv, now;
1915 uint32_t idx;
1916 pa_usec_t latency;
1917
1918 connection_assert_ref(c);
1919 pa_assert(t);
1920
1921 if (pa_tagstruct_getu32(t, &idx) < 0 ||
1922 pa_tagstruct_get_timeval(t, &tv) < 0 ||
1923 !pa_tagstruct_eof(t)) {
1924 protocol_error(c);
1925 return;
1926 }
1927
1928 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1929 s = pa_idxset_get_by_index(c->output_streams, idx);
1930 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
1931 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
1932 CHECK_VALIDITY(c->pstream, pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0, tag, PA_ERR_NOENTITY)
1933
1934 reply = reply_new(tag);
1935
1936 latency = pa_sink_get_latency(s->sink_input->sink);
1937 latency += pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sample_spec);
1938
1939 pa_tagstruct_put_usec(reply, latency);
1940
1941 pa_tagstruct_put_usec(reply, 0);
1942 pa_tagstruct_put_boolean(reply, pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
1943 pa_tagstruct_put_timeval(reply, &tv);
1944 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
1945 pa_tagstruct_puts64(reply, s->write_index);
1946 pa_tagstruct_puts64(reply, s->read_index);
1947 pa_pstream_send_tagstruct(c->pstream, reply);
1948 }
1949
1950 static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1951 connection *c = CONNECTION(userdata);
1952 pa_tagstruct *reply;
1953 record_stream *s;
1954 struct timeval tv, now;
1955 uint32_t idx;
1956
1957 connection_assert_ref(c);
1958 pa_assert(t);
1959
1960 if (pa_tagstruct_getu32(t, &idx) < 0 ||
1961 pa_tagstruct_get_timeval(t, &tv) < 0 ||
1962 !pa_tagstruct_eof(t)) {
1963 protocol_error(c);
1964 return;
1965 }
1966
1967 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1968 s = pa_idxset_get_by_index(c->record_streams, idx);
1969 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
1970
1971 reply = reply_new(tag);
1972 pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0);
1973 pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source));
1974 pa_tagstruct_put_boolean(reply, FALSE);
1975 pa_tagstruct_put_timeval(reply, &tv);
1976 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
1977 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
1978 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
1979 pa_pstream_send_tagstruct(c->pstream, reply);
1980 }
1981
1982 static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1983 connection *c = CONNECTION(userdata);
1984 upload_stream *s;
1985 uint32_t length;
1986 const char *name = NULL;
1987 pa_sample_spec ss;
1988 pa_channel_map map;
1989 pa_tagstruct *reply;
1990 pa_proplist *p;
1991
1992 connection_assert_ref(c);
1993 pa_assert(t);
1994
1995 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
1996 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
1997 pa_tagstruct_get_channel_map(t, &map) < 0 ||
1998 pa_tagstruct_getu32(t, &length) < 0) {
1999 protocol_error(c);
2000 return;
2001 }
2002
2003 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2004 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2005 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2006 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2007 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2008 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2009
2010 if (c->version < 13)
2011 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
2012
2013 p = pa_proplist_new();
2014
2015 if (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) {
2016 protocol_error(c);
2017 pa_proplist_free(p);
2018 return;
2019 }
2020
2021 if (c->version < 13)
2022 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2023
2024 s = upload_stream_new(c, &ss, &map, name, length, p);
2025 pa_proplist_free(p);
2026
2027 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2028
2029 reply = reply_new(tag);
2030 pa_tagstruct_putu32(reply, s->index);
2031 pa_tagstruct_putu32(reply, length);
2032 pa_pstream_send_tagstruct(c->pstream, reply);
2033 }
2034
2035 static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2036 connection *c = CONNECTION(userdata);
2037 uint32_t channel;
2038 upload_stream *s;
2039 uint32_t idx;
2040
2041 connection_assert_ref(c);
2042 pa_assert(t);
2043
2044 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2045 !pa_tagstruct_eof(t)) {
2046 protocol_error(c);
2047 return;
2048 }
2049
2050 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2051
2052 s = pa_idxset_get_by_index(c->output_streams, channel);
2053 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2054 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2055
2056 if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2057 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2058 else
2059 pa_pstream_send_simple_ack(c->pstream, tag);
2060
2061 upload_stream_unlink(s);
2062 }
2063
2064 static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2065 connection *c = CONNECTION(userdata);
2066 uint32_t sink_index;
2067 pa_volume_t volume;
2068 pa_sink *sink;
2069 const char *name, *sink_name;
2070 uint32_t idx;
2071 pa_proplist *p;
2072 pa_tagstruct *reply;
2073
2074 connection_assert_ref(c);
2075 pa_assert(t);
2076
2077 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2078
2079 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2080 pa_tagstruct_gets(t, &sink_name) < 0 ||
2081 pa_tagstruct_getu32(t, &volume) < 0 ||
2082 pa_tagstruct_gets(t, &name) < 0) {
2083 protocol_error(c);
2084 return;
2085 }
2086
2087 CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(name)), tag, PA_ERR_INVALID);
2088 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
2089
2090 if (sink_index != PA_INVALID_INDEX)
2091 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2092 else
2093 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1);
2094
2095 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2096
2097 p = pa_proplist_new();
2098
2099 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2100 !pa_tagstruct_eof(t)) {
2101 protocol_error(c);
2102 pa_proplist_free(p);
2103 return;
2104 }
2105
2106 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2107 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2108 pa_proplist_free(p);
2109 return;
2110 }
2111
2112 pa_proplist_free(p);
2113
2114 reply = reply_new(tag);
2115
2116 if (c->version >= 13)
2117 pa_tagstruct_putu32(reply, idx);
2118
2119 pa_pstream_send_tagstruct(c->pstream, reply);
2120 }
2121
2122 static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2123 connection *c = CONNECTION(userdata);
2124 const char *name;
2125
2126 connection_assert_ref(c);
2127 pa_assert(t);
2128
2129 if (pa_tagstruct_gets(t, &name) < 0 ||
2130 !pa_tagstruct_eof(t)) {
2131 protocol_error(c);
2132 return;
2133 }
2134
2135 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2136 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
2137
2138 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
2139 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2140 return;
2141 }
2142
2143 pa_pstream_send_simple_ack(c->pstream, tag);
2144 }
2145
2146 static void fixup_sample_spec(connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
2147 pa_assert(c);
2148 pa_assert(fixed);
2149 pa_assert(original);
2150
2151 *fixed = *original;
2152
2153 if (c->version < 12) {
2154 /* Before protocol version 12 we didn't support S32 samples,
2155 * so we need to lie about this to the client */
2156
2157 if (fixed->format == PA_SAMPLE_S32LE)
2158 fixed->format = PA_SAMPLE_FLOAT32LE;
2159 if (fixed->format == PA_SAMPLE_S32BE)
2160 fixed->format = PA_SAMPLE_FLOAT32BE;
2161 }
2162 }
2163
2164 static void sink_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink *sink) {
2165 pa_sample_spec fixed_ss;
2166
2167 pa_assert(t);
2168 pa_sink_assert_ref(sink);
2169
2170 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
2171
2172 pa_tagstruct_put(
2173 t,
2174 PA_TAG_U32, sink->index,
2175 PA_TAG_STRING, sink->name,
2176 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2177 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2178 PA_TAG_CHANNEL_MAP, &sink->channel_map,
2179 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
2180 PA_TAG_CVOLUME, pa_sink_get_volume(sink),
2181 PA_TAG_BOOLEAN, pa_sink_get_mute(sink),
2182 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
2183 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
2184 PA_TAG_USEC, pa_sink_get_latency(sink),
2185 PA_TAG_STRING, sink->driver,
2186 PA_TAG_U32, sink->flags,
2187 PA_TAG_INVALID);
2188
2189 if (c->version >= 13) {
2190 pa_tagstruct_put_proplist(t, sink->proplist);
2191 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
2192 }
2193 }
2194
2195 static void source_fill_tagstruct(connection *c, pa_tagstruct *t, pa_source *source) {
2196 pa_sample_spec fixed_ss;
2197
2198 pa_assert(t);
2199 pa_source_assert_ref(source);
2200
2201 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
2202
2203 pa_tagstruct_put(
2204 t,
2205 PA_TAG_U32, source->index,
2206 PA_TAG_STRING, source->name,
2207 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2208 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2209 PA_TAG_CHANNEL_MAP, &source->channel_map,
2210 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
2211 PA_TAG_CVOLUME, pa_source_get_volume(source),
2212 PA_TAG_BOOLEAN, pa_source_get_mute(source),
2213 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
2214 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
2215 PA_TAG_USEC, pa_source_get_latency(source),
2216 PA_TAG_STRING, source->driver,
2217 PA_TAG_U32, source->flags,
2218 PA_TAG_INVALID);
2219
2220 if (c->version >= 13) {
2221 pa_tagstruct_put_proplist(t, source->proplist);
2222 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
2223 }
2224 }
2225
2226
2227 static void client_fill_tagstruct(connection *c, pa_tagstruct *t, pa_client *client) {
2228 pa_assert(t);
2229 pa_assert(client);
2230
2231 pa_tagstruct_putu32(t, client->index);
2232 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
2233 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
2234 pa_tagstruct_puts(t, client->driver);
2235
2236 if (c->version >= 13)
2237 pa_tagstruct_put_proplist(t, client->proplist);
2238
2239 }
2240
2241 static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) {
2242 pa_assert(t);
2243 pa_assert(module);
2244
2245 pa_tagstruct_putu32(t, module->index);
2246 pa_tagstruct_puts(t, module->name);
2247 pa_tagstruct_puts(t, module->argument);
2248 pa_tagstruct_putu32(t, module->n_used);
2249 pa_tagstruct_put_boolean(t, module->auto_unload);
2250 }
2251
2252 static void sink_input_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink_input *s) {
2253 pa_sample_spec fixed_ss;
2254
2255 pa_assert(t);
2256 pa_sink_input_assert_ref(s);
2257
2258 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
2259
2260 pa_tagstruct_putu32(t, s->index);
2261 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
2262 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
2263 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
2264 pa_tagstruct_putu32(t, s->sink->index);
2265 pa_tagstruct_put_sample_spec(t, &fixed_ss);
2266 pa_tagstruct_put_channel_map(t, &s->channel_map);
2267 pa_tagstruct_put_cvolume(t, &s->volume);
2268 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s));
2269 pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink));
2270 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
2271 pa_tagstruct_puts(t, s->driver);
2272 if (c->version >= 11)
2273 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
2274 if (c->version >= 13)
2275 pa_tagstruct_put_proplist(t, s->proplist);
2276 }
2277
2278 static void source_output_fill_tagstruct(connection *c, pa_tagstruct *t, pa_source_output *s) {
2279 pa_sample_spec fixed_ss;
2280
2281 pa_assert(t);
2282 pa_source_output_assert_ref(s);
2283
2284 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
2285
2286 pa_tagstruct_putu32(t, s->index);
2287 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
2288 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
2289 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
2290 pa_tagstruct_putu32(t, s->source->index);
2291 pa_tagstruct_put_sample_spec(t, &fixed_ss);
2292 pa_tagstruct_put_channel_map(t, &s->channel_map);
2293 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s));
2294 pa_tagstruct_put_usec(t, pa_source_get_latency(s->source));
2295 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
2296 pa_tagstruct_puts(t, s->driver);
2297
2298 if (c->version >= 13)
2299 pa_tagstruct_put_proplist(t, s->proplist);
2300 }
2301
2302 static void scache_fill_tagstruct(connection *c, pa_tagstruct *t, pa_scache_entry *e) {
2303 pa_sample_spec fixed_ss;
2304
2305 pa_assert(t);
2306 pa_assert(e);
2307
2308 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
2309
2310 pa_tagstruct_putu32(t, e->index);
2311 pa_tagstruct_puts(t, e->name);
2312 pa_tagstruct_put_cvolume(t, &e->volume);
2313 pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec));
2314 pa_tagstruct_put_sample_spec(t, &fixed_ss);
2315 pa_tagstruct_put_channel_map(t, &e->channel_map);
2316 pa_tagstruct_putu32(t, e->memchunk.length);
2317 pa_tagstruct_put_boolean(t, e->lazy);
2318 pa_tagstruct_puts(t, e->filename);
2319
2320 if (c->version >= 13)
2321 pa_tagstruct_put_proplist(t, e->proplist);
2322 }
2323
2324 static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2325 connection *c = CONNECTION(userdata);
2326 uint32_t idx;
2327 pa_sink *sink = NULL;
2328 pa_source *source = NULL;
2329 pa_client *client = NULL;
2330 pa_module *module = NULL;
2331 pa_sink_input *si = NULL;
2332 pa_source_output *so = NULL;
2333 pa_scache_entry *sce = NULL;
2334 const char *name;
2335 pa_tagstruct *reply;
2336
2337 connection_assert_ref(c);
2338 pa_assert(t);
2339
2340 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2341 (command != PA_COMMAND_GET_CLIENT_INFO &&
2342 command != PA_COMMAND_GET_MODULE_INFO &&
2343 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
2344 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
2345 pa_tagstruct_gets(t, &name) < 0) ||
2346 !pa_tagstruct_eof(t)) {
2347 protocol_error(c);
2348 return;
2349 }
2350
2351 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2352 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID);
2353
2354 if (command == PA_COMMAND_GET_SINK_INFO) {
2355 if (idx != PA_INVALID_INDEX)
2356 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
2357 else
2358 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
2359 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
2360 if (idx != PA_INVALID_INDEX)
2361 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
2362 else
2363 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1);
2364 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
2365 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
2366 else if (command == PA_COMMAND_GET_MODULE_INFO)
2367 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
2368 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
2369 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
2370 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
2371 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
2372 else {
2373 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
2374 if (idx != PA_INVALID_INDEX)
2375 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
2376 else
2377 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE, 0);
2378 }
2379
2380 if (!sink && !source && !client && !module && !si && !so && !sce) {
2381 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2382 return;
2383 }
2384
2385 reply = reply_new(tag);
2386 if (sink)
2387 sink_fill_tagstruct(c, reply, sink);
2388 else if (source)
2389 source_fill_tagstruct(c, reply, source);
2390 else if (client)
2391 client_fill_tagstruct(c, reply, client);
2392 else if (module)
2393 module_fill_tagstruct(reply, module);
2394 else if (si)
2395 sink_input_fill_tagstruct(c, reply, si);
2396 else if (so)
2397 source_output_fill_tagstruct(c, reply, so);
2398 else
2399 scache_fill_tagstruct(c, reply, sce);
2400 pa_pstream_send_tagstruct(c->pstream, reply);
2401 }
2402
2403 static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2404 connection *c = CONNECTION(userdata);
2405 pa_idxset *i;
2406 uint32_t idx;
2407 void *p;
2408 pa_tagstruct *reply;
2409
2410 connection_assert_ref(c);
2411 pa_assert(t);
2412
2413 if (!pa_tagstruct_eof(t)) {
2414 protocol_error(c);
2415 return;
2416 }
2417
2418 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2419
2420 reply = reply_new(tag);
2421
2422 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
2423 i = c->protocol->core->sinks;
2424 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
2425 i = c->protocol->core->sources;
2426 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
2427 i = c->protocol->core->clients;
2428 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
2429 i = c->protocol->core->modules;
2430 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
2431 i = c->protocol->core->sink_inputs;
2432 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
2433 i = c->protocol->core->source_outputs;
2434 else {
2435 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
2436 i = c->protocol->core->scache;
2437 }
2438
2439 if (i) {
2440 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
2441 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
2442 sink_fill_tagstruct(c, reply, p);
2443 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
2444 source_fill_tagstruct(c, reply, p);
2445 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
2446 client_fill_tagstruct(c, reply, p);
2447 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
2448 module_fill_tagstruct(reply, p);
2449 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
2450 sink_input_fill_tagstruct(c, reply, p);
2451 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
2452 source_output_fill_tagstruct(c, reply, p);
2453 else {
2454 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
2455 scache_fill_tagstruct(c, reply, p);
2456 }
2457 }
2458 }
2459
2460 pa_pstream_send_tagstruct(c->pstream, reply);
2461 }
2462
2463 static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2464 connection *c = CONNECTION(userdata);
2465 pa_tagstruct *reply;
2466 char txt[256];
2467 const char *n;
2468 pa_sample_spec fixed_ss;
2469
2470 connection_assert_ref(c);
2471 pa_assert(t);
2472
2473 if (!pa_tagstruct_eof(t)) {
2474 protocol_error(c);
2475 return;
2476 }
2477
2478 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2479
2480 reply = reply_new(tag);
2481 pa_tagstruct_puts(reply, PACKAGE_NAME);
2482 pa_tagstruct_puts(reply, PACKAGE_VERSION);
2483 pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt)));
2484 pa_tagstruct_puts(reply, pa_get_host_name(txt, sizeof(txt)));
2485
2486 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
2487 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
2488
2489 n = pa_namereg_get_default_sink_name(c->protocol->core);
2490 pa_tagstruct_puts(reply, n);
2491 n = pa_namereg_get_default_source_name(c->protocol->core);
2492 pa_tagstruct_puts(reply, n);
2493
2494 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
2495
2496 pa_pstream_send_tagstruct(c->pstream, reply);
2497 }
2498
2499 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
2500 pa_tagstruct *t;
2501 connection *c = CONNECTION(userdata);
2502
2503 connection_assert_ref(c);
2504
2505 t = pa_tagstruct_new(NULL, 0);
2506 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
2507 pa_tagstruct_putu32(t, (uint32_t) -1);
2508 pa_tagstruct_putu32(t, e);
2509 pa_tagstruct_putu32(t, idx);
2510 pa_pstream_send_tagstruct(c->pstream, t);
2511 }
2512
2513 static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2514 connection *c = CONNECTION(userdata);
2515 pa_subscription_mask_t m;
2516
2517 connection_assert_ref(c);
2518 pa_assert(t);
2519
2520 if (pa_tagstruct_getu32(t, &m) < 0 ||
2521 !pa_tagstruct_eof(t)) {
2522 protocol_error(c);
2523 return;
2524 }
2525
2526 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2527 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
2528
2529 if (c->subscription)
2530 pa_subscription_free(c->subscription);
2531
2532 if (m != 0) {
2533 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
2534 pa_assert(c->subscription);
2535 } else
2536 c->subscription = NULL;
2537
2538 pa_pstream_send_simple_ack(c->pstream, tag);
2539 }
2540
2541 static void command_set_volume(
2542 PA_GCC_UNUSED pa_pdispatch *pd,
2543 uint32_t command,
2544 uint32_t tag,
2545 pa_tagstruct *t,
2546 void *userdata) {
2547
2548 connection *c = CONNECTION(userdata);
2549 uint32_t idx;
2550 pa_cvolume volume;
2551 pa_sink *sink = NULL;
2552 pa_source *source = NULL;
2553 pa_sink_input *si = NULL;
2554 const char *name = NULL;
2555
2556 connection_assert_ref(c);
2557 pa_assert(t);
2558
2559 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2560 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
2561 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
2562 pa_tagstruct_get_cvolume(t, &volume) ||
2563 !pa_tagstruct_eof(t)) {
2564 protocol_error(c);
2565 return;
2566 }
2567
2568 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2569 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID);
2570 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
2571
2572 switch (command) {
2573
2574 case PA_COMMAND_SET_SINK_VOLUME:
2575 if (idx != PA_INVALID_INDEX)
2576 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
2577 else
2578 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
2579 break;
2580
2581 case PA_COMMAND_SET_SOURCE_VOLUME:
2582 if (idx != PA_INVALID_INDEX)
2583 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
2584 else
2585 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1);
2586 break;
2587
2588 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
2589 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
2590 break;
2591
2592 default:
2593 pa_assert_not_reached();
2594 }
2595
2596 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
2597
2598 if (sink)
2599 pa_sink_set_volume(sink, &volume);
2600 else if (source)
2601 pa_source_set_volume(source, &volume);
2602 else if (si)
2603 pa_sink_input_set_volume(si, &volume);
2604
2605 pa_pstream_send_simple_ack(c->pstream, tag);
2606 }
2607
2608 static void command_set_mute(
2609 PA_GCC_UNUSED pa_pdispatch *pd,
2610 uint32_t command,
2611 uint32_t tag,
2612 pa_tagstruct *t,
2613 void *userdata) {
2614
2615 connection *c = CONNECTION(userdata);
2616 uint32_t idx;
2617 pa_bool_t mute;
2618 pa_sink *sink = NULL;
2619 pa_source *source = NULL;
2620 pa_sink_input *si = NULL;
2621 const char *name = NULL;
2622
2623 connection_assert_ref(c);
2624 pa_assert(t);
2625
2626 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2627 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
2628 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
2629 pa_tagstruct_get_boolean(t, &mute) ||
2630 !pa_tagstruct_eof(t)) {
2631 protocol_error(c);
2632 return;
2633 }
2634
2635 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2636 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID);
2637
2638 switch (command) {
2639
2640 case PA_COMMAND_SET_SINK_MUTE:
2641
2642 if (idx != PA_INVALID_INDEX)
2643 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
2644 else
2645 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
2646
2647 break;
2648
2649 case PA_COMMAND_SET_SOURCE_MUTE:
2650 if (idx != PA_INVALID_INDEX)
2651 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
2652 else
2653 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1);
2654
2655 break;
2656
2657 case PA_COMMAND_SET_SINK_INPUT_MUTE:
2658 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
2659 break;
2660
2661 default:
2662 pa_assert_not_reached();
2663 }
2664
2665 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
2666
2667 if (sink)
2668 pa_sink_set_mute(sink, mute);
2669 else if (source)
2670 pa_source_set_mute(source, mute);
2671 else if (si)
2672 pa_sink_input_set_mute(si, mute);
2673
2674 pa_pstream_send_simple_ack(c->pstream, tag);
2675 }
2676
2677 static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2678 connection *c = CONNECTION(userdata);
2679 uint32_t idx;
2680 pa_bool_t b;
2681 playback_stream *s;
2682
2683 connection_assert_ref(c);
2684 pa_assert(t);
2685
2686 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2687 pa_tagstruct_get_boolean(t, &b) < 0 ||
2688 !pa_tagstruct_eof(t)) {
2689 protocol_error(c);
2690 return;
2691 }
2692
2693 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2694 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2695 s = pa_idxset_get_by_index(c->output_streams, idx);
2696 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2697 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2698
2699 pa_sink_input_cork(s->sink_input, b);
2700 pa_pstream_send_simple_ack(c->pstream, tag);
2701 }
2702
2703 static void command_trigger_or_flush_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2704 connection *c = CONNECTION(userdata);
2705 uint32_t idx;
2706 playback_stream *s;
2707
2708 connection_assert_ref(c);
2709 pa_assert(t);
2710
2711 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2712 !pa_tagstruct_eof(t)) {
2713 protocol_error(c);
2714 return;
2715 }
2716
2717 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2718 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2719 s = pa_idxset_get_by_index(c->output_streams, idx);
2720 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2721 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2722
2723 switch (command) {
2724 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
2725 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
2726 break;
2727
2728 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
2729 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
2730 break;
2731
2732 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
2733 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
2734 break;
2735
2736 default:
2737 pa_assert_not_reached();
2738 }
2739
2740 pa_pstream_send_simple_ack(c->pstream, tag);
2741 }
2742
2743 static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2744 connection *c = CONNECTION(userdata);
2745 uint32_t idx;
2746 record_stream *s;
2747 pa_bool_t b;
2748
2749 connection_assert_ref(c);
2750 pa_assert(t);
2751
2752 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2753 pa_tagstruct_get_boolean(t, &b) < 0 ||
2754 !pa_tagstruct_eof(t)) {
2755 protocol_error(c);
2756 return;
2757 }
2758
2759 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2760 s = pa_idxset_get_by_index(c->record_streams, idx);
2761 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2762
2763 pa_source_output_cork(s->source_output, b);
2764 pa_memblockq_prebuf_force(s->memblockq);
2765 pa_pstream_send_simple_ack(c->pstream, tag);
2766 }
2767
2768 static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2769 connection *c = CONNECTION(userdata);
2770 uint32_t idx;
2771 record_stream *s;
2772
2773 connection_assert_ref(c);
2774 pa_assert(t);
2775
2776 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2777 !pa_tagstruct_eof(t)) {
2778 protocol_error(c);
2779 return;
2780 }
2781
2782 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2783 s = pa_idxset_get_by_index(c->record_streams, idx);
2784 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2785
2786 pa_memblockq_flush(s->memblockq);
2787 pa_pstream_send_simple_ack(c->pstream, tag);
2788 }
2789
2790 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2791 connection *c = CONNECTION(userdata);
2792 uint32_t idx;
2793 uint32_t maxlength, tlength, prebuf, minreq, fragsize;
2794 pa_tagstruct *reply;
2795
2796 connection_assert_ref(c);
2797 pa_assert(t);
2798
2799 if (pa_tagstruct_getu32(t, &idx) < 0) {
2800 protocol_error(c);
2801 return;
2802 }
2803
2804 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2805
2806 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
2807 playback_stream *s;
2808
2809 s = pa_idxset_get_by_index(c->output_streams, idx);
2810 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2811 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2812
2813 if (pa_tagstruct_get(
2814 t,
2815 PA_TAG_U32, &maxlength,
2816 PA_TAG_U32, &tlength,
2817 PA_TAG_U32, &prebuf,
2818 PA_TAG_U32, &minreq,
2819 PA_TAG_INVALID) < 0 ||
2820 !pa_tagstruct_eof(t)) {
2821 protocol_error(c);
2822 return;
2823 }
2824
2825 if (maxlength <= 0 || maxlength > MAX_MEMBLOCKQ_LENGTH)
2826 maxlength = MAX_MEMBLOCKQ_LENGTH;
2827 if (tlength <= 0)
2828 tlength = pa_usec_to_bytes(DEFAULT_TLENGTH_MSEC*1000, &s->sink_input->sample_spec);
2829 if (minreq <= 0)
2830 minreq = (tlength*9)/10;
2831 if (prebuf <= 0)
2832 prebuf = tlength;
2833
2834 pa_memblockq_set_maxlength(s->memblockq, maxlength);
2835 pa_memblockq_set_tlength(s->memblockq, tlength);
2836 pa_memblockq_set_prebuf(s->memblockq, prebuf);
2837 pa_memblockq_set_minreq(s->memblockq, minreq);
2838
2839 reply = reply_new(tag);
2840 pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq));
2841 pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_tlength(s->memblockq));
2842 pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_prebuf(s->memblockq));
2843 pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_minreq(s->memblockq));
2844
2845 } else {
2846 record_stream *s;
2847 size_t base;
2848 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
2849
2850 s = pa_idxset_get_by_index(c->record_streams, idx);
2851 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2852
2853 if (pa_tagstruct_get(
2854 t,
2855 PA_TAG_U32, &maxlength,
2856 PA_TAG_U32, &fragsize,
2857 PA_TAG_INVALID) < 0 ||
2858 !pa_tagstruct_eof(t)) {
2859 protocol_error(c);
2860 return;
2861 }
2862
2863 if (maxlength <= 0 || maxlength > MAX_MEMBLOCKQ_LENGTH)
2864 maxlength = MAX_MEMBLOCKQ_LENGTH;
2865 if (fragsize <= 0)
2866 fragsize = pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*1000, &s->source_output->sample_spec);
2867
2868 pa_memblockq_set_maxlength(s->memblockq, maxlength);
2869
2870 base = pa_frame_size(&s->source_output->sample_spec);
2871 s->fragment_size = (fragsize/base)*base;
2872 if (s->fragment_size <= 0)
2873 s->fragment_size = base;
2874
2875 if (s->fragment_size > pa_memblockq_get_maxlength(s->memblockq))
2876 s->fragment_size = pa_memblockq_get_maxlength(s->memblockq);
2877
2878 reply = reply_new(tag);
2879 pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq));
2880 pa_tagstruct_putu32(reply, s->fragment_size);
2881 }
2882
2883 pa_pstream_send_tagstruct(c->pstream, reply);
2884 }
2885
2886 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2887 connection *c = CONNECTION(userdata);
2888 uint32_t idx;
2889 uint32_t rate;
2890
2891 connection_assert_ref(c);
2892 pa_assert(t);
2893
2894 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2895 pa_tagstruct_getu32(t, &rate) < 0 ||
2896 !pa_tagstruct_eof(t)) {
2897 protocol_error(c);
2898 return;
2899 }
2900
2901 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2902 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
2903
2904 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
2905 playback_stream *s;
2906
2907 s = pa_idxset_get_by_index(c->output_streams, idx);
2908 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2909 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2910
2911 pa_sink_input_set_rate(s->sink_input, rate);
2912
2913 } else {
2914 record_stream *s;
2915 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
2916
2917 s = pa_idxset_get_by_index(c->record_streams, idx);
2918 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2919
2920 pa_source_output_set_rate(s->source_output, rate);
2921 }
2922
2923 pa_pstream_send_simple_ack(c->pstream, tag);
2924 }
2925
2926 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2927 connection *c = CONNECTION(userdata);
2928 uint32_t idx;
2929 uint32_t mode;
2930 pa_proplist *p;
2931
2932 connection_assert_ref(c);
2933 pa_assert(t);
2934
2935 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2936
2937 p = pa_proplist_new();
2938
2939 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
2940
2941 if (pa_tagstruct_getu32(t, &mode) < 0 ||
2942 pa_tagstruct_get_proplist(t, p) < 0 ||
2943 !pa_tagstruct_eof(t)) {
2944 protocol_error(c);
2945 pa_proplist_free(p);
2946 return;
2947 }
2948
2949 } else {
2950
2951 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2952 pa_tagstruct_getu32(t, &mode) < 0 ||
2953 pa_tagstruct_get_proplist(t, p) < 0 ||
2954 !pa_tagstruct_eof(t)) {
2955 protocol_error(c);
2956 pa_proplist_free(p);
2957 return;
2958 }
2959 }
2960
2961 CHECK_VALIDITY(c->pstream, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, tag, PA_ERR_INVALID);
2962
2963 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
2964 playback_stream *s;
2965
2966 s = pa_idxset_get_by_index(c->output_streams, idx);
2967 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2968 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2969
2970 pa_proplist_update(s->sink_input->proplist, mode, p);
2971 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
2972
2973 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
2974 record_stream *s;
2975
2976 s = pa_idxset_get_by_index(c->record_streams, idx);
2977 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2978
2979 pa_proplist_update(s->source_output->proplist, mode, p);
2980 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
2981 } else {
2982 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
2983
2984 pa_proplist_update(c->client->proplist, mode, p);
2985 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
2986 }
2987
2988 pa_pstream_send_simple_ack(c->pstream, tag);
2989 }
2990
2991 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2992 connection *c = CONNECTION(userdata);
2993 uint32_t idx;
2994 unsigned changed = 0;
2995 pa_proplist *p;
2996 pa_strlist *l = NULL;
2997
2998 connection_assert_ref(c);
2999 pa_assert(t);
3000
3001 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3002
3003 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
3004
3005 if (pa_tagstruct_getu32(t, &idx) < 0) {
3006 protocol_error(c);
3007 return;
3008 }
3009 }
3010
3011 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3012 playback_stream *s;
3013
3014 s = pa_idxset_get_by_index(c->output_streams, idx);
3015 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3016 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3017
3018 p = s->sink_input->proplist;
3019
3020 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3021 record_stream *s;
3022
3023 s = pa_idxset_get_by_index(c->record_streams, idx);
3024 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3025
3026 p = s->source_output->proplist;
3027 } else {
3028 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3029
3030 p = c->client->proplist;
3031 }
3032
3033 for (;;) {
3034 const char *k;
3035
3036 if (pa_tagstruct_gets(t, &k) < 0) {
3037 protocol_error(c);
3038 pa_strlist_free(l);
3039 return;
3040 }
3041
3042 if (!k)
3043 break;
3044
3045 l = pa_strlist_prepend(l, k);
3046 }
3047
3048 if (!pa_tagstruct_eof(t)) {
3049 protocol_error(c);
3050 pa_strlist_free(l);
3051 return;
3052 }
3053
3054 for (;;) {
3055 char *z;
3056
3057 l = pa_strlist_pop(l, &z);
3058
3059 if (!z)
3060 break;
3061
3062 changed += pa_proplist_unset(p, z) >= 0;
3063 pa_xfree(z);
3064 }
3065
3066 pa_pstream_send_simple_ack(c->pstream, tag);
3067
3068 if (changed) {
3069 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3070 playback_stream *s;
3071
3072 s = pa_idxset_get_by_index(c->output_streams, idx);
3073 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
3074
3075 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3076 record_stream *s;
3077
3078 s = pa_idxset_get_by_index(c->record_streams, idx);
3079 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
3080
3081 } else {
3082 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3083 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
3084 }
3085 }
3086 }
3087
3088 static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3089 connection *c = CONNECTION(userdata);
3090 const char *s;
3091
3092 connection_assert_ref(c);
3093 pa_assert(t);
3094
3095 if (pa_tagstruct_gets(t, &s) < 0 ||
3096 !pa_tagstruct_eof(t)) {
3097 protocol_error(c);
3098 return;
3099 }
3100
3101 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3102 CHECK_VALIDITY(c->pstream, !s || (*s && pa_utf8_valid(s)), tag, PA_ERR_INVALID);
3103
3104 pa_namereg_set_default(c->protocol->core, s, command == PA_COMMAND_SET_DEFAULT_SOURCE ? PA_NAMEREG_SOURCE : PA_NAMEREG_SINK);
3105 pa_pstream_send_simple_ack(c->pstream, tag);
3106 }
3107
3108 static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3109 connection *c = CONNECTION(userdata);
3110 uint32_t idx;
3111 const char *name;
3112
3113 connection_assert_ref(c);
3114 pa_assert(t);
3115
3116 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3117 pa_tagstruct_gets(t, &name) < 0 ||
3118 !pa_tagstruct_eof(t)) {
3119 protocol_error(c);
3120 return;
3121 }
3122
3123 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3124 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
3125
3126 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
3127 playback_stream *s;
3128
3129 s = pa_idxset_get_by_index(c->output_streams, idx);
3130 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3131 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3132
3133 pa_sink_input_set_name(s->sink_input, name);
3134
3135 } else {
3136 record_stream *s;
3137 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
3138
3139 s = pa_idxset_get_by_index(c->record_streams, idx);
3140 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3141
3142 pa_source_output_set_name(s->source_output, name);
3143 }
3144
3145 pa_pstream_send_simple_ack(c->pstream, tag);
3146 }
3147
3148 static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3149 connection *c = CONNECTION(userdata);
3150 uint32_t idx;
3151
3152 connection_assert_ref(c);
3153 pa_assert(t);
3154
3155 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3156 !pa_tagstruct_eof(t)) {
3157 protocol_error(c);
3158 return;
3159 }
3160
3161 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3162
3163 if (command == PA_COMMAND_KILL_CLIENT) {
3164 pa_client *client;
3165
3166 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3167 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
3168
3169 connection_ref(c);
3170 pa_client_kill(client);
3171
3172 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
3173 pa_sink_input *s;
3174
3175 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3176 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3177
3178 connection_ref(c);
3179 pa_sink_input_kill(s);
3180 } else {
3181 pa_source_output *s;
3182
3183 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
3184
3185 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3186 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3187
3188 connection_ref(c);
3189 pa_source_output_kill(s);
3190 }
3191
3192 pa_pstream_send_simple_ack(c->pstream, tag);
3193 connection_unref(c);
3194 }
3195
3196 static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3197 connection *c = CONNECTION(userdata);
3198 pa_module *m;
3199 const char *name, *argument;
3200 pa_tagstruct *reply;
3201
3202 connection_assert_ref(c);
3203 pa_assert(t);
3204
3205 if (pa_tagstruct_gets(t, &name) < 0 ||
3206 pa_tagstruct_gets(t, &argument) < 0 ||
3207 !pa_tagstruct_eof(t)) {
3208 protocol_error(c);
3209 return;
3210 }
3211
3212 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3213 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
3214 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
3215
3216 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
3217 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
3218 return;
3219 }
3220
3221 reply = reply_new(tag);
3222 pa_tagstruct_putu32(reply, m->index);
3223 pa_pstream_send_tagstruct(c->pstream, reply);
3224 }
3225
3226 static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3227 connection *c = CONNECTION(userdata);
3228 uint32_t idx;
3229 pa_module *m;
3230
3231 connection_assert_ref(c);
3232 pa_assert(t);
3233
3234 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3235 !pa_tagstruct_eof(t)) {
3236 protocol_error(c);
3237 return;
3238 }
3239
3240 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3241 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3242 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
3243
3244 pa_module_unload_request(m);
3245 pa_pstream_send_simple_ack(c->pstream, tag);
3246 }
3247
3248 static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3249 connection *c = CONNECTION(userdata);
3250 const char *name, *module, *argument;
3251 uint32_t type;
3252 uint32_t idx;
3253 pa_tagstruct *reply;
3254
3255 connection_assert_ref(c);
3256 pa_assert(t);
3257
3258 if (pa_tagstruct_gets(t, &name) < 0 ||
3259 pa_tagstruct_getu32(t, &type) < 0 ||
3260 pa_tagstruct_gets(t, &module) < 0 ||
3261 pa_tagstruct_gets(t, &argument) < 0 ||
3262 !pa_tagstruct_eof(t)) {
3263 protocol_error(c);
3264 return;
3265 }
3266
3267 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3268 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
3269 CHECK_VALIDITY(c->pstream, type == 0 || type == 1, tag, PA_ERR_INVALID);
3270 CHECK_VALIDITY(c->pstream, module && *module && pa_utf8_valid(module), tag, PA_ERR_INVALID);
3271 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
3272
3273 if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &idx) < 0) {
3274 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
3275 return;
3276 }
3277
3278 reply = reply_new(tag);
3279 pa_tagstruct_putu32(reply, idx);
3280 pa_pstream_send_tagstruct(c->pstream, reply);
3281 }
3282
3283 static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3284 connection *c = CONNECTION(userdata);
3285 const char *name = NULL;
3286 uint32_t type, idx = PA_IDXSET_INVALID;
3287 int r;
3288
3289 connection_assert_ref(c);
3290 pa_assert(t);
3291
3292 if ((pa_tagstruct_getu32(t, &idx) < 0 &&
3293 (pa_tagstruct_gets(t, &name) < 0 ||
3294 pa_tagstruct_getu32(t, &type) < 0)) ||
3295 !pa_tagstruct_eof(t)) {
3296 protocol_error(c);
3297 return;
3298 }
3299
3300 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3301 CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID);
3302 CHECK_VALIDITY(c->pstream, !name || (*name && pa_utf8_valid(name) && (type == 0 || type == 1)), tag, PA_ERR_INVALID);
3303
3304 if (name)
3305 r = pa_autoload_remove_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE);
3306 else
3307 r = pa_autoload_remove_by_index(c->protocol->core, idx);
3308
3309 CHECK_VALIDITY(c->pstream, r >= 0, tag, PA_ERR_NOENTITY);
3310
3311 pa_pstream_send_simple_ack(c->pstream, tag);
3312 }
3313
3314 static void autoload_fill_tagstruct(pa_tagstruct *t, const pa_autoload_entry *e) {
3315 pa_assert(t && e);
3316
3317 pa_tagstruct_putu32(t, e->index);
3318 pa_tagstruct_puts(t, e->name);
3319 pa_tagstruct_putu32(t, e->type == PA_NAMEREG_SINK ? 0 : 1);
3320 pa_tagstruct_puts(t, e->module);
3321 pa_tagstruct_puts(t, e->argument);
3322 }
3323
3324 static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3325 connection *c = CONNECTION(userdata);
3326 const pa_autoload_entry *a = NULL;
3327 uint32_t type, idx;
3328 const char *name;
3329 pa_tagstruct *reply;
3330
3331 connection_assert_ref(c);
3332 pa_assert(t);
3333
3334 if ((pa_tagstruct_getu32(t, &idx) < 0 &&
3335 (pa_tagstruct_gets(t, &name) < 0 ||
3336 pa_tagstruct_getu32(t, &type) < 0)) ||
3337 !pa_tagstruct_eof(t)) {
3338 protocol_error(c);
3339 return;
3340 }
3341
3342 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3343 CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID);
3344 CHECK_VALIDITY(c->pstream, !name || (*name && (type == 0 || type == 1) && pa_utf8_valid(name)), tag, PA_ERR_INVALID);
3345
3346 if (name)
3347 a = pa_autoload_get_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE);
3348 else
3349 a = pa_autoload_get_by_index(c->protocol->core, idx);
3350
3351 CHECK_VALIDITY(c->pstream, a, tag, PA_ERR_NOENTITY);
3352
3353 reply = reply_new(tag);
3354 autoload_fill_tagstruct(reply, a);
3355 pa_pstream_send_tagstruct(c->pstream, reply);
3356 }
3357
3358 static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3359 connection *c = CONNECTION(userdata);
3360 pa_tagstruct *reply;
3361
3362 connection_assert_ref(c);
3363 pa_assert(t);
3364
3365 if (!pa_tagstruct_eof(t)) {
3366 protocol_error(c);
3367 return;
3368 }
3369
3370 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3371
3372 reply = reply_new(tag);
3373
3374 if (c->protocol->core->autoload_hashmap) {
3375 pa_autoload_entry *a;
3376 void *state = NULL;
3377
3378 while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state, NULL)))
3379 autoload_fill_tagstruct(reply, a);
3380 }
3381
3382 pa_pstream_send_tagstruct(c->pstream, reply);
3383 }
3384
3385 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3386 connection *c = CONNECTION(userdata);
3387 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
3388 const char *name = NULL;
3389
3390 connection_assert_ref(c);
3391 pa_assert(t);
3392
3393 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3394 pa_tagstruct_getu32(t, &idx_device) < 0 ||
3395 pa_tagstruct_gets(t, &name) < 0 ||
3396 !pa_tagstruct_eof(t)) {
3397 protocol_error(c);
3398 return;
3399 }
3400
3401 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3402 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3403 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID);
3404
3405 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
3406 pa_sink_input *si = NULL;
3407 pa_sink *sink = NULL;
3408
3409 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3410
3411 if (idx_device != PA_INVALID_INDEX)
3412 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
3413 else
3414 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
3415
3416 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
3417
3418 if (pa_sink_input_move_to(si, sink, 0) < 0) {
3419 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
3420 return;
3421 }
3422 } else {
3423 pa_source_output *so = NULL;
3424 pa_source *source;
3425
3426 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
3427
3428 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3429
3430 if (idx_device != PA_INVALID_INDEX)
3431 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
3432 else
3433 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1);
3434
3435 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
3436
3437 if (pa_source_output_move_to(so, source) < 0) {
3438 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
3439 return;
3440 }
3441 }
3442
3443 pa_pstream_send_simple_ack(c->pstream, tag);
3444 }
3445
3446 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3447 connection *c = CONNECTION(userdata);
3448 uint32_t idx = PA_INVALID_INDEX;
3449 const char *name = NULL;
3450 pa_bool_t b;
3451
3452 connection_assert_ref(c);
3453 pa_assert(t);
3454
3455 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3456 pa_tagstruct_gets(t, &name) < 0 ||
3457 pa_tagstruct_get_boolean(t, &b) < 0 ||
3458 !pa_tagstruct_eof(t)) {
3459 protocol_error(c);
3460 return;
3461 }
3462
3463 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3464 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || !*name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
3465
3466 if (command == PA_COMMAND_SUSPEND_SINK) {
3467
3468 if (idx == PA_INVALID_INDEX && name && !*name) {
3469
3470 if (pa_sink_suspend_all(c->protocol->core, b) < 0) {
3471 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
3472 return;
3473 }
3474 } else {
3475 pa_sink *sink = NULL;
3476
3477 if (idx != PA_INVALID_INDEX)
3478 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3479 else
3480 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
3481
3482 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3483
3484 if (pa_sink_suspend(sink, b) < 0) {
3485 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
3486 return;
3487 }
3488 }
3489 } else {
3490
3491 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
3492
3493 if (idx == PA_INVALID_INDEX && name && !*name) {
3494
3495 if (pa_source_suspend_all(c->protocol->core, b) < 0) {
3496 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
3497 return;
3498 }
3499
3500 } else {
3501 pa_source *source;
3502
3503 if (idx != PA_INVALID_INDEX)
3504 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3505 else
3506 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1);
3507
3508 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
3509
3510 if (pa_source_suspend(source, b) < 0) {
3511 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
3512 return;
3513 }
3514 }
3515 }
3516
3517 pa_pstream_send_simple_ack(c->pstream, tag);
3518 }
3519
3520 /*** pstream callbacks ***/
3521
3522 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
3523 connection *c = CONNECTION(userdata);
3524
3525 pa_assert(p);
3526 pa_assert(packet);
3527 connection_assert_ref(c);
3528
3529 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
3530 pa_log("invalid packet.");
3531 connection_unlink(c);
3532 }
3533 }
3534
3535 static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) {
3536 connection *c = CONNECTION(userdata);
3537 output_stream *stream;
3538
3539 pa_assert(p);
3540 pa_assert(chunk);
3541 connection_assert_ref(c);
3542
3543 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
3544 pa_log("client sent block for invalid stream.");
3545 /* Ignoring */
3546 return;
3547 }
3548
3549 if (playback_stream_isinstance(stream)) {
3550 playback_stream *ps = PLAYBACK_STREAM(stream);
3551
3552 if (seek != PA_SEEK_RELATIVE || offset != 0)
3553 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, NULL, NULL);
3554
3555 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
3556
3557 } else {
3558 upload_stream *u = UPLOAD_STREAM(stream);
3559 size_t l;
3560
3561 if (!u->memchunk.memblock) {
3562 if (u->length == chunk->length) {
3563 u->memchunk = *chunk;
3564 pa_memblock_ref(u->memchunk.memblock);
3565 u->length = 0;
3566 } else {
3567 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
3568 u->memchunk.index = u->memchunk.length = 0;
3569 }
3570 }
3571
3572 pa_assert(u->memchunk.memblock);
3573
3574 l = u->length;
3575 if (l > chunk->length)
3576 l = chunk->length;
3577
3578
3579 if (l > 0) {
3580 void *src, *dst;
3581 dst = pa_memblock_acquire(u->memchunk.memblock);
3582 src = pa_memblock_acquire(chunk->memblock);
3583
3584 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
3585 (uint8_t*) src+chunk->index, l);
3586
3587 pa_memblock_release(u->memchunk.memblock);
3588 pa_memblock_release(chunk->memblock);
3589
3590 u->memchunk.length += l;
3591 u->length -= l;
3592 }
3593 }
3594 }
3595
3596 static void pstream_die_callback(pa_pstream *p, void *userdata) {
3597 connection *c = CONNECTION(userdata);
3598
3599 pa_assert(p);
3600 connection_assert_ref(c);
3601
3602 connection_unlink(c);
3603 pa_log_info("connection died.");
3604 }
3605
3606 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
3607 connection *c = CONNECTION(userdata);
3608
3609 pa_assert(p);
3610 connection_assert_ref(c);
3611
3612 send_memblock(c);
3613 }
3614
3615 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
3616 pa_thread_mq *q;
3617
3618 if (!(q = pa_thread_mq_get()))
3619 pa_pstream_send_revoke(p, block_id);
3620 else
3621 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
3622 }
3623
3624 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
3625 pa_thread_mq *q;
3626
3627 if (!(q = pa_thread_mq_get()))
3628 pa_pstream_send_release(p, block_id);
3629 else
3630 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
3631 }
3632
3633 /*** client callbacks ***/
3634
3635 static void client_kill_cb(pa_client *c) {
3636 pa_assert(c);
3637
3638 connection_unlink(CONNECTION(c->userdata));
3639 }
3640
3641 /*** socket server callbacks ***/
3642
3643 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
3644 connection *c = CONNECTION(userdata);
3645
3646 pa_assert(m);
3647 pa_assert(tv);
3648 connection_assert_ref(c);
3649 pa_assert(c->auth_timeout_event == e);
3650
3651 if (!c->authorized)
3652 connection_unlink(c);
3653 }
3654
3655 static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, void *userdata) {
3656 pa_protocol_native *p = userdata;
3657 connection *c;
3658 char cname[256], pname[128];
3659
3660 pa_assert(s);
3661 pa_assert(io);
3662 pa_assert(p);
3663
3664 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
3665 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
3666 pa_iochannel_free(io);
3667 return;
3668 }
3669
3670 c = pa_msgobject_new(connection);
3671 c->parent.parent.free = connection_free;
3672 c->parent.process_msg = connection_process_msg;
3673
3674 c->authorized = p->public;
3675
3676 if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
3677 pa_log_info("Client authenticated by IP ACL.");
3678 c->authorized = TRUE;
3679 }
3680
3681 if (!c->authorized) {
3682 struct timeval tv;
3683 pa_gettimeofday(&tv);
3684 tv.tv_sec += AUTH_TIMEOUT;
3685 c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c);
3686 } else
3687 c->auth_timeout_event = NULL;
3688
3689 c->version = 8;
3690 c->protocol = p;
3691 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
3692 pa_snprintf(cname, sizeof(cname), "Native client (%s)", pname);
3693 c->client = pa_client_new(p->core, __FILE__, cname);
3694 c->client->kill = client_kill_cb;
3695 c->client->userdata = c;
3696 c->client->module = p->module;
3697
3698 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
3699
3700 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
3701 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
3702 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
3703 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
3704 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
3705 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
3706
3707 c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX);
3708
3709 c->record_streams = pa_idxset_new(NULL, NULL);
3710 c->output_streams = pa_idxset_new(NULL, NULL);
3711
3712 c->rrobin_index = PA_IDXSET_INVALID;
3713 c->subscription = NULL;
3714
3715 pa_idxset_put(p->connections, c, NULL);
3716
3717 #ifdef HAVE_CREDS
3718 if (pa_iochannel_creds_supported(io))
3719 pa_iochannel_creds_enable(io);
3720
3721 #endif
3722 }
3723
3724 /*** module entry points ***/
3725
3726 static int load_key(pa_protocol_native*p, const char*fn) {
3727 pa_assert(p);
3728
3729 p->auth_cookie_in_property = FALSE;
3730
3731 if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) {
3732 pa_log_info("using already loaded auth cookie.");
3733 pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
3734 p->auth_cookie_in_property = TRUE;
3735 return 0;
3736 }
3737
3738 if (!fn)
3739 fn = PA_NATIVE_COOKIE_FILE;
3740
3741 if (pa_authkey_load_auto(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0)
3742 return -1;
3743
3744 pa_log_info("loading cookie from disk.");
3745
3746 if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0)
3747 p->auth_cookie_in_property = TRUE;
3748
3749 return 0;
3750 }
3751
3752 static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_modargs *ma) {
3753 pa_protocol_native *p;
3754 pa_bool_t public = FALSE;
3755 const char *acl;
3756
3757 pa_assert(c);
3758 pa_assert(ma);
3759
3760 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) {
3761 pa_log("auth-anonymous= expects a boolean argument.");
3762 return NULL;
3763 }
3764
3765 p = pa_xnew(pa_protocol_native, 1);
3766 p->core = c;
3767 p->module = m;
3768 p->public = public;
3769 p->server = NULL;
3770 p->auth_ip_acl = NULL;
3771
3772 #ifdef HAVE_CREDS
3773 {
3774 pa_bool_t a = 1;
3775 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &a) < 0) {
3776 pa_log("auth-group-enabled= expects a boolean argument.");
3777 return NULL;
3778 }
3779 p->auth_group = a ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", c->is_system_instance ? PA_ACCESS_GROUP : NULL)) : NULL;
3780
3781 if (p->auth_group)
3782 pa_log_info("Allowing access to group '%s'.", p->auth_group);
3783 }
3784 #endif
3785
3786
3787 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
3788
3789 if (!(p->auth_ip_acl = pa_ip_acl_new(acl))) {
3790 pa_log("Failed to parse IP ACL '%s'", acl);
3791 goto fail;
3792 }
3793 }
3794
3795 if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0)
3796 goto fail;
3797
3798 p->connections = pa_idxset_new(NULL, NULL);
3799
3800 return p;
3801
3802 fail:
3803 #ifdef HAVE_CREDS
3804 pa_xfree(p->auth_group);
3805 #endif
3806 if (p->auth_ip_acl)
3807 pa_ip_acl_free(p->auth_ip_acl);
3808 pa_xfree(p);
3809 return NULL;
3810 }
3811
3812 pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
3813 char t[256];
3814 pa_protocol_native *p;
3815
3816 if (!(p = protocol_new_internal(core, m, ma)))
3817 return NULL;
3818
3819 p->server = server;
3820 pa_socket_server_set_callback(p->server, on_connection, p);
3821
3822 if (pa_socket_server_get_address(p->server, t, sizeof(t))) {
3823 pa_strlist *l;
3824 l = pa_property_get(core, PA_NATIVE_SERVER_PROPERTY_NAME);
3825 l = pa_strlist_prepend(l, t);
3826 pa_property_replace(core, PA_NATIVE_SERVER_PROPERTY_NAME, l);
3827 }
3828
3829 return p;
3830 }
3831
3832 void pa_protocol_native_free(pa_protocol_native *p) {
3833 connection *c;
3834 pa_assert(p);
3835
3836 while ((c = pa_idxset_first(p->connections, NULL)))
3837 connection_unlink(c);
3838 pa_idxset_free(p->connections, NULL, NULL);
3839
3840 if (p->server) {
3841 char t[256];
3842
3843 if (pa_socket_server_get_address(p->server, t, sizeof(t))) {
3844 pa_strlist *l;
3845 l = pa_property_get(p->core, PA_NATIVE_SERVER_PROPERTY_NAME);
3846 l = pa_strlist_remove(l, t);
3847
3848 if (l)
3849 pa_property_replace(p->core, PA_NATIVE_SERVER_PROPERTY_NAME, l);
3850 else
3851 pa_property_remove(p->core, PA_NATIVE_SERVER_PROPERTY_NAME);
3852 }
3853
3854 pa_socket_server_unref(p->server);
3855 }
3856
3857 if (p->auth_cookie_in_property)
3858 pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
3859
3860 if (p->auth_ip_acl)
3861 pa_ip_acl_free(p->auth_ip_acl);
3862
3863 #ifdef HAVE_CREDS
3864 pa_xfree(p->auth_group);
3865 #endif
3866 pa_xfree(p);
3867 }
3868
3869 pa_protocol_native* pa_protocol_native_new_iochannel(
3870 pa_core*core,
3871 pa_iochannel *io,
3872 pa_module *m,
3873 pa_modargs *ma) {
3874
3875 pa_protocol_native *p;
3876
3877 if (!(p = protocol_new_internal(core, m, ma)))
3878 return NULL;
3879
3880 on_connection(NULL, io, p);
3881
3882 return p;
3883 }