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