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