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