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