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