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