]> code.delx.au - pulseaudio/blob - src/pulsecore/protocol-native.c
native: fix request counter miscalculations
[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 /* Called from thread context */
1330 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1331 pa_sink_input *i = PA_SINK_INPUT(o);
1332 playback_stream *s;
1333
1334 pa_sink_input_assert_ref(i);
1335 s = PLAYBACK_STREAM(i->userdata);
1336 playback_stream_assert_ref(s);
1337
1338 switch (code) {
1339
1340 case SINK_INPUT_MESSAGE_SEEK: {
1341 int64_t windex;
1342
1343 windex = pa_memblockq_get_write_index(s->memblockq);
1344
1345 /* The client side is incapable of accounting correctly
1346 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1347 * able to deal with that. */
1348
1349 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1350
1351 handle_seek(s, windex);
1352 return 0;
1353 }
1354
1355 case SINK_INPUT_MESSAGE_POST_DATA: {
1356 int64_t windex;
1357
1358 pa_assert(chunk);
1359
1360 windex = pa_memblockq_get_write_index(s->memblockq);
1361
1362 /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
1363
1364 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1365
1366 if (pa_log_ratelimit())
1367 pa_log_warn("Failed to push data into queue");
1368 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1369 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1370 }
1371
1372 handle_seek(s, windex);
1373
1374 /* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1375
1376 return 0;
1377 }
1378
1379 case SINK_INPUT_MESSAGE_DRAIN:
1380 case SINK_INPUT_MESSAGE_FLUSH:
1381 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1382 case SINK_INPUT_MESSAGE_TRIGGER: {
1383
1384 int64_t windex;
1385 pa_sink_input *isync;
1386 void (*func)(pa_memblockq *bq);
1387
1388 switch (code) {
1389 case SINK_INPUT_MESSAGE_FLUSH:
1390 func = pa_memblockq_flush_write;
1391 break;
1392
1393 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1394 func = pa_memblockq_prebuf_force;
1395 break;
1396
1397 case SINK_INPUT_MESSAGE_DRAIN:
1398 case SINK_INPUT_MESSAGE_TRIGGER:
1399 func = pa_memblockq_prebuf_disable;
1400 break;
1401
1402 default:
1403 pa_assert_not_reached();
1404 }
1405
1406 windex = pa_memblockq_get_write_index(s->memblockq);
1407 func(s->memblockq);
1408 handle_seek(s, windex);
1409
1410 /* Do the same for all other members in the sync group */
1411 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1412 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1413 windex = pa_memblockq_get_write_index(ssync->memblockq);
1414 func(ssync->memblockq);
1415 handle_seek(ssync, windex);
1416 }
1417
1418 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1419 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1420 windex = pa_memblockq_get_write_index(ssync->memblockq);
1421 func(ssync->memblockq);
1422 handle_seek(ssync, windex);
1423 }
1424
1425 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1426 if (!pa_memblockq_is_readable(s->memblockq))
1427 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1428 else {
1429 s->drain_tag = PA_PTR_TO_UINT(userdata);
1430 s->drain_request = TRUE;
1431 }
1432 }
1433
1434 return 0;
1435 }
1436
1437 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1438 /* Atomically get a snapshot of all timing parameters... */
1439 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1440 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1441 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1442 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1443 s->underrun_for = s->sink_input->thread_info.underrun_for;
1444 s->playing_for = s->sink_input->thread_info.playing_for;
1445
1446 return 0;
1447
1448 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1449 int64_t windex;
1450
1451 windex = pa_memblockq_get_write_index(s->memblockq);
1452
1453 pa_memblockq_prebuf_force(s->memblockq);
1454
1455 handle_seek(s, windex);
1456
1457 /* Fall through to the default handler */
1458 break;
1459 }
1460
1461 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1462 pa_usec_t *r = userdata;
1463
1464 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1465
1466 /* Fall through, the default handler will add in the extra
1467 * latency added by the resampler */
1468 break;
1469 }
1470
1471 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1472 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1473 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1474 return 0;
1475 }
1476 }
1477
1478 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1479 }
1480
1481 /* Called from thread context */
1482 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1483 playback_stream *s;
1484
1485 pa_sink_input_assert_ref(i);
1486 s = PLAYBACK_STREAM(i->userdata);
1487 playback_stream_assert_ref(s);
1488 pa_assert(chunk);
1489
1490 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1491
1492 if (pa_memblockq_is_readable(s->memblockq))
1493 s->is_underrun = FALSE;
1494 else {
1495 if (!s->is_underrun)
1496 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));
1497
1498 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1499 s->drain_request = FALSE;
1500 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);
1501 } else if (!s->is_underrun)
1502 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1503
1504 s->is_underrun = TRUE;
1505
1506 playback_stream_request_bytes(s);
1507 }
1508
1509 /* This call will not fail with prebuf=0, hence we check for
1510 underrun explicitly above */
1511 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1512 return -1;
1513
1514 chunk->length = PA_MIN(nbytes, chunk->length);
1515
1516 if (i->thread_info.underrun_for > 0)
1517 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1518
1519 pa_memblockq_drop(s->memblockq, chunk->length);
1520 playback_stream_request_bytes(s);
1521
1522 return 0;
1523 }
1524
1525 /* Called from thread context */
1526 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1527 playback_stream *s;
1528
1529 pa_sink_input_assert_ref(i);
1530 s = PLAYBACK_STREAM(i->userdata);
1531 playback_stream_assert_ref(s);
1532
1533 /* If we are in an underrun, then we don't rewind */
1534 if (i->thread_info.underrun_for > 0)
1535 return;
1536
1537 pa_memblockq_rewind(s->memblockq, nbytes);
1538 }
1539
1540 /* Called from thread context */
1541 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1542 playback_stream *s;
1543
1544 pa_sink_input_assert_ref(i);
1545 s = PLAYBACK_STREAM(i->userdata);
1546 playback_stream_assert_ref(s);
1547
1548 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1549 }
1550
1551 /* Called from thread context */
1552 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1553 playback_stream *s;
1554 size_t new_tlength, old_tlength;
1555
1556 pa_sink_input_assert_ref(i);
1557 s = PLAYBACK_STREAM(i->userdata);
1558 playback_stream_assert_ref(s);
1559
1560 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1561 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1562
1563 if (old_tlength < new_tlength) {
1564 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1565 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1566 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1567
1568 if (new_tlength == old_tlength)
1569 pa_log_debug("Failed to increase tlength");
1570 else {
1571 pa_log_debug("Notifying client about increased tlength");
1572 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);
1573 }
1574 }
1575 }
1576
1577 /* Called from main context */
1578 static void sink_input_kill_cb(pa_sink_input *i) {
1579 playback_stream *s;
1580
1581 pa_sink_input_assert_ref(i);
1582 s = PLAYBACK_STREAM(i->userdata);
1583 playback_stream_assert_ref(s);
1584
1585 playback_stream_send_killed(s);
1586 playback_stream_unlink(s);
1587 }
1588
1589 /* Called from main context */
1590 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1591 playback_stream *s;
1592 pa_tagstruct *t;
1593
1594 pa_sink_input_assert_ref(i);
1595 s = PLAYBACK_STREAM(i->userdata);
1596 playback_stream_assert_ref(s);
1597
1598 if (s->connection->version < 15)
1599 return;
1600
1601 t = pa_tagstruct_new(NULL, 0);
1602 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1603 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1604 pa_tagstruct_putu32(t, s->index);
1605 pa_tagstruct_puts(t, event);
1606 pa_tagstruct_put_proplist(t, pl);
1607 pa_pstream_send_tagstruct(s->connection->pstream, t);
1608 }
1609
1610 /* Called from main context */
1611 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1612 playback_stream *s;
1613 pa_tagstruct *t;
1614
1615 pa_sink_input_assert_ref(i);
1616 s = PLAYBACK_STREAM(i->userdata);
1617 playback_stream_assert_ref(s);
1618
1619 if (s->connection->version < 12)
1620 return;
1621
1622 t = pa_tagstruct_new(NULL, 0);
1623 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1624 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1625 pa_tagstruct_putu32(t, s->index);
1626 pa_tagstruct_put_boolean(t, suspend);
1627 pa_pstream_send_tagstruct(s->connection->pstream, t);
1628 }
1629
1630 /* Called from main context */
1631 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1632 playback_stream *s;
1633 pa_tagstruct *t;
1634
1635 pa_sink_input_assert_ref(i);
1636 s = PLAYBACK_STREAM(i->userdata);
1637 playback_stream_assert_ref(s);
1638
1639 if (!dest)
1640 return;
1641
1642 fix_playback_buffer_attr(s);
1643 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1644 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1645
1646 if (s->connection->version < 12)
1647 return;
1648
1649 t = pa_tagstruct_new(NULL, 0);
1650 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1651 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1652 pa_tagstruct_putu32(t, s->index);
1653 pa_tagstruct_putu32(t, dest->index);
1654 pa_tagstruct_puts(t, dest->name);
1655 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1656
1657 if (s->connection->version >= 13) {
1658 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1659 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1660 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1661 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1662 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1663 }
1664
1665 pa_pstream_send_tagstruct(s->connection->pstream, t);
1666 }
1667
1668 /*** source_output callbacks ***/
1669
1670 /* Called from thread context */
1671 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1672 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1673 record_stream *s;
1674
1675 pa_source_output_assert_ref(o);
1676 s = RECORD_STREAM(o->userdata);
1677 record_stream_assert_ref(s);
1678
1679 switch (code) {
1680 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1681 /* Atomically get a snapshot of all timing parameters... */
1682 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1683 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1684 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1685 return 0;
1686 }
1687
1688 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1689 }
1690
1691 /* Called from thread context */
1692 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1693 record_stream *s;
1694
1695 pa_source_output_assert_ref(o);
1696 s = RECORD_STREAM(o->userdata);
1697 record_stream_assert_ref(s);
1698 pa_assert(chunk);
1699
1700 pa_atomic_add(&s->on_the_fly, chunk->length);
1701 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1702 }
1703
1704 static void source_output_kill_cb(pa_source_output *o) {
1705 record_stream *s;
1706
1707 pa_source_output_assert_ref(o);
1708 s = RECORD_STREAM(o->userdata);
1709 record_stream_assert_ref(s);
1710
1711 record_stream_send_killed(s);
1712 record_stream_unlink(s);
1713 }
1714
1715 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1716 record_stream *s;
1717
1718 pa_source_output_assert_ref(o);
1719 s = RECORD_STREAM(o->userdata);
1720 record_stream_assert_ref(s);
1721
1722 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1723
1724 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1725 }
1726
1727 /* Called from main context */
1728 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1729 record_stream *s;
1730 pa_tagstruct *t;
1731
1732 pa_source_output_assert_ref(o);
1733 s = RECORD_STREAM(o->userdata);
1734 record_stream_assert_ref(s);
1735
1736 if (s->connection->version < 15)
1737 return;
1738
1739 t = pa_tagstruct_new(NULL, 0);
1740 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1741 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1742 pa_tagstruct_putu32(t, s->index);
1743 pa_tagstruct_puts(t, event);
1744 pa_tagstruct_put_proplist(t, pl);
1745 pa_pstream_send_tagstruct(s->connection->pstream, t);
1746 }
1747
1748 /* Called from main context */
1749 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1750 record_stream *s;
1751 pa_tagstruct *t;
1752
1753 pa_source_output_assert_ref(o);
1754 s = RECORD_STREAM(o->userdata);
1755 record_stream_assert_ref(s);
1756
1757 if (s->connection->version < 12)
1758 return;
1759
1760 t = pa_tagstruct_new(NULL, 0);
1761 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1762 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1763 pa_tagstruct_putu32(t, s->index);
1764 pa_tagstruct_put_boolean(t, suspend);
1765 pa_pstream_send_tagstruct(s->connection->pstream, t);
1766 }
1767
1768 /* Called from main context */
1769 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1770 record_stream *s;
1771 pa_tagstruct *t;
1772
1773 pa_source_output_assert_ref(o);
1774 s = RECORD_STREAM(o->userdata);
1775 record_stream_assert_ref(s);
1776
1777 if (!dest)
1778 return;
1779
1780 fix_record_buffer_attr_pre(s);
1781 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1782 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1783 fix_record_buffer_attr_post(s);
1784
1785 if (s->connection->version < 12)
1786 return;
1787
1788 t = pa_tagstruct_new(NULL, 0);
1789 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1790 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1791 pa_tagstruct_putu32(t, s->index);
1792 pa_tagstruct_putu32(t, dest->index);
1793 pa_tagstruct_puts(t, dest->name);
1794 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1795
1796 if (s->connection->version >= 13) {
1797 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1798 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1799 pa_tagstruct_put_usec(t, s->configured_source_latency);
1800 }
1801
1802 pa_pstream_send_tagstruct(s->connection->pstream, t);
1803 }
1804
1805 /*** pdispatch callbacks ***/
1806
1807 static void protocol_error(pa_native_connection *c) {
1808 pa_log("protocol error, kicking client");
1809 native_connection_unlink(c);
1810 }
1811
1812 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1813 if (!(expression)) { \
1814 pa_pstream_send_error((pstream), (tag), (error)); \
1815 return; \
1816 } \
1817 } while(0);
1818
1819 static pa_tagstruct *reply_new(uint32_t tag) {
1820 pa_tagstruct *reply;
1821
1822 reply = pa_tagstruct_new(NULL, 0);
1823 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1824 pa_tagstruct_putu32(reply, tag);
1825 return reply;
1826 }
1827
1828 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1829 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1830 playback_stream *s;
1831 uint32_t sink_index, syncid, missing;
1832 pa_buffer_attr attr;
1833 const char *name = NULL, *sink_name;
1834 pa_sample_spec ss;
1835 pa_channel_map map;
1836 pa_tagstruct *reply;
1837 pa_sink *sink = NULL;
1838 pa_cvolume volume;
1839 pa_bool_t
1840 corked = FALSE,
1841 no_remap = FALSE,
1842 no_remix = FALSE,
1843 fix_format = FALSE,
1844 fix_rate = FALSE,
1845 fix_channels = FALSE,
1846 no_move = FALSE,
1847 variable_rate = FALSE,
1848 muted = FALSE,
1849 adjust_latency = FALSE,
1850 early_requests = FALSE,
1851 dont_inhibit_auto_suspend = FALSE,
1852 muted_set = FALSE,
1853 fail_on_suspend = FALSE,
1854 relative_volume = FALSE;
1855 pa_sink_input_flags_t flags = 0;
1856 pa_proplist *p;
1857 pa_bool_t volume_set = TRUE;
1858 int ret = PA_ERR_INVALID;
1859
1860 pa_native_connection_assert_ref(c);
1861 pa_assert(t);
1862 memset(&attr, 0, sizeof(attr));
1863
1864 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1865 pa_tagstruct_get(
1866 t,
1867 PA_TAG_SAMPLE_SPEC, &ss,
1868 PA_TAG_CHANNEL_MAP, &map,
1869 PA_TAG_U32, &sink_index,
1870 PA_TAG_STRING, &sink_name,
1871 PA_TAG_U32, &attr.maxlength,
1872 PA_TAG_BOOLEAN, &corked,
1873 PA_TAG_U32, &attr.tlength,
1874 PA_TAG_U32, &attr.prebuf,
1875 PA_TAG_U32, &attr.minreq,
1876 PA_TAG_U32, &syncid,
1877 PA_TAG_CVOLUME, &volume,
1878 PA_TAG_INVALID) < 0) {
1879
1880 protocol_error(c);
1881 return;
1882 }
1883
1884 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1885 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
1886 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
1887 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
1888 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
1889 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
1890 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
1891 CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID);
1892
1893 p = pa_proplist_new();
1894
1895 if (name)
1896 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1897
1898 if (c->version >= 12) {
1899 /* Since 0.9.8 the user can ask for a couple of additional flags */
1900
1901 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1902 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1903 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1904 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1905 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1906 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1907 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1908
1909 protocol_error(c);
1910 pa_proplist_free(p);
1911 return;
1912 }
1913 }
1914
1915 if (c->version >= 13) {
1916
1917 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1918 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1919 pa_tagstruct_get_proplist(t, p) < 0) {
1920 protocol_error(c);
1921 pa_proplist_free(p);
1922 return;
1923 }
1924 }
1925
1926 if (c->version >= 14) {
1927
1928 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
1929 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
1930 protocol_error(c);
1931 pa_proplist_free(p);
1932 return;
1933 }
1934 }
1935
1936 if (c->version >= 15) {
1937
1938 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
1939 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
1940 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
1941 protocol_error(c);
1942 pa_proplist_free(p);
1943 return;
1944 }
1945 }
1946
1947 if (c->version >= 17) {
1948
1949 if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
1950 protocol_error(c);
1951 pa_proplist_free(p);
1952 return;
1953 }
1954 }
1955
1956 if (!pa_tagstruct_eof(t)) {
1957 protocol_error(c);
1958 pa_proplist_free(p);
1959 return;
1960 }
1961
1962 if (sink_index != PA_INVALID_INDEX) {
1963
1964 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
1965 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1966 pa_proplist_free(p);
1967 return;
1968 }
1969
1970 } else if (sink_name) {
1971
1972 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
1973 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1974 pa_proplist_free(p);
1975 return;
1976 }
1977 }
1978
1979 flags =
1980 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
1981 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
1982 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
1983 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
1984 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
1985 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
1986 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
1987 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
1988 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
1989 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0);
1990
1991 /* Only since protocol version 15 there's a seperate muted_set
1992 * flag. For older versions we synthesize it here */
1993 muted_set = muted_set || muted;
1994
1995 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);
1996 pa_proplist_free(p);
1997
1998 CHECK_VALIDITY(c->pstream, s, tag, ret);
1999
2000 reply = reply_new(tag);
2001 pa_tagstruct_putu32(reply, s->index);
2002 pa_assert(s->sink_input);
2003 pa_tagstruct_putu32(reply, s->sink_input->index);
2004 pa_tagstruct_putu32(reply, missing);
2005
2006 /* pa_log("initial request is %u", missing); */
2007
2008 if (c->version >= 9) {
2009 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2010
2011 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2012 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2013 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2014 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2015 }
2016
2017 if (c->version >= 12) {
2018 /* Since 0.9.8 we support sending the chosen sample
2019 * spec/channel map/device/suspend status back to the
2020 * client */
2021
2022 pa_tagstruct_put_sample_spec(reply, &ss);
2023 pa_tagstruct_put_channel_map(reply, &map);
2024
2025 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2026 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2027
2028 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2029 }
2030
2031 if (c->version >= 13)
2032 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2033
2034 pa_pstream_send_tagstruct(c->pstream, reply);
2035 }
2036
2037 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2038 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2039 uint32_t channel;
2040
2041 pa_native_connection_assert_ref(c);
2042 pa_assert(t);
2043
2044 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2045 !pa_tagstruct_eof(t)) {
2046 protocol_error(c);
2047 return;
2048 }
2049
2050 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2051
2052 switch (command) {
2053
2054 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2055 playback_stream *s;
2056 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2057 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2058 return;
2059 }
2060
2061 playback_stream_unlink(s);
2062 break;
2063 }
2064
2065 case PA_COMMAND_DELETE_RECORD_STREAM: {
2066 record_stream *s;
2067 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2068 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2069 return;
2070 }
2071
2072 record_stream_unlink(s);
2073 break;
2074 }
2075
2076 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2077 upload_stream *s;
2078
2079 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2080 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2081 return;
2082 }
2083
2084 upload_stream_unlink(s);
2085 break;
2086 }
2087
2088 default:
2089 pa_assert_not_reached();
2090 }
2091
2092 pa_pstream_send_simple_ack(c->pstream, tag);
2093 }
2094
2095 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2096 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2097 record_stream *s;
2098 pa_buffer_attr attr;
2099 uint32_t source_index;
2100 const char *name = NULL, *source_name;
2101 pa_sample_spec ss;
2102 pa_channel_map map;
2103 pa_tagstruct *reply;
2104 pa_source *source = NULL;
2105 pa_bool_t
2106 corked = FALSE,
2107 no_remap = FALSE,
2108 no_remix = FALSE,
2109 fix_format = FALSE,
2110 fix_rate = FALSE,
2111 fix_channels = FALSE,
2112 no_move = FALSE,
2113 variable_rate = FALSE,
2114 adjust_latency = FALSE,
2115 peak_detect = FALSE,
2116 early_requests = FALSE,
2117 dont_inhibit_auto_suspend = FALSE,
2118 fail_on_suspend = FALSE;
2119 pa_source_output_flags_t flags = 0;
2120 pa_proplist *p;
2121 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2122 pa_sink_input *direct_on_input = NULL;
2123 int ret = PA_ERR_INVALID;
2124
2125 pa_native_connection_assert_ref(c);
2126 pa_assert(t);
2127
2128 memset(&attr, 0, sizeof(attr));
2129
2130 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2131 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2132 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2133 pa_tagstruct_getu32(t, &source_index) < 0 ||
2134 pa_tagstruct_gets(t, &source_name) < 0 ||
2135 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2136 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2137 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2138 protocol_error(c);
2139 return;
2140 }
2141
2142 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2143 CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
2144 CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID);
2145 CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2146 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2147 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2148 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2149
2150 p = pa_proplist_new();
2151
2152 if (name)
2153 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2154
2155 if (c->version >= 12) {
2156 /* Since 0.9.8 the user can ask for a couple of additional flags */
2157
2158 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2159 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2160 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2161 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2162 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2163 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2164 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2165
2166 protocol_error(c);
2167 pa_proplist_free(p);
2168 return;
2169 }
2170 }
2171
2172 if (c->version >= 13) {
2173
2174 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2175 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2176 pa_tagstruct_get_proplist(t, p) < 0 ||
2177 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2178 protocol_error(c);
2179 pa_proplist_free(p);
2180 return;
2181 }
2182 }
2183
2184 if (c->version >= 14) {
2185
2186 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2187 protocol_error(c);
2188 pa_proplist_free(p);
2189 return;
2190 }
2191 }
2192
2193 if (c->version >= 15) {
2194
2195 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2196 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2197 protocol_error(c);
2198 pa_proplist_free(p);
2199 return;
2200 }
2201 }
2202
2203 if (!pa_tagstruct_eof(t)) {
2204 protocol_error(c);
2205 pa_proplist_free(p);
2206 return;
2207 }
2208
2209 if (source_index != PA_INVALID_INDEX) {
2210
2211 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2212 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2213 pa_proplist_free(p);
2214 return;
2215 }
2216
2217 } else if (source_name) {
2218
2219 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2220 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2221 pa_proplist_free(p);
2222 return;
2223 }
2224 }
2225
2226 if (direct_on_input_idx != PA_INVALID_INDEX) {
2227
2228 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2229 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2230 pa_proplist_free(p);
2231 return;
2232 }
2233 }
2234
2235 flags =
2236 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2237 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2238 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2239 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2240 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2241 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2242 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2243 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2244 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2245 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0);
2246
2247 s = record_stream_new(c, source, &ss, &map, peak_detect, &attr, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
2248 pa_proplist_free(p);
2249
2250 CHECK_VALIDITY(c->pstream, s, tag, ret);
2251
2252 reply = reply_new(tag);
2253 pa_tagstruct_putu32(reply, s->index);
2254 pa_assert(s->source_output);
2255 pa_tagstruct_putu32(reply, s->source_output->index);
2256
2257 if (c->version >= 9) {
2258 /* Since 0.9 we support sending the buffer metrics back to the client */
2259
2260 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2261 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2262 }
2263
2264 if (c->version >= 12) {
2265 /* Since 0.9.8 we support sending the chosen sample
2266 * spec/channel map/device/suspend status back to the
2267 * client */
2268
2269 pa_tagstruct_put_sample_spec(reply, &ss);
2270 pa_tagstruct_put_channel_map(reply, &map);
2271
2272 pa_tagstruct_putu32(reply, s->source_output->source->index);
2273 pa_tagstruct_puts(reply, s->source_output->source->name);
2274
2275 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2276 }
2277
2278 if (c->version >= 13)
2279 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2280
2281 pa_pstream_send_tagstruct(c->pstream, reply);
2282 }
2283
2284 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2285 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2286 int ret;
2287
2288 pa_native_connection_assert_ref(c);
2289 pa_assert(t);
2290
2291 if (!pa_tagstruct_eof(t)) {
2292 protocol_error(c);
2293 return;
2294 }
2295
2296 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2297 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2298 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2299
2300 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2301
2302 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2303 }
2304
2305 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2306 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2307 const void*cookie;
2308 pa_tagstruct *reply;
2309 pa_bool_t shm_on_remote = FALSE, do_shm;
2310
2311 pa_native_connection_assert_ref(c);
2312 pa_assert(t);
2313
2314 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2315 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2316 !pa_tagstruct_eof(t)) {
2317 protocol_error(c);
2318 return;
2319 }
2320
2321 /* Minimum supported version */
2322 if (c->version < 8) {
2323 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2324 return;
2325 }
2326
2327 /* Starting with protocol version 13 the MSB of the version tag
2328 reflects if shm is available for this pa_native_connection or
2329 not. */
2330 if (c->version >= 13) {
2331 shm_on_remote = !!(c->version & 0x80000000U);
2332 c->version &= 0x7FFFFFFFU;
2333 }
2334
2335 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2336
2337 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2338
2339 if (!c->authorized) {
2340 pa_bool_t success = FALSE;
2341
2342 #ifdef HAVE_CREDS
2343 const pa_creds *creds;
2344
2345 if ((creds = pa_pdispatch_creds(pd))) {
2346 if (creds->uid == getuid())
2347 success = TRUE;
2348 else if (c->options->auth_group) {
2349 int r;
2350 gid_t gid;
2351
2352 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2353 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2354 else if (gid == creds->gid)
2355 success = TRUE;
2356
2357 if (!success) {
2358 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2359 pa_log_warn("Failed to check group membership.");
2360 else if (r > 0)
2361 success = TRUE;
2362 }
2363 }
2364
2365 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2366 (unsigned long) creds->uid,
2367 (unsigned long) creds->gid,
2368 (int) success);
2369 }
2370 #endif
2371
2372 if (!success && c->options->auth_cookie) {
2373 const uint8_t *ac;
2374
2375 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2376 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2377 success = TRUE;
2378 }
2379
2380 if (!success) {
2381 pa_log_warn("Denied access to client with invalid authorization data.");
2382 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2383 return;
2384 }
2385
2386 c->authorized = TRUE;
2387 if (c->auth_timeout_event) {
2388 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2389 c->auth_timeout_event = NULL;
2390 }
2391 }
2392
2393 /* Enable shared memory support if possible */
2394 do_shm =
2395 pa_mempool_is_shared(c->protocol->core->mempool) &&
2396 c->is_local;
2397
2398 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2399
2400 if (do_shm)
2401 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2402 do_shm = FALSE;
2403
2404 #ifdef HAVE_CREDS
2405 if (do_shm) {
2406 /* Only enable SHM if both sides are owned by the same
2407 * user. This is a security measure because otherwise data
2408 * private to the user might leak. */
2409
2410 const pa_creds *creds;
2411 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2412 do_shm = FALSE;
2413 }
2414 #endif
2415
2416 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2417 pa_pstream_enable_shm(c->pstream, do_shm);
2418
2419 reply = reply_new(tag);
2420 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2421
2422 #ifdef HAVE_CREDS
2423 {
2424 /* SHM support is only enabled after both sides made sure they are the same user. */
2425
2426 pa_creds ucred;
2427
2428 ucred.uid = getuid();
2429 ucred.gid = getgid();
2430
2431 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2432 }
2433 #else
2434 pa_pstream_send_tagstruct(c->pstream, reply);
2435 #endif
2436 }
2437
2438 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2439 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2440 const char *name = NULL;
2441 pa_proplist *p;
2442 pa_tagstruct *reply;
2443
2444 pa_native_connection_assert_ref(c);
2445 pa_assert(t);
2446
2447 p = pa_proplist_new();
2448
2449 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2450 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2451 !pa_tagstruct_eof(t)) {
2452
2453 protocol_error(c);
2454 pa_proplist_free(p);
2455 return;
2456 }
2457
2458 if (name)
2459 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2460 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2461 pa_proplist_free(p);
2462 return;
2463 }
2464
2465 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2466 pa_proplist_free(p);
2467
2468 reply = reply_new(tag);
2469
2470 if (c->version >= 13)
2471 pa_tagstruct_putu32(reply, c->client->index);
2472
2473 pa_pstream_send_tagstruct(c->pstream, reply);
2474 }
2475
2476 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2477 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2478 const char *name;
2479 uint32_t idx = PA_IDXSET_INVALID;
2480
2481 pa_native_connection_assert_ref(c);
2482 pa_assert(t);
2483
2484 if (pa_tagstruct_gets(t, &name) < 0 ||
2485 !pa_tagstruct_eof(t)) {
2486 protocol_error(c);
2487 return;
2488 }
2489
2490 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2491 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);
2492
2493 if (command == PA_COMMAND_LOOKUP_SINK) {
2494 pa_sink *sink;
2495 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2496 idx = sink->index;
2497 } else {
2498 pa_source *source;
2499 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2500 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2501 idx = source->index;
2502 }
2503
2504 if (idx == PA_IDXSET_INVALID)
2505 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2506 else {
2507 pa_tagstruct *reply;
2508 reply = reply_new(tag);
2509 pa_tagstruct_putu32(reply, idx);
2510 pa_pstream_send_tagstruct(c->pstream, reply);
2511 }
2512 }
2513
2514 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2515 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2516 uint32_t idx;
2517 playback_stream *s;
2518
2519 pa_native_connection_assert_ref(c);
2520 pa_assert(t);
2521
2522 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2523 !pa_tagstruct_eof(t)) {
2524 protocol_error(c);
2525 return;
2526 }
2527
2528 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2529 s = pa_idxset_get_by_index(c->output_streams, idx);
2530 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2531 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2532
2533 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);
2534 }
2535
2536 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2537 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2538 pa_tagstruct *reply;
2539 const pa_mempool_stat *stat;
2540
2541 pa_native_connection_assert_ref(c);
2542 pa_assert(t);
2543
2544 if (!pa_tagstruct_eof(t)) {
2545 protocol_error(c);
2546 return;
2547 }
2548
2549 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2550
2551 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2552
2553 reply = reply_new(tag);
2554 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2555 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2556 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2557 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2558 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2559 pa_pstream_send_tagstruct(c->pstream, reply);
2560 }
2561
2562 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2563 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2564 pa_tagstruct *reply;
2565 playback_stream *s;
2566 struct timeval tv, now;
2567 uint32_t idx;
2568
2569 pa_native_connection_assert_ref(c);
2570 pa_assert(t);
2571
2572 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2573 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2574 !pa_tagstruct_eof(t)) {
2575 protocol_error(c);
2576 return;
2577 }
2578
2579 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2580 s = pa_idxset_get_by_index(c->output_streams, idx);
2581 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2582 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2583
2584 /* Get an atomic snapshot of all timing parameters */
2585 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);
2586
2587 reply = reply_new(tag);
2588 pa_tagstruct_put_usec(reply,
2589 s->current_sink_latency +
2590 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2591 pa_tagstruct_put_usec(reply, 0);
2592 pa_tagstruct_put_boolean(reply,
2593 s->playing_for > 0 &&
2594 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2595 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2596 pa_tagstruct_put_timeval(reply, &tv);
2597 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2598 pa_tagstruct_puts64(reply, s->write_index);
2599 pa_tagstruct_puts64(reply, s->read_index);
2600
2601 if (c->version >= 13) {
2602 pa_tagstruct_putu64(reply, s->underrun_for);
2603 pa_tagstruct_putu64(reply, s->playing_for);
2604 }
2605
2606 pa_pstream_send_tagstruct(c->pstream, reply);
2607 }
2608
2609 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2610 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2611 pa_tagstruct *reply;
2612 record_stream *s;
2613 struct timeval tv, now;
2614 uint32_t idx;
2615
2616 pa_native_connection_assert_ref(c);
2617 pa_assert(t);
2618
2619 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2620 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2621 !pa_tagstruct_eof(t)) {
2622 protocol_error(c);
2623 return;
2624 }
2625
2626 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2627 s = pa_idxset_get_by_index(c->record_streams, idx);
2628 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2629
2630 /* Get an atomic snapshot of all timing parameters */
2631 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);
2632
2633 reply = reply_new(tag);
2634 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2635 pa_tagstruct_put_usec(reply,
2636 s->current_source_latency +
2637 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec));
2638 pa_tagstruct_put_boolean(reply,
2639 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2640 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2641 pa_tagstruct_put_timeval(reply, &tv);
2642 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2643 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2644 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2645 pa_pstream_send_tagstruct(c->pstream, reply);
2646 }
2647
2648 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2649 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2650 upload_stream *s;
2651 uint32_t length;
2652 const char *name = NULL;
2653 pa_sample_spec ss;
2654 pa_channel_map map;
2655 pa_tagstruct *reply;
2656 pa_proplist *p;
2657
2658 pa_native_connection_assert_ref(c);
2659 pa_assert(t);
2660
2661 if (pa_tagstruct_gets(t, &name) < 0 ||
2662 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2663 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2664 pa_tagstruct_getu32(t, &length) < 0) {
2665 protocol_error(c);
2666 return;
2667 }
2668
2669 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2670 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2671 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2672 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2673 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2674 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2675
2676 p = pa_proplist_new();
2677
2678 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2679 !pa_tagstruct_eof(t)) {
2680
2681 protocol_error(c);
2682 pa_proplist_free(p);
2683 return;
2684 }
2685
2686 if (c->version < 13)
2687 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2688 else if (!name)
2689 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2690 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2691
2692 if (!name || !pa_namereg_is_valid_name(name)) {
2693 pa_proplist_free(p);
2694 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2695 }
2696
2697 s = upload_stream_new(c, &ss, &map, name, length, p);
2698 pa_proplist_free(p);
2699
2700 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2701
2702 reply = reply_new(tag);
2703 pa_tagstruct_putu32(reply, s->index);
2704 pa_tagstruct_putu32(reply, length);
2705 pa_pstream_send_tagstruct(c->pstream, reply);
2706 }
2707
2708 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2709 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2710 uint32_t channel;
2711 upload_stream *s;
2712 uint32_t idx;
2713
2714 pa_native_connection_assert_ref(c);
2715 pa_assert(t);
2716
2717 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2718 !pa_tagstruct_eof(t)) {
2719 protocol_error(c);
2720 return;
2721 }
2722
2723 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2724
2725 s = pa_idxset_get_by_index(c->output_streams, channel);
2726 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2727 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2728
2729 if (!s->memchunk.memblock)
2730 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2731 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2732 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2733 else
2734 pa_pstream_send_simple_ack(c->pstream, tag);
2735
2736 upload_stream_unlink(s);
2737 }
2738
2739 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2740 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2741 uint32_t sink_index;
2742 pa_volume_t volume;
2743 pa_sink *sink;
2744 const char *name, *sink_name;
2745 uint32_t idx;
2746 pa_proplist *p;
2747 pa_tagstruct *reply;
2748
2749 pa_native_connection_assert_ref(c);
2750 pa_assert(t);
2751
2752 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2753
2754 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2755 pa_tagstruct_gets(t, &sink_name) < 0 ||
2756 pa_tagstruct_getu32(t, &volume) < 0 ||
2757 pa_tagstruct_gets(t, &name) < 0) {
2758 protocol_error(c);
2759 return;
2760 }
2761
2762 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2763 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2764 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2765 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2766
2767 if (sink_index != PA_INVALID_INDEX)
2768 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2769 else
2770 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2771
2772 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2773
2774 p = pa_proplist_new();
2775
2776 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2777 !pa_tagstruct_eof(t)) {
2778 protocol_error(c);
2779 pa_proplist_free(p);
2780 return;
2781 }
2782
2783 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2784
2785 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2786 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2787 pa_proplist_free(p);
2788 return;
2789 }
2790
2791 pa_proplist_free(p);
2792
2793 reply = reply_new(tag);
2794
2795 if (c->version >= 13)
2796 pa_tagstruct_putu32(reply, idx);
2797
2798 pa_pstream_send_tagstruct(c->pstream, reply);
2799 }
2800
2801 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2802 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2803 const char *name;
2804
2805 pa_native_connection_assert_ref(c);
2806 pa_assert(t);
2807
2808 if (pa_tagstruct_gets(t, &name) < 0 ||
2809 !pa_tagstruct_eof(t)) {
2810 protocol_error(c);
2811 return;
2812 }
2813
2814 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2815 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2816
2817 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
2818 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2819 return;
2820 }
2821
2822 pa_pstream_send_simple_ack(c->pstream, tag);
2823 }
2824
2825 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
2826 pa_assert(c);
2827 pa_assert(fixed);
2828 pa_assert(original);
2829
2830 *fixed = *original;
2831
2832 if (c->version < 12) {
2833 /* Before protocol version 12 we didn't support S32 samples,
2834 * so we need to lie about this to the client */
2835
2836 if (fixed->format == PA_SAMPLE_S32LE)
2837 fixed->format = PA_SAMPLE_FLOAT32LE;
2838 if (fixed->format == PA_SAMPLE_S32BE)
2839 fixed->format = PA_SAMPLE_FLOAT32BE;
2840 }
2841
2842 if (c->version < 15) {
2843 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
2844 fixed->format = PA_SAMPLE_FLOAT32LE;
2845 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
2846 fixed->format = PA_SAMPLE_FLOAT32BE;
2847 }
2848 }
2849
2850 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
2851 pa_sample_spec fixed_ss;
2852
2853 pa_assert(t);
2854 pa_sink_assert_ref(sink);
2855
2856 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
2857
2858 pa_tagstruct_put(
2859 t,
2860 PA_TAG_U32, sink->index,
2861 PA_TAG_STRING, sink->name,
2862 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2863 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2864 PA_TAG_CHANNEL_MAP, &sink->channel_map,
2865 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
2866 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
2867 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
2868 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
2869 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
2870 PA_TAG_USEC, pa_sink_get_latency(sink),
2871 PA_TAG_STRING, sink->driver,
2872 PA_TAG_U32, sink->flags,
2873 PA_TAG_INVALID);
2874
2875 if (c->version >= 13) {
2876 pa_tagstruct_put_proplist(t, sink->proplist);
2877 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
2878 }
2879
2880 if (c->version >= 15) {
2881 pa_tagstruct_put_volume(t, sink->base_volume);
2882 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
2883 pa_log_error("Internal sink state is invalid.");
2884 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
2885 pa_tagstruct_putu32(t, sink->n_volume_steps);
2886 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
2887 }
2888
2889 if (c->version >= 16) {
2890 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
2891
2892 if (sink->ports) {
2893 void *state;
2894 pa_device_port *p;
2895
2896 PA_HASHMAP_FOREACH(p, sink->ports, state) {
2897 pa_tagstruct_puts(t, p->name);
2898 pa_tagstruct_puts(t, p->description);
2899 pa_tagstruct_putu32(t, p->priority);
2900 }
2901 }
2902
2903 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
2904 }
2905 }
2906
2907 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
2908 pa_sample_spec fixed_ss;
2909
2910 pa_assert(t);
2911 pa_source_assert_ref(source);
2912
2913 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
2914
2915 pa_tagstruct_put(
2916 t,
2917 PA_TAG_U32, source->index,
2918 PA_TAG_STRING, source->name,
2919 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2920 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2921 PA_TAG_CHANNEL_MAP, &source->channel_map,
2922 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
2923 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
2924 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
2925 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
2926 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
2927 PA_TAG_USEC, pa_source_get_latency(source),
2928 PA_TAG_STRING, source->driver,
2929 PA_TAG_U32, source->flags,
2930 PA_TAG_INVALID);
2931
2932 if (c->version >= 13) {
2933 pa_tagstruct_put_proplist(t, source->proplist);
2934 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
2935 }
2936
2937 if (c->version >= 15) {
2938 pa_tagstruct_put_volume(t, source->base_volume);
2939 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
2940 pa_log_error("Internal source state is invalid.");
2941 pa_tagstruct_putu32(t, pa_source_get_state(source));
2942 pa_tagstruct_putu32(t, source->n_volume_steps);
2943 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
2944 }
2945
2946 if (c->version >= 16) {
2947
2948 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
2949
2950 if (source->ports) {
2951 void *state;
2952 pa_device_port *p;
2953
2954 PA_HASHMAP_FOREACH(p, source->ports, state) {
2955 pa_tagstruct_puts(t, p->name);
2956 pa_tagstruct_puts(t, p->description);
2957 pa_tagstruct_putu32(t, p->priority);
2958 }
2959 }
2960
2961 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
2962 }
2963 }
2964
2965 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
2966 pa_assert(t);
2967 pa_assert(client);
2968
2969 pa_tagstruct_putu32(t, client->index);
2970 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
2971 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
2972 pa_tagstruct_puts(t, client->driver);
2973
2974 if (c->version >= 13)
2975 pa_tagstruct_put_proplist(t, client->proplist);
2976 }
2977
2978 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
2979 void *state = NULL;
2980 pa_card_profile *p;
2981
2982 pa_assert(t);
2983 pa_assert(card);
2984
2985 pa_tagstruct_putu32(t, card->index);
2986 pa_tagstruct_puts(t, card->name);
2987 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
2988 pa_tagstruct_puts(t, card->driver);
2989
2990 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
2991
2992 if (card->profiles) {
2993 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
2994 pa_tagstruct_puts(t, p->name);
2995 pa_tagstruct_puts(t, p->description);
2996 pa_tagstruct_putu32(t, p->n_sinks);
2997 pa_tagstruct_putu32(t, p->n_sources);
2998 pa_tagstruct_putu32(t, p->priority);
2999 }
3000 }
3001
3002 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
3003 pa_tagstruct_put_proplist(t, card->proplist);
3004 }
3005
3006 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3007 pa_assert(t);
3008 pa_assert(module);
3009
3010 pa_tagstruct_putu32(t, module->index);
3011 pa_tagstruct_puts(t, module->name);
3012 pa_tagstruct_puts(t, module->argument);
3013 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3014
3015 if (c->version < 15)
3016 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
3017
3018 if (c->version >= 15)
3019 pa_tagstruct_put_proplist(t, module->proplist);
3020 }
3021
3022 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3023 pa_sample_spec fixed_ss;
3024 pa_usec_t sink_latency;
3025 pa_cvolume v;
3026
3027 pa_assert(t);
3028 pa_sink_input_assert_ref(s);
3029
3030 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3031
3032 pa_tagstruct_putu32(t, s->index);
3033 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3034 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3035 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3036 pa_tagstruct_putu32(t, s->sink->index);
3037 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3038 pa_tagstruct_put_channel_map(t, &s->channel_map);
3039 pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s, &v, TRUE));
3040 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3041 pa_tagstruct_put_usec(t, sink_latency);
3042 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3043 pa_tagstruct_puts(t, s->driver);
3044 if (c->version >= 11)
3045 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3046 if (c->version >= 13)
3047 pa_tagstruct_put_proplist(t, s->proplist);
3048 }
3049
3050 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3051 pa_sample_spec fixed_ss;
3052 pa_usec_t source_latency;
3053
3054 pa_assert(t);
3055 pa_source_output_assert_ref(s);
3056
3057 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3058
3059 pa_tagstruct_putu32(t, s->index);
3060 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3061 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3062 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3063 pa_tagstruct_putu32(t, s->source->index);
3064 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3065 pa_tagstruct_put_channel_map(t, &s->channel_map);
3066 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3067 pa_tagstruct_put_usec(t, source_latency);
3068 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3069 pa_tagstruct_puts(t, s->driver);
3070
3071 if (c->version >= 13)
3072 pa_tagstruct_put_proplist(t, s->proplist);
3073 }
3074
3075 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3076 pa_sample_spec fixed_ss;
3077 pa_cvolume v;
3078
3079 pa_assert(t);
3080 pa_assert(e);
3081
3082 if (e->memchunk.memblock)
3083 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3084 else
3085 memset(&fixed_ss, 0, sizeof(fixed_ss));
3086
3087 pa_tagstruct_putu32(t, e->index);
3088 pa_tagstruct_puts(t, e->name);
3089
3090 if (e->volume_is_set)
3091 v = e->volume;
3092 else
3093 pa_cvolume_init(&v);
3094
3095 pa_tagstruct_put_cvolume(t, &v);
3096 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3097 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3098 pa_tagstruct_put_channel_map(t, &e->channel_map);
3099 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3100 pa_tagstruct_put_boolean(t, e->lazy);
3101 pa_tagstruct_puts(t, e->filename);
3102
3103 if (c->version >= 13)
3104 pa_tagstruct_put_proplist(t, e->proplist);
3105 }
3106
3107 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3108 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3109 uint32_t idx;
3110 pa_sink *sink = NULL;
3111 pa_source *source = NULL;
3112 pa_client *client = NULL;
3113 pa_card *card = NULL;
3114 pa_module *module = NULL;
3115 pa_sink_input *si = NULL;
3116 pa_source_output *so = NULL;
3117 pa_scache_entry *sce = NULL;
3118 const char *name = NULL;
3119 pa_tagstruct *reply;
3120
3121 pa_native_connection_assert_ref(c);
3122 pa_assert(t);
3123
3124 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3125 (command != PA_COMMAND_GET_CLIENT_INFO &&
3126 command != PA_COMMAND_GET_MODULE_INFO &&
3127 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3128 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3129 pa_tagstruct_gets(t, &name) < 0) ||
3130 !pa_tagstruct_eof(t)) {
3131 protocol_error(c);
3132 return;
3133 }
3134
3135 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3136 CHECK_VALIDITY(c->pstream, !name ||
3137 (command == PA_COMMAND_GET_SINK_INFO &&
3138 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3139 (command == PA_COMMAND_GET_SOURCE_INFO &&
3140 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3141 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3142 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3143 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3144 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3145
3146 if (command == PA_COMMAND_GET_SINK_INFO) {
3147 if (idx != PA_INVALID_INDEX)
3148 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3149 else
3150 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3151 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3152 if (idx != PA_INVALID_INDEX)
3153 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3154 else
3155 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3156 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3157 if (idx != PA_INVALID_INDEX)
3158 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3159 else
3160 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3161 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3162 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3163 else if (command == PA_COMMAND_GET_MODULE_INFO)
3164 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3165 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3166 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3167 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3168 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3169 else {
3170 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3171 if (idx != PA_INVALID_INDEX)
3172 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3173 else
3174 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3175 }
3176
3177 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3178 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3179 return;
3180 }
3181
3182 reply = reply_new(tag);
3183 if (sink)
3184 sink_fill_tagstruct(c, reply, sink);
3185 else if (source)
3186 source_fill_tagstruct(c, reply, source);
3187 else if (client)
3188 client_fill_tagstruct(c, reply, client);
3189 else if (card)
3190 card_fill_tagstruct(c, reply, card);
3191 else if (module)
3192 module_fill_tagstruct(c, reply, module);
3193 else if (si)
3194 sink_input_fill_tagstruct(c, reply, si);
3195 else if (so)
3196 source_output_fill_tagstruct(c, reply, so);
3197 else
3198 scache_fill_tagstruct(c, reply, sce);
3199 pa_pstream_send_tagstruct(c->pstream, reply);
3200 }
3201
3202 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3203 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3204 pa_idxset *i;
3205 uint32_t idx;
3206 void *p;
3207 pa_tagstruct *reply;
3208
3209 pa_native_connection_assert_ref(c);
3210 pa_assert(t);
3211
3212 if (!pa_tagstruct_eof(t)) {
3213 protocol_error(c);
3214 return;
3215 }
3216
3217 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3218
3219 reply = reply_new(tag);
3220
3221 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3222 i = c->protocol->core->sinks;
3223 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3224 i = c->protocol->core->sources;
3225 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3226 i = c->protocol->core->clients;
3227 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3228 i = c->protocol->core->cards;
3229 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3230 i = c->protocol->core->modules;
3231 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3232 i = c->protocol->core->sink_inputs;
3233 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3234 i = c->protocol->core->source_outputs;
3235 else {
3236 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3237 i = c->protocol->core->scache;
3238 }
3239
3240 if (i) {
3241 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3242 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3243 sink_fill_tagstruct(c, reply, p);
3244 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3245 source_fill_tagstruct(c, reply, p);
3246 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3247 client_fill_tagstruct(c, reply, p);
3248 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3249 card_fill_tagstruct(c, reply, p);
3250 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3251 module_fill_tagstruct(c, reply, p);
3252 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3253 sink_input_fill_tagstruct(c, reply, p);
3254 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3255 source_output_fill_tagstruct(c, reply, p);
3256 else {
3257 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3258 scache_fill_tagstruct(c, reply, p);
3259 }
3260 }
3261 }
3262
3263 pa_pstream_send_tagstruct(c->pstream, reply);
3264 }
3265
3266 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3267 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3268 pa_tagstruct *reply;
3269 pa_sink *def_sink;
3270 pa_source *def_source;
3271 pa_sample_spec fixed_ss;
3272 char *h, *u;
3273
3274 pa_native_connection_assert_ref(c);
3275 pa_assert(t);
3276
3277 if (!pa_tagstruct_eof(t)) {
3278 protocol_error(c);
3279 return;
3280 }
3281
3282 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3283
3284 reply = reply_new(tag);
3285 pa_tagstruct_puts(reply, PACKAGE_NAME);
3286 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3287
3288 u = pa_get_user_name_malloc();
3289 pa_tagstruct_puts(reply, u);
3290 pa_xfree(u);
3291
3292 h = pa_get_host_name_malloc();
3293 pa_tagstruct_puts(reply, h);
3294 pa_xfree(h);
3295
3296 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3297 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3298
3299 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3300 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3301 def_source = pa_namereg_get_default_source(c->protocol->core);
3302 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3303
3304 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3305
3306 if (c->version >= 15)
3307 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3308
3309 pa_pstream_send_tagstruct(c->pstream, reply);
3310 }
3311
3312 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3313 pa_tagstruct *t;
3314 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3315
3316 pa_native_connection_assert_ref(c);
3317
3318 t = pa_tagstruct_new(NULL, 0);
3319 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3320 pa_tagstruct_putu32(t, (uint32_t) -1);
3321 pa_tagstruct_putu32(t, e);
3322 pa_tagstruct_putu32(t, idx);
3323 pa_pstream_send_tagstruct(c->pstream, t);
3324 }
3325
3326 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3327 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3328 pa_subscription_mask_t m;
3329
3330 pa_native_connection_assert_ref(c);
3331 pa_assert(t);
3332
3333 if (pa_tagstruct_getu32(t, &m) < 0 ||
3334 !pa_tagstruct_eof(t)) {
3335 protocol_error(c);
3336 return;
3337 }
3338
3339 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3340 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3341
3342 if (c->subscription)
3343 pa_subscription_free(c->subscription);
3344
3345 if (m != 0) {
3346 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3347 pa_assert(c->subscription);
3348 } else
3349 c->subscription = NULL;
3350
3351 pa_pstream_send_simple_ack(c->pstream, tag);
3352 }
3353
3354 static void command_set_volume(
3355 pa_pdispatch *pd,
3356 uint32_t command,
3357 uint32_t tag,
3358 pa_tagstruct *t,
3359 void *userdata) {
3360
3361 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3362 uint32_t idx;
3363 pa_cvolume volume;
3364 pa_sink *sink = NULL;
3365 pa_source *source = NULL;
3366 pa_sink_input *si = NULL;
3367 const char *name = NULL;
3368 const char *client_name;
3369
3370 pa_native_connection_assert_ref(c);
3371 pa_assert(t);
3372
3373 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3374 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3375 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3376 pa_tagstruct_get_cvolume(t, &volume) ||
3377 !pa_tagstruct_eof(t)) {
3378 protocol_error(c);
3379 return;
3380 }
3381
3382 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3383 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);
3384 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3385 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3386 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3387 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3388
3389 switch (command) {
3390
3391 case PA_COMMAND_SET_SINK_VOLUME:
3392 if (idx != PA_INVALID_INDEX)
3393 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3394 else
3395 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3396 break;
3397
3398 case PA_COMMAND_SET_SOURCE_VOLUME:
3399 if (idx != PA_INVALID_INDEX)
3400 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3401 else
3402 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3403 break;
3404
3405 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3406 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3407 break;
3408
3409 default:
3410 pa_assert_not_reached();
3411 }
3412
3413 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3414
3415 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3416
3417 if (sink) {
3418 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3419
3420 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3421 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3422 } else if (source) {
3423 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3424
3425 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3426 pa_source_set_volume(source, &volume, TRUE);
3427 } else if (si) {
3428 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3429
3430 pa_log_debug("Client %s changes volume of sink input %s.",
3431 client_name,
3432 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3433 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3434 }
3435
3436 pa_pstream_send_simple_ack(c->pstream, tag);
3437 }
3438
3439 static void command_set_mute(
3440 pa_pdispatch *pd,
3441 uint32_t command,
3442 uint32_t tag,
3443 pa_tagstruct *t,
3444 void *userdata) {
3445
3446 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3447 uint32_t idx;
3448 pa_bool_t mute;
3449 pa_sink *sink = NULL;
3450 pa_source *source = NULL;
3451 pa_sink_input *si = NULL;
3452 const char *name = NULL, *client_name;
3453
3454 pa_native_connection_assert_ref(c);
3455 pa_assert(t);
3456
3457 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3458 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3459 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3460 pa_tagstruct_get_boolean(t, &mute) ||
3461 !pa_tagstruct_eof(t)) {
3462 protocol_error(c);
3463 return;
3464 }
3465
3466 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3467 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);
3468 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3469 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3470 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3471
3472 switch (command) {
3473
3474 case PA_COMMAND_SET_SINK_MUTE:
3475 if (idx != PA_INVALID_INDEX)
3476 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3477 else
3478 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3479
3480 break;
3481
3482 case PA_COMMAND_SET_SOURCE_MUTE:
3483 if (idx != PA_INVALID_INDEX)
3484 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3485 else
3486 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3487
3488 break;
3489
3490 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3491 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3492 break;
3493
3494 default:
3495 pa_assert_not_reached();
3496 }
3497
3498 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3499
3500 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3501
3502 if (sink) {
3503 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3504 pa_sink_set_mute(sink, mute, TRUE);
3505 } else if (source) {
3506 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3507 pa_source_set_mute(source, mute, TRUE);
3508 } else if (si) {
3509 pa_log_debug("Client %s changes mute of sink input %s.",
3510 client_name,
3511 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3512 pa_sink_input_set_mute(si, mute, TRUE);
3513 }
3514
3515 pa_pstream_send_simple_ack(c->pstream, tag);
3516 }
3517
3518 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3519 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3520 uint32_t idx;
3521 pa_bool_t b;
3522 playback_stream *s;
3523
3524 pa_native_connection_assert_ref(c);
3525 pa_assert(t);
3526
3527 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3528 pa_tagstruct_get_boolean(t, &b) < 0 ||
3529 !pa_tagstruct_eof(t)) {
3530 protocol_error(c);
3531 return;
3532 }
3533
3534 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3535 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3536 s = pa_idxset_get_by_index(c->output_streams, idx);
3537 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3538 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3539
3540 pa_sink_input_cork(s->sink_input, b);
3541
3542 if (b)
3543 s->is_underrun = TRUE;
3544
3545 pa_pstream_send_simple_ack(c->pstream, tag);
3546 }
3547
3548 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3549 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3550 uint32_t idx;
3551 playback_stream *s;
3552
3553 pa_native_connection_assert_ref(c);
3554 pa_assert(t);
3555
3556 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3557 !pa_tagstruct_eof(t)) {
3558 protocol_error(c);
3559 return;
3560 }
3561
3562 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3563 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3564 s = pa_idxset_get_by_index(c->output_streams, idx);
3565 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3566 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3567
3568 switch (command) {
3569 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3570 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3571 break;
3572
3573 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3574 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3575 break;
3576
3577 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3578 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3579 break;
3580
3581 default:
3582 pa_assert_not_reached();
3583 }
3584
3585 pa_pstream_send_simple_ack(c->pstream, tag);
3586 }
3587
3588 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3589 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3590 uint32_t idx;
3591 record_stream *s;
3592 pa_bool_t b;
3593
3594 pa_native_connection_assert_ref(c);
3595 pa_assert(t);
3596
3597 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3598 pa_tagstruct_get_boolean(t, &b) < 0 ||
3599 !pa_tagstruct_eof(t)) {
3600 protocol_error(c);
3601 return;
3602 }
3603
3604 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3605 s = pa_idxset_get_by_index(c->record_streams, idx);
3606 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3607
3608 pa_source_output_cork(s->source_output, b);
3609 pa_memblockq_prebuf_force(s->memblockq);
3610 pa_pstream_send_simple_ack(c->pstream, tag);
3611 }
3612
3613 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3614 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3615 uint32_t idx;
3616 record_stream *s;
3617
3618 pa_native_connection_assert_ref(c);
3619 pa_assert(t);
3620
3621 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3622 !pa_tagstruct_eof(t)) {
3623 protocol_error(c);
3624 return;
3625 }
3626
3627 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3628 s = pa_idxset_get_by_index(c->record_streams, idx);
3629 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3630
3631 pa_memblockq_flush_read(s->memblockq);
3632 pa_pstream_send_simple_ack(c->pstream, tag);
3633 }
3634
3635 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3636 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3637 uint32_t idx;
3638 pa_buffer_attr a;
3639 pa_tagstruct *reply;
3640
3641 pa_native_connection_assert_ref(c);
3642 pa_assert(t);
3643
3644 memset(&a, 0, sizeof(a));
3645
3646 if (pa_tagstruct_getu32(t, &idx) < 0) {
3647 protocol_error(c);
3648 return;
3649 }
3650
3651 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3652
3653 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3654 playback_stream *s;
3655 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3656
3657 s = pa_idxset_get_by_index(c->output_streams, idx);
3658 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3659 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3660
3661 if (pa_tagstruct_get(
3662 t,
3663 PA_TAG_U32, &a.maxlength,
3664 PA_TAG_U32, &a.tlength,
3665 PA_TAG_U32, &a.prebuf,
3666 PA_TAG_U32, &a.minreq,
3667 PA_TAG_INVALID) < 0 ||
3668 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3669 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3670 !pa_tagstruct_eof(t)) {
3671 protocol_error(c);
3672 return;
3673 }
3674
3675 s->adjust_latency = adjust_latency;
3676 s->early_requests = early_requests;
3677 s->buffer_attr = a;
3678
3679 fix_playback_buffer_attr(s);
3680 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);
3681
3682 reply = reply_new(tag);
3683 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3684 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3685 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3686 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3687
3688 if (c->version >= 13)
3689 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3690
3691 } else {
3692 record_stream *s;
3693 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3694 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3695
3696 s = pa_idxset_get_by_index(c->record_streams, idx);
3697 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3698
3699 if (pa_tagstruct_get(
3700 t,
3701 PA_TAG_U32, &a.maxlength,
3702 PA_TAG_U32, &a.fragsize,
3703 PA_TAG_INVALID) < 0 ||
3704 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3705 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3706 !pa_tagstruct_eof(t)) {
3707 protocol_error(c);
3708 return;
3709 }
3710
3711 s->adjust_latency = adjust_latency;
3712 s->early_requests = early_requests;
3713 s->buffer_attr = a;
3714
3715 fix_record_buffer_attr_pre(s);
3716 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3717 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3718 fix_record_buffer_attr_post(s);
3719
3720 reply = reply_new(tag);
3721 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3722 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3723
3724 if (c->version >= 13)
3725 pa_tagstruct_put_usec(reply, s->configured_source_latency);
3726 }
3727
3728 pa_pstream_send_tagstruct(c->pstream, reply);
3729 }
3730
3731 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3732 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3733 uint32_t idx;
3734 uint32_t rate;
3735
3736 pa_native_connection_assert_ref(c);
3737 pa_assert(t);
3738
3739 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3740 pa_tagstruct_getu32(t, &rate) < 0 ||
3741 !pa_tagstruct_eof(t)) {
3742 protocol_error(c);
3743 return;
3744 }
3745
3746 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3747 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
3748
3749 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
3750 playback_stream *s;
3751
3752 s = pa_idxset_get_by_index(c->output_streams, idx);
3753 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3754 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3755
3756 pa_sink_input_set_rate(s->sink_input, rate);
3757
3758 } else {
3759 record_stream *s;
3760 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
3761
3762 s = pa_idxset_get_by_index(c->record_streams, idx);
3763 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3764
3765 pa_source_output_set_rate(s->source_output, rate);
3766 }
3767
3768 pa_pstream_send_simple_ack(c->pstream, tag);
3769 }
3770
3771 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3772 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3773 uint32_t idx;
3774 uint32_t mode;
3775 pa_proplist *p;
3776
3777 pa_native_connection_assert_ref(c);
3778 pa_assert(t);
3779
3780 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3781
3782 p = pa_proplist_new();
3783
3784 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
3785
3786 if (pa_tagstruct_getu32(t, &mode) < 0 ||
3787 pa_tagstruct_get_proplist(t, p) < 0 ||
3788 !pa_tagstruct_eof(t)) {
3789 protocol_error(c);
3790 pa_proplist_free(p);
3791 return;
3792 }
3793
3794 } else {
3795
3796 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3797 pa_tagstruct_getu32(t, &mode) < 0 ||
3798 pa_tagstruct_get_proplist(t, p) < 0 ||
3799 !pa_tagstruct_eof(t)) {
3800 protocol_error(c);
3801 pa_proplist_free(p);
3802 return;
3803 }
3804 }
3805
3806 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
3807 pa_proplist_free(p);
3808 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
3809 }
3810
3811 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
3812 playback_stream *s;
3813
3814 s = pa_idxset_get_by_index(c->output_streams, idx);
3815 if (!s || !playback_stream_isinstance(s)) {
3816 pa_proplist_free(p);
3817 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3818 }
3819 pa_sink_input_update_proplist(s->sink_input, mode, p);
3820
3821 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
3822 record_stream *s;
3823
3824 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
3825 pa_proplist_free(p);
3826 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3827 }
3828 pa_source_output_update_proplist(s->source_output, mode, p);
3829
3830 } else {
3831 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
3832
3833 pa_client_update_proplist(c->client, mode, p);
3834 }
3835
3836 pa_pstream_send_simple_ack(c->pstream, tag);
3837 pa_proplist_free(p);
3838 }
3839
3840 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3841 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3842 uint32_t idx;
3843 unsigned changed = 0;
3844 pa_proplist *p;
3845 pa_strlist *l = NULL;
3846
3847 pa_native_connection_assert_ref(c);
3848 pa_assert(t);
3849
3850 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3851
3852 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
3853
3854 if (pa_tagstruct_getu32(t, &idx) < 0) {
3855 protocol_error(c);
3856 return;
3857 }
3858 }
3859
3860 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3861 playback_stream *s;
3862
3863 s = pa_idxset_get_by_index(c->output_streams, idx);
3864 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3865 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3866
3867 p = s->sink_input->proplist;
3868
3869 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3870 record_stream *s;
3871
3872 s = pa_idxset_get_by_index(c->record_streams, idx);
3873 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3874
3875 p = s->source_output->proplist;
3876 } else {
3877 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3878
3879 p = c->client->proplist;
3880 }
3881
3882 for (;;) {
3883 const char *k;
3884
3885 if (pa_tagstruct_gets(t, &k) < 0) {
3886 protocol_error(c);
3887 pa_strlist_free(l);
3888 return;
3889 }
3890
3891 if (!k)
3892 break;
3893
3894 l = pa_strlist_prepend(l, k);
3895 }
3896
3897 if (!pa_tagstruct_eof(t)) {
3898 protocol_error(c);
3899 pa_strlist_free(l);
3900 return;
3901 }
3902
3903 for (;;) {
3904 char *z;
3905
3906 l = pa_strlist_pop(l, &z);
3907
3908 if (!z)
3909 break;
3910
3911 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
3912 pa_xfree(z);
3913 }
3914
3915 pa_pstream_send_simple_ack(c->pstream, tag);
3916
3917 if (changed) {
3918 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3919 playback_stream *s;
3920
3921 s = pa_idxset_get_by_index(c->output_streams, idx);
3922 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
3923
3924 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3925 record_stream *s;
3926
3927 s = pa_idxset_get_by_index(c->record_streams, idx);
3928 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
3929
3930 } else {
3931 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3932 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
3933 }
3934 }
3935 }
3936
3937 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3938 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3939 const char *s;
3940
3941 pa_native_connection_assert_ref(c);
3942 pa_assert(t);
3943
3944 if (pa_tagstruct_gets(t, &s) < 0 ||
3945 !pa_tagstruct_eof(t)) {
3946 protocol_error(c);
3947 return;
3948 }
3949
3950 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3951 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
3952
3953 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
3954 pa_source *source;
3955
3956 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
3957 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
3958
3959 pa_namereg_set_default_source(c->protocol->core, source);
3960 } else {
3961 pa_sink *sink;
3962 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
3963
3964 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
3965 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3966
3967 pa_namereg_set_default_sink(c->protocol->core, sink);
3968 }
3969
3970 pa_pstream_send_simple_ack(c->pstream, tag);
3971 }
3972
3973 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3974 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3975 uint32_t idx;
3976 const char *name;
3977
3978 pa_native_connection_assert_ref(c);
3979 pa_assert(t);
3980
3981 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3982 pa_tagstruct_gets(t, &name) < 0 ||
3983 !pa_tagstruct_eof(t)) {
3984 protocol_error(c);
3985 return;
3986 }
3987
3988 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3989 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
3990
3991 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
3992 playback_stream *s;
3993
3994 s = pa_idxset_get_by_index(c->output_streams, idx);
3995 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3996 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3997
3998 pa_sink_input_set_name(s->sink_input, name);
3999
4000 } else {
4001 record_stream *s;
4002 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4003
4004 s = pa_idxset_get_by_index(c->record_streams, idx);
4005 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4006
4007 pa_source_output_set_name(s->source_output, name);
4008 }
4009
4010 pa_pstream_send_simple_ack(c->pstream, tag);
4011 }
4012
4013 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4014 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4015 uint32_t idx;
4016
4017 pa_native_connection_assert_ref(c);
4018 pa_assert(t);
4019
4020 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4021 !pa_tagstruct_eof(t)) {
4022 protocol_error(c);
4023 return;
4024 }
4025
4026 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4027
4028 if (command == PA_COMMAND_KILL_CLIENT) {
4029 pa_client *client;
4030
4031 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4032 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4033
4034 pa_native_connection_ref(c);
4035 pa_client_kill(client);
4036
4037 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4038 pa_sink_input *s;
4039
4040 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4041 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4042
4043 pa_native_connection_ref(c);
4044 pa_sink_input_kill(s);
4045 } else {
4046 pa_source_output *s;
4047
4048 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4049
4050 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4051 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4052
4053 pa_native_connection_ref(c);
4054 pa_source_output_kill(s);
4055 }
4056
4057 pa_pstream_send_simple_ack(c->pstream, tag);
4058 pa_native_connection_unref(c);
4059 }
4060
4061 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4062 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4063 pa_module *m;
4064 const char *name, *argument;
4065 pa_tagstruct *reply;
4066
4067 pa_native_connection_assert_ref(c);
4068 pa_assert(t);
4069
4070 if (pa_tagstruct_gets(t, &name) < 0 ||
4071 pa_tagstruct_gets(t, &argument) < 0 ||
4072 !pa_tagstruct_eof(t)) {
4073 protocol_error(c);
4074 return;
4075 }
4076
4077 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4078 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4079 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4080
4081 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4082 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4083 return;
4084 }
4085
4086 reply = reply_new(tag);
4087 pa_tagstruct_putu32(reply, m->index);
4088 pa_pstream_send_tagstruct(c->pstream, reply);
4089 }
4090
4091 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4092 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4093 uint32_t idx;
4094 pa_module *m;
4095
4096 pa_native_connection_assert_ref(c);
4097 pa_assert(t);
4098
4099 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4100 !pa_tagstruct_eof(t)) {
4101 protocol_error(c);
4102 return;
4103 }
4104
4105 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4106 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4107 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4108
4109 pa_module_unload_request(m, FALSE);
4110 pa_pstream_send_simple_ack(c->pstream, tag);
4111 }
4112
4113 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4114 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4115 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4116 const char *name_device = NULL;
4117
4118 pa_native_connection_assert_ref(c);
4119 pa_assert(t);
4120
4121 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4122 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4123 pa_tagstruct_gets(t, &name_device) < 0 ||
4124 !pa_tagstruct_eof(t)) {
4125 protocol_error(c);
4126 return;
4127 }
4128
4129 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4130 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4131
4132 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);
4133 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4134 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4135 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4136
4137 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4138 pa_sink_input *si = NULL;
4139 pa_sink *sink = NULL;
4140
4141 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4142
4143 if (idx_device != PA_INVALID_INDEX)
4144 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4145 else
4146 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4147
4148 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4149
4150 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4151 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4152 return;
4153 }
4154 } else {
4155 pa_source_output *so = NULL;
4156 pa_source *source;
4157
4158 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4159
4160 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4161
4162 if (idx_device != PA_INVALID_INDEX)
4163 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4164 else
4165 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4166
4167 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4168
4169 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4170 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4171 return;
4172 }
4173 }
4174
4175 pa_pstream_send_simple_ack(c->pstream, tag);
4176 }
4177
4178 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4179 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4180 uint32_t idx = PA_INVALID_INDEX;
4181 const char *name = NULL;
4182 pa_bool_t b;
4183
4184 pa_native_connection_assert_ref(c);
4185 pa_assert(t);
4186
4187 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4188 pa_tagstruct_gets(t, &name) < 0 ||
4189 pa_tagstruct_get_boolean(t, &b) < 0 ||
4190 !pa_tagstruct_eof(t)) {
4191 protocol_error(c);
4192 return;
4193 }
4194
4195 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4196 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);
4197 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4198 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4199 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4200
4201 if (command == PA_COMMAND_SUSPEND_SINK) {
4202
4203 if (idx == PA_INVALID_INDEX && name && !*name) {
4204
4205 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4206
4207 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4208 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4209 return;
4210 }
4211 } else {
4212 pa_sink *sink = NULL;
4213
4214 if (idx != PA_INVALID_INDEX)
4215 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4216 else
4217 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4218
4219 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4220
4221 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4222 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4223 return;
4224 }
4225 }
4226 } else {
4227
4228 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4229
4230 if (idx == PA_INVALID_INDEX && name && !*name) {
4231
4232 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4233
4234 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4235 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4236 return;
4237 }
4238
4239 } else {
4240 pa_source *source;
4241
4242 if (idx != PA_INVALID_INDEX)
4243 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4244 else
4245 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4246
4247 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4248
4249 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4250 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4251 return;
4252 }
4253 }
4254 }
4255
4256 pa_pstream_send_simple_ack(c->pstream, tag);
4257 }
4258
4259 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4260 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4261 uint32_t idx = PA_INVALID_INDEX;
4262 const char *name = NULL;
4263 pa_module *m;
4264 pa_native_protocol_ext_cb_t cb;
4265
4266 pa_native_connection_assert_ref(c);
4267 pa_assert(t);
4268
4269 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4270 pa_tagstruct_gets(t, &name) < 0) {
4271 protocol_error(c);
4272 return;
4273 }
4274
4275 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4276 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4277 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4278 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4279 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4280
4281 if (idx != PA_INVALID_INDEX)
4282 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4283 else {
4284 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4285 if (strcmp(name, m->name) == 0)
4286 break;
4287 }
4288
4289 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4290 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4291
4292 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4293 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4294
4295 if (cb(c->protocol, m, c, tag, t) < 0)
4296 protocol_error(c);
4297 }
4298
4299 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4300 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4301 uint32_t idx = PA_INVALID_INDEX;
4302 const char *name = NULL, *profile = NULL;
4303 pa_card *card = NULL;
4304 int ret;
4305
4306 pa_native_connection_assert_ref(c);
4307 pa_assert(t);
4308
4309 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4310 pa_tagstruct_gets(t, &name) < 0 ||
4311 pa_tagstruct_gets(t, &profile) < 0 ||
4312 !pa_tagstruct_eof(t)) {
4313 protocol_error(c);
4314 return;
4315 }
4316
4317 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4318 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4319 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4320 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4321 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4322
4323 if (idx != PA_INVALID_INDEX)
4324 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4325 else
4326 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4327
4328 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4329
4330 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4331 pa_pstream_send_error(c->pstream, tag, -ret);
4332 return;
4333 }
4334
4335 pa_pstream_send_simple_ack(c->pstream, tag);
4336 }
4337
4338 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4339 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4340 uint32_t idx = PA_INVALID_INDEX;
4341 const char *name = NULL, *port = NULL;
4342 int ret;
4343
4344 pa_native_connection_assert_ref(c);
4345 pa_assert(t);
4346
4347 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4348 pa_tagstruct_gets(t, &name) < 0 ||
4349 pa_tagstruct_gets(t, &port) < 0 ||
4350 !pa_tagstruct_eof(t)) {
4351 protocol_error(c);
4352 return;
4353 }
4354
4355 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4356 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);
4357 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4358 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4359 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4360
4361 if (command == PA_COMMAND_SET_SINK_PORT) {
4362 pa_sink *sink;
4363
4364 if (idx != PA_INVALID_INDEX)
4365 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4366 else
4367 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4368
4369 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4370
4371 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4372 pa_pstream_send_error(c->pstream, tag, -ret);
4373 return;
4374 }
4375 } else {
4376 pa_source *source;
4377
4378 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4379
4380 if (idx != PA_INVALID_INDEX)
4381 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4382 else
4383 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4384
4385 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4386
4387 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4388 pa_pstream_send_error(c->pstream, tag, -ret);
4389 return;
4390 }
4391 }
4392
4393 pa_pstream_send_simple_ack(c->pstream, tag);
4394 }
4395
4396 /*** pstream callbacks ***/
4397
4398 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4399 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4400
4401 pa_assert(p);
4402 pa_assert(packet);
4403 pa_native_connection_assert_ref(c);
4404
4405 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4406 pa_log("invalid packet.");
4407 native_connection_unlink(c);
4408 }
4409 }
4410
4411 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) {
4412 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4413 output_stream *stream;
4414
4415 pa_assert(p);
4416 pa_assert(chunk);
4417 pa_native_connection_assert_ref(c);
4418
4419 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4420 pa_log_debug("Client sent block for invalid stream.");
4421 /* Ignoring */
4422 return;
4423 }
4424
4425 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4426
4427 if (playback_stream_isinstance(stream)) {
4428 playback_stream *ps = PLAYBACK_STREAM(stream);
4429
4430 if (chunk->memblock) {
4431 if (seek != PA_SEEK_RELATIVE || offset != 0)
4432 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);
4433
4434 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4435 } else
4436 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);
4437
4438 } else {
4439 upload_stream *u = UPLOAD_STREAM(stream);
4440 size_t l;
4441
4442 if (!u->memchunk.memblock) {
4443 if (u->length == chunk->length && chunk->memblock) {
4444 u->memchunk = *chunk;
4445 pa_memblock_ref(u->memchunk.memblock);
4446 u->length = 0;
4447 } else {
4448 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4449 u->memchunk.index = u->memchunk.length = 0;
4450 }
4451 }
4452
4453 pa_assert(u->memchunk.memblock);
4454
4455 l = u->length;
4456 if (l > chunk->length)
4457 l = chunk->length;
4458
4459 if (l > 0) {
4460 void *dst;
4461 dst = pa_memblock_acquire(u->memchunk.memblock);
4462
4463 if (chunk->memblock) {
4464 void *src;
4465 src = pa_memblock_acquire(chunk->memblock);
4466
4467 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4468 (uint8_t*) src + chunk->index, l);
4469
4470 pa_memblock_release(chunk->memblock);
4471 } else
4472 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4473
4474 pa_memblock_release(u->memchunk.memblock);
4475
4476 u->memchunk.length += l;
4477 u->length -= l;
4478 }
4479 }
4480 }
4481
4482 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4483 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4484
4485 pa_assert(p);
4486 pa_native_connection_assert_ref(c);
4487
4488 native_connection_unlink(c);
4489 pa_log_info("Connection died.");
4490 }
4491
4492 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4493 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4494
4495 pa_assert(p);
4496 pa_native_connection_assert_ref(c);
4497
4498 native_connection_send_memblock(c);
4499 }
4500
4501 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4502 pa_thread_mq *q;
4503
4504 if (!(q = pa_thread_mq_get()))
4505 pa_pstream_send_revoke(p, block_id);
4506 else
4507 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4508 }
4509
4510 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4511 pa_thread_mq *q;
4512
4513 if (!(q = pa_thread_mq_get()))
4514 pa_pstream_send_release(p, block_id);
4515 else
4516 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4517 }
4518
4519 /*** client callbacks ***/
4520
4521 static void client_kill_cb(pa_client *c) {
4522 pa_assert(c);
4523
4524 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4525 pa_log_info("Connection killed.");
4526 }
4527
4528 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4529 pa_tagstruct *t;
4530 pa_native_connection *c;
4531
4532 pa_assert(client);
4533 c = PA_NATIVE_CONNECTION(client->userdata);
4534 pa_native_connection_assert_ref(c);
4535
4536 if (c->version < 15)
4537 return;
4538
4539 t = pa_tagstruct_new(NULL, 0);
4540 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4541 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4542 pa_tagstruct_puts(t, event);
4543 pa_tagstruct_put_proplist(t, pl);
4544 pa_pstream_send_tagstruct(c->pstream, t);
4545 }
4546
4547 /*** module entry points ***/
4548
4549 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4550 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4551
4552 pa_assert(m);
4553 pa_native_connection_assert_ref(c);
4554 pa_assert(c->auth_timeout_event == e);
4555
4556 if (!c->authorized) {
4557 native_connection_unlink(c);
4558 pa_log_info("Connection terminated due to authentication timeout.");
4559 }
4560 }
4561
4562 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4563 pa_native_connection *c;
4564 char pname[128];
4565 pa_client *client;
4566 pa_client_new_data data;
4567
4568 pa_assert(p);
4569 pa_assert(io);
4570 pa_assert(o);
4571
4572 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4573 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4574 pa_iochannel_free(io);
4575 return;
4576 }
4577
4578 pa_client_new_data_init(&data);
4579 data.module = o->module;
4580 data.driver = __FILE__;
4581 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4582 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4583 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4584 client = pa_client_new(p->core, &data);
4585 pa_client_new_data_done(&data);
4586
4587 if (!client)
4588 return;
4589
4590 c = pa_msgobject_new(pa_native_connection);
4591 c->parent.parent.free = native_connection_free;
4592 c->parent.process_msg = native_connection_process_msg;
4593 c->protocol = p;
4594 c->options = pa_native_options_ref(o);
4595 c->authorized = FALSE;
4596
4597 if (o->auth_anonymous) {
4598 pa_log_info("Client authenticated anonymously.");
4599 c->authorized = TRUE;
4600 }
4601
4602 if (!c->authorized &&
4603 o->auth_ip_acl &&
4604 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4605
4606 pa_log_info("Client authenticated by IP ACL.");
4607 c->authorized = TRUE;
4608 }
4609
4610 if (!c->authorized)
4611 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4612 else
4613 c->auth_timeout_event = NULL;
4614
4615 c->is_local = pa_iochannel_socket_is_local(io);
4616 c->version = 8;
4617
4618 c->client = client;
4619 c->client->kill = client_kill_cb;
4620 c->client->send_event = client_send_event_cb;
4621 c->client->userdata = c;
4622
4623 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4624 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4625 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4626 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4627 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4628 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4629 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4630
4631 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4632
4633 c->record_streams = pa_idxset_new(NULL, NULL);
4634 c->output_streams = pa_idxset_new(NULL, NULL);
4635
4636 c->rrobin_index = PA_IDXSET_INVALID;
4637 c->subscription = NULL;
4638
4639 pa_idxset_put(p->connections, c, NULL);
4640
4641 #ifdef HAVE_CREDS
4642 if (pa_iochannel_creds_supported(io))
4643 pa_iochannel_creds_enable(io);
4644 #endif
4645
4646 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4647 }
4648
4649 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4650 pa_native_connection *c;
4651 void *state = NULL;
4652
4653 pa_assert(p);
4654 pa_assert(m);
4655
4656 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4657 if (c->options->module == m)
4658 native_connection_unlink(c);
4659 }
4660
4661 static pa_native_protocol* native_protocol_new(pa_core *c) {
4662 pa_native_protocol *p;
4663 pa_native_hook_t h;
4664
4665 pa_assert(c);
4666
4667 p = pa_xnew(pa_native_protocol, 1);
4668 PA_REFCNT_INIT(p);
4669 p->core = c;
4670 p->connections = pa_idxset_new(NULL, NULL);
4671
4672 p->servers = NULL;
4673
4674 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4675
4676 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4677 pa_hook_init(&p->hooks[h], p);
4678
4679 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4680
4681 return p;
4682 }
4683
4684 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4685 pa_native_protocol *p;
4686
4687 if ((p = pa_shared_get(c, "native-protocol")))
4688 return pa_native_protocol_ref(p);
4689
4690 return native_protocol_new(c);
4691 }
4692
4693 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4694 pa_assert(p);
4695 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4696
4697 PA_REFCNT_INC(p);
4698
4699 return p;
4700 }
4701
4702 void pa_native_protocol_unref(pa_native_protocol *p) {
4703 pa_native_connection *c;
4704 pa_native_hook_t h;
4705
4706 pa_assert(p);
4707 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4708
4709 if (PA_REFCNT_DEC(p) > 0)
4710 return;
4711
4712 while ((c = pa_idxset_first(p->connections, NULL)))
4713 native_connection_unlink(c);
4714
4715 pa_idxset_free(p->connections, NULL, NULL);
4716
4717 pa_strlist_free(p->servers);
4718
4719 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4720 pa_hook_done(&p->hooks[h]);
4721
4722 pa_hashmap_free(p->extensions, NULL, NULL);
4723
4724 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4725
4726 pa_xfree(p);
4727 }
4728
4729 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
4730 pa_assert(p);
4731 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4732 pa_assert(name);
4733
4734 p->servers = pa_strlist_prepend(p->servers, name);
4735
4736 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4737 }
4738
4739 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
4740 pa_assert(p);
4741 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4742 pa_assert(name);
4743
4744 p->servers = pa_strlist_remove(p->servers, name);
4745
4746 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4747 }
4748
4749 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
4750 pa_assert(p);
4751 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4752
4753 return p->hooks;
4754 }
4755
4756 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
4757 pa_assert(p);
4758 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4759
4760 return p->servers;
4761 }
4762
4763 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
4764 pa_assert(p);
4765 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4766 pa_assert(m);
4767 pa_assert(cb);
4768 pa_assert(!pa_hashmap_get(p->extensions, m));
4769
4770 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
4771 return 0;
4772 }
4773
4774 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
4775 pa_assert(p);
4776 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4777 pa_assert(m);
4778
4779 pa_assert_se(pa_hashmap_remove(p->extensions, m));
4780 }
4781
4782 pa_native_options* pa_native_options_new(void) {
4783 pa_native_options *o;
4784
4785 o = pa_xnew0(pa_native_options, 1);
4786 PA_REFCNT_INIT(o);
4787
4788 return o;
4789 }
4790
4791 pa_native_options* pa_native_options_ref(pa_native_options *o) {
4792 pa_assert(o);
4793 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4794
4795 PA_REFCNT_INC(o);
4796
4797 return o;
4798 }
4799
4800 void pa_native_options_unref(pa_native_options *o) {
4801 pa_assert(o);
4802 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4803
4804 if (PA_REFCNT_DEC(o) > 0)
4805 return;
4806
4807 pa_xfree(o->auth_group);
4808
4809 if (o->auth_ip_acl)
4810 pa_ip_acl_free(o->auth_ip_acl);
4811
4812 if (o->auth_cookie)
4813 pa_auth_cookie_unref(o->auth_cookie);
4814
4815 pa_xfree(o);
4816 }
4817
4818 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
4819 pa_bool_t enabled;
4820 const char *acl;
4821
4822 pa_assert(o);
4823 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4824 pa_assert(ma);
4825
4826 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
4827 pa_log("auth-anonymous= expects a boolean argument.");
4828 return -1;
4829 }
4830
4831 enabled = TRUE;
4832 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
4833 pa_log("auth-group-enabled= expects a boolean argument.");
4834 return -1;
4835 }
4836
4837 pa_xfree(o->auth_group);
4838 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
4839
4840 #ifndef HAVE_CREDS
4841 if (o->auth_group)
4842 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4843 #endif
4844
4845 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
4846 pa_ip_acl *ipa;
4847
4848 if (!(ipa = pa_ip_acl_new(acl))) {
4849 pa_log("Failed to parse IP ACL '%s'", acl);
4850 return -1;
4851 }
4852
4853 if (o->auth_ip_acl)
4854 pa_ip_acl_free(o->auth_ip_acl);
4855
4856 o->auth_ip_acl = ipa;
4857 }
4858
4859 enabled = TRUE;
4860 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
4861 pa_log("auth-cookie-enabled= expects a boolean argument.");
4862 return -1;
4863 }
4864
4865 if (o->auth_cookie)
4866 pa_auth_cookie_unref(o->auth_cookie);
4867
4868 if (enabled) {
4869 const char *cn;
4870
4871 /* The new name for this is 'auth-cookie', for compat reasons
4872 * we check the old name too */
4873 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
4874 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
4875 cn = PA_NATIVE_COOKIE_FILE;
4876
4877 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
4878 return -1;
4879
4880 } else
4881 o->auth_cookie = NULL;
4882
4883 return 0;
4884 }
4885
4886 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
4887 pa_native_connection_assert_ref(c);
4888
4889 return c->pstream;
4890 }
4891
4892 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
4893 pa_native_connection_assert_ref(c);
4894
4895 return c->client;
4896 }