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