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