]> code.delx.au - pulseaudio/blob - src/pulsecore/protocol-native.c
Sending translation for Serbian (Latin)
[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 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3394
3395 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3396 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3397 } else if (source) {
3398 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3399
3400 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3401 pa_source_set_volume(source, &volume, TRUE);
3402 } else if (si) {
3403 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3404
3405 pa_log_debug("Client %s changes volume of sink input %s.",
3406 client_name,
3407 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3408 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3409 }
3410
3411 pa_pstream_send_simple_ack(c->pstream, tag);
3412 }
3413
3414 static void command_set_mute(
3415 pa_pdispatch *pd,
3416 uint32_t command,
3417 uint32_t tag,
3418 pa_tagstruct *t,
3419 void *userdata) {
3420
3421 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3422 uint32_t idx;
3423 pa_bool_t mute;
3424 pa_sink *sink = NULL;
3425 pa_source *source = NULL;
3426 pa_sink_input *si = NULL;
3427 const char *name = NULL, *client_name;
3428
3429 pa_native_connection_assert_ref(c);
3430 pa_assert(t);
3431
3432 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3433 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3434 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3435 pa_tagstruct_get_boolean(t, &mute) ||
3436 !pa_tagstruct_eof(t)) {
3437 protocol_error(c);
3438 return;
3439 }
3440
3441 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3442 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);
3443 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3444 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3445 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3446
3447 switch (command) {
3448
3449 case PA_COMMAND_SET_SINK_MUTE:
3450 if (idx != PA_INVALID_INDEX)
3451 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3452 else
3453 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3454
3455 break;
3456
3457 case PA_COMMAND_SET_SOURCE_MUTE:
3458 if (idx != PA_INVALID_INDEX)
3459 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3460 else
3461 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3462
3463 break;
3464
3465 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3466 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3467 break;
3468
3469 default:
3470 pa_assert_not_reached();
3471 }
3472
3473 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3474
3475 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3476
3477 if (sink) {
3478 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3479 pa_sink_set_mute(sink, mute, TRUE);
3480 } else if (source) {
3481 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3482 pa_source_set_mute(source, mute, TRUE);
3483 } else if (si) {
3484 pa_log_debug("Client %s changes mute of sink input %s.",
3485 client_name,
3486 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3487 pa_sink_input_set_mute(si, mute, TRUE);
3488 }
3489
3490 pa_pstream_send_simple_ack(c->pstream, tag);
3491 }
3492
3493 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3494 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3495 uint32_t idx;
3496 pa_bool_t b;
3497 playback_stream *s;
3498
3499 pa_native_connection_assert_ref(c);
3500 pa_assert(t);
3501
3502 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3503 pa_tagstruct_get_boolean(t, &b) < 0 ||
3504 !pa_tagstruct_eof(t)) {
3505 protocol_error(c);
3506 return;
3507 }
3508
3509 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3510 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3511 s = pa_idxset_get_by_index(c->output_streams, idx);
3512 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3513 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3514
3515 pa_sink_input_cork(s->sink_input, b);
3516
3517 if (b)
3518 s->is_underrun = TRUE;
3519
3520 pa_pstream_send_simple_ack(c->pstream, tag);
3521 }
3522
3523 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3524 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3525 uint32_t idx;
3526 playback_stream *s;
3527
3528 pa_native_connection_assert_ref(c);
3529 pa_assert(t);
3530
3531 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3532 !pa_tagstruct_eof(t)) {
3533 protocol_error(c);
3534 return;
3535 }
3536
3537 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3538 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3539 s = pa_idxset_get_by_index(c->output_streams, idx);
3540 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3541 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3542
3543 switch (command) {
3544 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3545 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3546 break;
3547
3548 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3549 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3550 break;
3551
3552 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3553 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3554 break;
3555
3556 default:
3557 pa_assert_not_reached();
3558 }
3559
3560 pa_pstream_send_simple_ack(c->pstream, tag);
3561 }
3562
3563 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3564 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3565 uint32_t idx;
3566 record_stream *s;
3567 pa_bool_t b;
3568
3569 pa_native_connection_assert_ref(c);
3570 pa_assert(t);
3571
3572 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3573 pa_tagstruct_get_boolean(t, &b) < 0 ||
3574 !pa_tagstruct_eof(t)) {
3575 protocol_error(c);
3576 return;
3577 }
3578
3579 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3580 s = pa_idxset_get_by_index(c->record_streams, idx);
3581 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3582
3583 pa_source_output_cork(s->source_output, b);
3584 pa_memblockq_prebuf_force(s->memblockq);
3585 pa_pstream_send_simple_ack(c->pstream, tag);
3586 }
3587
3588 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3589 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3590 uint32_t idx;
3591 record_stream *s;
3592
3593 pa_native_connection_assert_ref(c);
3594 pa_assert(t);
3595
3596 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3597 !pa_tagstruct_eof(t)) {
3598 protocol_error(c);
3599 return;
3600 }
3601
3602 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3603 s = pa_idxset_get_by_index(c->record_streams, idx);
3604 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3605
3606 pa_memblockq_flush_read(s->memblockq);
3607 pa_pstream_send_simple_ack(c->pstream, tag);
3608 }
3609
3610 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3611 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3612 uint32_t idx;
3613 pa_buffer_attr a;
3614 pa_tagstruct *reply;
3615
3616 pa_native_connection_assert_ref(c);
3617 pa_assert(t);
3618
3619 memset(&a, 0, sizeof(a));
3620
3621 if (pa_tagstruct_getu32(t, &idx) < 0) {
3622 protocol_error(c);
3623 return;
3624 }
3625
3626 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3627
3628 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3629 playback_stream *s;
3630 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3631
3632 s = pa_idxset_get_by_index(c->output_streams, idx);
3633 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3634 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3635
3636 if (pa_tagstruct_get(
3637 t,
3638 PA_TAG_U32, &a.maxlength,
3639 PA_TAG_U32, &a.tlength,
3640 PA_TAG_U32, &a.prebuf,
3641 PA_TAG_U32, &a.minreq,
3642 PA_TAG_INVALID) < 0 ||
3643 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3644 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3645 !pa_tagstruct_eof(t)) {
3646 protocol_error(c);
3647 return;
3648 }
3649
3650 s->adjust_latency = adjust_latency;
3651 s->early_requests = early_requests;
3652 s->buffer_attr = a;
3653
3654 fix_playback_buffer_attr(s);
3655 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);
3656
3657 reply = reply_new(tag);
3658 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3659 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3660 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3661 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3662
3663 if (c->version >= 13)
3664 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3665
3666 } else {
3667 record_stream *s;
3668 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3669 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3670
3671 s = pa_idxset_get_by_index(c->record_streams, idx);
3672 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3673
3674 if (pa_tagstruct_get(
3675 t,
3676 PA_TAG_U32, &a.maxlength,
3677 PA_TAG_U32, &a.fragsize,
3678 PA_TAG_INVALID) < 0 ||
3679 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3680 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3681 !pa_tagstruct_eof(t)) {
3682 protocol_error(c);
3683 return;
3684 }
3685
3686 s->adjust_latency = adjust_latency;
3687 s->early_requests = early_requests;
3688 s->buffer_attr = a;
3689
3690 fix_record_buffer_attr_pre(s);
3691 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3692 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3693 fix_record_buffer_attr_post(s);
3694
3695 reply = reply_new(tag);
3696 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3697 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3698
3699 if (c->version >= 13)
3700 pa_tagstruct_put_usec(reply, s->configured_source_latency);
3701 }
3702
3703 pa_pstream_send_tagstruct(c->pstream, reply);
3704 }
3705
3706 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3707 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3708 uint32_t idx;
3709 uint32_t rate;
3710
3711 pa_native_connection_assert_ref(c);
3712 pa_assert(t);
3713
3714 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3715 pa_tagstruct_getu32(t, &rate) < 0 ||
3716 !pa_tagstruct_eof(t)) {
3717 protocol_error(c);
3718 return;
3719 }
3720
3721 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3722 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
3723
3724 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
3725 playback_stream *s;
3726
3727 s = pa_idxset_get_by_index(c->output_streams, idx);
3728 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3729 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3730
3731 pa_sink_input_set_rate(s->sink_input, rate);
3732
3733 } else {
3734 record_stream *s;
3735 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
3736
3737 s = pa_idxset_get_by_index(c->record_streams, idx);
3738 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3739
3740 pa_source_output_set_rate(s->source_output, rate);
3741 }
3742
3743 pa_pstream_send_simple_ack(c->pstream, tag);
3744 }
3745
3746 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3747 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3748 uint32_t idx;
3749 uint32_t mode;
3750 pa_proplist *p;
3751
3752 pa_native_connection_assert_ref(c);
3753 pa_assert(t);
3754
3755 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3756
3757 p = pa_proplist_new();
3758
3759 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
3760
3761 if (pa_tagstruct_getu32(t, &mode) < 0 ||
3762 pa_tagstruct_get_proplist(t, p) < 0 ||
3763 !pa_tagstruct_eof(t)) {
3764 protocol_error(c);
3765 pa_proplist_free(p);
3766 return;
3767 }
3768
3769 } else {
3770
3771 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3772 pa_tagstruct_getu32(t, &mode) < 0 ||
3773 pa_tagstruct_get_proplist(t, p) < 0 ||
3774 !pa_tagstruct_eof(t)) {
3775 protocol_error(c);
3776 pa_proplist_free(p);
3777 return;
3778 }
3779 }
3780
3781 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
3782 pa_proplist_free(p);
3783 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
3784 }
3785
3786 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
3787 playback_stream *s;
3788
3789 s = pa_idxset_get_by_index(c->output_streams, idx);
3790 if (!s || !playback_stream_isinstance(s)) {
3791 pa_proplist_free(p);
3792 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3793 }
3794 pa_sink_input_update_proplist(s->sink_input, mode, p);
3795
3796 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
3797 record_stream *s;
3798
3799 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
3800 pa_proplist_free(p);
3801 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3802 }
3803 pa_source_output_update_proplist(s->source_output, mode, p);
3804
3805 } else {
3806 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
3807
3808 pa_client_update_proplist(c->client, mode, p);
3809 }
3810
3811 pa_pstream_send_simple_ack(c->pstream, tag);
3812 pa_proplist_free(p);
3813 }
3814
3815 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3816 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3817 uint32_t idx;
3818 unsigned changed = 0;
3819 pa_proplist *p;
3820 pa_strlist *l = NULL;
3821
3822 pa_native_connection_assert_ref(c);
3823 pa_assert(t);
3824
3825 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3826
3827 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
3828
3829 if (pa_tagstruct_getu32(t, &idx) < 0) {
3830 protocol_error(c);
3831 return;
3832 }
3833 }
3834
3835 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3836 playback_stream *s;
3837
3838 s = pa_idxset_get_by_index(c->output_streams, idx);
3839 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3840 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3841
3842 p = s->sink_input->proplist;
3843
3844 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3845 record_stream *s;
3846
3847 s = pa_idxset_get_by_index(c->record_streams, idx);
3848 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3849
3850 p = s->source_output->proplist;
3851 } else {
3852 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3853
3854 p = c->client->proplist;
3855 }
3856
3857 for (;;) {
3858 const char *k;
3859
3860 if (pa_tagstruct_gets(t, &k) < 0) {
3861 protocol_error(c);
3862 pa_strlist_free(l);
3863 return;
3864 }
3865
3866 if (!k)
3867 break;
3868
3869 l = pa_strlist_prepend(l, k);
3870 }
3871
3872 if (!pa_tagstruct_eof(t)) {
3873 protocol_error(c);
3874 pa_strlist_free(l);
3875 return;
3876 }
3877
3878 for (;;) {
3879 char *z;
3880
3881 l = pa_strlist_pop(l, &z);
3882
3883 if (!z)
3884 break;
3885
3886 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
3887 pa_xfree(z);
3888 }
3889
3890 pa_pstream_send_simple_ack(c->pstream, tag);
3891
3892 if (changed) {
3893 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3894 playback_stream *s;
3895
3896 s = pa_idxset_get_by_index(c->output_streams, idx);
3897 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
3898
3899 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3900 record_stream *s;
3901
3902 s = pa_idxset_get_by_index(c->record_streams, idx);
3903 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
3904
3905 } else {
3906 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3907 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
3908 }
3909 }
3910 }
3911
3912 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3913 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3914 const char *s;
3915
3916 pa_native_connection_assert_ref(c);
3917 pa_assert(t);
3918
3919 if (pa_tagstruct_gets(t, &s) < 0 ||
3920 !pa_tagstruct_eof(t)) {
3921 protocol_error(c);
3922 return;
3923 }
3924
3925 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3926 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
3927
3928 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
3929 pa_source *source;
3930
3931 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
3932 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
3933
3934 pa_namereg_set_default_source(c->protocol->core, source);
3935 } else {
3936 pa_sink *sink;
3937 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
3938
3939 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
3940 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3941
3942 pa_namereg_set_default_sink(c->protocol->core, sink);
3943 }
3944
3945 pa_pstream_send_simple_ack(c->pstream, tag);
3946 }
3947
3948 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3949 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3950 uint32_t idx;
3951 const char *name;
3952
3953 pa_native_connection_assert_ref(c);
3954 pa_assert(t);
3955
3956 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3957 pa_tagstruct_gets(t, &name) < 0 ||
3958 !pa_tagstruct_eof(t)) {
3959 protocol_error(c);
3960 return;
3961 }
3962
3963 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3964 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
3965
3966 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
3967 playback_stream *s;
3968
3969 s = pa_idxset_get_by_index(c->output_streams, idx);
3970 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3971 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3972
3973 pa_sink_input_set_name(s->sink_input, name);
3974
3975 } else {
3976 record_stream *s;
3977 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
3978
3979 s = pa_idxset_get_by_index(c->record_streams, idx);
3980 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3981
3982 pa_source_output_set_name(s->source_output, name);
3983 }
3984
3985 pa_pstream_send_simple_ack(c->pstream, tag);
3986 }
3987
3988 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3989 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3990 uint32_t idx;
3991
3992 pa_native_connection_assert_ref(c);
3993 pa_assert(t);
3994
3995 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3996 !pa_tagstruct_eof(t)) {
3997 protocol_error(c);
3998 return;
3999 }
4000
4001 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4002
4003 if (command == PA_COMMAND_KILL_CLIENT) {
4004 pa_client *client;
4005
4006 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4007 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4008
4009 pa_native_connection_ref(c);
4010 pa_client_kill(client);
4011
4012 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4013 pa_sink_input *s;
4014
4015 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4016 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4017
4018 pa_native_connection_ref(c);
4019 pa_sink_input_kill(s);
4020 } else {
4021 pa_source_output *s;
4022
4023 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4024
4025 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4026 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4027
4028 pa_native_connection_ref(c);
4029 pa_source_output_kill(s);
4030 }
4031
4032 pa_pstream_send_simple_ack(c->pstream, tag);
4033 pa_native_connection_unref(c);
4034 }
4035
4036 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4037 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4038 pa_module *m;
4039 const char *name, *argument;
4040 pa_tagstruct *reply;
4041
4042 pa_native_connection_assert_ref(c);
4043 pa_assert(t);
4044
4045 if (pa_tagstruct_gets(t, &name) < 0 ||
4046 pa_tagstruct_gets(t, &argument) < 0 ||
4047 !pa_tagstruct_eof(t)) {
4048 protocol_error(c);
4049 return;
4050 }
4051
4052 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4053 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4054 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4055
4056 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4057 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4058 return;
4059 }
4060
4061 reply = reply_new(tag);
4062 pa_tagstruct_putu32(reply, m->index);
4063 pa_pstream_send_tagstruct(c->pstream, reply);
4064 }
4065
4066 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4067 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4068 uint32_t idx;
4069 pa_module *m;
4070
4071 pa_native_connection_assert_ref(c);
4072 pa_assert(t);
4073
4074 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4075 !pa_tagstruct_eof(t)) {
4076 protocol_error(c);
4077 return;
4078 }
4079
4080 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4081 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4082 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4083
4084 pa_module_unload_request(m, FALSE);
4085 pa_pstream_send_simple_ack(c->pstream, tag);
4086 }
4087
4088 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4089 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4090 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4091 const char *name_device = NULL;
4092
4093 pa_native_connection_assert_ref(c);
4094 pa_assert(t);
4095
4096 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4097 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4098 pa_tagstruct_gets(t, &name_device) < 0 ||
4099 !pa_tagstruct_eof(t)) {
4100 protocol_error(c);
4101 return;
4102 }
4103
4104 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4105 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4106
4107 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);
4108 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4109 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4110 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4111
4112 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4113 pa_sink_input *si = NULL;
4114 pa_sink *sink = NULL;
4115
4116 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4117
4118 if (idx_device != PA_INVALID_INDEX)
4119 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4120 else
4121 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4122
4123 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4124
4125 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4126 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4127 return;
4128 }
4129 } else {
4130 pa_source_output *so = NULL;
4131 pa_source *source;
4132
4133 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4134
4135 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4136
4137 if (idx_device != PA_INVALID_INDEX)
4138 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4139 else
4140 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4141
4142 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4143
4144 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4145 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4146 return;
4147 }
4148 }
4149
4150 pa_pstream_send_simple_ack(c->pstream, tag);
4151 }
4152
4153 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4154 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4155 uint32_t idx = PA_INVALID_INDEX;
4156 const char *name = NULL;
4157 pa_bool_t b;
4158
4159 pa_native_connection_assert_ref(c);
4160 pa_assert(t);
4161
4162 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4163 pa_tagstruct_gets(t, &name) < 0 ||
4164 pa_tagstruct_get_boolean(t, &b) < 0 ||
4165 !pa_tagstruct_eof(t)) {
4166 protocol_error(c);
4167 return;
4168 }
4169
4170 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4171 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);
4172 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4173 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4174 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4175
4176 if (command == PA_COMMAND_SUSPEND_SINK) {
4177
4178 if (idx == PA_INVALID_INDEX && name && !*name) {
4179
4180 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4181
4182 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4183 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4184 return;
4185 }
4186 } else {
4187 pa_sink *sink = NULL;
4188
4189 if (idx != PA_INVALID_INDEX)
4190 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4191 else
4192 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4193
4194 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4195
4196 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4197 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4198 return;
4199 }
4200 }
4201 } else {
4202
4203 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4204
4205 if (idx == PA_INVALID_INDEX && name && !*name) {
4206
4207 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4208
4209 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4210 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4211 return;
4212 }
4213
4214 } else {
4215 pa_source *source;
4216
4217 if (idx != PA_INVALID_INDEX)
4218 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4219 else
4220 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4221
4222 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4223
4224 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4225 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4226 return;
4227 }
4228 }
4229 }
4230
4231 pa_pstream_send_simple_ack(c->pstream, tag);
4232 }
4233
4234 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4235 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4236 uint32_t idx = PA_INVALID_INDEX;
4237 const char *name = NULL;
4238 pa_module *m;
4239 pa_native_protocol_ext_cb_t cb;
4240
4241 pa_native_connection_assert_ref(c);
4242 pa_assert(t);
4243
4244 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4245 pa_tagstruct_gets(t, &name) < 0) {
4246 protocol_error(c);
4247 return;
4248 }
4249
4250 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4251 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4252 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4253 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4254 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4255
4256 if (idx != PA_INVALID_INDEX)
4257 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4258 else {
4259 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4260 if (strcmp(name, m->name) == 0)
4261 break;
4262 }
4263
4264 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4265 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4266
4267 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4268 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4269
4270 if (cb(c->protocol, m, c, tag, t) < 0)
4271 protocol_error(c);
4272 }
4273
4274 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4275 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4276 uint32_t idx = PA_INVALID_INDEX;
4277 const char *name = NULL, *profile = NULL;
4278 pa_card *card = NULL;
4279 int ret;
4280
4281 pa_native_connection_assert_ref(c);
4282 pa_assert(t);
4283
4284 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4285 pa_tagstruct_gets(t, &name) < 0 ||
4286 pa_tagstruct_gets(t, &profile) < 0 ||
4287 !pa_tagstruct_eof(t)) {
4288 protocol_error(c);
4289 return;
4290 }
4291
4292 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4293 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4294 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4295 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4296 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4297
4298 if (idx != PA_INVALID_INDEX)
4299 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4300 else
4301 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4302
4303 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4304
4305 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4306 pa_pstream_send_error(c->pstream, tag, -ret);
4307 return;
4308 }
4309
4310 pa_pstream_send_simple_ack(c->pstream, tag);
4311 }
4312
4313 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4314 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4315 uint32_t idx = PA_INVALID_INDEX;
4316 const char *name = NULL, *port = NULL;
4317 int ret;
4318
4319 pa_native_connection_assert_ref(c);
4320 pa_assert(t);
4321
4322 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4323 pa_tagstruct_gets(t, &name) < 0 ||
4324 pa_tagstruct_gets(t, &port) < 0 ||
4325 !pa_tagstruct_eof(t)) {
4326 protocol_error(c);
4327 return;
4328 }
4329
4330 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4331 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);
4332 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4333 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4334 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4335
4336 if (command == PA_COMMAND_SET_SINK_PORT) {
4337 pa_sink *sink;
4338
4339 if (idx != PA_INVALID_INDEX)
4340 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4341 else
4342 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4343
4344 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4345
4346 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4347 pa_pstream_send_error(c->pstream, tag, -ret);
4348 return;
4349 }
4350 } else {
4351 pa_source *source;
4352
4353 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4354
4355 if (idx != PA_INVALID_INDEX)
4356 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4357 else
4358 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4359
4360 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4361
4362 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4363 pa_pstream_send_error(c->pstream, tag, -ret);
4364 return;
4365 }
4366 }
4367
4368 pa_pstream_send_simple_ack(c->pstream, tag);
4369 }
4370
4371 /*** pstream callbacks ***/
4372
4373 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4374 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4375
4376 pa_assert(p);
4377 pa_assert(packet);
4378 pa_native_connection_assert_ref(c);
4379
4380 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4381 pa_log("invalid packet.");
4382 native_connection_unlink(c);
4383 }
4384 }
4385
4386 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) {
4387 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4388 output_stream *stream;
4389
4390 pa_assert(p);
4391 pa_assert(chunk);
4392 pa_native_connection_assert_ref(c);
4393
4394 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4395 pa_log_debug("Client sent block for invalid stream.");
4396 /* Ignoring */
4397 return;
4398 }
4399
4400 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4401
4402 if (playback_stream_isinstance(stream)) {
4403 playback_stream *ps = PLAYBACK_STREAM(stream);
4404
4405 if (chunk->memblock) {
4406 if (seek != PA_SEEK_RELATIVE || offset != 0)
4407 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);
4408
4409 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4410 } else
4411 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);
4412
4413 } else {
4414 upload_stream *u = UPLOAD_STREAM(stream);
4415 size_t l;
4416
4417 if (!u->memchunk.memblock) {
4418 if (u->length == chunk->length && chunk->memblock) {
4419 u->memchunk = *chunk;
4420 pa_memblock_ref(u->memchunk.memblock);
4421 u->length = 0;
4422 } else {
4423 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4424 u->memchunk.index = u->memchunk.length = 0;
4425 }
4426 }
4427
4428 pa_assert(u->memchunk.memblock);
4429
4430 l = u->length;
4431 if (l > chunk->length)
4432 l = chunk->length;
4433
4434 if (l > 0) {
4435 void *dst;
4436 dst = pa_memblock_acquire(u->memchunk.memblock);
4437
4438 if (chunk->memblock) {
4439 void *src;
4440 src = pa_memblock_acquire(chunk->memblock);
4441
4442 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4443 (uint8_t*) src + chunk->index, l);
4444
4445 pa_memblock_release(chunk->memblock);
4446 } else
4447 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4448
4449 pa_memblock_release(u->memchunk.memblock);
4450
4451 u->memchunk.length += l;
4452 u->length -= l;
4453 }
4454 }
4455 }
4456
4457 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4458 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4459
4460 pa_assert(p);
4461 pa_native_connection_assert_ref(c);
4462
4463 native_connection_unlink(c);
4464 pa_log_info("Connection died.");
4465 }
4466
4467 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4468 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4469
4470 pa_assert(p);
4471 pa_native_connection_assert_ref(c);
4472
4473 native_connection_send_memblock(c);
4474 }
4475
4476 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4477 pa_thread_mq *q;
4478
4479 if (!(q = pa_thread_mq_get()))
4480 pa_pstream_send_revoke(p, block_id);
4481 else
4482 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4483 }
4484
4485 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4486 pa_thread_mq *q;
4487
4488 if (!(q = pa_thread_mq_get()))
4489 pa_pstream_send_release(p, block_id);
4490 else
4491 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4492 }
4493
4494 /*** client callbacks ***/
4495
4496 static void client_kill_cb(pa_client *c) {
4497 pa_assert(c);
4498
4499 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4500 pa_log_info("Connection killed.");
4501 }
4502
4503 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4504 pa_tagstruct *t;
4505 pa_native_connection *c;
4506
4507 pa_assert(client);
4508 c = PA_NATIVE_CONNECTION(client->userdata);
4509 pa_native_connection_assert_ref(c);
4510
4511 if (c->version < 15)
4512 return;
4513
4514 t = pa_tagstruct_new(NULL, 0);
4515 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4516 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4517 pa_tagstruct_puts(t, event);
4518 pa_tagstruct_put_proplist(t, pl);
4519 pa_pstream_send_tagstruct(c->pstream, t);
4520 }
4521
4522 /*** module entry points ***/
4523
4524 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4525 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4526
4527 pa_assert(m);
4528 pa_native_connection_assert_ref(c);
4529 pa_assert(c->auth_timeout_event == e);
4530
4531 if (!c->authorized) {
4532 native_connection_unlink(c);
4533 pa_log_info("Connection terminated due to authentication timeout.");
4534 }
4535 }
4536
4537 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4538 pa_native_connection *c;
4539 char pname[128];
4540 pa_client *client;
4541 pa_client_new_data data;
4542
4543 pa_assert(p);
4544 pa_assert(io);
4545 pa_assert(o);
4546
4547 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4548 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4549 pa_iochannel_free(io);
4550 return;
4551 }
4552
4553 pa_client_new_data_init(&data);
4554 data.module = o->module;
4555 data.driver = __FILE__;
4556 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4557 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4558 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4559 client = pa_client_new(p->core, &data);
4560 pa_client_new_data_done(&data);
4561
4562 if (!client)
4563 return;
4564
4565 c = pa_msgobject_new(pa_native_connection);
4566 c->parent.parent.free = native_connection_free;
4567 c->parent.process_msg = native_connection_process_msg;
4568 c->protocol = p;
4569 c->options = pa_native_options_ref(o);
4570 c->authorized = FALSE;
4571
4572 if (o->auth_anonymous) {
4573 pa_log_info("Client authenticated anonymously.");
4574 c->authorized = TRUE;
4575 }
4576
4577 if (!c->authorized &&
4578 o->auth_ip_acl &&
4579 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4580
4581 pa_log_info("Client authenticated by IP ACL.");
4582 c->authorized = TRUE;
4583 }
4584
4585 if (!c->authorized)
4586 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4587 else
4588 c->auth_timeout_event = NULL;
4589
4590 c->is_local = pa_iochannel_socket_is_local(io);
4591 c->version = 8;
4592
4593 c->client = client;
4594 c->client->kill = client_kill_cb;
4595 c->client->send_event = client_send_event_cb;
4596 c->client->userdata = c;
4597
4598 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4599 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4600 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4601 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4602 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4603 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4604 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4605
4606 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4607
4608 c->record_streams = pa_idxset_new(NULL, NULL);
4609 c->output_streams = pa_idxset_new(NULL, NULL);
4610
4611 c->rrobin_index = PA_IDXSET_INVALID;
4612 c->subscription = NULL;
4613
4614 pa_idxset_put(p->connections, c, NULL);
4615
4616 #ifdef HAVE_CREDS
4617 if (pa_iochannel_creds_supported(io))
4618 pa_iochannel_creds_enable(io);
4619 #endif
4620
4621 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4622 }
4623
4624 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4625 pa_native_connection *c;
4626 void *state = NULL;
4627
4628 pa_assert(p);
4629 pa_assert(m);
4630
4631 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4632 if (c->options->module == m)
4633 native_connection_unlink(c);
4634 }
4635
4636 static pa_native_protocol* native_protocol_new(pa_core *c) {
4637 pa_native_protocol *p;
4638 pa_native_hook_t h;
4639
4640 pa_assert(c);
4641
4642 p = pa_xnew(pa_native_protocol, 1);
4643 PA_REFCNT_INIT(p);
4644 p->core = c;
4645 p->connections = pa_idxset_new(NULL, NULL);
4646
4647 p->servers = NULL;
4648
4649 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4650
4651 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4652 pa_hook_init(&p->hooks[h], p);
4653
4654 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4655
4656 return p;
4657 }
4658
4659 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4660 pa_native_protocol *p;
4661
4662 if ((p = pa_shared_get(c, "native-protocol")))
4663 return pa_native_protocol_ref(p);
4664
4665 return native_protocol_new(c);
4666 }
4667
4668 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4669 pa_assert(p);
4670 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4671
4672 PA_REFCNT_INC(p);
4673
4674 return p;
4675 }
4676
4677 void pa_native_protocol_unref(pa_native_protocol *p) {
4678 pa_native_connection *c;
4679 pa_native_hook_t h;
4680
4681 pa_assert(p);
4682 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4683
4684 if (PA_REFCNT_DEC(p) > 0)
4685 return;
4686
4687 while ((c = pa_idxset_first(p->connections, NULL)))
4688 native_connection_unlink(c);
4689
4690 pa_idxset_free(p->connections, NULL, NULL);
4691
4692 pa_strlist_free(p->servers);
4693
4694 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4695 pa_hook_done(&p->hooks[h]);
4696
4697 pa_hashmap_free(p->extensions, NULL, NULL);
4698
4699 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4700
4701 pa_xfree(p);
4702 }
4703
4704 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
4705 pa_assert(p);
4706 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4707 pa_assert(name);
4708
4709 p->servers = pa_strlist_prepend(p->servers, name);
4710
4711 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4712 }
4713
4714 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
4715 pa_assert(p);
4716 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4717 pa_assert(name);
4718
4719 p->servers = pa_strlist_remove(p->servers, name);
4720
4721 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4722 }
4723
4724 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
4725 pa_assert(p);
4726 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4727
4728 return p->hooks;
4729 }
4730
4731 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
4732 pa_assert(p);
4733 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4734
4735 return p->servers;
4736 }
4737
4738 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
4739 pa_assert(p);
4740 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4741 pa_assert(m);
4742 pa_assert(cb);
4743 pa_assert(!pa_hashmap_get(p->extensions, m));
4744
4745 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
4746 return 0;
4747 }
4748
4749 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
4750 pa_assert(p);
4751 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4752 pa_assert(m);
4753
4754 pa_assert_se(pa_hashmap_remove(p->extensions, m));
4755 }
4756
4757 pa_native_options* pa_native_options_new(void) {
4758 pa_native_options *o;
4759
4760 o = pa_xnew0(pa_native_options, 1);
4761 PA_REFCNT_INIT(o);
4762
4763 return o;
4764 }
4765
4766 pa_native_options* pa_native_options_ref(pa_native_options *o) {
4767 pa_assert(o);
4768 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4769
4770 PA_REFCNT_INC(o);
4771
4772 return o;
4773 }
4774
4775 void pa_native_options_unref(pa_native_options *o) {
4776 pa_assert(o);
4777 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4778
4779 if (PA_REFCNT_DEC(o) > 0)
4780 return;
4781
4782 pa_xfree(o->auth_group);
4783
4784 if (o->auth_ip_acl)
4785 pa_ip_acl_free(o->auth_ip_acl);
4786
4787 if (o->auth_cookie)
4788 pa_auth_cookie_unref(o->auth_cookie);
4789
4790 pa_xfree(o);
4791 }
4792
4793 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
4794 pa_bool_t enabled;
4795 const char *acl;
4796
4797 pa_assert(o);
4798 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4799 pa_assert(ma);
4800
4801 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
4802 pa_log("auth-anonymous= expects a boolean argument.");
4803 return -1;
4804 }
4805
4806 enabled = TRUE;
4807 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
4808 pa_log("auth-group-enabled= expects a boolean argument.");
4809 return -1;
4810 }
4811
4812 pa_xfree(o->auth_group);
4813 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
4814
4815 #ifndef HAVE_CREDS
4816 if (o->auth_group)
4817 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4818 #endif
4819
4820 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
4821 pa_ip_acl *ipa;
4822
4823 if (!(ipa = pa_ip_acl_new(acl))) {
4824 pa_log("Failed to parse IP ACL '%s'", acl);
4825 return -1;
4826 }
4827
4828 if (o->auth_ip_acl)
4829 pa_ip_acl_free(o->auth_ip_acl);
4830
4831 o->auth_ip_acl = ipa;
4832 }
4833
4834 enabled = TRUE;
4835 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
4836 pa_log("auth-cookie-enabled= expects a boolean argument.");
4837 return -1;
4838 }
4839
4840 if (o->auth_cookie)
4841 pa_auth_cookie_unref(o->auth_cookie);
4842
4843 if (enabled) {
4844 const char *cn;
4845
4846 /* The new name for this is 'auth-cookie', for compat reasons
4847 * we check the old name too */
4848 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
4849 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
4850 cn = PA_NATIVE_COOKIE_FILE;
4851
4852 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
4853 return -1;
4854
4855 } else
4856 o->auth_cookie = NULL;
4857
4858 return 0;
4859 }
4860
4861 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
4862 pa_native_connection_assert_ref(c);
4863
4864 return c->pstream;
4865 }
4866
4867 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
4868 pa_native_connection_assert_ref(c);
4869
4870 return c->client;
4871 }