]> code.delx.au - pulseaudio/blob - src/pulsecore/protocol-native.c
native: rework handling of seeks that depend on variables the client does not know...
[pulseaudio] / src / pulsecore / protocol-native.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31
32 #include <pulse/rtclock.h>
33 #include <pulse/timeval.h>
34 #include <pulse/version.h>
35 #include <pulse/utf8.h>
36 #include <pulse/util.h>
37 #include <pulse/xmalloc.h>
38
39 #include <pulsecore/native-common.h>
40 #include <pulsecore/packet.h>
41 #include <pulsecore/client.h>
42 #include <pulsecore/source-output.h>
43 #include <pulsecore/sink-input.h>
44 #include <pulsecore/pstream.h>
45 #include <pulsecore/tagstruct.h>
46 #include <pulsecore/pdispatch.h>
47 #include <pulsecore/pstream-util.h>
48 #include <pulsecore/authkey.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/core-scache.h>
51 #include <pulsecore/core-subscribe.h>
52 #include <pulsecore/log.h>
53 #include <pulsecore/strlist.h>
54 #include <pulsecore/shared.h>
55 #include <pulsecore/sample-util.h>
56 #include <pulsecore/llist.h>
57 #include <pulsecore/creds.h>
58 #include <pulsecore/core-util.h>
59 #include <pulsecore/ipacl.h>
60 #include <pulsecore/thread-mq.h>
61
62 #include "protocol-native.h"
63
64 /* Kick a client if it doesn't authenticate within this time */
65 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
66
67 /* Don't accept more connection than this */
68 #define MAX_CONNECTIONS 64
69
70 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
71 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
72 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
73 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
74
75 struct pa_native_protocol;
76
77 typedef struct record_stream {
78 pa_msgobject parent;
79
80 pa_native_connection *connection;
81 uint32_t index;
82
83 pa_source_output *source_output;
84 pa_memblockq *memblockq;
85
86 pa_bool_t adjust_latency:1;
87 pa_bool_t early_requests:1;
88
89 pa_buffer_attr buffer_attr;
90
91 pa_atomic_t on_the_fly;
92 pa_usec_t configured_source_latency;
93 size_t drop_initial;
94
95 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
96 size_t on_the_fly_snapshot;
97 pa_usec_t current_monitor_latency;
98 pa_usec_t current_source_latency;
99 } record_stream;
100
101 #define RECORD_STREAM(o) (record_stream_cast(o))
102 PA_DEFINE_PRIVATE_CLASS(record_stream, pa_msgobject);
103
104 typedef struct output_stream {
105 pa_msgobject parent;
106 } output_stream;
107
108 #define OUTPUT_STREAM(o) (output_stream_cast(o))
109 PA_DEFINE_PRIVATE_CLASS(output_stream, pa_msgobject);
110
111 typedef struct playback_stream {
112 output_stream parent;
113
114 pa_native_connection *connection;
115 uint32_t index;
116
117 pa_sink_input *sink_input;
118 pa_memblockq *memblockq;
119
120 pa_bool_t adjust_latency:1;
121 pa_bool_t early_requests:1;
122
123 pa_bool_t is_underrun:1;
124 pa_bool_t drain_request:1;
125 uint32_t drain_tag;
126 uint32_t syncid;
127
128 pa_atomic_t missing;
129 pa_usec_t configured_sink_latency;
130 pa_buffer_attr buffer_attr;
131
132 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
133 int64_t read_index, write_index;
134 size_t render_memblockq_length;
135 pa_usec_t current_sink_latency;
136 uint64_t playing_for, underrun_for;
137 } playback_stream;
138
139 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
140 PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
141
142 typedef struct upload_stream {
143 output_stream parent;
144
145 pa_native_connection *connection;
146 uint32_t index;
147
148 pa_memchunk memchunk;
149 size_t length;
150 char *name;
151 pa_sample_spec sample_spec;
152 pa_channel_map channel_map;
153 pa_proplist *proplist;
154 } upload_stream;
155
156 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
157 PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
158
159 struct pa_native_connection {
160 pa_msgobject parent;
161 pa_native_protocol *protocol;
162 pa_native_options *options;
163 pa_bool_t authorized:1;
164 pa_bool_t is_local:1;
165 uint32_t version;
166 pa_client *client;
167 pa_pstream *pstream;
168 pa_pdispatch *pdispatch;
169 pa_idxset *record_streams, *output_streams;
170 uint32_t rrobin_index;
171 pa_subscription *subscription;
172 pa_time_event *auth_timeout_event;
173 };
174
175 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
176 PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
177
178 struct pa_native_protocol {
179 PA_REFCNT_DECLARE;
180
181 pa_core *core;
182 pa_idxset *connections;
183
184 pa_strlist *servers;
185 pa_hook hooks[PA_NATIVE_HOOK_MAX];
186
187 pa_hashmap *extensions;
188 };
189
190 enum {
191 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
192 };
193
194 enum {
195 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
196 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
197 SINK_INPUT_MESSAGE_FLUSH,
198 SINK_INPUT_MESSAGE_TRIGGER,
199 SINK_INPUT_MESSAGE_SEEK,
200 SINK_INPUT_MESSAGE_PREBUF_FORCE,
201 SINK_INPUT_MESSAGE_UPDATE_LATENCY,
202 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
203 };
204
205 enum {
206 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
207 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
208 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
209 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
210 PLAYBACK_STREAM_MESSAGE_STARTED,
211 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
212 };
213
214 enum {
215 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
216 };
217
218 enum {
219 CONNECTION_MESSAGE_RELEASE,
220 CONNECTION_MESSAGE_REVOKE
221 };
222
223 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
224 static void sink_input_kill_cb(pa_sink_input *i);
225 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
226 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
227 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
228 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
229 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
230 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
231
232 static void native_connection_send_memblock(pa_native_connection *c);
233 static void playback_stream_request_bytes(struct playback_stream*s);
234
235 static void source_output_kill_cb(pa_source_output *o);
236 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
237 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend);
238 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
239 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
240 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
241
242 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
243 static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
244
245 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
246 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
247 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
248 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
249 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
250 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
251 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
252 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
253 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
254 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
255 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
256 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
257 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
258 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
259 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
260 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
261 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
262 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
263 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
264 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
265 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
266 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
267 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
268 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
269 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
270 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
271 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
272 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
273 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
274 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
275 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
276 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
277 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
278 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
279 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
280 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
281 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
282 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
283 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
284
285 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
286 [PA_COMMAND_ERROR] = NULL,
287 [PA_COMMAND_TIMEOUT] = NULL,
288 [PA_COMMAND_REPLY] = NULL,
289 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
290 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
291 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
292 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
293 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
294 [PA_COMMAND_AUTH] = command_auth,
295 [PA_COMMAND_REQUEST] = NULL,
296 [PA_COMMAND_EXIT] = command_exit,
297 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
298 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
299 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
300 [PA_COMMAND_STAT] = command_stat,
301 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
302 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
303 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
304 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
305 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
306 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
307 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
308 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
309 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
310 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
311 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
312 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
313 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
314 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
315 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
316 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
317 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
318 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
319 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
320 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
321 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
322 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
323 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
324 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
325 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
326
327 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
328 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
329 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
330
331 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
332 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
333 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
334
335 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
336 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
337
338 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
339 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
340 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
341 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
342
343 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
344 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
345
346 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
347 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
348 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
349 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
350 [PA_COMMAND_KILL_CLIENT] = command_kill,
351 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
352 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
353 [PA_COMMAND_LOAD_MODULE] = command_load_module,
354 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
355
356 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
357 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
358 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
359 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
360
361 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
362 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
363
364 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
365 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
366
367 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
368 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
369
370 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
371 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
372 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
373
374 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
375 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
376 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
377
378 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
379
380 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
381 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
382
383 [PA_COMMAND_EXTENSION] = command_extension
384 };
385
386 /* structure management */
387
388 /* Called from main context */
389 static void upload_stream_unlink(upload_stream *s) {
390 pa_assert(s);
391
392 if (!s->connection)
393 return;
394
395 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
396 s->connection = NULL;
397 upload_stream_unref(s);
398 }
399
400 /* Called from main context */
401 static void upload_stream_free(pa_object *o) {
402 upload_stream *s = UPLOAD_STREAM(o);
403 pa_assert(s);
404
405 upload_stream_unlink(s);
406
407 pa_xfree(s->name);
408
409 if (s->proplist)
410 pa_proplist_free(s->proplist);
411
412 if (s->memchunk.memblock)
413 pa_memblock_unref(s->memchunk.memblock);
414
415 pa_xfree(s);
416 }
417
418 /* Called from main context */
419 static upload_stream* upload_stream_new(
420 pa_native_connection *c,
421 const pa_sample_spec *ss,
422 const pa_channel_map *map,
423 const char *name,
424 size_t length,
425 pa_proplist *p) {
426
427 upload_stream *s;
428
429 pa_assert(c);
430 pa_assert(ss);
431 pa_assert(name);
432 pa_assert(length > 0);
433 pa_assert(p);
434
435 s = pa_msgobject_new(upload_stream);
436 s->parent.parent.parent.free = upload_stream_free;
437 s->connection = c;
438 s->sample_spec = *ss;
439 s->channel_map = *map;
440 s->name = pa_xstrdup(name);
441 pa_memchunk_reset(&s->memchunk);
442 s->length = length;
443 s->proplist = pa_proplist_copy(p);
444 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
445
446 pa_idxset_put(c->output_streams, s, &s->index);
447
448 return s;
449 }
450
451 /* Called from main context */
452 static void record_stream_unlink(record_stream *s) {
453 pa_assert(s);
454
455 if (!s->connection)
456 return;
457
458 if (s->source_output) {
459 pa_source_output_unlink(s->source_output);
460 pa_source_output_unref(s->source_output);
461 s->source_output = NULL;
462 }
463
464 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
465 s->connection = NULL;
466 record_stream_unref(s);
467 }
468
469 /* Called from main context */
470 static void record_stream_free(pa_object *o) {
471 record_stream *s = RECORD_STREAM(o);
472 pa_assert(s);
473
474 record_stream_unlink(s);
475
476 pa_memblockq_free(s->memblockq);
477 pa_xfree(s);
478 }
479
480 /* Called from main context */
481 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
482 record_stream *s = RECORD_STREAM(o);
483 record_stream_assert_ref(s);
484
485 if (!s->connection)
486 return -1;
487
488 switch (code) {
489
490 case RECORD_STREAM_MESSAGE_POST_DATA:
491
492 /* We try to keep up to date with how many bytes are
493 * currently on the fly */
494 pa_atomic_sub(&s->on_the_fly, chunk->length);
495
496 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
497 /* pa_log_warn("Failed to push data into output queue."); */
498 return -1;
499 }
500
501 if (!pa_pstream_is_pending(s->connection->pstream))
502 native_connection_send_memblock(s->connection);
503
504 break;
505 }
506
507 return 0;
508 }
509
510 /* Called from main context */
511 static void fix_record_buffer_attr_pre(record_stream *s) {
512
513 size_t frame_size;
514 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
515
516 pa_assert(s);
517
518 /* This function will be called from the main thread, before as
519 * well as after the source output has been activated using
520 * pa_source_output_put()! That means it may not touch any
521 * ->thread_info data! */
522
523 frame_size = pa_frame_size(&s->source_output->sample_spec);
524
525 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
526 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
527 if (s->buffer_attr.maxlength <= 0)
528 s->buffer_attr.maxlength = (uint32_t) frame_size;
529
530 if (s->buffer_attr.fragsize == (uint32_t) -1)
531 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
532 if (s->buffer_attr.fragsize <= 0)
533 s->buffer_attr.fragsize = (uint32_t) frame_size;
534
535 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
536
537 if (s->early_requests) {
538
539 /* In early request mode we need to emulate the classic
540 * fragment-based playback model. We do this setting the source
541 * latency to the fragment size. */
542
543 source_usec = fragsize_usec;
544
545 } else if (s->adjust_latency) {
546
547 /* So, the user asked us to adjust the latency according to
548 * what the source can provide. Half the latency will be
549 * spent on the hw buffer, half of it in the async buffer
550 * queue we maintain for each client. */
551
552 source_usec = fragsize_usec/2;
553
554 } else {
555
556 /* Ok, the user didn't ask us to adjust the latency, hence we
557 * don't */
558
559 source_usec = (pa_usec_t) -1;
560 }
561
562 if (source_usec != (pa_usec_t) -1)
563 s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
564 else
565 s->configured_source_latency = 0;
566
567 if (s->early_requests) {
568
569 /* Ok, we didn't necessarily get what we were asking for, so
570 * let's tell the user */
571
572 fragsize_usec = s->configured_source_latency;
573
574 } else if (s->adjust_latency) {
575
576 /* Now subtract what we actually got */
577
578 if (fragsize_usec >= s->configured_source_latency*2)
579 fragsize_usec -= s->configured_source_latency;
580 else
581 fragsize_usec = s->configured_source_latency;
582 }
583
584 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
585 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
586
587 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
588
589 if (s->buffer_attr.fragsize <= 0)
590 s->buffer_attr.fragsize = (uint32_t) frame_size;
591 }
592
593 /* Called from main context */
594 static void fix_record_buffer_attr_post(record_stream *s) {
595 size_t base;
596
597 pa_assert(s);
598
599 /* This function will be called from the main thread, before as
600 * well as after the source output has been activated using
601 * pa_source_output_put()! That means it may not touch and
602 * ->thread_info data! */
603
604 base = pa_frame_size(&s->source_output->sample_spec);
605
606 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
607 if (s->buffer_attr.fragsize <= 0)
608 s->buffer_attr.fragsize = base;
609
610 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
611 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
612 }
613
614 /* Called from main context */
615 static record_stream* record_stream_new(
616 pa_native_connection *c,
617 pa_source *source,
618 pa_sample_spec *ss,
619 pa_channel_map *map,
620 pa_bool_t peak_detect,
621 pa_buffer_attr *attr,
622 pa_source_output_flags_t flags,
623 pa_proplist *p,
624 pa_bool_t adjust_latency,
625 pa_sink_input *direct_on_input,
626 pa_bool_t early_requests,
627 int *ret) {
628
629 record_stream *s;
630 pa_source_output *source_output = NULL;
631 pa_source_output_new_data data;
632
633 pa_assert(c);
634 pa_assert(ss);
635 pa_assert(p);
636 pa_assert(ret);
637
638 pa_source_output_new_data_init(&data);
639
640 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
641 data.driver = __FILE__;
642 data.module = c->options->module;
643 data.client = c->client;
644 data.source = source;
645 data.direct_on_input = direct_on_input;
646 pa_source_output_new_data_set_sample_spec(&data, ss);
647 pa_source_output_new_data_set_channel_map(&data, map);
648 if (peak_detect)
649 data.resample_method = PA_RESAMPLER_PEAKS;
650 data.flags = flags;
651
652 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
653
654 pa_source_output_new_data_done(&data);
655
656 if (!source_output)
657 return NULL;
658
659 s = pa_msgobject_new(record_stream);
660 s->parent.parent.free = record_stream_free;
661 s->parent.process_msg = record_stream_process_msg;
662 s->connection = c;
663 s->source_output = source_output;
664 s->buffer_attr = *attr;
665 s->adjust_latency = adjust_latency;
666 s->early_requests = early_requests;
667 pa_atomic_store(&s->on_the_fly, 0);
668
669 s->source_output->parent.process_msg = source_output_process_msg;
670 s->source_output->push = source_output_push_cb;
671 s->source_output->kill = source_output_kill_cb;
672 s->source_output->get_latency = source_output_get_latency_cb;
673 s->source_output->moving = source_output_moving_cb;
674 s->source_output->suspend = source_output_suspend_cb;
675 s->source_output->send_event = source_output_send_event_cb;
676 s->source_output->userdata = s;
677
678 fix_record_buffer_attr_pre(s);
679
680 s->memblockq = pa_memblockq_new(
681 0,
682 s->buffer_attr.maxlength,
683 0,
684 pa_frame_size(&source_output->sample_spec),
685 1,
686 0,
687 0,
688 NULL);
689
690 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
691 fix_record_buffer_attr_post(s);
692
693 *ss = s->source_output->sample_spec;
694 *map = s->source_output->channel_map;
695
696 pa_idxset_put(c->record_streams, s, &s->index);
697
698 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
699 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
700 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
701 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
702
703 pa_source_output_put(s->source_output);
704 return s;
705 }
706
707 /* Called from main context */
708 static void record_stream_send_killed(record_stream *r) {
709 pa_tagstruct *t;
710 record_stream_assert_ref(r);
711
712 t = pa_tagstruct_new(NULL, 0);
713 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
714 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
715 pa_tagstruct_putu32(t, r->index);
716 pa_pstream_send_tagstruct(r->connection->pstream, t);
717 }
718
719 /* Called from main context */
720 static void playback_stream_unlink(playback_stream *s) {
721 pa_assert(s);
722
723 if (!s->connection)
724 return;
725
726 if (s->sink_input) {
727 pa_sink_input_unlink(s->sink_input);
728 pa_sink_input_unref(s->sink_input);
729 s->sink_input = NULL;
730 }
731
732 if (s->drain_request)
733 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
734
735 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
736 s->connection = NULL;
737 playback_stream_unref(s);
738 }
739
740 /* Called from main context */
741 static void playback_stream_free(pa_object* o) {
742 playback_stream *s = PLAYBACK_STREAM(o);
743 pa_assert(s);
744
745 playback_stream_unlink(s);
746
747 pa_memblockq_free(s->memblockq);
748 pa_xfree(s);
749 }
750
751 /* Called from main context */
752 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
753 playback_stream *s = PLAYBACK_STREAM(o);
754 playback_stream_assert_ref(s);
755
756 if (!s->connection)
757 return -1;
758
759 switch (code) {
760
761 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
762 pa_tagstruct *t;
763 int l = 0;
764
765 for (;;) {
766 if ((l = pa_atomic_load(&s->missing)) <= 0)
767 return 0;
768
769 if (pa_atomic_cmpxchg(&s->missing, l, 0))
770 break;
771 }
772
773 t = pa_tagstruct_new(NULL, 0);
774 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
775 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
776 pa_tagstruct_putu32(t, s->index);
777 pa_tagstruct_putu32(t, (uint32_t) l);
778 pa_pstream_send_tagstruct(s->connection->pstream, t);
779
780 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
781 break;
782 }
783
784 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
785 pa_tagstruct *t;
786
787 /* pa_log("signalling underflow"); */
788
789 /* Report that we're empty */
790 t = pa_tagstruct_new(NULL, 0);
791 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
792 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
793 pa_tagstruct_putu32(t, s->index);
794 pa_pstream_send_tagstruct(s->connection->pstream, t);
795 break;
796 }
797
798 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
799 pa_tagstruct *t;
800
801 /* Notify the user we're overflowed*/
802 t = pa_tagstruct_new(NULL, 0);
803 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
804 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
805 pa_tagstruct_putu32(t, s->index);
806 pa_pstream_send_tagstruct(s->connection->pstream, t);
807 break;
808 }
809
810 case PLAYBACK_STREAM_MESSAGE_STARTED:
811
812 if (s->connection->version >= 13) {
813 pa_tagstruct *t;
814
815 /* Notify the user we started playback */
816 t = pa_tagstruct_new(NULL, 0);
817 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
818 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
819 pa_tagstruct_putu32(t, s->index);
820 pa_pstream_send_tagstruct(s->connection->pstream, t);
821 }
822
823 break;
824
825 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
826 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
827 break;
828
829 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
830
831 s->buffer_attr.tlength = (uint32_t) offset;
832
833 if (s->connection->version >= 15) {
834 pa_tagstruct *t;
835
836 t = pa_tagstruct_new(NULL, 0);
837 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
838 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
839 pa_tagstruct_putu32(t, s->index);
840 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
841 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
842 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
843 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
844 pa_tagstruct_put_usec(t, s->configured_sink_latency);
845 pa_pstream_send_tagstruct(s->connection->pstream, t);
846 }
847
848 break;
849 }
850
851 return 0;
852 }
853
854 /* Called from main context */
855 static void fix_playback_buffer_attr(playback_stream *s) {
856 size_t frame_size, max_prebuf;
857 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
858
859 pa_assert(s);
860
861 /* This function will be called from the main thread, before as
862 * well as after the sink input has been activated using
863 * pa_sink_input_put()! That means it may not touch any
864 * ->thread_info data, such as the memblockq! */
865
866 frame_size = pa_frame_size(&s->sink_input->sample_spec);
867
868 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
869 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
870 if (s->buffer_attr.maxlength <= 0)
871 s->buffer_attr.maxlength = (uint32_t) frame_size;
872
873 if (s->buffer_attr.tlength == (uint32_t) -1)
874 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
875 if (s->buffer_attr.tlength <= 0)
876 s->buffer_attr.tlength = (uint32_t) frame_size;
877
878 if (s->buffer_attr.minreq == (uint32_t) -1)
879 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
880 if (s->buffer_attr.minreq <= 0)
881 s->buffer_attr.minreq = (uint32_t) frame_size;
882
883 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
884 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
885
886 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
887 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
888
889 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
890 (double) tlength_usec / PA_USEC_PER_MSEC,
891 (double) minreq_usec / PA_USEC_PER_MSEC);
892
893 if (s->early_requests) {
894
895 /* In early request mode we need to emulate the classic
896 * fragment-based playback model. We do this setting the sink
897 * latency to the fragment size. */
898
899 sink_usec = minreq_usec;
900 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
901
902 } else if (s->adjust_latency) {
903
904 /* So, the user asked us to adjust the latency of the stream
905 * buffer according to the what the sink can provide. The
906 * tlength passed in shall be the overall latency. Roughly
907 * half the latency will be spent on the hw buffer, the other
908 * half of it in the async buffer queue we maintain for each
909 * client. In between we'll have a safety space of size
910 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
911 * empty and needs to be filled, then our buffer must have
912 * enough data to fulfill this request immediatly and thus
913 * have at least the same tlength as the size of the hw
914 * buffer. It additionally needs space for 2 times minreq
915 * because if the buffer ran empty and a partial fillup
916 * happens immediately on the next iteration we need to be
917 * able to fulfill it and give the application also minreq
918 * time to fill it up again for the next request Makes 2 times
919 * minreq in plus.. */
920
921 if (tlength_usec > minreq_usec*2)
922 sink_usec = (tlength_usec - minreq_usec*2)/2;
923 else
924 sink_usec = 0;
925
926 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
927
928 } else {
929
930 /* Ok, the user didn't ask us to adjust the latency, but we
931 * still need to make sure that the parameters from the user
932 * do make sense. */
933
934 if (tlength_usec > minreq_usec*2)
935 sink_usec = (tlength_usec - minreq_usec*2);
936 else
937 sink_usec = 0;
938
939 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
940 }
941
942 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
943
944 if (s->early_requests) {
945
946 /* Ok, we didn't necessarily get what we were asking for, so
947 * let's tell the user */
948
949 minreq_usec = s->configured_sink_latency;
950
951 } else if (s->adjust_latency) {
952
953 /* Ok, we didn't necessarily get what we were asking for, so
954 * let's subtract from what we asked for for the remaining
955 * buffer space */
956
957 if (tlength_usec >= s->configured_sink_latency)
958 tlength_usec -= s->configured_sink_latency;
959 }
960
961 /* FIXME: This is actually larger than necessary, since not all of
962 * the sink latency is actually rewritable. */
963 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
964 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
965
966 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
967 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
968 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
969
970 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
971 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
972 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
973
974 if (s->buffer_attr.minreq <= 0) {
975 s->buffer_attr.minreq = (uint32_t) frame_size;
976 s->buffer_attr.tlength += (uint32_t) frame_size*2;
977 }
978
979 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
980 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
981
982 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
983
984 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
985 s->buffer_attr.prebuf > max_prebuf)
986 s->buffer_attr.prebuf = max_prebuf;
987 }
988
989 /* Called from main context */
990 static playback_stream* playback_stream_new(
991 pa_native_connection *c,
992 pa_sink *sink,
993 pa_sample_spec *ss,
994 pa_channel_map *map,
995 pa_buffer_attr *a,
996 pa_cvolume *volume,
997 pa_bool_t muted,
998 pa_bool_t muted_set,
999 uint32_t syncid,
1000 uint32_t *missing,
1001 pa_sink_input_flags_t flags,
1002 pa_proplist *p,
1003 pa_bool_t adjust_latency,
1004 pa_bool_t early_requests,
1005 pa_bool_t relative_volume,
1006 int *ret) {
1007
1008 playback_stream *s, *ssync;
1009 pa_sink_input *sink_input = NULL;
1010 pa_memchunk silence;
1011 uint32_t idx;
1012 int64_t start_index;
1013 pa_sink_input_new_data data;
1014
1015 pa_assert(c);
1016 pa_assert(ss);
1017 pa_assert(missing);
1018 pa_assert(p);
1019 pa_assert(ret);
1020
1021 /* Find syncid group */
1022 for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) {
1023
1024 if (!playback_stream_isinstance(ssync))
1025 continue;
1026
1027 if (ssync->syncid == syncid)
1028 break;
1029 }
1030
1031 /* Synced streams must connect to the same sink */
1032 if (ssync) {
1033
1034 if (!sink)
1035 sink = ssync->sink_input->sink;
1036 else if (sink != ssync->sink_input->sink) {
1037 *ret = PA_ERR_INVALID;
1038 return NULL;
1039 }
1040 }
1041
1042 pa_sink_input_new_data_init(&data);
1043
1044 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1045 data.driver = __FILE__;
1046 data.module = c->options->module;
1047 data.client = c->client;
1048 if (sink) {
1049 data.sink = sink;
1050 data.save_sink = TRUE;
1051 }
1052 pa_sink_input_new_data_set_sample_spec(&data, ss);
1053 pa_sink_input_new_data_set_channel_map(&data, map);
1054 if (volume) {
1055 pa_sink_input_new_data_set_volume(&data, volume);
1056 data.volume_is_absolute = !relative_volume;
1057 data.save_volume = TRUE;
1058 }
1059 if (muted_set) {
1060 pa_sink_input_new_data_set_muted(&data, muted);
1061 data.save_muted = TRUE;
1062 }
1063 data.sync_base = ssync ? ssync->sink_input : NULL;
1064 data.flags = flags;
1065
1066 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1067
1068 pa_sink_input_new_data_done(&data);
1069
1070 if (!sink_input)
1071 return NULL;
1072
1073 s = pa_msgobject_new(playback_stream);
1074 s->parent.parent.parent.free = playback_stream_free;
1075 s->parent.parent.process_msg = playback_stream_process_msg;
1076 s->connection = c;
1077 s->syncid = syncid;
1078 s->sink_input = sink_input;
1079 s->is_underrun = TRUE;
1080 s->drain_request = FALSE;
1081 pa_atomic_store(&s->missing, 0);
1082 s->buffer_attr = *a;
1083 s->adjust_latency = adjust_latency;
1084 s->early_requests = early_requests;
1085
1086 s->sink_input->parent.process_msg = sink_input_process_msg;
1087 s->sink_input->pop = sink_input_pop_cb;
1088 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1089 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1090 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1091 s->sink_input->kill = sink_input_kill_cb;
1092 s->sink_input->moving = sink_input_moving_cb;
1093 s->sink_input->suspend = sink_input_suspend_cb;
1094 s->sink_input->send_event = sink_input_send_event_cb;
1095 s->sink_input->userdata = s;
1096
1097 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1098
1099 fix_playback_buffer_attr(s);
1100
1101 pa_sink_input_get_silence(sink_input, &silence);
1102 s->memblockq = pa_memblockq_new(
1103 start_index,
1104 s->buffer_attr.maxlength,
1105 s->buffer_attr.tlength,
1106 pa_frame_size(&sink_input->sample_spec),
1107 s->buffer_attr.prebuf,
1108 s->buffer_attr.minreq,
1109 0,
1110 &silence);
1111 pa_memblock_unref(silence.memblock);
1112
1113 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1114
1115 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1116
1117 /* pa_log("missing original: %li", (long int) *missing); */
1118
1119 *ss = s->sink_input->sample_spec;
1120 *map = s->sink_input->channel_map;
1121
1122 pa_idxset_put(c->output_streams, s, &s->index);
1123
1124 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1125 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1126 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1127 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1128 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1129
1130 pa_sink_input_put(s->sink_input);
1131 return s;
1132 }
1133
1134 /* Called from IO context */
1135 static void playback_stream_request_bytes(playback_stream *s) {
1136 size_t m, minreq;
1137 int previous_missing;
1138
1139 playback_stream_assert_ref(s);
1140
1141 m = pa_memblockq_pop_missing(s->memblockq);
1142
1143 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1144 /* (unsigned long) m, */
1145 /* pa_memblockq_get_tlength(s->memblockq), */
1146 /* pa_memblockq_get_minreq(s->memblockq), */
1147 /* pa_memblockq_get_length(s->memblockq), */
1148 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1149
1150 if (m <= 0)
1151 return;
1152
1153 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1154
1155 previous_missing = pa_atomic_add(&s->missing, (int) m);
1156 minreq = pa_memblockq_get_minreq(s->memblockq);
1157
1158 if (pa_memblockq_prebuf_active(s->memblockq) ||
1159 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1160 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1161 }
1162
1163 /* Called from main context */
1164 static void playback_stream_send_killed(playback_stream *p) {
1165 pa_tagstruct *t;
1166 playback_stream_assert_ref(p);
1167
1168 t = pa_tagstruct_new(NULL, 0);
1169 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1170 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1171 pa_tagstruct_putu32(t, p->index);
1172 pa_pstream_send_tagstruct(p->connection->pstream, t);
1173 }
1174
1175 /* Called from main context */
1176 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1177 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1178 pa_native_connection_assert_ref(c);
1179
1180 if (!c->protocol)
1181 return -1;
1182
1183 switch (code) {
1184
1185 case CONNECTION_MESSAGE_REVOKE:
1186 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1187 break;
1188
1189 case CONNECTION_MESSAGE_RELEASE:
1190 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1191 break;
1192 }
1193
1194 return 0;
1195 }
1196
1197 /* Called from main context */
1198 static void native_connection_unlink(pa_native_connection *c) {
1199 record_stream *r;
1200 output_stream *o;
1201
1202 pa_assert(c);
1203
1204 if (!c->protocol)
1205 return;
1206
1207 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1208
1209 if (c->options)
1210 pa_native_options_unref(c->options);
1211
1212 while ((r = pa_idxset_first(c->record_streams, NULL)))
1213 record_stream_unlink(r);
1214
1215 while ((o = pa_idxset_first(c->output_streams, NULL)))
1216 if (playback_stream_isinstance(o))
1217 playback_stream_unlink(PLAYBACK_STREAM(o));
1218 else
1219 upload_stream_unlink(UPLOAD_STREAM(o));
1220
1221 if (c->subscription)
1222 pa_subscription_free(c->subscription);
1223
1224 if (c->pstream)
1225 pa_pstream_unlink(c->pstream);
1226
1227 if (c->auth_timeout_event) {
1228 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1229 c->auth_timeout_event = NULL;
1230 }
1231
1232 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1233 c->protocol = NULL;
1234 pa_native_connection_unref(c);
1235 }
1236
1237 /* Called from main context */
1238 static void native_connection_free(pa_object *o) {
1239 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1240
1241 pa_assert(c);
1242
1243 native_connection_unlink(c);
1244
1245 pa_idxset_free(c->record_streams, NULL, NULL);
1246 pa_idxset_free(c->output_streams, NULL, NULL);
1247
1248 pa_pdispatch_unref(c->pdispatch);
1249 pa_pstream_unref(c->pstream);
1250 pa_client_free(c->client);
1251
1252 pa_xfree(c);
1253 }
1254
1255 /* Called from main context */
1256 static void native_connection_send_memblock(pa_native_connection *c) {
1257 uint32_t start;
1258 record_stream *r;
1259
1260 start = PA_IDXSET_INVALID;
1261 for (;;) {
1262 pa_memchunk chunk;
1263
1264 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1265 return;
1266
1267 if (start == PA_IDXSET_INVALID)
1268 start = c->rrobin_index;
1269 else if (start == c->rrobin_index)
1270 return;
1271
1272 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1273 pa_memchunk schunk = chunk;
1274
1275 if (schunk.length > r->buffer_attr.fragsize)
1276 schunk.length = r->buffer_attr.fragsize;
1277
1278 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1279
1280 pa_memblockq_drop(r->memblockq, schunk.length);
1281 pa_memblock_unref(schunk.memblock);
1282
1283 return;
1284 }
1285 }
1286 }
1287
1288 /*** sink input callbacks ***/
1289
1290 /* Called from thread context */
1291 static void handle_seek(playback_stream *s, int64_t indexw) {
1292 playback_stream_assert_ref(s);
1293
1294 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1295
1296 if (s->sink_input->thread_info.underrun_for > 0) {
1297
1298 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1299
1300 if (pa_memblockq_is_readable(s->memblockq)) {
1301
1302 /* We just ended an underrun, let's ask the sink
1303 * for a complete rewind rewrite */
1304
1305 pa_log_debug("Requesting rewind due to end of underrun.");
1306 pa_sink_input_request_rewind(s->sink_input,
1307 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1308 s->sink_input->thread_info.underrun_for),
1309 FALSE, TRUE, FALSE);
1310 }
1311
1312 } else {
1313 int64_t indexr;
1314
1315 indexr = pa_memblockq_get_read_index(s->memblockq);
1316
1317 if (indexw < indexr) {
1318 /* OK, the sink already asked for this data, so
1319 * let's have it usk us again */
1320
1321 pa_log_debug("Requesting rewind due to rewrite.");
1322 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1323 }
1324 }
1325
1326 playback_stream_request_bytes(s);
1327 }
1328
1329 static void flush_write_no_account(pa_memblockq *q) {
1330 pa_memblockq_flush_write(q, FALSE);
1331 }
1332
1333 /* Called from thread context */
1334 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1335 pa_sink_input *i = PA_SINK_INPUT(o);
1336 playback_stream *s;
1337
1338 pa_sink_input_assert_ref(i);
1339 s = PLAYBACK_STREAM(i->userdata);
1340 playback_stream_assert_ref(s);
1341
1342 switch (code) {
1343
1344 case SINK_INPUT_MESSAGE_SEEK: {
1345 int64_t windex;
1346
1347 windex = pa_memblockq_get_write_index(s->memblockq);
1348
1349 /* The client side is incapable of accounting correctly
1350 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1351 * able to deal with that. */
1352
1353 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1354
1355 handle_seek(s, windex);
1356 return 0;
1357 }
1358
1359 case SINK_INPUT_MESSAGE_POST_DATA: {
1360 int64_t windex;
1361
1362 pa_assert(chunk);
1363
1364 windex = pa_memblockq_get_write_index(s->memblockq);
1365
1366 /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
1367
1368 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1369
1370 if (pa_log_ratelimit())
1371 pa_log_warn("Failed to push data into queue");
1372 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1373 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1374 }
1375
1376 handle_seek(s, windex);
1377
1378 /* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1379
1380 return 0;
1381 }
1382
1383 case SINK_INPUT_MESSAGE_DRAIN:
1384 case SINK_INPUT_MESSAGE_FLUSH:
1385 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1386 case SINK_INPUT_MESSAGE_TRIGGER: {
1387
1388 int64_t windex;
1389 pa_sink_input *isync;
1390 void (*func)(pa_memblockq *bq);
1391
1392 switch (code) {
1393 case SINK_INPUT_MESSAGE_FLUSH:
1394 func = flush_write_no_account;
1395 break;
1396
1397 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1398 func = pa_memblockq_prebuf_force;
1399 break;
1400
1401 case SINK_INPUT_MESSAGE_DRAIN:
1402 case SINK_INPUT_MESSAGE_TRIGGER:
1403 func = pa_memblockq_prebuf_disable;
1404 break;
1405
1406 default:
1407 pa_assert_not_reached();
1408 }
1409
1410 windex = pa_memblockq_get_write_index(s->memblockq);
1411 func(s->memblockq);
1412 handle_seek(s, windex);
1413
1414 /* Do the same for all other members in the sync group */
1415 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1416 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1417 windex = pa_memblockq_get_write_index(ssync->memblockq);
1418 func(ssync->memblockq);
1419 handle_seek(ssync, windex);
1420 }
1421
1422 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1423 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1424 windex = pa_memblockq_get_write_index(ssync->memblockq);
1425 func(ssync->memblockq);
1426 handle_seek(ssync, windex);
1427 }
1428
1429 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1430 if (!pa_memblockq_is_readable(s->memblockq))
1431 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1432 else {
1433 s->drain_tag = PA_PTR_TO_UINT(userdata);
1434 s->drain_request = TRUE;
1435 }
1436 }
1437
1438 return 0;
1439 }
1440
1441 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1442 /* Atomically get a snapshot of all timing parameters... */
1443 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1444 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1445 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1446 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1447 s->underrun_for = s->sink_input->thread_info.underrun_for;
1448 s->playing_for = s->sink_input->thread_info.playing_for;
1449
1450 return 0;
1451
1452 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1453 int64_t windex;
1454
1455 windex = pa_memblockq_get_write_index(s->memblockq);
1456
1457 pa_memblockq_prebuf_force(s->memblockq);
1458
1459 handle_seek(s, windex);
1460
1461 /* Fall through to the default handler */
1462 break;
1463 }
1464
1465 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1466 pa_usec_t *r = userdata;
1467
1468 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1469
1470 /* Fall through, the default handler will add in the extra
1471 * latency added by the resampler */
1472 break;
1473 }
1474
1475 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1476 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1477 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1478 return 0;
1479 }
1480 }
1481
1482 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1483 }
1484
1485 /* Called from thread context */
1486 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1487 playback_stream *s;
1488
1489 pa_sink_input_assert_ref(i);
1490 s = PLAYBACK_STREAM(i->userdata);
1491 playback_stream_assert_ref(s);
1492 pa_assert(chunk);
1493
1494 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1495
1496 if (pa_memblockq_is_readable(s->memblockq))
1497 s->is_underrun = FALSE;
1498 else {
1499 if (!s->is_underrun)
1500 pa_log_debug("Underrun on '%s', %lu bytes in queue.", pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)), (unsigned long) pa_memblockq_get_length(s->memblockq));
1501
1502 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1503 s->drain_request = FALSE;
1504 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);
1505 } else if (!s->is_underrun)
1506 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1507
1508 s->is_underrun = TRUE;
1509
1510 playback_stream_request_bytes(s);
1511 }
1512
1513 /* This call will not fail with prebuf=0, hence we check for
1514 underrun explicitly above */
1515 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1516 return -1;
1517
1518 chunk->length = PA_MIN(nbytes, chunk->length);
1519
1520 if (i->thread_info.underrun_for > 0)
1521 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1522
1523 pa_memblockq_drop(s->memblockq, chunk->length);
1524 playback_stream_request_bytes(s);
1525
1526 return 0;
1527 }
1528
1529 /* Called from thread context */
1530 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1531 playback_stream *s;
1532
1533 pa_sink_input_assert_ref(i);
1534 s = PLAYBACK_STREAM(i->userdata);
1535 playback_stream_assert_ref(s);
1536
1537 /* If we are in an underrun, then we don't rewind */
1538 if (i->thread_info.underrun_for > 0)
1539 return;
1540
1541 pa_memblockq_rewind(s->memblockq, nbytes);
1542 }
1543
1544 /* Called from thread context */
1545 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1546 playback_stream *s;
1547
1548 pa_sink_input_assert_ref(i);
1549 s = PLAYBACK_STREAM(i->userdata);
1550 playback_stream_assert_ref(s);
1551
1552 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1553 }
1554
1555 /* Called from thread context */
1556 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1557 playback_stream *s;
1558 size_t new_tlength, old_tlength;
1559
1560 pa_sink_input_assert_ref(i);
1561 s = PLAYBACK_STREAM(i->userdata);
1562 playback_stream_assert_ref(s);
1563
1564 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1565 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1566
1567 if (old_tlength < new_tlength) {
1568 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1569 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1570 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1571
1572 if (new_tlength == old_tlength)
1573 pa_log_debug("Failed to increase tlength");
1574 else {
1575 pa_log_debug("Notifying client about increased tlength");
1576 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH, NULL, pa_memblockq_get_tlength(s->memblockq), NULL, NULL);
1577 }
1578 }
1579 }
1580
1581 /* Called from main context */
1582 static void sink_input_kill_cb(pa_sink_input *i) {
1583 playback_stream *s;
1584
1585 pa_sink_input_assert_ref(i);
1586 s = PLAYBACK_STREAM(i->userdata);
1587 playback_stream_assert_ref(s);
1588
1589 playback_stream_send_killed(s);
1590 playback_stream_unlink(s);
1591 }
1592
1593 /* Called from main context */
1594 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1595 playback_stream *s;
1596 pa_tagstruct *t;
1597
1598 pa_sink_input_assert_ref(i);
1599 s = PLAYBACK_STREAM(i->userdata);
1600 playback_stream_assert_ref(s);
1601
1602 if (s->connection->version < 15)
1603 return;
1604
1605 t = pa_tagstruct_new(NULL, 0);
1606 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1607 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1608 pa_tagstruct_putu32(t, s->index);
1609 pa_tagstruct_puts(t, event);
1610 pa_tagstruct_put_proplist(t, pl);
1611 pa_pstream_send_tagstruct(s->connection->pstream, t);
1612 }
1613
1614 /* Called from main context */
1615 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1616 playback_stream *s;
1617 pa_tagstruct *t;
1618
1619 pa_sink_input_assert_ref(i);
1620 s = PLAYBACK_STREAM(i->userdata);
1621 playback_stream_assert_ref(s);
1622
1623 if (s->connection->version < 12)
1624 return;
1625
1626 t = pa_tagstruct_new(NULL, 0);
1627 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1628 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1629 pa_tagstruct_putu32(t, s->index);
1630 pa_tagstruct_put_boolean(t, suspend);
1631 pa_pstream_send_tagstruct(s->connection->pstream, t);
1632 }
1633
1634 /* Called from main context */
1635 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1636 playback_stream *s;
1637 pa_tagstruct *t;
1638
1639 pa_sink_input_assert_ref(i);
1640 s = PLAYBACK_STREAM(i->userdata);
1641 playback_stream_assert_ref(s);
1642
1643 if (!dest)
1644 return;
1645
1646 fix_playback_buffer_attr(s);
1647 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1648 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1649
1650 if (s->connection->version < 12)
1651 return;
1652
1653 t = pa_tagstruct_new(NULL, 0);
1654 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1655 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1656 pa_tagstruct_putu32(t, s->index);
1657 pa_tagstruct_putu32(t, dest->index);
1658 pa_tagstruct_puts(t, dest->name);
1659 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1660
1661 if (s->connection->version >= 13) {
1662 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1663 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1664 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1665 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1666 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1667 }
1668
1669 pa_pstream_send_tagstruct(s->connection->pstream, t);
1670 }
1671
1672 /*** source_output callbacks ***/
1673
1674 /* Called from thread context */
1675 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1676 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1677 record_stream *s;
1678
1679 pa_source_output_assert_ref(o);
1680 s = RECORD_STREAM(o->userdata);
1681 record_stream_assert_ref(s);
1682
1683 switch (code) {
1684 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1685 /* Atomically get a snapshot of all timing parameters... */
1686 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1687 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1688 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1689 return 0;
1690 }
1691
1692 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1693 }
1694
1695 /* Called from thread context */
1696 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1697 record_stream *s;
1698
1699 pa_source_output_assert_ref(o);
1700 s = RECORD_STREAM(o->userdata);
1701 record_stream_assert_ref(s);
1702 pa_assert(chunk);
1703
1704 pa_atomic_add(&s->on_the_fly, chunk->length);
1705 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1706 }
1707
1708 static void source_output_kill_cb(pa_source_output *o) {
1709 record_stream *s;
1710
1711 pa_source_output_assert_ref(o);
1712 s = RECORD_STREAM(o->userdata);
1713 record_stream_assert_ref(s);
1714
1715 record_stream_send_killed(s);
1716 record_stream_unlink(s);
1717 }
1718
1719 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1720 record_stream *s;
1721
1722 pa_source_output_assert_ref(o);
1723 s = RECORD_STREAM(o->userdata);
1724 record_stream_assert_ref(s);
1725
1726 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1727
1728 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1729 }
1730
1731 /* Called from main context */
1732 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1733 record_stream *s;
1734 pa_tagstruct *t;
1735
1736 pa_source_output_assert_ref(o);
1737 s = RECORD_STREAM(o->userdata);
1738 record_stream_assert_ref(s);
1739
1740 if (s->connection->version < 15)
1741 return;
1742
1743 t = pa_tagstruct_new(NULL, 0);
1744 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1745 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1746 pa_tagstruct_putu32(t, s->index);
1747 pa_tagstruct_puts(t, event);
1748 pa_tagstruct_put_proplist(t, pl);
1749 pa_pstream_send_tagstruct(s->connection->pstream, t);
1750 }
1751
1752 /* Called from main context */
1753 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1754 record_stream *s;
1755 pa_tagstruct *t;
1756
1757 pa_source_output_assert_ref(o);
1758 s = RECORD_STREAM(o->userdata);
1759 record_stream_assert_ref(s);
1760
1761 if (s->connection->version < 12)
1762 return;
1763
1764 t = pa_tagstruct_new(NULL, 0);
1765 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1766 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1767 pa_tagstruct_putu32(t, s->index);
1768 pa_tagstruct_put_boolean(t, suspend);
1769 pa_pstream_send_tagstruct(s->connection->pstream, t);
1770 }
1771
1772 /* Called from main context */
1773 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1774 record_stream *s;
1775 pa_tagstruct *t;
1776
1777 pa_source_output_assert_ref(o);
1778 s = RECORD_STREAM(o->userdata);
1779 record_stream_assert_ref(s);
1780
1781 if (!dest)
1782 return;
1783
1784 fix_record_buffer_attr_pre(s);
1785 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1786 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1787 fix_record_buffer_attr_post(s);
1788
1789 if (s->connection->version < 12)
1790 return;
1791
1792 t = pa_tagstruct_new(NULL, 0);
1793 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1794 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1795 pa_tagstruct_putu32(t, s->index);
1796 pa_tagstruct_putu32(t, dest->index);
1797 pa_tagstruct_puts(t, dest->name);
1798 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1799
1800 if (s->connection->version >= 13) {
1801 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1802 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1803 pa_tagstruct_put_usec(t, s->configured_source_latency);
1804 }
1805
1806 pa_pstream_send_tagstruct(s->connection->pstream, t);
1807 }
1808
1809 /*** pdispatch callbacks ***/
1810
1811 static void protocol_error(pa_native_connection *c) {
1812 pa_log("protocol error, kicking client");
1813 native_connection_unlink(c);
1814 }
1815
1816 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1817 if (!(expression)) { \
1818 pa_pstream_send_error((pstream), (tag), (error)); \
1819 return; \
1820 } \
1821 } while(0);
1822
1823 static pa_tagstruct *reply_new(uint32_t tag) {
1824 pa_tagstruct *reply;
1825
1826 reply = pa_tagstruct_new(NULL, 0);
1827 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1828 pa_tagstruct_putu32(reply, tag);
1829 return reply;
1830 }
1831
1832 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1833 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1834 playback_stream *s;
1835 uint32_t sink_index, syncid, missing;
1836 pa_buffer_attr attr;
1837 const char *name = NULL, *sink_name;
1838 pa_sample_spec ss;
1839 pa_channel_map map;
1840 pa_tagstruct *reply;
1841 pa_sink *sink = NULL;
1842 pa_cvolume volume;
1843 pa_bool_t
1844 corked = FALSE,
1845 no_remap = FALSE,
1846 no_remix = FALSE,
1847 fix_format = FALSE,
1848 fix_rate = FALSE,
1849 fix_channels = FALSE,
1850 no_move = FALSE,
1851 variable_rate = FALSE,
1852 muted = FALSE,
1853 adjust_latency = FALSE,
1854 early_requests = FALSE,
1855 dont_inhibit_auto_suspend = FALSE,
1856 muted_set = FALSE,
1857 fail_on_suspend = FALSE,
1858 relative_volume = FALSE;
1859 pa_sink_input_flags_t flags = 0;
1860 pa_proplist *p;
1861 pa_bool_t volume_set = TRUE;
1862 int ret = PA_ERR_INVALID;
1863
1864 pa_native_connection_assert_ref(c);
1865 pa_assert(t);
1866 memset(&attr, 0, sizeof(attr));
1867
1868 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1869 pa_tagstruct_get(
1870 t,
1871 PA_TAG_SAMPLE_SPEC, &ss,
1872 PA_TAG_CHANNEL_MAP, &map,
1873 PA_TAG_U32, &sink_index,
1874 PA_TAG_STRING, &sink_name,
1875 PA_TAG_U32, &attr.maxlength,
1876 PA_TAG_BOOLEAN, &corked,
1877 PA_TAG_U32, &attr.tlength,
1878 PA_TAG_U32, &attr.prebuf,
1879 PA_TAG_U32, &attr.minreq,
1880 PA_TAG_U32, &syncid,
1881 PA_TAG_CVOLUME, &volume,
1882 PA_TAG_INVALID) < 0) {
1883
1884 protocol_error(c);
1885 return;
1886 }
1887
1888 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1889 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
1890 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
1891 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
1892 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
1893 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
1894 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
1895 CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID);
1896
1897 p = pa_proplist_new();
1898
1899 if (name)
1900 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1901
1902 if (c->version >= 12) {
1903 /* Since 0.9.8 the user can ask for a couple of additional flags */
1904
1905 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1906 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1907 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1908 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1909 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1910 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1911 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1912
1913 protocol_error(c);
1914 pa_proplist_free(p);
1915 return;
1916 }
1917 }
1918
1919 if (c->version >= 13) {
1920
1921 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1922 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1923 pa_tagstruct_get_proplist(t, p) < 0) {
1924 protocol_error(c);
1925 pa_proplist_free(p);
1926 return;
1927 }
1928 }
1929
1930 if (c->version >= 14) {
1931
1932 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
1933 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
1934 protocol_error(c);
1935 pa_proplist_free(p);
1936 return;
1937 }
1938 }
1939
1940 if (c->version >= 15) {
1941
1942 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
1943 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
1944 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
1945 protocol_error(c);
1946 pa_proplist_free(p);
1947 return;
1948 }
1949 }
1950
1951 if (c->version >= 17) {
1952
1953 if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
1954 protocol_error(c);
1955 pa_proplist_free(p);
1956 return;
1957 }
1958 }
1959
1960 if (!pa_tagstruct_eof(t)) {
1961 protocol_error(c);
1962 pa_proplist_free(p);
1963 return;
1964 }
1965
1966 if (sink_index != PA_INVALID_INDEX) {
1967
1968 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
1969 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1970 pa_proplist_free(p);
1971 return;
1972 }
1973
1974 } else if (sink_name) {
1975
1976 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
1977 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1978 pa_proplist_free(p);
1979 return;
1980 }
1981 }
1982
1983 flags =
1984 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
1985 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
1986 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
1987 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
1988 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
1989 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
1990 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
1991 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
1992 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
1993 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0);
1994
1995 /* Only since protocol version 15 there's a seperate muted_set
1996 * flag. For older versions we synthesize it here */
1997 muted_set = muted_set || muted;
1998
1999 s = playback_stream_new(c, sink, &ss, &map, &attr, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, relative_volume, &ret);
2000 pa_proplist_free(p);
2001
2002 CHECK_VALIDITY(c->pstream, s, tag, ret);
2003
2004 reply = reply_new(tag);
2005 pa_tagstruct_putu32(reply, s->index);
2006 pa_assert(s->sink_input);
2007 pa_tagstruct_putu32(reply, s->sink_input->index);
2008 pa_tagstruct_putu32(reply, missing);
2009
2010 /* pa_log("initial request is %u", missing); */
2011
2012 if (c->version >= 9) {
2013 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2014
2015 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2016 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2017 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2018 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2019 }
2020
2021 if (c->version >= 12) {
2022 /* Since 0.9.8 we support sending the chosen sample
2023 * spec/channel map/device/suspend status back to the
2024 * client */
2025
2026 pa_tagstruct_put_sample_spec(reply, &ss);
2027 pa_tagstruct_put_channel_map(reply, &map);
2028
2029 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2030 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2031
2032 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2033 }
2034
2035 if (c->version >= 13)
2036 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2037
2038 pa_pstream_send_tagstruct(c->pstream, reply);
2039 }
2040
2041 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2042 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2043 uint32_t channel;
2044
2045 pa_native_connection_assert_ref(c);
2046 pa_assert(t);
2047
2048 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2049 !pa_tagstruct_eof(t)) {
2050 protocol_error(c);
2051 return;
2052 }
2053
2054 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2055
2056 switch (command) {
2057
2058 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2059 playback_stream *s;
2060 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2061 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2062 return;
2063 }
2064
2065 playback_stream_unlink(s);
2066 break;
2067 }
2068
2069 case PA_COMMAND_DELETE_RECORD_STREAM: {
2070 record_stream *s;
2071 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2072 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2073 return;
2074 }
2075
2076 record_stream_unlink(s);
2077 break;
2078 }
2079
2080 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2081 upload_stream *s;
2082
2083 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2084 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2085 return;
2086 }
2087
2088 upload_stream_unlink(s);
2089 break;
2090 }
2091
2092 default:
2093 pa_assert_not_reached();
2094 }
2095
2096 pa_pstream_send_simple_ack(c->pstream, tag);
2097 }
2098
2099 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2100 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2101 record_stream *s;
2102 pa_buffer_attr attr;
2103 uint32_t source_index;
2104 const char *name = NULL, *source_name;
2105 pa_sample_spec ss;
2106 pa_channel_map map;
2107 pa_tagstruct *reply;
2108 pa_source *source = NULL;
2109 pa_bool_t
2110 corked = FALSE,
2111 no_remap = FALSE,
2112 no_remix = FALSE,
2113 fix_format = FALSE,
2114 fix_rate = FALSE,
2115 fix_channels = FALSE,
2116 no_move = FALSE,
2117 variable_rate = FALSE,
2118 adjust_latency = FALSE,
2119 peak_detect = FALSE,
2120 early_requests = FALSE,
2121 dont_inhibit_auto_suspend = FALSE,
2122 fail_on_suspend = FALSE;
2123 pa_source_output_flags_t flags = 0;
2124 pa_proplist *p;
2125 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2126 pa_sink_input *direct_on_input = NULL;
2127 int ret = PA_ERR_INVALID;
2128
2129 pa_native_connection_assert_ref(c);
2130 pa_assert(t);
2131
2132 memset(&attr, 0, sizeof(attr));
2133
2134 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2135 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2136 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2137 pa_tagstruct_getu32(t, &source_index) < 0 ||
2138 pa_tagstruct_gets(t, &source_name) < 0 ||
2139 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2140 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2141 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2142 protocol_error(c);
2143 return;
2144 }
2145
2146 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2147 CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
2148 CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID);
2149 CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2150 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2151 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2152 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2153
2154 p = pa_proplist_new();
2155
2156 if (name)
2157 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2158
2159 if (c->version >= 12) {
2160 /* Since 0.9.8 the user can ask for a couple of additional flags */
2161
2162 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2163 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2164 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2165 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2166 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2167 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2168 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2169
2170 protocol_error(c);
2171 pa_proplist_free(p);
2172 return;
2173 }
2174 }
2175
2176 if (c->version >= 13) {
2177
2178 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2179 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2180 pa_tagstruct_get_proplist(t, p) < 0 ||
2181 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2182 protocol_error(c);
2183 pa_proplist_free(p);
2184 return;
2185 }
2186 }
2187
2188 if (c->version >= 14) {
2189
2190 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2191 protocol_error(c);
2192 pa_proplist_free(p);
2193 return;
2194 }
2195 }
2196
2197 if (c->version >= 15) {
2198
2199 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2200 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2201 protocol_error(c);
2202 pa_proplist_free(p);
2203 return;
2204 }
2205 }
2206
2207 if (!pa_tagstruct_eof(t)) {
2208 protocol_error(c);
2209 pa_proplist_free(p);
2210 return;
2211 }
2212
2213 if (source_index != PA_INVALID_INDEX) {
2214
2215 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2216 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2217 pa_proplist_free(p);
2218 return;
2219 }
2220
2221 } else if (source_name) {
2222
2223 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2224 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2225 pa_proplist_free(p);
2226 return;
2227 }
2228 }
2229
2230 if (direct_on_input_idx != PA_INVALID_INDEX) {
2231
2232 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2233 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2234 pa_proplist_free(p);
2235 return;
2236 }
2237 }
2238
2239 flags =
2240 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2241 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2242 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2243 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2244 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2245 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2246 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2247 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2248 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2249 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0);
2250
2251 s = record_stream_new(c, source, &ss, &map, peak_detect, &attr, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
2252 pa_proplist_free(p);
2253
2254 CHECK_VALIDITY(c->pstream, s, tag, ret);
2255
2256 reply = reply_new(tag);
2257 pa_tagstruct_putu32(reply, s->index);
2258 pa_assert(s->source_output);
2259 pa_tagstruct_putu32(reply, s->source_output->index);
2260
2261 if (c->version >= 9) {
2262 /* Since 0.9 we support sending the buffer metrics back to the client */
2263
2264 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2265 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2266 }
2267
2268 if (c->version >= 12) {
2269 /* Since 0.9.8 we support sending the chosen sample
2270 * spec/channel map/device/suspend status back to the
2271 * client */
2272
2273 pa_tagstruct_put_sample_spec(reply, &ss);
2274 pa_tagstruct_put_channel_map(reply, &map);
2275
2276 pa_tagstruct_putu32(reply, s->source_output->source->index);
2277 pa_tagstruct_puts(reply, s->source_output->source->name);
2278
2279 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2280 }
2281
2282 if (c->version >= 13)
2283 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2284
2285 pa_pstream_send_tagstruct(c->pstream, reply);
2286 }
2287
2288 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2289 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2290 int ret;
2291
2292 pa_native_connection_assert_ref(c);
2293 pa_assert(t);
2294
2295 if (!pa_tagstruct_eof(t)) {
2296 protocol_error(c);
2297 return;
2298 }
2299
2300 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2301 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2302 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2303
2304 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2305
2306 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2307 }
2308
2309 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2310 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2311 const void*cookie;
2312 pa_tagstruct *reply;
2313 pa_bool_t shm_on_remote = FALSE, do_shm;
2314
2315 pa_native_connection_assert_ref(c);
2316 pa_assert(t);
2317
2318 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2319 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2320 !pa_tagstruct_eof(t)) {
2321 protocol_error(c);
2322 return;
2323 }
2324
2325 /* Minimum supported version */
2326 if (c->version < 8) {
2327 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2328 return;
2329 }
2330
2331 /* Starting with protocol version 13 the MSB of the version tag
2332 reflects if shm is available for this pa_native_connection or
2333 not. */
2334 if (c->version >= 13) {
2335 shm_on_remote = !!(c->version & 0x80000000U);
2336 c->version &= 0x7FFFFFFFU;
2337 }
2338
2339 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2340
2341 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2342
2343 if (!c->authorized) {
2344 pa_bool_t success = FALSE;
2345
2346 #ifdef HAVE_CREDS
2347 const pa_creds *creds;
2348
2349 if ((creds = pa_pdispatch_creds(pd))) {
2350 if (creds->uid == getuid())
2351 success = TRUE;
2352 else if (c->options->auth_group) {
2353 int r;
2354 gid_t gid;
2355
2356 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2357 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2358 else if (gid == creds->gid)
2359 success = TRUE;
2360
2361 if (!success) {
2362 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2363 pa_log_warn("Failed to check group membership.");
2364 else if (r > 0)
2365 success = TRUE;
2366 }
2367 }
2368
2369 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2370 (unsigned long) creds->uid,
2371 (unsigned long) creds->gid,
2372 (int) success);
2373 }
2374 #endif
2375
2376 if (!success && c->options->auth_cookie) {
2377 const uint8_t *ac;
2378
2379 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2380 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2381 success = TRUE;
2382 }
2383
2384 if (!success) {
2385 pa_log_warn("Denied access to client with invalid authorization data.");
2386 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2387 return;
2388 }
2389
2390 c->authorized = TRUE;
2391 if (c->auth_timeout_event) {
2392 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2393 c->auth_timeout_event = NULL;
2394 }
2395 }
2396
2397 /* Enable shared memory support if possible */
2398 do_shm =
2399 pa_mempool_is_shared(c->protocol->core->mempool) &&
2400 c->is_local;
2401
2402 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2403
2404 if (do_shm)
2405 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2406 do_shm = FALSE;
2407
2408 #ifdef HAVE_CREDS
2409 if (do_shm) {
2410 /* Only enable SHM if both sides are owned by the same
2411 * user. This is a security measure because otherwise data
2412 * private to the user might leak. */
2413
2414 const pa_creds *creds;
2415 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2416 do_shm = FALSE;
2417 }
2418 #endif
2419
2420 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2421 pa_pstream_enable_shm(c->pstream, do_shm);
2422
2423 reply = reply_new(tag);
2424 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2425
2426 #ifdef HAVE_CREDS
2427 {
2428 /* SHM support is only enabled after both sides made sure they are the same user. */
2429
2430 pa_creds ucred;
2431
2432 ucred.uid = getuid();
2433 ucred.gid = getgid();
2434
2435 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2436 }
2437 #else
2438 pa_pstream_send_tagstruct(c->pstream, reply);
2439 #endif
2440 }
2441
2442 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2443 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2444 const char *name = NULL;
2445 pa_proplist *p;
2446 pa_tagstruct *reply;
2447
2448 pa_native_connection_assert_ref(c);
2449 pa_assert(t);
2450
2451 p = pa_proplist_new();
2452
2453 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2454 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2455 !pa_tagstruct_eof(t)) {
2456
2457 protocol_error(c);
2458 pa_proplist_free(p);
2459 return;
2460 }
2461
2462 if (name)
2463 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2464 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2465 pa_proplist_free(p);
2466 return;
2467 }
2468
2469 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2470 pa_proplist_free(p);
2471
2472 reply = reply_new(tag);
2473
2474 if (c->version >= 13)
2475 pa_tagstruct_putu32(reply, c->client->index);
2476
2477 pa_pstream_send_tagstruct(c->pstream, reply);
2478 }
2479
2480 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2481 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2482 const char *name;
2483 uint32_t idx = PA_IDXSET_INVALID;
2484
2485 pa_native_connection_assert_ref(c);
2486 pa_assert(t);
2487
2488 if (pa_tagstruct_gets(t, &name) < 0 ||
2489 !pa_tagstruct_eof(t)) {
2490 protocol_error(c);
2491 return;
2492 }
2493
2494 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2495 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_LOOKUP_SINK ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
2496
2497 if (command == PA_COMMAND_LOOKUP_SINK) {
2498 pa_sink *sink;
2499 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2500 idx = sink->index;
2501 } else {
2502 pa_source *source;
2503 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2504 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2505 idx = source->index;
2506 }
2507
2508 if (idx == PA_IDXSET_INVALID)
2509 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2510 else {
2511 pa_tagstruct *reply;
2512 reply = reply_new(tag);
2513 pa_tagstruct_putu32(reply, idx);
2514 pa_pstream_send_tagstruct(c->pstream, reply);
2515 }
2516 }
2517
2518 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2519 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2520 uint32_t idx;
2521 playback_stream *s;
2522
2523 pa_native_connection_assert_ref(c);
2524 pa_assert(t);
2525
2526 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2527 !pa_tagstruct_eof(t)) {
2528 protocol_error(c);
2529 return;
2530 }
2531
2532 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2533 s = pa_idxset_get_by_index(c->output_streams, idx);
2534 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2535 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2536
2537 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);
2538 }
2539
2540 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2541 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2542 pa_tagstruct *reply;
2543 const pa_mempool_stat *stat;
2544
2545 pa_native_connection_assert_ref(c);
2546 pa_assert(t);
2547
2548 if (!pa_tagstruct_eof(t)) {
2549 protocol_error(c);
2550 return;
2551 }
2552
2553 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2554
2555 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2556
2557 reply = reply_new(tag);
2558 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2559 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2560 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2561 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2562 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2563 pa_pstream_send_tagstruct(c->pstream, reply);
2564 }
2565
2566 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2567 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2568 pa_tagstruct *reply;
2569 playback_stream *s;
2570 struct timeval tv, now;
2571 uint32_t idx;
2572
2573 pa_native_connection_assert_ref(c);
2574 pa_assert(t);
2575
2576 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2577 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2578 !pa_tagstruct_eof(t)) {
2579 protocol_error(c);
2580 return;
2581 }
2582
2583 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2584 s = pa_idxset_get_by_index(c->output_streams, idx);
2585 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2586 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2587
2588 /* Get an atomic snapshot of all timing parameters */
2589 pa_assert_se(pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0);
2590
2591 reply = reply_new(tag);
2592 pa_tagstruct_put_usec(reply,
2593 s->current_sink_latency +
2594 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2595 pa_tagstruct_put_usec(reply, 0);
2596 pa_tagstruct_put_boolean(reply,
2597 s->playing_for > 0 &&
2598 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2599 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2600 pa_tagstruct_put_timeval(reply, &tv);
2601 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2602 pa_tagstruct_puts64(reply, s->write_index);
2603 pa_tagstruct_puts64(reply, s->read_index);
2604
2605 if (c->version >= 13) {
2606 pa_tagstruct_putu64(reply, s->underrun_for);
2607 pa_tagstruct_putu64(reply, s->playing_for);
2608 }
2609
2610 pa_pstream_send_tagstruct(c->pstream, reply);
2611 }
2612
2613 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2614 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2615 pa_tagstruct *reply;
2616 record_stream *s;
2617 struct timeval tv, now;
2618 uint32_t idx;
2619
2620 pa_native_connection_assert_ref(c);
2621 pa_assert(t);
2622
2623 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2624 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2625 !pa_tagstruct_eof(t)) {
2626 protocol_error(c);
2627 return;
2628 }
2629
2630 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2631 s = pa_idxset_get_by_index(c->record_streams, idx);
2632 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2633
2634 /* Get an atomic snapshot of all timing parameters */
2635 pa_assert_se(pa_asyncmsgq_send(s->source_output->source->asyncmsgq, PA_MSGOBJECT(s->source_output), SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0);
2636
2637 reply = reply_new(tag);
2638 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2639 pa_tagstruct_put_usec(reply,
2640 s->current_source_latency +
2641 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec));
2642 pa_tagstruct_put_boolean(reply,
2643 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2644 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2645 pa_tagstruct_put_timeval(reply, &tv);
2646 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2647 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2648 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2649 pa_pstream_send_tagstruct(c->pstream, reply);
2650 }
2651
2652 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2653 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2654 upload_stream *s;
2655 uint32_t length;
2656 const char *name = NULL;
2657 pa_sample_spec ss;
2658 pa_channel_map map;
2659 pa_tagstruct *reply;
2660 pa_proplist *p;
2661
2662 pa_native_connection_assert_ref(c);
2663 pa_assert(t);
2664
2665 if (pa_tagstruct_gets(t, &name) < 0 ||
2666 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2667 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2668 pa_tagstruct_getu32(t, &length) < 0) {
2669 protocol_error(c);
2670 return;
2671 }
2672
2673 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2674 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2675 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2676 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2677 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2678 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2679
2680 p = pa_proplist_new();
2681
2682 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2683 !pa_tagstruct_eof(t)) {
2684
2685 protocol_error(c);
2686 pa_proplist_free(p);
2687 return;
2688 }
2689
2690 if (c->version < 13)
2691 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2692 else if (!name)
2693 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2694 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2695
2696 if (!name || !pa_namereg_is_valid_name(name)) {
2697 pa_proplist_free(p);
2698 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2699 }
2700
2701 s = upload_stream_new(c, &ss, &map, name, length, p);
2702 pa_proplist_free(p);
2703
2704 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2705
2706 reply = reply_new(tag);
2707 pa_tagstruct_putu32(reply, s->index);
2708 pa_tagstruct_putu32(reply, length);
2709 pa_pstream_send_tagstruct(c->pstream, reply);
2710 }
2711
2712 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2713 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2714 uint32_t channel;
2715 upload_stream *s;
2716 uint32_t idx;
2717
2718 pa_native_connection_assert_ref(c);
2719 pa_assert(t);
2720
2721 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2722 !pa_tagstruct_eof(t)) {
2723 protocol_error(c);
2724 return;
2725 }
2726
2727 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2728
2729 s = pa_idxset_get_by_index(c->output_streams, channel);
2730 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2731 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2732
2733 if (!s->memchunk.memblock)
2734 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2735 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2736 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2737 else
2738 pa_pstream_send_simple_ack(c->pstream, tag);
2739
2740 upload_stream_unlink(s);
2741 }
2742
2743 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2744 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2745 uint32_t sink_index;
2746 pa_volume_t volume;
2747 pa_sink *sink;
2748 const char *name, *sink_name;
2749 uint32_t idx;
2750 pa_proplist *p;
2751 pa_tagstruct *reply;
2752
2753 pa_native_connection_assert_ref(c);
2754 pa_assert(t);
2755
2756 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2757
2758 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2759 pa_tagstruct_gets(t, &sink_name) < 0 ||
2760 pa_tagstruct_getu32(t, &volume) < 0 ||
2761 pa_tagstruct_gets(t, &name) < 0) {
2762 protocol_error(c);
2763 return;
2764 }
2765
2766 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2767 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2768 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2769 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2770
2771 if (sink_index != PA_INVALID_INDEX)
2772 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2773 else
2774 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2775
2776 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2777
2778 p = pa_proplist_new();
2779
2780 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2781 !pa_tagstruct_eof(t)) {
2782 protocol_error(c);
2783 pa_proplist_free(p);
2784 return;
2785 }
2786
2787 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2788
2789 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2790 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2791 pa_proplist_free(p);
2792 return;
2793 }
2794
2795 pa_proplist_free(p);
2796
2797 reply = reply_new(tag);
2798
2799 if (c->version >= 13)
2800 pa_tagstruct_putu32(reply, idx);
2801
2802 pa_pstream_send_tagstruct(c->pstream, reply);
2803 }
2804
2805 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2806 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2807 const char *name;
2808
2809 pa_native_connection_assert_ref(c);
2810 pa_assert(t);
2811
2812 if (pa_tagstruct_gets(t, &name) < 0 ||
2813 !pa_tagstruct_eof(t)) {
2814 protocol_error(c);
2815 return;
2816 }
2817
2818 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2819 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2820
2821 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
2822 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2823 return;
2824 }
2825
2826 pa_pstream_send_simple_ack(c->pstream, tag);
2827 }
2828
2829 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
2830 pa_assert(c);
2831 pa_assert(fixed);
2832 pa_assert(original);
2833
2834 *fixed = *original;
2835
2836 if (c->version < 12) {
2837 /* Before protocol version 12 we didn't support S32 samples,
2838 * so we need to lie about this to the client */
2839
2840 if (fixed->format == PA_SAMPLE_S32LE)
2841 fixed->format = PA_SAMPLE_FLOAT32LE;
2842 if (fixed->format == PA_SAMPLE_S32BE)
2843 fixed->format = PA_SAMPLE_FLOAT32BE;
2844 }
2845
2846 if (c->version < 15) {
2847 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
2848 fixed->format = PA_SAMPLE_FLOAT32LE;
2849 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
2850 fixed->format = PA_SAMPLE_FLOAT32BE;
2851 }
2852 }
2853
2854 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
2855 pa_sample_spec fixed_ss;
2856
2857 pa_assert(t);
2858 pa_sink_assert_ref(sink);
2859
2860 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
2861
2862 pa_tagstruct_put(
2863 t,
2864 PA_TAG_U32, sink->index,
2865 PA_TAG_STRING, sink->name,
2866 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2867 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2868 PA_TAG_CHANNEL_MAP, &sink->channel_map,
2869 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
2870 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
2871 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
2872 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
2873 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
2874 PA_TAG_USEC, pa_sink_get_latency(sink),
2875 PA_TAG_STRING, sink->driver,
2876 PA_TAG_U32, sink->flags,
2877 PA_TAG_INVALID);
2878
2879 if (c->version >= 13) {
2880 pa_tagstruct_put_proplist(t, sink->proplist);
2881 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
2882 }
2883
2884 if (c->version >= 15) {
2885 pa_tagstruct_put_volume(t, sink->base_volume);
2886 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
2887 pa_log_error("Internal sink state is invalid.");
2888 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
2889 pa_tagstruct_putu32(t, sink->n_volume_steps);
2890 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
2891 }
2892
2893 if (c->version >= 16) {
2894 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
2895
2896 if (sink->ports) {
2897 void *state;
2898 pa_device_port *p;
2899
2900 PA_HASHMAP_FOREACH(p, sink->ports, state) {
2901 pa_tagstruct_puts(t, p->name);
2902 pa_tagstruct_puts(t, p->description);
2903 pa_tagstruct_putu32(t, p->priority);
2904 }
2905 }
2906
2907 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
2908 }
2909 }
2910
2911 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
2912 pa_sample_spec fixed_ss;
2913
2914 pa_assert(t);
2915 pa_source_assert_ref(source);
2916
2917 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
2918
2919 pa_tagstruct_put(
2920 t,
2921 PA_TAG_U32, source->index,
2922 PA_TAG_STRING, source->name,
2923 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2924 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2925 PA_TAG_CHANNEL_MAP, &source->channel_map,
2926 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
2927 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
2928 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
2929 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
2930 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
2931 PA_TAG_USEC, pa_source_get_latency(source),
2932 PA_TAG_STRING, source->driver,
2933 PA_TAG_U32, source->flags,
2934 PA_TAG_INVALID);
2935
2936 if (c->version >= 13) {
2937 pa_tagstruct_put_proplist(t, source->proplist);
2938 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
2939 }
2940
2941 if (c->version >= 15) {
2942 pa_tagstruct_put_volume(t, source->base_volume);
2943 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
2944 pa_log_error("Internal source state is invalid.");
2945 pa_tagstruct_putu32(t, pa_source_get_state(source));
2946 pa_tagstruct_putu32(t, source->n_volume_steps);
2947 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
2948 }
2949
2950 if (c->version >= 16) {
2951
2952 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
2953
2954 if (source->ports) {
2955 void *state;
2956 pa_device_port *p;
2957
2958 PA_HASHMAP_FOREACH(p, source->ports, state) {
2959 pa_tagstruct_puts(t, p->name);
2960 pa_tagstruct_puts(t, p->description);
2961 pa_tagstruct_putu32(t, p->priority);
2962 }
2963 }
2964
2965 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
2966 }
2967 }
2968
2969 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
2970 pa_assert(t);
2971 pa_assert(client);
2972
2973 pa_tagstruct_putu32(t, client->index);
2974 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
2975 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
2976 pa_tagstruct_puts(t, client->driver);
2977
2978 if (c->version >= 13)
2979 pa_tagstruct_put_proplist(t, client->proplist);
2980 }
2981
2982 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
2983 void *state = NULL;
2984 pa_card_profile *p;
2985
2986 pa_assert(t);
2987 pa_assert(card);
2988
2989 pa_tagstruct_putu32(t, card->index);
2990 pa_tagstruct_puts(t, card->name);
2991 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
2992 pa_tagstruct_puts(t, card->driver);
2993
2994 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
2995
2996 if (card->profiles) {
2997 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
2998 pa_tagstruct_puts(t, p->name);
2999 pa_tagstruct_puts(t, p->description);
3000 pa_tagstruct_putu32(t, p->n_sinks);
3001 pa_tagstruct_putu32(t, p->n_sources);
3002 pa_tagstruct_putu32(t, p->priority);
3003 }
3004 }
3005
3006 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
3007 pa_tagstruct_put_proplist(t, card->proplist);
3008 }
3009
3010 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3011 pa_assert(t);
3012 pa_assert(module);
3013
3014 pa_tagstruct_putu32(t, module->index);
3015 pa_tagstruct_puts(t, module->name);
3016 pa_tagstruct_puts(t, module->argument);
3017 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3018
3019 if (c->version < 15)
3020 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
3021
3022 if (c->version >= 15)
3023 pa_tagstruct_put_proplist(t, module->proplist);
3024 }
3025
3026 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3027 pa_sample_spec fixed_ss;
3028 pa_usec_t sink_latency;
3029 pa_cvolume v;
3030
3031 pa_assert(t);
3032 pa_sink_input_assert_ref(s);
3033
3034 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3035
3036 pa_tagstruct_putu32(t, s->index);
3037 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3038 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3039 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3040 pa_tagstruct_putu32(t, s->sink->index);
3041 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3042 pa_tagstruct_put_channel_map(t, &s->channel_map);
3043 pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s, &v, TRUE));
3044 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3045 pa_tagstruct_put_usec(t, sink_latency);
3046 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3047 pa_tagstruct_puts(t, s->driver);
3048 if (c->version >= 11)
3049 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3050 if (c->version >= 13)
3051 pa_tagstruct_put_proplist(t, s->proplist);
3052 }
3053
3054 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3055 pa_sample_spec fixed_ss;
3056 pa_usec_t source_latency;
3057
3058 pa_assert(t);
3059 pa_source_output_assert_ref(s);
3060
3061 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3062
3063 pa_tagstruct_putu32(t, s->index);
3064 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3065 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3066 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3067 pa_tagstruct_putu32(t, s->source->index);
3068 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3069 pa_tagstruct_put_channel_map(t, &s->channel_map);
3070 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3071 pa_tagstruct_put_usec(t, source_latency);
3072 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3073 pa_tagstruct_puts(t, s->driver);
3074
3075 if (c->version >= 13)
3076 pa_tagstruct_put_proplist(t, s->proplist);
3077 }
3078
3079 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3080 pa_sample_spec fixed_ss;
3081 pa_cvolume v;
3082
3083 pa_assert(t);
3084 pa_assert(e);
3085
3086 if (e->memchunk.memblock)
3087 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3088 else
3089 memset(&fixed_ss, 0, sizeof(fixed_ss));
3090
3091 pa_tagstruct_putu32(t, e->index);
3092 pa_tagstruct_puts(t, e->name);
3093
3094 if (e->volume_is_set)
3095 v = e->volume;
3096 else
3097 pa_cvolume_init(&v);
3098
3099 pa_tagstruct_put_cvolume(t, &v);
3100 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3101 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3102 pa_tagstruct_put_channel_map(t, &e->channel_map);
3103 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3104 pa_tagstruct_put_boolean(t, e->lazy);
3105 pa_tagstruct_puts(t, e->filename);
3106
3107 if (c->version >= 13)
3108 pa_tagstruct_put_proplist(t, e->proplist);
3109 }
3110
3111 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3112 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3113 uint32_t idx;
3114 pa_sink *sink = NULL;
3115 pa_source *source = NULL;
3116 pa_client *client = NULL;
3117 pa_card *card = NULL;
3118 pa_module *module = NULL;
3119 pa_sink_input *si = NULL;
3120 pa_source_output *so = NULL;
3121 pa_scache_entry *sce = NULL;
3122 const char *name = NULL;
3123 pa_tagstruct *reply;
3124
3125 pa_native_connection_assert_ref(c);
3126 pa_assert(t);
3127
3128 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3129 (command != PA_COMMAND_GET_CLIENT_INFO &&
3130 command != PA_COMMAND_GET_MODULE_INFO &&
3131 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3132 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3133 pa_tagstruct_gets(t, &name) < 0) ||
3134 !pa_tagstruct_eof(t)) {
3135 protocol_error(c);
3136 return;
3137 }
3138
3139 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3140 CHECK_VALIDITY(c->pstream, !name ||
3141 (command == PA_COMMAND_GET_SINK_INFO &&
3142 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3143 (command == PA_COMMAND_GET_SOURCE_INFO &&
3144 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3145 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3146 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3147 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3148 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3149
3150 if (command == PA_COMMAND_GET_SINK_INFO) {
3151 if (idx != PA_INVALID_INDEX)
3152 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3153 else
3154 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3155 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3156 if (idx != PA_INVALID_INDEX)
3157 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3158 else
3159 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3160 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3161 if (idx != PA_INVALID_INDEX)
3162 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3163 else
3164 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3165 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3166 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3167 else if (command == PA_COMMAND_GET_MODULE_INFO)
3168 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3169 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3170 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3171 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3172 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3173 else {
3174 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3175 if (idx != PA_INVALID_INDEX)
3176 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3177 else
3178 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3179 }
3180
3181 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3182 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3183 return;
3184 }
3185
3186 reply = reply_new(tag);
3187 if (sink)
3188 sink_fill_tagstruct(c, reply, sink);
3189 else if (source)
3190 source_fill_tagstruct(c, reply, source);
3191 else if (client)
3192 client_fill_tagstruct(c, reply, client);
3193 else if (card)
3194 card_fill_tagstruct(c, reply, card);
3195 else if (module)
3196 module_fill_tagstruct(c, reply, module);
3197 else if (si)
3198 sink_input_fill_tagstruct(c, reply, si);
3199 else if (so)
3200 source_output_fill_tagstruct(c, reply, so);
3201 else
3202 scache_fill_tagstruct(c, reply, sce);
3203 pa_pstream_send_tagstruct(c->pstream, reply);
3204 }
3205
3206 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3207 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3208 pa_idxset *i;
3209 uint32_t idx;
3210 void *p;
3211 pa_tagstruct *reply;
3212
3213 pa_native_connection_assert_ref(c);
3214 pa_assert(t);
3215
3216 if (!pa_tagstruct_eof(t)) {
3217 protocol_error(c);
3218 return;
3219 }
3220
3221 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3222
3223 reply = reply_new(tag);
3224
3225 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3226 i = c->protocol->core->sinks;
3227 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3228 i = c->protocol->core->sources;
3229 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3230 i = c->protocol->core->clients;
3231 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3232 i = c->protocol->core->cards;
3233 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3234 i = c->protocol->core->modules;
3235 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3236 i = c->protocol->core->sink_inputs;
3237 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3238 i = c->protocol->core->source_outputs;
3239 else {
3240 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3241 i = c->protocol->core->scache;
3242 }
3243
3244 if (i) {
3245 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3246 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3247 sink_fill_tagstruct(c, reply, p);
3248 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3249 source_fill_tagstruct(c, reply, p);
3250 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3251 client_fill_tagstruct(c, reply, p);
3252 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3253 card_fill_tagstruct(c, reply, p);
3254 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3255 module_fill_tagstruct(c, reply, p);
3256 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3257 sink_input_fill_tagstruct(c, reply, p);
3258 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3259 source_output_fill_tagstruct(c, reply, p);
3260 else {
3261 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3262 scache_fill_tagstruct(c, reply, p);
3263 }
3264 }
3265 }
3266
3267 pa_pstream_send_tagstruct(c->pstream, reply);
3268 }
3269
3270 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3271 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3272 pa_tagstruct *reply;
3273 pa_sink *def_sink;
3274 pa_source *def_source;
3275 pa_sample_spec fixed_ss;
3276 char *h, *u;
3277
3278 pa_native_connection_assert_ref(c);
3279 pa_assert(t);
3280
3281 if (!pa_tagstruct_eof(t)) {
3282 protocol_error(c);
3283 return;
3284 }
3285
3286 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3287
3288 reply = reply_new(tag);
3289 pa_tagstruct_puts(reply, PACKAGE_NAME);
3290 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3291
3292 u = pa_get_user_name_malloc();
3293 pa_tagstruct_puts(reply, u);
3294 pa_xfree(u);
3295
3296 h = pa_get_host_name_malloc();
3297 pa_tagstruct_puts(reply, h);
3298 pa_xfree(h);
3299
3300 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3301 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3302
3303 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3304 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3305 def_source = pa_namereg_get_default_source(c->protocol->core);
3306 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3307
3308 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3309
3310 if (c->version >= 15)
3311 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3312
3313 pa_pstream_send_tagstruct(c->pstream, reply);
3314 }
3315
3316 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3317 pa_tagstruct *t;
3318 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3319
3320 pa_native_connection_assert_ref(c);
3321
3322 t = pa_tagstruct_new(NULL, 0);
3323 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3324 pa_tagstruct_putu32(t, (uint32_t) -1);
3325 pa_tagstruct_putu32(t, e);
3326 pa_tagstruct_putu32(t, idx);
3327 pa_pstream_send_tagstruct(c->pstream, t);
3328 }
3329
3330 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3331 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3332 pa_subscription_mask_t m;
3333
3334 pa_native_connection_assert_ref(c);
3335 pa_assert(t);
3336
3337 if (pa_tagstruct_getu32(t, &m) < 0 ||
3338 !pa_tagstruct_eof(t)) {
3339 protocol_error(c);
3340 return;
3341 }
3342
3343 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3344 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3345
3346 if (c->subscription)
3347 pa_subscription_free(c->subscription);
3348
3349 if (m != 0) {
3350 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3351 pa_assert(c->subscription);
3352 } else
3353 c->subscription = NULL;
3354
3355 pa_pstream_send_simple_ack(c->pstream, tag);
3356 }
3357
3358 static void command_set_volume(
3359 pa_pdispatch *pd,
3360 uint32_t command,
3361 uint32_t tag,
3362 pa_tagstruct *t,
3363 void *userdata) {
3364
3365 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3366 uint32_t idx;
3367 pa_cvolume volume;
3368 pa_sink *sink = NULL;
3369 pa_source *source = NULL;
3370 pa_sink_input *si = NULL;
3371 const char *name = NULL;
3372 const char *client_name;
3373
3374 pa_native_connection_assert_ref(c);
3375 pa_assert(t);
3376
3377 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3378 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3379 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3380 pa_tagstruct_get_cvolume(t, &volume) ||
3381 !pa_tagstruct_eof(t)) {
3382 protocol_error(c);
3383 return;
3384 }
3385
3386 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3387 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_VOLUME ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
3388 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3389 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3390 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3391 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3392
3393 switch (command) {
3394
3395 case PA_COMMAND_SET_SINK_VOLUME:
3396 if (idx != PA_INVALID_INDEX)
3397 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3398 else
3399 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3400 break;
3401
3402 case PA_COMMAND_SET_SOURCE_VOLUME:
3403 if (idx != PA_INVALID_INDEX)
3404 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3405 else
3406 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3407 break;
3408
3409 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3410 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3411 break;
3412
3413 default:
3414 pa_assert_not_reached();
3415 }
3416
3417 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3418
3419 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3420
3421 if (sink) {
3422 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3423
3424 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3425 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3426 } else if (source) {
3427 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3428
3429 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3430 pa_source_set_volume(source, &volume, TRUE);
3431 } else if (si) {
3432 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3433
3434 pa_log_debug("Client %s changes volume of sink input %s.",
3435 client_name,
3436 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3437 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3438 }
3439
3440 pa_pstream_send_simple_ack(c->pstream, tag);
3441 }
3442
3443 static void command_set_mute(
3444 pa_pdispatch *pd,
3445 uint32_t command,
3446 uint32_t tag,
3447 pa_tagstruct *t,
3448 void *userdata) {
3449
3450 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3451 uint32_t idx;
3452 pa_bool_t mute;
3453 pa_sink *sink = NULL;
3454 pa_source *source = NULL;
3455 pa_sink_input *si = NULL;
3456 const char *name = NULL, *client_name;
3457
3458 pa_native_connection_assert_ref(c);
3459 pa_assert(t);
3460
3461 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3462 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3463 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3464 pa_tagstruct_get_boolean(t, &mute) ||
3465 !pa_tagstruct_eof(t)) {
3466 protocol_error(c);
3467 return;
3468 }
3469
3470 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3471 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_MUTE ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
3472 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3473 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3474 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3475
3476 switch (command) {
3477
3478 case PA_COMMAND_SET_SINK_MUTE:
3479 if (idx != PA_INVALID_INDEX)
3480 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3481 else
3482 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3483
3484 break;
3485
3486 case PA_COMMAND_SET_SOURCE_MUTE:
3487 if (idx != PA_INVALID_INDEX)
3488 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3489 else
3490 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3491
3492 break;
3493
3494 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3495 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3496 break;
3497
3498 default:
3499 pa_assert_not_reached();
3500 }
3501
3502 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3503
3504 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3505
3506 if (sink) {
3507 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3508 pa_sink_set_mute(sink, mute, TRUE);
3509 } else if (source) {
3510 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3511 pa_source_set_mute(source, mute, TRUE);
3512 } else if (si) {
3513 pa_log_debug("Client %s changes mute of sink input %s.",
3514 client_name,
3515 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3516 pa_sink_input_set_mute(si, mute, TRUE);
3517 }
3518
3519 pa_pstream_send_simple_ack(c->pstream, tag);
3520 }
3521
3522 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3523 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3524 uint32_t idx;
3525 pa_bool_t b;
3526 playback_stream *s;
3527
3528 pa_native_connection_assert_ref(c);
3529 pa_assert(t);
3530
3531 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3532 pa_tagstruct_get_boolean(t, &b) < 0 ||
3533 !pa_tagstruct_eof(t)) {
3534 protocol_error(c);
3535 return;
3536 }
3537
3538 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3539 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3540 s = pa_idxset_get_by_index(c->output_streams, idx);
3541 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3542 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3543
3544 pa_sink_input_cork(s->sink_input, b);
3545
3546 if (b)
3547 s->is_underrun = TRUE;
3548
3549 pa_pstream_send_simple_ack(c->pstream, tag);
3550 }
3551
3552 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3553 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3554 uint32_t idx;
3555 playback_stream *s;
3556
3557 pa_native_connection_assert_ref(c);
3558 pa_assert(t);
3559
3560 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3561 !pa_tagstruct_eof(t)) {
3562 protocol_error(c);
3563 return;
3564 }
3565
3566 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3567 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3568 s = pa_idxset_get_by_index(c->output_streams, idx);
3569 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3570 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3571
3572 switch (command) {
3573 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3574 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3575 break;
3576
3577 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3578 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3579 break;
3580
3581 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3582 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3583 break;
3584
3585 default:
3586 pa_assert_not_reached();
3587 }
3588
3589 pa_pstream_send_simple_ack(c->pstream, tag);
3590 }
3591
3592 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3593 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3594 uint32_t idx;
3595 record_stream *s;
3596 pa_bool_t b;
3597
3598 pa_native_connection_assert_ref(c);
3599 pa_assert(t);
3600
3601 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3602 pa_tagstruct_get_boolean(t, &b) < 0 ||
3603 !pa_tagstruct_eof(t)) {
3604 protocol_error(c);
3605 return;
3606 }
3607
3608 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3609 s = pa_idxset_get_by_index(c->record_streams, idx);
3610 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3611
3612 pa_source_output_cork(s->source_output, b);
3613 pa_memblockq_prebuf_force(s->memblockq);
3614 pa_pstream_send_simple_ack(c->pstream, tag);
3615 }
3616
3617 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3618 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3619 uint32_t idx;
3620 record_stream *s;
3621
3622 pa_native_connection_assert_ref(c);
3623 pa_assert(t);
3624
3625 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3626 !pa_tagstruct_eof(t)) {
3627 protocol_error(c);
3628 return;
3629 }
3630
3631 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3632 s = pa_idxset_get_by_index(c->record_streams, idx);
3633 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3634
3635 pa_memblockq_flush_read(s->memblockq);
3636 pa_pstream_send_simple_ack(c->pstream, tag);
3637 }
3638
3639 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3640 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3641 uint32_t idx;
3642 pa_buffer_attr a;
3643 pa_tagstruct *reply;
3644
3645 pa_native_connection_assert_ref(c);
3646 pa_assert(t);
3647
3648 memset(&a, 0, sizeof(a));
3649
3650 if (pa_tagstruct_getu32(t, &idx) < 0) {
3651 protocol_error(c);
3652 return;
3653 }
3654
3655 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3656
3657 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3658 playback_stream *s;
3659 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3660
3661 s = pa_idxset_get_by_index(c->output_streams, idx);
3662 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3663 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3664
3665 if (pa_tagstruct_get(
3666 t,
3667 PA_TAG_U32, &a.maxlength,
3668 PA_TAG_U32, &a.tlength,
3669 PA_TAG_U32, &a.prebuf,
3670 PA_TAG_U32, &a.minreq,
3671 PA_TAG_INVALID) < 0 ||
3672 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3673 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3674 !pa_tagstruct_eof(t)) {
3675 protocol_error(c);
3676 return;
3677 }
3678
3679 s->adjust_latency = adjust_latency;
3680 s->early_requests = early_requests;
3681 s->buffer_attr = a;
3682
3683 fix_playback_buffer_attr(s);
3684 pa_assert_se(pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR, NULL, 0, NULL) == 0);
3685
3686 reply = reply_new(tag);
3687 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3688 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3689 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3690 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3691
3692 if (c->version >= 13)
3693 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3694
3695 } else {
3696 record_stream *s;
3697 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3698 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3699
3700 s = pa_idxset_get_by_index(c->record_streams, idx);
3701 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3702
3703 if (pa_tagstruct_get(
3704 t,
3705 PA_TAG_U32, &a.maxlength,
3706 PA_TAG_U32, &a.fragsize,
3707 PA_TAG_INVALID) < 0 ||
3708 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3709 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3710 !pa_tagstruct_eof(t)) {
3711 protocol_error(c);
3712 return;
3713 }
3714
3715 s->adjust_latency = adjust_latency;
3716 s->early_requests = early_requests;
3717 s->buffer_attr = a;
3718
3719 fix_record_buffer_attr_pre(s);
3720 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3721 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3722 fix_record_buffer_attr_post(s);
3723
3724 reply = reply_new(tag);
3725 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3726 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3727
3728 if (c->version >= 13)
3729 pa_tagstruct_put_usec(reply, s->configured_source_latency);
3730 }
3731
3732 pa_pstream_send_tagstruct(c->pstream, reply);
3733 }
3734
3735 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3736 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3737 uint32_t idx;
3738 uint32_t rate;
3739
3740 pa_native_connection_assert_ref(c);
3741 pa_assert(t);
3742
3743 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3744 pa_tagstruct_getu32(t, &rate) < 0 ||
3745 !pa_tagstruct_eof(t)) {
3746 protocol_error(c);
3747 return;
3748 }
3749
3750 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3751 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
3752
3753 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
3754 playback_stream *s;
3755
3756 s = pa_idxset_get_by_index(c->output_streams, idx);
3757 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3758 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3759
3760 pa_sink_input_set_rate(s->sink_input, rate);
3761
3762 } else {
3763 record_stream *s;
3764 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
3765
3766 s = pa_idxset_get_by_index(c->record_streams, idx);
3767 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3768
3769 pa_source_output_set_rate(s->source_output, rate);
3770 }
3771
3772 pa_pstream_send_simple_ack(c->pstream, tag);
3773 }
3774
3775 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3776 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3777 uint32_t idx;
3778 uint32_t mode;
3779 pa_proplist *p;
3780
3781 pa_native_connection_assert_ref(c);
3782 pa_assert(t);
3783
3784 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3785
3786 p = pa_proplist_new();
3787
3788 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
3789
3790 if (pa_tagstruct_getu32(t, &mode) < 0 ||
3791 pa_tagstruct_get_proplist(t, p) < 0 ||
3792 !pa_tagstruct_eof(t)) {
3793 protocol_error(c);
3794 pa_proplist_free(p);
3795 return;
3796 }
3797
3798 } else {
3799
3800 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3801 pa_tagstruct_getu32(t, &mode) < 0 ||
3802 pa_tagstruct_get_proplist(t, p) < 0 ||
3803 !pa_tagstruct_eof(t)) {
3804 protocol_error(c);
3805 pa_proplist_free(p);
3806 return;
3807 }
3808 }
3809
3810 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
3811 pa_proplist_free(p);
3812 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
3813 }
3814
3815 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
3816 playback_stream *s;
3817
3818 s = pa_idxset_get_by_index(c->output_streams, idx);
3819 if (!s || !playback_stream_isinstance(s)) {
3820 pa_proplist_free(p);
3821 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3822 }
3823 pa_sink_input_update_proplist(s->sink_input, mode, p);
3824
3825 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
3826 record_stream *s;
3827
3828 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
3829 pa_proplist_free(p);
3830 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3831 }
3832 pa_source_output_update_proplist(s->source_output, mode, p);
3833
3834 } else {
3835 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
3836
3837 pa_client_update_proplist(c->client, mode, p);
3838 }
3839
3840 pa_pstream_send_simple_ack(c->pstream, tag);
3841 pa_proplist_free(p);
3842 }
3843
3844 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3845 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3846 uint32_t idx;
3847 unsigned changed = 0;
3848 pa_proplist *p;
3849 pa_strlist *l = NULL;
3850
3851 pa_native_connection_assert_ref(c);
3852 pa_assert(t);
3853
3854 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3855
3856 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
3857
3858 if (pa_tagstruct_getu32(t, &idx) < 0) {
3859 protocol_error(c);
3860 return;
3861 }
3862 }
3863
3864 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3865 playback_stream *s;
3866
3867 s = pa_idxset_get_by_index(c->output_streams, idx);
3868 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3869 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3870
3871 p = s->sink_input->proplist;
3872
3873 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3874 record_stream *s;
3875
3876 s = pa_idxset_get_by_index(c->record_streams, idx);
3877 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3878
3879 p = s->source_output->proplist;
3880 } else {
3881 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3882
3883 p = c->client->proplist;
3884 }
3885
3886 for (;;) {
3887 const char *k;
3888
3889 if (pa_tagstruct_gets(t, &k) < 0) {
3890 protocol_error(c);
3891 pa_strlist_free(l);
3892 return;
3893 }
3894
3895 if (!k)
3896 break;
3897
3898 l = pa_strlist_prepend(l, k);
3899 }
3900
3901 if (!pa_tagstruct_eof(t)) {
3902 protocol_error(c);
3903 pa_strlist_free(l);
3904 return;
3905 }
3906
3907 for (;;) {
3908 char *z;
3909
3910 l = pa_strlist_pop(l, &z);
3911
3912 if (!z)
3913 break;
3914
3915 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
3916 pa_xfree(z);
3917 }
3918
3919 pa_pstream_send_simple_ack(c->pstream, tag);
3920
3921 if (changed) {
3922 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3923 playback_stream *s;
3924
3925 s = pa_idxset_get_by_index(c->output_streams, idx);
3926 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
3927
3928 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3929 record_stream *s;
3930
3931 s = pa_idxset_get_by_index(c->record_streams, idx);
3932 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
3933
3934 } else {
3935 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3936 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
3937 }
3938 }
3939 }
3940
3941 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3942 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3943 const char *s;
3944
3945 pa_native_connection_assert_ref(c);
3946 pa_assert(t);
3947
3948 if (pa_tagstruct_gets(t, &s) < 0 ||
3949 !pa_tagstruct_eof(t)) {
3950 protocol_error(c);
3951 return;
3952 }
3953
3954 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3955 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
3956
3957 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
3958 pa_source *source;
3959
3960 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
3961 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
3962
3963 pa_namereg_set_default_source(c->protocol->core, source);
3964 } else {
3965 pa_sink *sink;
3966 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
3967
3968 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
3969 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3970
3971 pa_namereg_set_default_sink(c->protocol->core, sink);
3972 }
3973
3974 pa_pstream_send_simple_ack(c->pstream, tag);
3975 }
3976
3977 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3978 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3979 uint32_t idx;
3980 const char *name;
3981
3982 pa_native_connection_assert_ref(c);
3983 pa_assert(t);
3984
3985 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3986 pa_tagstruct_gets(t, &name) < 0 ||
3987 !pa_tagstruct_eof(t)) {
3988 protocol_error(c);
3989 return;
3990 }
3991
3992 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3993 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
3994
3995 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
3996 playback_stream *s;
3997
3998 s = pa_idxset_get_by_index(c->output_streams, idx);
3999 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4000 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4001
4002 pa_sink_input_set_name(s->sink_input, name);
4003
4004 } else {
4005 record_stream *s;
4006 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4007
4008 s = pa_idxset_get_by_index(c->record_streams, idx);
4009 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4010
4011 pa_source_output_set_name(s->source_output, name);
4012 }
4013
4014 pa_pstream_send_simple_ack(c->pstream, tag);
4015 }
4016
4017 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4018 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4019 uint32_t idx;
4020
4021 pa_native_connection_assert_ref(c);
4022 pa_assert(t);
4023
4024 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4025 !pa_tagstruct_eof(t)) {
4026 protocol_error(c);
4027 return;
4028 }
4029
4030 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4031
4032 if (command == PA_COMMAND_KILL_CLIENT) {
4033 pa_client *client;
4034
4035 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4036 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4037
4038 pa_native_connection_ref(c);
4039 pa_client_kill(client);
4040
4041 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4042 pa_sink_input *s;
4043
4044 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4045 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4046
4047 pa_native_connection_ref(c);
4048 pa_sink_input_kill(s);
4049 } else {
4050 pa_source_output *s;
4051
4052 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4053
4054 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4055 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4056
4057 pa_native_connection_ref(c);
4058 pa_source_output_kill(s);
4059 }
4060
4061 pa_pstream_send_simple_ack(c->pstream, tag);
4062 pa_native_connection_unref(c);
4063 }
4064
4065 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4066 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4067 pa_module *m;
4068 const char *name, *argument;
4069 pa_tagstruct *reply;
4070
4071 pa_native_connection_assert_ref(c);
4072 pa_assert(t);
4073
4074 if (pa_tagstruct_gets(t, &name) < 0 ||
4075 pa_tagstruct_gets(t, &argument) < 0 ||
4076 !pa_tagstruct_eof(t)) {
4077 protocol_error(c);
4078 return;
4079 }
4080
4081 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4082 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4083 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4084
4085 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4086 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4087 return;
4088 }
4089
4090 reply = reply_new(tag);
4091 pa_tagstruct_putu32(reply, m->index);
4092 pa_pstream_send_tagstruct(c->pstream, reply);
4093 }
4094
4095 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4096 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4097 uint32_t idx;
4098 pa_module *m;
4099
4100 pa_native_connection_assert_ref(c);
4101 pa_assert(t);
4102
4103 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4104 !pa_tagstruct_eof(t)) {
4105 protocol_error(c);
4106 return;
4107 }
4108
4109 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4110 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4111 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4112
4113 pa_module_unload_request(m, FALSE);
4114 pa_pstream_send_simple_ack(c->pstream, tag);
4115 }
4116
4117 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4118 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4119 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4120 const char *name_device = NULL;
4121
4122 pa_native_connection_assert_ref(c);
4123 pa_assert(t);
4124
4125 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4126 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4127 pa_tagstruct_gets(t, &name_device) < 0 ||
4128 !pa_tagstruct_eof(t)) {
4129 protocol_error(c);
4130 return;
4131 }
4132
4133 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4134 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4135
4136 CHECK_VALIDITY(c->pstream, !name_device || pa_namereg_is_valid_name_or_wildcard(name_device, command == PA_COMMAND_MOVE_SINK_INPUT ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
4137 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4138 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4139 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4140
4141 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4142 pa_sink_input *si = NULL;
4143 pa_sink *sink = NULL;
4144
4145 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4146
4147 if (idx_device != PA_INVALID_INDEX)
4148 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4149 else
4150 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4151
4152 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4153
4154 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4155 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4156 return;
4157 }
4158 } else {
4159 pa_source_output *so = NULL;
4160 pa_source *source;
4161
4162 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4163
4164 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4165
4166 if (idx_device != PA_INVALID_INDEX)
4167 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4168 else
4169 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4170
4171 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4172
4173 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4174 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4175 return;
4176 }
4177 }
4178
4179 pa_pstream_send_simple_ack(c->pstream, tag);
4180 }
4181
4182 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4183 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4184 uint32_t idx = PA_INVALID_INDEX;
4185 const char *name = NULL;
4186 pa_bool_t b;
4187
4188 pa_native_connection_assert_ref(c);
4189 pa_assert(t);
4190
4191 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4192 pa_tagstruct_gets(t, &name) < 0 ||
4193 pa_tagstruct_get_boolean(t, &b) < 0 ||
4194 !pa_tagstruct_eof(t)) {
4195 protocol_error(c);
4196 return;
4197 }
4198
4199 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4200 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SUSPEND_SINK ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) || *name == 0, tag, PA_ERR_INVALID);
4201 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4202 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4203 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4204
4205 if (command == PA_COMMAND_SUSPEND_SINK) {
4206
4207 if (idx == PA_INVALID_INDEX && name && !*name) {
4208
4209 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4210
4211 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4212 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4213 return;
4214 }
4215 } else {
4216 pa_sink *sink = NULL;
4217
4218 if (idx != PA_INVALID_INDEX)
4219 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4220 else
4221 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4222
4223 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4224
4225 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4226 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4227 return;
4228 }
4229 }
4230 } else {
4231
4232 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4233
4234 if (idx == PA_INVALID_INDEX && name && !*name) {
4235
4236 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4237
4238 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4239 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4240 return;
4241 }
4242
4243 } else {
4244 pa_source *source;
4245
4246 if (idx != PA_INVALID_INDEX)
4247 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4248 else
4249 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4250
4251 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4252
4253 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4254 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4255 return;
4256 }
4257 }
4258 }
4259
4260 pa_pstream_send_simple_ack(c->pstream, tag);
4261 }
4262
4263 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4264 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4265 uint32_t idx = PA_INVALID_INDEX;
4266 const char *name = NULL;
4267 pa_module *m;
4268 pa_native_protocol_ext_cb_t cb;
4269
4270 pa_native_connection_assert_ref(c);
4271 pa_assert(t);
4272
4273 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4274 pa_tagstruct_gets(t, &name) < 0) {
4275 protocol_error(c);
4276 return;
4277 }
4278
4279 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4280 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4281 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4282 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4283 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4284
4285 if (idx != PA_INVALID_INDEX)
4286 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4287 else {
4288 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4289 if (strcmp(name, m->name) == 0)
4290 break;
4291 }
4292
4293 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4294 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4295
4296 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4297 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4298
4299 if (cb(c->protocol, m, c, tag, t) < 0)
4300 protocol_error(c);
4301 }
4302
4303 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4304 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4305 uint32_t idx = PA_INVALID_INDEX;
4306 const char *name = NULL, *profile = NULL;
4307 pa_card *card = NULL;
4308 int ret;
4309
4310 pa_native_connection_assert_ref(c);
4311 pa_assert(t);
4312
4313 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4314 pa_tagstruct_gets(t, &name) < 0 ||
4315 pa_tagstruct_gets(t, &profile) < 0 ||
4316 !pa_tagstruct_eof(t)) {
4317 protocol_error(c);
4318 return;
4319 }
4320
4321 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4322 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4323 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4324 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4325 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4326
4327 if (idx != PA_INVALID_INDEX)
4328 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4329 else
4330 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4331
4332 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4333
4334 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4335 pa_pstream_send_error(c->pstream, tag, -ret);
4336 return;
4337 }
4338
4339 pa_pstream_send_simple_ack(c->pstream, tag);
4340 }
4341
4342 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4343 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4344 uint32_t idx = PA_INVALID_INDEX;
4345 const char *name = NULL, *port = NULL;
4346 int ret;
4347
4348 pa_native_connection_assert_ref(c);
4349 pa_assert(t);
4350
4351 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4352 pa_tagstruct_gets(t, &name) < 0 ||
4353 pa_tagstruct_gets(t, &port) < 0 ||
4354 !pa_tagstruct_eof(t)) {
4355 protocol_error(c);
4356 return;
4357 }
4358
4359 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4360 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_PORT ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
4361 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4362 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4363 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4364
4365 if (command == PA_COMMAND_SET_SINK_PORT) {
4366 pa_sink *sink;
4367
4368 if (idx != PA_INVALID_INDEX)
4369 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4370 else
4371 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4372
4373 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4374
4375 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4376 pa_pstream_send_error(c->pstream, tag, -ret);
4377 return;
4378 }
4379 } else {
4380 pa_source *source;
4381
4382 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4383
4384 if (idx != PA_INVALID_INDEX)
4385 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4386 else
4387 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4388
4389 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4390
4391 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4392 pa_pstream_send_error(c->pstream, tag, -ret);
4393 return;
4394 }
4395 }
4396
4397 pa_pstream_send_simple_ack(c->pstream, tag);
4398 }
4399
4400 /*** pstream callbacks ***/
4401
4402 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4403 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4404
4405 pa_assert(p);
4406 pa_assert(packet);
4407 pa_native_connection_assert_ref(c);
4408
4409 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4410 pa_log("invalid packet.");
4411 native_connection_unlink(c);
4412 }
4413 }
4414
4415 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) {
4416 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4417 output_stream *stream;
4418
4419 pa_assert(p);
4420 pa_assert(chunk);
4421 pa_native_connection_assert_ref(c);
4422
4423 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4424 pa_log_debug("Client sent block for invalid stream.");
4425 /* Ignoring */
4426 return;
4427 }
4428
4429 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4430
4431 if (playback_stream_isinstance(stream)) {
4432 playback_stream *ps = PLAYBACK_STREAM(stream);
4433
4434 if (chunk->memblock) {
4435 if (seek != PA_SEEK_RELATIVE || offset != 0)
4436 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);
4437
4438 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4439 } else
4440 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset+chunk->length, NULL, NULL);
4441
4442 } else {
4443 upload_stream *u = UPLOAD_STREAM(stream);
4444 size_t l;
4445
4446 if (!u->memchunk.memblock) {
4447 if (u->length == chunk->length && chunk->memblock) {
4448 u->memchunk = *chunk;
4449 pa_memblock_ref(u->memchunk.memblock);
4450 u->length = 0;
4451 } else {
4452 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4453 u->memchunk.index = u->memchunk.length = 0;
4454 }
4455 }
4456
4457 pa_assert(u->memchunk.memblock);
4458
4459 l = u->length;
4460 if (l > chunk->length)
4461 l = chunk->length;
4462
4463 if (l > 0) {
4464 void *dst;
4465 dst = pa_memblock_acquire(u->memchunk.memblock);
4466
4467 if (chunk->memblock) {
4468 void *src;
4469 src = pa_memblock_acquire(chunk->memblock);
4470
4471 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4472 (uint8_t*) src + chunk->index, l);
4473
4474 pa_memblock_release(chunk->memblock);
4475 } else
4476 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4477
4478 pa_memblock_release(u->memchunk.memblock);
4479
4480 u->memchunk.length += l;
4481 u->length -= l;
4482 }
4483 }
4484 }
4485
4486 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4487 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4488
4489 pa_assert(p);
4490 pa_native_connection_assert_ref(c);
4491
4492 native_connection_unlink(c);
4493 pa_log_info("Connection died.");
4494 }
4495
4496 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4497 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4498
4499 pa_assert(p);
4500 pa_native_connection_assert_ref(c);
4501
4502 native_connection_send_memblock(c);
4503 }
4504
4505 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4506 pa_thread_mq *q;
4507
4508 if (!(q = pa_thread_mq_get()))
4509 pa_pstream_send_revoke(p, block_id);
4510 else
4511 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4512 }
4513
4514 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4515 pa_thread_mq *q;
4516
4517 if (!(q = pa_thread_mq_get()))
4518 pa_pstream_send_release(p, block_id);
4519 else
4520 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4521 }
4522
4523 /*** client callbacks ***/
4524
4525 static void client_kill_cb(pa_client *c) {
4526 pa_assert(c);
4527
4528 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4529 pa_log_info("Connection killed.");
4530 }
4531
4532 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4533 pa_tagstruct *t;
4534 pa_native_connection *c;
4535
4536 pa_assert(client);
4537 c = PA_NATIVE_CONNECTION(client->userdata);
4538 pa_native_connection_assert_ref(c);
4539
4540 if (c->version < 15)
4541 return;
4542
4543 t = pa_tagstruct_new(NULL, 0);
4544 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4545 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4546 pa_tagstruct_puts(t, event);
4547 pa_tagstruct_put_proplist(t, pl);
4548 pa_pstream_send_tagstruct(c->pstream, t);
4549 }
4550
4551 /*** module entry points ***/
4552
4553 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4554 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4555
4556 pa_assert(m);
4557 pa_native_connection_assert_ref(c);
4558 pa_assert(c->auth_timeout_event == e);
4559
4560 if (!c->authorized) {
4561 native_connection_unlink(c);
4562 pa_log_info("Connection terminated due to authentication timeout.");
4563 }
4564 }
4565
4566 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4567 pa_native_connection *c;
4568 char pname[128];
4569 pa_client *client;
4570 pa_client_new_data data;
4571
4572 pa_assert(p);
4573 pa_assert(io);
4574 pa_assert(o);
4575
4576 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4577 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4578 pa_iochannel_free(io);
4579 return;
4580 }
4581
4582 pa_client_new_data_init(&data);
4583 data.module = o->module;
4584 data.driver = __FILE__;
4585 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4586 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4587 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4588 client = pa_client_new(p->core, &data);
4589 pa_client_new_data_done(&data);
4590
4591 if (!client)
4592 return;
4593
4594 c = pa_msgobject_new(pa_native_connection);
4595 c->parent.parent.free = native_connection_free;
4596 c->parent.process_msg = native_connection_process_msg;
4597 c->protocol = p;
4598 c->options = pa_native_options_ref(o);
4599 c->authorized = FALSE;
4600
4601 if (o->auth_anonymous) {
4602 pa_log_info("Client authenticated anonymously.");
4603 c->authorized = TRUE;
4604 }
4605
4606 if (!c->authorized &&
4607 o->auth_ip_acl &&
4608 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4609
4610 pa_log_info("Client authenticated by IP ACL.");
4611 c->authorized = TRUE;
4612 }
4613
4614 if (!c->authorized)
4615 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4616 else
4617 c->auth_timeout_event = NULL;
4618
4619 c->is_local = pa_iochannel_socket_is_local(io);
4620 c->version = 8;
4621
4622 c->client = client;
4623 c->client->kill = client_kill_cb;
4624 c->client->send_event = client_send_event_cb;
4625 c->client->userdata = c;
4626
4627 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4628 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4629 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4630 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4631 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4632 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4633 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4634
4635 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4636
4637 c->record_streams = pa_idxset_new(NULL, NULL);
4638 c->output_streams = pa_idxset_new(NULL, NULL);
4639
4640 c->rrobin_index = PA_IDXSET_INVALID;
4641 c->subscription = NULL;
4642
4643 pa_idxset_put(p->connections, c, NULL);
4644
4645 #ifdef HAVE_CREDS
4646 if (pa_iochannel_creds_supported(io))
4647 pa_iochannel_creds_enable(io);
4648 #endif
4649
4650 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4651 }
4652
4653 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4654 pa_native_connection *c;
4655 void *state = NULL;
4656
4657 pa_assert(p);
4658 pa_assert(m);
4659
4660 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4661 if (c->options->module == m)
4662 native_connection_unlink(c);
4663 }
4664
4665 static pa_native_protocol* native_protocol_new(pa_core *c) {
4666 pa_native_protocol *p;
4667 pa_native_hook_t h;
4668
4669 pa_assert(c);
4670
4671 p = pa_xnew(pa_native_protocol, 1);
4672 PA_REFCNT_INIT(p);
4673 p->core = c;
4674 p->connections = pa_idxset_new(NULL, NULL);
4675
4676 p->servers = NULL;
4677
4678 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4679
4680 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4681 pa_hook_init(&p->hooks[h], p);
4682
4683 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4684
4685 return p;
4686 }
4687
4688 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4689 pa_native_protocol *p;
4690
4691 if ((p = pa_shared_get(c, "native-protocol")))
4692 return pa_native_protocol_ref(p);
4693
4694 return native_protocol_new(c);
4695 }
4696
4697 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4698 pa_assert(p);
4699 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4700
4701 PA_REFCNT_INC(p);
4702
4703 return p;
4704 }
4705
4706 void pa_native_protocol_unref(pa_native_protocol *p) {
4707 pa_native_connection *c;
4708 pa_native_hook_t h;
4709
4710 pa_assert(p);
4711 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4712
4713 if (PA_REFCNT_DEC(p) > 0)
4714 return;
4715
4716 while ((c = pa_idxset_first(p->connections, NULL)))
4717 native_connection_unlink(c);
4718
4719 pa_idxset_free(p->connections, NULL, NULL);
4720
4721 pa_strlist_free(p->servers);
4722
4723 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4724 pa_hook_done(&p->hooks[h]);
4725
4726 pa_hashmap_free(p->extensions, NULL, NULL);
4727
4728 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4729
4730 pa_xfree(p);
4731 }
4732
4733 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
4734 pa_assert(p);
4735 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4736 pa_assert(name);
4737
4738 p->servers = pa_strlist_prepend(p->servers, name);
4739
4740 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4741 }
4742
4743 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
4744 pa_assert(p);
4745 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4746 pa_assert(name);
4747
4748 p->servers = pa_strlist_remove(p->servers, name);
4749
4750 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4751 }
4752
4753 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
4754 pa_assert(p);
4755 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4756
4757 return p->hooks;
4758 }
4759
4760 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
4761 pa_assert(p);
4762 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4763
4764 return p->servers;
4765 }
4766
4767 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
4768 pa_assert(p);
4769 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4770 pa_assert(m);
4771 pa_assert(cb);
4772 pa_assert(!pa_hashmap_get(p->extensions, m));
4773
4774 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
4775 return 0;
4776 }
4777
4778 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
4779 pa_assert(p);
4780 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4781 pa_assert(m);
4782
4783 pa_assert_se(pa_hashmap_remove(p->extensions, m));
4784 }
4785
4786 pa_native_options* pa_native_options_new(void) {
4787 pa_native_options *o;
4788
4789 o = pa_xnew0(pa_native_options, 1);
4790 PA_REFCNT_INIT(o);
4791
4792 return o;
4793 }
4794
4795 pa_native_options* pa_native_options_ref(pa_native_options *o) {
4796 pa_assert(o);
4797 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4798
4799 PA_REFCNT_INC(o);
4800
4801 return o;
4802 }
4803
4804 void pa_native_options_unref(pa_native_options *o) {
4805 pa_assert(o);
4806 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4807
4808 if (PA_REFCNT_DEC(o) > 0)
4809 return;
4810
4811 pa_xfree(o->auth_group);
4812
4813 if (o->auth_ip_acl)
4814 pa_ip_acl_free(o->auth_ip_acl);
4815
4816 if (o->auth_cookie)
4817 pa_auth_cookie_unref(o->auth_cookie);
4818
4819 pa_xfree(o);
4820 }
4821
4822 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
4823 pa_bool_t enabled;
4824 const char *acl;
4825
4826 pa_assert(o);
4827 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4828 pa_assert(ma);
4829
4830 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
4831 pa_log("auth-anonymous= expects a boolean argument.");
4832 return -1;
4833 }
4834
4835 enabled = TRUE;
4836 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
4837 pa_log("auth-group-enabled= expects a boolean argument.");
4838 return -1;
4839 }
4840
4841 pa_xfree(o->auth_group);
4842 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
4843
4844 #ifndef HAVE_CREDS
4845 if (o->auth_group)
4846 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4847 #endif
4848
4849 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
4850 pa_ip_acl *ipa;
4851
4852 if (!(ipa = pa_ip_acl_new(acl))) {
4853 pa_log("Failed to parse IP ACL '%s'", acl);
4854 return -1;
4855 }
4856
4857 if (o->auth_ip_acl)
4858 pa_ip_acl_free(o->auth_ip_acl);
4859
4860 o->auth_ip_acl = ipa;
4861 }
4862
4863 enabled = TRUE;
4864 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
4865 pa_log("auth-cookie-enabled= expects a boolean argument.");
4866 return -1;
4867 }
4868
4869 if (o->auth_cookie)
4870 pa_auth_cookie_unref(o->auth_cookie);
4871
4872 if (enabled) {
4873 const char *cn;
4874
4875 /* The new name for this is 'auth-cookie', for compat reasons
4876 * we check the old name too */
4877 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
4878 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
4879 cn = PA_NATIVE_COOKIE_FILE;
4880
4881 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
4882 return -1;
4883
4884 } else
4885 o->auth_cookie = NULL;
4886
4887 return 0;
4888 }
4889
4890 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
4891 pa_native_connection_assert_ref(c);
4892
4893 return c->pstream;
4894 }
4895
4896 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
4897 pa_native_connection_assert_ref(c);
4898
4899 return c->client;
4900 }