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