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_memblockq_flush_read(s->source_output->thread_info.delay_memblockq);
3971 pa_resampler_reset(s->source_output->thread_info.resampler);
3972 pa_pstream_send_simple_ack(c->pstream, tag);
3973 }
3974
command_set_stream_buffer_attr(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)3975 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3976 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3977 uint32_t idx;
3978 pa_buffer_attr a;
3979 pa_tagstruct *reply;
3980
3981 pa_native_connection_assert_ref(c);
3982 pa_assert(t);
3983
3984 memset(&a, 0, sizeof(a));
3985
3986 if (pa_tagstruct_getu32(t, &idx) < 0) {
3987 protocol_error(c);
3988 return;
3989 }
3990
3991 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3992
3993 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3994 playback_stream *s;
3995 bool adjust_latency = false, early_requests = false;
3996
3997 s = pa_idxset_get_by_index(c->output_streams, idx);
3998 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3999 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4000
4001 if (pa_tagstruct_get(
4002 t,
4003 PA_TAG_U32, &a.maxlength,
4004 PA_TAG_U32, &a.tlength,
4005 PA_TAG_U32, &a.prebuf,
4006 PA_TAG_U32, &a.minreq,
4007 PA_TAG_INVALID) < 0 ||
4008 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
4009 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
4010 !pa_tagstruct_eof(t)) {
4011 protocol_error(c);
4012 return;
4013 }
4014
4015 s->adjust_latency = adjust_latency;
4016 s->early_requests = early_requests;
4017 s->buffer_attr_req = a;
4018
4019 fix_playback_buffer_attr(s);
4020 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);
4021
4022 reply = reply_new(tag);
4023 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
4024 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
4025 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
4026 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
4027
4028 if (c->version >= 13)
4029 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
4030
4031 } else {
4032 record_stream *s;
4033 bool adjust_latency = false, early_requests = false;
4034 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
4035
4036 s = pa_idxset_get_by_index(c->record_streams, idx);
4037 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4038
4039 if (pa_tagstruct_get(
4040 t,
4041 PA_TAG_U32, &a.maxlength,
4042 PA_TAG_U32, &a.fragsize,
4043 PA_TAG_INVALID) < 0 ||
4044 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
4045 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
4046 !pa_tagstruct_eof(t)) {
4047 protocol_error(c);
4048 return;
4049 }
4050
4051 s->adjust_latency = adjust_latency;
4052 s->early_requests = early_requests;
4053 s->buffer_attr_req = a;
4054
4055 fix_record_buffer_attr_pre(s);
4056 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
4057 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
4058 fix_record_buffer_attr_post(s);
4059
4060 reply = reply_new(tag);
4061 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
4062 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
4063
4064 if (c->version >= 13)
4065 pa_tagstruct_put_usec(reply, s->configured_source_latency);
4066 }
4067
4068 pa_pstream_send_tagstruct(c->pstream, reply);
4069 }
4070
command_update_stream_sample_rate(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4071 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4072 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4073 uint32_t idx;
4074 uint32_t rate;
4075
4076 pa_native_connection_assert_ref(c);
4077 pa_assert(t);
4078
4079 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4080 pa_tagstruct_getu32(t, &rate) < 0 ||
4081 !pa_tagstruct_eof(t)) {
4082 protocol_error(c);
4083 return;
4084 }
4085
4086 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4087 CHECK_VALIDITY(c->pstream, pa_sample_rate_valid(rate), tag, PA_ERR_INVALID);
4088
4089 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
4090 playback_stream *s;
4091
4092 s = pa_idxset_get_by_index(c->output_streams, idx);
4093 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4094 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4095
4096 pa_sink_input_set_rate(s->sink_input, rate);
4097
4098 } else {
4099 record_stream *s;
4100 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
4101
4102 s = pa_idxset_get_by_index(c->record_streams, idx);
4103 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4104
4105 pa_source_output_set_rate(s->source_output, rate);
4106 }
4107
4108 pa_pstream_send_simple_ack(c->pstream, tag);
4109 }
4110
command_update_proplist(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4111 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4112 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4113 uint32_t idx;
4114 uint32_t mode;
4115 pa_proplist *p;
4116
4117 pa_native_connection_assert_ref(c);
4118 pa_assert(t);
4119
4120 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4121
4122 p = pa_proplist_new();
4123
4124 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
4125
4126 if (pa_tagstruct_getu32(t, &mode) < 0 ||
4127 pa_tagstruct_get_proplist(t, p) < 0 ||
4128 !pa_tagstruct_eof(t)) {
4129 protocol_error(c);
4130 pa_proplist_free(p);
4131 return;
4132 }
4133
4134 } else {
4135
4136 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4137 pa_tagstruct_getu32(t, &mode) < 0 ||
4138 pa_tagstruct_get_proplist(t, p) < 0 ||
4139 !pa_tagstruct_eof(t)) {
4140 protocol_error(c);
4141 pa_proplist_free(p);
4142 return;
4143 }
4144 }
4145
4146 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
4147 pa_proplist_free(p);
4148 CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_INVALID);
4149 }
4150
4151 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
4152 playback_stream *s;
4153
4154 s = pa_idxset_get_by_index(c->output_streams, idx);
4155 if (!s || !playback_stream_isinstance(s)) {
4156 pa_proplist_free(p);
4157 CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_NOENTITY);
4158 }
4159 pa_sink_input_update_proplist(s->sink_input, mode, p);
4160
4161 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
4162 record_stream *s;
4163
4164 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
4165 pa_proplist_free(p);
4166 CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_NOENTITY);
4167 }
4168 pa_source_output_update_proplist(s->source_output, mode, p);
4169
4170 } else {
4171 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
4172
4173 pa_client_update_proplist(c->client, mode, p);
4174 }
4175
4176 pa_pstream_send_simple_ack(c->pstream, tag);
4177 pa_proplist_free(p);
4178 }
4179
command_remove_proplist(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4180 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4181 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4182 uint32_t idx;
4183 unsigned changed = 0;
4184 pa_proplist *p;
4185 pa_strlist *l = NULL;
4186
4187 pa_native_connection_assert_ref(c);
4188 pa_assert(t);
4189
4190 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4191
4192 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
4193
4194 if (pa_tagstruct_getu32(t, &idx) < 0) {
4195 protocol_error(c);
4196 return;
4197 }
4198 }
4199
4200 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4201 playback_stream *s;
4202
4203 s = pa_idxset_get_by_index(c->output_streams, idx);
4204 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4205 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4206
4207 p = s->sink_input->proplist;
4208
4209 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4210 record_stream *s;
4211
4212 s = pa_idxset_get_by_index(c->record_streams, idx);
4213 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4214
4215 p = s->source_output->proplist;
4216 } else {
4217 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4218
4219 p = c->client->proplist;
4220 }
4221
4222 for (;;) {
4223 const char *k;
4224
4225 if (pa_tagstruct_gets(t, &k) < 0) {
4226 protocol_error(c);
4227 pa_strlist_free(l);
4228 return;
4229 }
4230
4231 if (!k)
4232 break;
4233
4234 l = pa_strlist_prepend(l, k);
4235 }
4236
4237 if (!pa_tagstruct_eof(t)) {
4238 protocol_error(c);
4239 pa_strlist_free(l);
4240 return;
4241 }
4242
4243 for (;;) {
4244 char *z;
4245
4246 l = pa_strlist_pop(l, &z);
4247
4248 if (!z)
4249 break;
4250
4251 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
4252 pa_xfree(z);
4253 }
4254
4255 pa_pstream_send_simple_ack(c->pstream, tag);
4256
4257 if (changed) {
4258 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4259 playback_stream *s;
4260
4261 s = pa_idxset_get_by_index(c->output_streams, idx);
4262 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
4263
4264 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4265 record_stream *s;
4266
4267 s = pa_idxset_get_by_index(c->record_streams, idx);
4268 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
4269
4270 } else {
4271 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4272 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
4273 }
4274 }
4275 }
4276
command_set_default_sink_or_source(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4277 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4278 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4279 const char *s;
4280
4281 pa_native_connection_assert_ref(c);
4282 pa_assert(t);
4283
4284 if (pa_tagstruct_gets(t, &s) < 0 ||
4285 !pa_tagstruct_eof(t)) {
4286 protocol_error(c);
4287 return;
4288 }
4289
4290 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4291 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s) || pa_safe_streq(s,"@NONE@"), tag, PA_ERR_INVALID);
4292
4293 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
4294 char *source_name = NULL;
4295
4296 if (!pa_safe_streq(s,"@NONE@")) {
4297 pa_source *source;
4298
4299 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
4300 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4301 source_name = source->name;
4302 }
4303
4304 pa_core_set_configured_default_source(c->protocol->core, source_name);
4305 } else {
4306 char *sink_name = NULL;
4307 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
4308
4309 if (!pa_safe_streq(s,"@NONE@")) {
4310 pa_sink *sink;
4311
4312 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
4313 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4314 sink_name = sink->name;
4315 }
4316
4317 pa_core_set_configured_default_sink(c->protocol->core, sink_name);
4318 }
4319
4320 pa_pstream_send_simple_ack(c->pstream, tag);
4321 }
4322
command_set_stream_name(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4323 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4324 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4325 uint32_t idx;
4326 const char *name;
4327
4328 pa_native_connection_assert_ref(c);
4329 pa_assert(t);
4330
4331 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4332 pa_tagstruct_gets(t, &name) < 0 ||
4333 !pa_tagstruct_eof(t)) {
4334 protocol_error(c);
4335 return;
4336 }
4337
4338 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4339 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
4340
4341 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
4342 playback_stream *s;
4343
4344 s = pa_idxset_get_by_index(c->output_streams, idx);
4345 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4346 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4347
4348 pa_sink_input_set_property(s->sink_input, PA_PROP_MEDIA_NAME, name);
4349
4350 } else {
4351 record_stream *s;
4352 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4353
4354 s = pa_idxset_get_by_index(c->record_streams, idx);
4355 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4356
4357 pa_source_output_set_property(s->source_output, PA_PROP_MEDIA_NAME, name);
4358 }
4359
4360 pa_pstream_send_simple_ack(c->pstream, tag);
4361 }
4362
command_kill(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4363 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4364 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4365 uint32_t idx;
4366
4367 pa_native_connection_assert_ref(c);
4368 pa_assert(t);
4369
4370 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4371 !pa_tagstruct_eof(t)) {
4372 protocol_error(c);
4373 return;
4374 }
4375
4376 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4377
4378 if (command == PA_COMMAND_KILL_CLIENT) {
4379 pa_client *client;
4380
4381 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4382 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4383
4384 pa_native_connection_ref(c);
4385 pa_client_kill(client);
4386
4387 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4388 pa_sink_input *s;
4389
4390 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4391 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4392
4393 pa_native_connection_ref(c);
4394 pa_sink_input_kill(s);
4395 } else {
4396 pa_source_output *s;
4397
4398 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4399
4400 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4401 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4402
4403 pa_native_connection_ref(c);
4404 pa_source_output_kill(s);
4405 }
4406
4407 pa_pstream_send_simple_ack(c->pstream, tag);
4408 pa_native_connection_unref(c);
4409 }
4410
command_load_module(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4411 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4412 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4413 pa_module *m;
4414 const char *name, *argument;
4415 pa_tagstruct *reply;
4416
4417 pa_native_connection_assert_ref(c);
4418 pa_assert(t);
4419
4420 if (pa_tagstruct_gets(t, &name) < 0 ||
4421 pa_tagstruct_gets(t, &argument) < 0 ||
4422 !pa_tagstruct_eof(t)) {
4423 protocol_error(c);
4424 return;
4425 }
4426
4427 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4428 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4429 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4430
4431 if (pa_module_load(&m, c->protocol->core, name, argument) < 0) {
4432 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4433 return;
4434 }
4435
4436 reply = reply_new(tag);
4437 pa_tagstruct_putu32(reply, m->index);
4438 pa_pstream_send_tagstruct(c->pstream, reply);
4439 }
4440
command_unload_module(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4441 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4442 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4443 uint32_t idx;
4444 pa_module *m;
4445
4446 pa_native_connection_assert_ref(c);
4447 pa_assert(t);
4448
4449 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4450 !pa_tagstruct_eof(t)) {
4451 protocol_error(c);
4452 return;
4453 }
4454
4455 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4456 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4457 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4458
4459 pa_module_unload(m, true);
4460 pa_pstream_send_simple_ack(c->pstream, tag);
4461 }
4462
command_move_stream(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4463 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4464 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4465 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4466 const char *name_device = NULL;
4467
4468 pa_native_connection_assert_ref(c);
4469 pa_assert(t);
4470
4471 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4472 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4473 pa_tagstruct_gets(t, &name_device) < 0 ||
4474 !pa_tagstruct_eof(t)) {
4475 protocol_error(c);
4476 return;
4477 }
4478
4479 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4480 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4481
4482 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);
4483 CHECK_VALIDITY(c->pstream, (idx_device != PA_INVALID_INDEX) ^ (name_device != NULL), tag, PA_ERR_INVALID);
4484
4485 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4486 pa_sink_input *si = NULL;
4487 pa_sink *sink = NULL;
4488
4489 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4490
4491 if (idx_device != PA_INVALID_INDEX)
4492 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4493 else
4494 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4495
4496 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4497
4498 if (pa_sink_input_move_to(si, sink, true) < 0) {
4499 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4500 return;
4501 }
4502 } else {
4503 pa_source_output *so = NULL;
4504 pa_source *source;
4505
4506 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4507
4508 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4509
4510 if (idx_device != PA_INVALID_INDEX)
4511 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4512 else
4513 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4514
4515 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4516
4517 if (pa_source_output_move_to(so, source, true) < 0) {
4518 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4519 return;
4520 }
4521 }
4522
4523 pa_pstream_send_simple_ack(c->pstream, tag);
4524 }
4525
command_suspend(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4526 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4527 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4528 uint32_t idx = PA_INVALID_INDEX;
4529 const char *name = NULL;
4530 bool b;
4531
4532 pa_native_connection_assert_ref(c);
4533 pa_assert(t);
4534
4535 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4536 pa_tagstruct_gets(t, &name) < 0 ||
4537 pa_tagstruct_get_boolean(t, &b) < 0 ||
4538 !pa_tagstruct_eof(t)) {
4539 protocol_error(c);
4540 return;
4541 }
4542
4543 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4544 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);
4545 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
4546
4547 if (command == PA_COMMAND_SUSPEND_SINK) {
4548
4549 if (idx == PA_INVALID_INDEX && name && !*name) {
4550
4551 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4552
4553 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4554 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4555 return;
4556 }
4557 } else {
4558 pa_sink *sink = NULL;
4559
4560 if (idx != PA_INVALID_INDEX)
4561 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4562 else
4563 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4564
4565 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4566
4567 pa_log_debug("%s of sink %s requested by client %" PRIu32 ".",
4568 b ? "Suspending" : "Resuming", sink->name, c->client->index);
4569
4570 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4571 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4572 return;
4573 }
4574 }
4575 } else {
4576
4577 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4578
4579 if (idx == PA_INVALID_INDEX && name && !*name) {
4580
4581 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4582
4583 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4584 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4585 return;
4586 }
4587
4588 } else {
4589 pa_source *source;
4590
4591 if (idx != PA_INVALID_INDEX)
4592 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4593 else
4594 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4595
4596 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4597
4598 pa_log_debug("%s of source %s requested by client %" PRIu32 ".",
4599 b ? "Suspending" : "Resuming", source->name, c->client->index);
4600
4601 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4602 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4603 return;
4604 }
4605 }
4606 }
4607
4608 pa_pstream_send_simple_ack(c->pstream, tag);
4609 }
4610
command_extension(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4611 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4612 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4613 uint32_t idx = PA_INVALID_INDEX;
4614 const char *name = NULL;
4615 pa_module *m;
4616 pa_native_protocol_ext_cb_t cb;
4617
4618 pa_native_connection_assert_ref(c);
4619 pa_assert(t);
4620
4621 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4622 pa_tagstruct_gets(t, &name) < 0) {
4623 protocol_error(c);
4624 return;
4625 }
4626
4627 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4628 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4629 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
4630
4631 if (idx != PA_INVALID_INDEX)
4632 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4633 else
4634 PA_IDXSET_FOREACH(m, c->protocol->core->modules, idx)
4635 if (pa_streq(name, m->name))
4636 break;
4637
4638 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4639 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4640
4641 cb = pa_hashmap_get(c->protocol->extensions, m);
4642 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4643
4644 if (cb(c->protocol, m, c, tag, t) < 0)
4645 protocol_error(c);
4646 }
4647
4648 /* 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)4649 static void command_send_object_message(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4650 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4651 const char *object_path = NULL;
4652 const char *message = NULL;
4653 const char *message_parameters = NULL;
4654 const char *client_name;
4655 char *response = NULL;
4656 int ret;
4657 pa_tagstruct *reply;
4658
4659 pa_native_connection_assert_ref(c);
4660 pa_assert(t);
4661
4662 if (pa_tagstruct_gets(t, &object_path) < 0 ||
4663 pa_tagstruct_gets(t, &message) < 0 ||
4664 pa_tagstruct_gets(t, &message_parameters) < 0 ||
4665 !pa_tagstruct_eof(t)) {
4666 protocol_error(c);
4667 return;
4668 }
4669
4670 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4671 CHECK_VALIDITY(c->pstream, object_path != NULL, tag, PA_ERR_INVALID);
4672 CHECK_VALIDITY(c->pstream, pa_utf8_valid(object_path), tag, PA_ERR_INVALID);
4673 CHECK_VALIDITY(c->pstream, message != NULL, tag, PA_ERR_INVALID);
4674 CHECK_VALIDITY(c->pstream, pa_utf8_valid(message), tag, PA_ERR_INVALID);
4675 if (message_parameters)
4676 CHECK_VALIDITY(c->pstream, pa_utf8_valid(message_parameters), tag, PA_ERR_INVALID);
4677
4678 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
4679 pa_log_debug("Client %s sent message %s to path %s", client_name, message, object_path);
4680 if (message_parameters)
4681 pa_log_debug("Message parameters: %s", message_parameters);
4682
4683 ret = pa_message_handler_send_message(c->protocol->core, object_path, message, message_parameters, &response);
4684
4685 if (ret < 0) {
4686 pa_pstream_send_error(c->pstream, tag, -ret);
4687 return;
4688 }
4689
4690 reply = reply_new(tag);
4691 pa_tagstruct_puts(reply, response);
4692 pa_xfree(response);
4693
4694 pa_pstream_send_tagstruct(c->pstream, reply);
4695 }
4696
command_set_card_profile(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4697 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4698 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4699 uint32_t idx = PA_INVALID_INDEX;
4700 const char *name = NULL, *profile_name = NULL;
4701 pa_card *card = NULL;
4702 pa_card_profile *profile;
4703 int ret;
4704
4705 pa_native_connection_assert_ref(c);
4706 pa_assert(t);
4707
4708 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4709 pa_tagstruct_gets(t, &name) < 0 ||
4710 pa_tagstruct_gets(t, &profile_name) < 0 ||
4711 !pa_tagstruct_eof(t)) {
4712 protocol_error(c);
4713 return;
4714 }
4715
4716 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4717 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4718 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
4719 CHECK_VALIDITY(c->pstream, profile_name, tag, PA_ERR_INVALID);
4720
4721 if (idx != PA_INVALID_INDEX)
4722 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4723 else
4724 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4725
4726 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4727
4728 profile = pa_hashmap_get(card->profiles, profile_name);
4729
4730 CHECK_VALIDITY(c->pstream, profile, tag, PA_ERR_NOENTITY);
4731
4732 pa_log_info("Application \"%s\" requests card profile change. card = %s, profile = %s",
4733 pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_NAME)),
4734 card->name,
4735 profile->name);
4736
4737 if ((ret = pa_card_set_profile(card, profile, true)) < 0) {
4738 pa_pstream_send_error(c->pstream, tag, -ret);
4739 return;
4740 }
4741
4742 pa_pstream_send_simple_ack(c->pstream, tag);
4743 }
4744
command_set_sink_or_source_port(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4745 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4746 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4747 uint32_t idx = PA_INVALID_INDEX;
4748 const char *name = NULL, *port = NULL;
4749 int ret;
4750
4751 pa_native_connection_assert_ref(c);
4752 pa_assert(t);
4753
4754 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4755 pa_tagstruct_gets(t, &name) < 0 ||
4756 pa_tagstruct_gets(t, &port) < 0 ||
4757 !pa_tagstruct_eof(t)) {
4758 protocol_error(c);
4759 return;
4760 }
4761
4762 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4763 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);
4764 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
4765 CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_INVALID);
4766
4767 if (command == PA_COMMAND_SET_SINK_PORT) {
4768 pa_sink *sink;
4769
4770 if (idx != PA_INVALID_INDEX)
4771 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4772 else
4773 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4774
4775 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4776
4777 if ((ret = pa_sink_set_port(sink, port, true)) < 0) {
4778 pa_pstream_send_error(c->pstream, tag, -ret);
4779 return;
4780 }
4781 } else {
4782 pa_source *source;
4783
4784 pa_assert(command == PA_COMMAND_SET_SOURCE_PORT);
4785
4786 if (idx != PA_INVALID_INDEX)
4787 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4788 else
4789 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4790
4791 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4792
4793 if ((ret = pa_source_set_port(source, port, true)) < 0) {
4794 pa_pstream_send_error(c->pstream, tag, -ret);
4795 return;
4796 }
4797 }
4798
4799 pa_pstream_send_simple_ack(c->pstream, tag);
4800 }
4801
command_set_port_latency_offset(pa_pdispatch * pd,uint32_t command,uint32_t tag,pa_tagstruct * t,void * userdata)4802 static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4803 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4804 const char *port_name, *card_name;
4805 uint32_t idx = PA_INVALID_INDEX;
4806 int64_t offset;
4807 pa_card *card = NULL;
4808 pa_device_port *port = NULL;
4809
4810 pa_native_connection_assert_ref(c);
4811 pa_assert(t);
4812
4813 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4814 pa_tagstruct_gets(t, &card_name) < 0 ||
4815 pa_tagstruct_gets(t, &port_name) < 0 ||
4816 pa_tagstruct_gets64(t, &offset) < 0 ||
4817 !pa_tagstruct_eof(t)) {
4818 protocol_error(c);
4819 return;
4820 }
4821
4822 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4823 CHECK_VALIDITY(c->pstream, !card_name || pa_namereg_is_valid_name(card_name), tag, PA_ERR_INVALID);
4824 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (card_name != NULL), tag, PA_ERR_INVALID);
4825 CHECK_VALIDITY(c->pstream, port_name, tag, PA_ERR_INVALID);
4826
4827 if (idx != PA_INVALID_INDEX)
4828 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4829 else
4830 card = pa_namereg_get(c->protocol->core, card_name, PA_NAMEREG_CARD);
4831
4832 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4833
4834 port = pa_hashmap_get(card->ports, port_name);
4835 CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_NOENTITY);
4836
4837 pa_device_port_set_latency_offset(port, offset);
4838
4839 pa_pstream_send_simple_ack(c->pstream, tag);
4840 }
4841
4842 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
4843 [PA_COMMAND_ERROR] = NULL,
4844 [PA_COMMAND_TIMEOUT] = NULL,
4845 [PA_COMMAND_REPLY] = NULL,
4846 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
4847 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
4848 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
4849 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
4850 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
4851 [PA_COMMAND_AUTH] = command_auth,
4852 [PA_COMMAND_REQUEST] = NULL,
4853 [PA_COMMAND_EXIT] = command_exit,
4854 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
4855 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
4856 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
4857 [PA_COMMAND_STAT] = command_stat,
4858 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
4859 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
4860 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
4861 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
4862 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
4863 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
4864 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
4865 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
4866 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
4867 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
4868 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
4869 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
4870 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
4871 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
4872 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
4873 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
4874 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
4875 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
4876 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
4877 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
4878 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
4879 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
4880 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
4881 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
4882 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
4883
4884 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
4885 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
4886 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
4887 [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = command_set_volume,
4888
4889 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
4890 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
4891 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
4892 [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = command_set_mute,
4893
4894 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
4895 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
4896
4897 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
4898 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
4899 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
4900 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
4901
4902 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
4903 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
4904
4905 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
4906 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
4907 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
4908 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
4909 [PA_COMMAND_KILL_CLIENT] = command_kill,
4910 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
4911 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
4912 [PA_COMMAND_LOAD_MODULE] = command_load_module,
4913 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
4914
4915 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
4916 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
4917 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
4918 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
4919
4920 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
4921 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
4922
4923 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
4924 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
4925
4926 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
4927 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
4928
4929 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
4930 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
4931 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
4932
4933 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
4934 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
4935 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
4936
4937 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
4938
4939 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
4940 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
4941
4942 [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = command_set_port_latency_offset,
4943
4944 [PA_COMMAND_ENABLE_SRBCHANNEL] = command_enable_srbchannel,
4945
4946 [PA_COMMAND_REGISTER_MEMFD_SHMID] = command_register_memfd_shmid,
4947
4948 [PA_COMMAND_SEND_OBJECT_MESSAGE] = command_send_object_message,
4949
4950 [PA_COMMAND_EXTENSION] = command_extension
4951 };
4952
4953 /*** pstream callbacks ***/
4954
pstream_packet_callback(pa_pstream * p,pa_packet * packet,pa_cmsg_ancil_data * ancil_data,void * userdata)4955 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, pa_cmsg_ancil_data *ancil_data, void *userdata) {
4956 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4957
4958 pa_assert(p);
4959 pa_assert(packet);
4960 pa_native_connection_assert_ref(c);
4961
4962 if (pa_pdispatch_run(c->pdispatch, packet, ancil_data, c) < 0) {
4963 pa_log("invalid packet.");
4964 native_connection_unlink(c);
4965 }
4966 }
4967
pstream_memblock_callback(pa_pstream * p,uint32_t channel,int64_t offset,pa_seek_mode_t seek,const pa_memchunk * chunk,void * userdata)4968 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) {
4969 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4970 output_stream *stream;
4971
4972 pa_assert(p);
4973 pa_assert(chunk);
4974 pa_native_connection_assert_ref(c);
4975
4976 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4977 pa_log_debug("Client sent block for invalid stream.");
4978 /* Ignoring */
4979 return;
4980 }
4981
4982 #ifdef PROTOCOL_NATIVE_DEBUG
4983 pa_log("got %lu bytes from client", (unsigned long) chunk->length);
4984 #endif
4985
4986 if (playback_stream_isinstance(stream)) {
4987 playback_stream *ps = PLAYBACK_STREAM(stream);
4988
4989 size_t frame_size = pa_frame_size(&ps->sink_input->sample_spec);
4990 if (chunk->length % frame_size != 0) {
4991 pa_log_warn("Client sent non-aligned memblock: length %d, frame size: %d",
4992 (int) chunk->length, (int) frame_size);
4993 return;
4994 }
4995
4996 pa_atomic_inc(&ps->seek_or_post_in_queue);
4997 if (chunk->memblock) {
4998 if (seek != PA_SEEK_RELATIVE || offset != 0)
4999 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);
5000 else
5001 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
5002 } else
5003 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);
5004
5005 } else {
5006 upload_stream *u = UPLOAD_STREAM(stream);
5007 size_t l;
5008
5009 if (!u->memchunk.memblock) {
5010 if (u->length == chunk->length && chunk->memblock) {
5011 u->memchunk = *chunk;
5012 pa_memblock_ref(u->memchunk.memblock);
5013 u->length = 0;
5014 } else {
5015 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
5016 u->memchunk.index = u->memchunk.length = 0;
5017 }
5018 }
5019
5020 pa_assert(u->memchunk.memblock);
5021
5022 l = u->length;
5023 if (l > chunk->length)
5024 l = chunk->length;
5025
5026 if (l > 0) {
5027 void *dst;
5028 dst = pa_memblock_acquire(u->memchunk.memblock);
5029
5030 if (chunk->memblock) {
5031 void *src;
5032 src = pa_memblock_acquire(chunk->memblock);
5033
5034 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
5035 (uint8_t*) src + chunk->index, l);
5036
5037 pa_memblock_release(chunk->memblock);
5038 } else
5039 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
5040
5041 pa_memblock_release(u->memchunk.memblock);
5042
5043 u->memchunk.length += l;
5044 u->length -= l;
5045 }
5046 }
5047 }
5048
pstream_die_callback(pa_pstream * p,void * userdata)5049 static void pstream_die_callback(pa_pstream *p, void *userdata) {
5050 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5051
5052 pa_assert(p);
5053 pa_native_connection_assert_ref(c);
5054
5055 native_connection_unlink(c);
5056 pa_log_info("Connection died.");
5057 }
5058
pstream_drain_callback(pa_pstream * p,void * userdata)5059 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
5060 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5061
5062 pa_assert(p);
5063 pa_native_connection_assert_ref(c);
5064
5065 native_connection_send_memblock(c);
5066 }
5067
pstream_revoke_callback(pa_pstream * p,uint32_t block_id,void * userdata)5068 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
5069 pa_thread_mq *q;
5070
5071 if (!(q = pa_thread_mq_get()))
5072 pa_pstream_send_revoke(p, block_id);
5073 else
5074 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
5075 }
5076
pstream_release_callback(pa_pstream * p,uint32_t block_id,void * userdata)5077 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
5078 pa_thread_mq *q;
5079
5080 if (!(q = pa_thread_mq_get()))
5081 pa_pstream_send_release(p, block_id);
5082 else
5083 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
5084 }
5085
5086 /*** client callbacks ***/
5087
client_kill_cb(pa_client * c)5088 static void client_kill_cb(pa_client *c) {
5089 pa_assert(c);
5090
5091 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
5092 pa_log_info("Connection killed.");
5093 }
5094
client_send_event_cb(pa_client * client,const char * event,pa_proplist * pl)5095 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
5096 pa_tagstruct *t;
5097 pa_native_connection *c;
5098
5099 pa_assert(client);
5100 c = PA_NATIVE_CONNECTION(client->userdata);
5101 pa_native_connection_assert_ref(c);
5102
5103 if (c->version < 15)
5104 return;
5105
5106 t = pa_tagstruct_new();
5107 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
5108 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
5109 pa_tagstruct_puts(t, event);
5110 pa_tagstruct_put_proplist(t, pl);
5111 pa_pstream_send_tagstruct(c->pstream, t);
5112 }
5113
5114 /*** module entry points ***/
5115
auth_timeout(pa_mainloop_api * m,pa_time_event * e,const struct timeval * t,void * userdata)5116 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
5117 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5118
5119 pa_assert(m);
5120 pa_native_connection_assert_ref(c);
5121 pa_assert(c->auth_timeout_event == e);
5122
5123 if (!c->authorized) {
5124 native_connection_unlink(c);
5125 pa_log_info("Connection terminated due to authentication timeout.");
5126 }
5127 }
5128
pa_native_protocol_connect(pa_native_protocol * p,pa_iochannel * io,pa_native_options * o)5129 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
5130 pa_native_connection *c;
5131 char pname[128];
5132 pa_client *client;
5133 pa_client_new_data data;
5134
5135 pa_assert(p);
5136 pa_assert(io);
5137 pa_assert(o);
5138
5139 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
5140 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
5141 pa_iochannel_free(io);
5142 return;
5143 }
5144
5145 pa_client_new_data_init(&data);
5146 data.module = o->module;
5147 data.driver = __FILE__;
5148 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
5149 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
5150 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
5151 client = pa_client_new(p->core, &data);
5152 pa_client_new_data_done(&data);
5153
5154 if (!client)
5155 return;
5156
5157 c = pa_msgobject_new(pa_native_connection);
5158 c->parent.parent.free = native_connection_free;
5159 c->parent.process_msg = native_connection_process_msg;
5160 c->protocol = p;
5161 c->options = pa_native_options_ref(o);
5162 c->authorized = false;
5163 c->srbpending = NULL;
5164
5165 if (o->auth_anonymous) {
5166 pa_log_info("Client authenticated anonymously.");
5167 c->authorized = true;
5168 }
5169
5170 if (!c->authorized &&
5171 o->auth_ip_acl &&
5172 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
5173
5174 pa_log_info("Client authenticated by IP ACL.");
5175 c->authorized = true;
5176 }
5177
5178 if (!c->authorized)
5179 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
5180 else
5181 c->auth_timeout_event = NULL;
5182
5183 c->is_local = pa_iochannel_socket_is_local(io);
5184 c->version = 8;
5185
5186 c->client = client;
5187 c->client->kill = client_kill_cb;
5188 c->client->send_event = client_send_event_cb;
5189 c->client->userdata = c;
5190
5191 c->rw_mempool = NULL;
5192
5193 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
5194 pa_pstream_set_receive_packet_callback(c->pstream, pstream_packet_callback, c);
5195 pa_pstream_set_receive_memblock_callback(c->pstream, pstream_memblock_callback, c);
5196 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
5197 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
5198 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
5199 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
5200
5201 c->pdispatch = pa_pdispatch_new(p->core->mainloop, true, command_table, PA_COMMAND_MAX);
5202
5203 c->record_streams = pa_idxset_new(NULL, NULL);
5204 c->output_streams = pa_idxset_new(NULL, NULL);
5205
5206 c->rrobin_index = PA_IDXSET_INVALID;
5207 c->subscription = NULL;
5208
5209 pa_idxset_put(p->connections, c, NULL);
5210
5211 #ifdef HAVE_CREDS
5212 if (pa_iochannel_creds_supported(io))
5213 pa_iochannel_creds_enable(io);
5214 #endif
5215
5216 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
5217 }
5218
pa_native_protocol_disconnect(pa_native_protocol * p,pa_module * m)5219 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
5220 pa_native_connection *c;
5221 void *state = NULL;
5222
5223 pa_assert(p);
5224 pa_assert(m);
5225
5226 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
5227 if (c->options->module == m)
5228 native_connection_unlink(c);
5229 }
5230
native_protocol_new(pa_core * c)5231 static pa_native_protocol* native_protocol_new(pa_core *c) {
5232 pa_native_protocol *p;
5233 pa_native_hook_t h;
5234
5235 pa_assert(c);
5236
5237 p = pa_xnew(pa_native_protocol, 1);
5238 PA_REFCNT_INIT(p);
5239 p->core = c;
5240 p->connections = pa_idxset_new(NULL, NULL);
5241
5242 p->servers = NULL;
5243
5244 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
5245
5246 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
5247 pa_hook_init(&p->hooks[h], p);
5248
5249 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
5250
5251 return p;
5252 }
5253
pa_native_protocol_get(pa_core * c)5254 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
5255 pa_native_protocol *p;
5256
5257 if ((p = pa_shared_get(c, "native-protocol")))
5258 return pa_native_protocol_ref(p);
5259
5260 return native_protocol_new(c);
5261 }
5262
pa_native_protocol_ref(pa_native_protocol * p)5263 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
5264 pa_assert(p);
5265 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5266
5267 PA_REFCNT_INC(p);
5268
5269 return p;
5270 }
5271
pa_native_protocol_unref(pa_native_protocol * p)5272 void pa_native_protocol_unref(pa_native_protocol *p) {
5273 pa_native_connection *c;
5274 pa_native_hook_t h;
5275
5276 pa_assert(p);
5277 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5278
5279 if (PA_REFCNT_DEC(p) > 0)
5280 return;
5281
5282 while ((c = pa_idxset_first(p->connections, NULL)))
5283 native_connection_unlink(c);
5284
5285 pa_idxset_free(p->connections, NULL);
5286
5287 pa_strlist_free(p->servers);
5288
5289 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
5290 pa_hook_done(&p->hooks[h]);
5291
5292 pa_hashmap_free(p->extensions);
5293
5294 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
5295
5296 pa_xfree(p);
5297 }
5298
pa_native_protocol_add_server_string(pa_native_protocol * p,const char * name)5299 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
5300 pa_assert(p);
5301 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5302 pa_assert(name);
5303
5304 p->servers = pa_strlist_prepend(p->servers, name);
5305
5306 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5307 }
5308
pa_native_protocol_remove_server_string(pa_native_protocol * p,const char * name)5309 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
5310 pa_assert(p);
5311 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5312 pa_assert(name);
5313
5314 p->servers = pa_strlist_remove(p->servers, name);
5315
5316 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5317 }
5318
pa_native_protocol_hooks(pa_native_protocol * p)5319 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
5320 pa_assert(p);
5321 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5322
5323 return p->hooks;
5324 }
5325
pa_native_protocol_servers(pa_native_protocol * p)5326 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
5327 pa_assert(p);
5328 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5329
5330 return p->servers;
5331 }
5332
pa_native_protocol_install_ext(pa_native_protocol * p,pa_module * m,pa_native_protocol_ext_cb_t cb)5333 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
5334 pa_assert(p);
5335 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5336 pa_assert(m);
5337 pa_assert(cb);
5338 pa_assert(!pa_hashmap_get(p->extensions, m));
5339
5340 pa_assert_se(pa_hashmap_put(p->extensions, m, cb) == 0);
5341 return 0;
5342 }
5343
pa_native_protocol_remove_ext(pa_native_protocol * p,pa_module * m)5344 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
5345 pa_assert(p);
5346 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5347 pa_assert(m);
5348
5349 pa_assert_se(pa_hashmap_remove(p->extensions, m));
5350 }
5351
pa_native_options_new(void)5352 pa_native_options* pa_native_options_new(void) {
5353 pa_native_options *o;
5354
5355 o = pa_xnew0(pa_native_options, 1);
5356 PA_REFCNT_INIT(o);
5357
5358 return o;
5359 }
5360
pa_native_options_ref(pa_native_options * o)5361 pa_native_options* pa_native_options_ref(pa_native_options *o) {
5362 pa_assert(o);
5363 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5364
5365 PA_REFCNT_INC(o);
5366
5367 return o;
5368 }
5369
pa_native_options_unref(pa_native_options * o)5370 void pa_native_options_unref(pa_native_options *o) {
5371 pa_assert(o);
5372 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5373
5374 if (PA_REFCNT_DEC(o) > 0)
5375 return;
5376
5377 pa_xfree(o->auth_group);
5378
5379 if (o->auth_ip_acl)
5380 pa_ip_acl_free(o->auth_ip_acl);
5381
5382 if (o->auth_cookie)
5383 pa_auth_cookie_unref(o->auth_cookie);
5384
5385 pa_xfree(o);
5386 }
5387
pa_native_options_parse(pa_native_options * o,pa_core * c,pa_modargs * ma)5388 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
5389 bool enabled;
5390 const char *acl;
5391
5392 pa_assert(o);
5393 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5394 pa_assert(ma);
5395
5396 o->srbchannel = true;
5397 if (pa_modargs_get_value_boolean(ma, "srbchannel", &o->srbchannel) < 0) {
5398 pa_log_error("srbchannel= expects a boolean argument.");
5399 return -1;
5400 }
5401
5402 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
5403 pa_log_error("auth-anonymous= expects a boolean argument.");
5404 return -1;
5405 }
5406
5407 enabled = true;
5408 if (pa_modargs_get_value_boolean(ma, "auth-group-enable", &enabled) < 0) {
5409 pa_log_error("auth-group-enable= expects a boolean argument.");
5410 return -1;
5411 }
5412
5413 pa_xfree(o->auth_group);
5414 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
5415
5416 #ifndef HAVE_CREDS
5417 if (o->auth_group)
5418 pa_log_error("Authentication group configured, but not available on local system. Ignoring.");
5419 #endif
5420
5421 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
5422 pa_ip_acl *ipa;
5423
5424 if (!(ipa = pa_ip_acl_new(acl))) {
5425 pa_log_error("Failed to parse IP ACL '%s'", acl);
5426 return -1;
5427 }
5428
5429 if (o->auth_ip_acl)
5430 pa_ip_acl_free(o->auth_ip_acl);
5431
5432 o->auth_ip_acl = ipa;
5433 }
5434
5435 enabled = true;
5436 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
5437 pa_log_error("auth-cookie-enabled= expects a boolean argument.");
5438 return -1;
5439 }
5440
5441 if (o->auth_cookie)
5442 pa_auth_cookie_unref(o->auth_cookie);
5443
5444 if (enabled) {
5445 const char *cn;
5446
5447 /* The new name for this is 'auth-cookie', for compat reasons
5448 * we check the old name too */
5449 cn = pa_modargs_get_value(ma, "auth-cookie", NULL);
5450 if (!cn)
5451 cn = pa_modargs_get_value(ma, "cookie", NULL);
5452
5453 if (cn)
5454 o->auth_cookie = pa_auth_cookie_get(c, cn, true, PA_NATIVE_COOKIE_LENGTH);
5455 else {
5456 o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE, false, PA_NATIVE_COOKIE_LENGTH);
5457 if (!o->auth_cookie) {
5458 char *fallback_path;
5459
5460 if (pa_append_to_home_dir(PA_NATIVE_COOKIE_FILE_FALLBACK, &fallback_path) >= 0) {
5461 o->auth_cookie = pa_auth_cookie_get(c, fallback_path, false, PA_NATIVE_COOKIE_LENGTH);
5462 pa_xfree(fallback_path);
5463 }
5464
5465 if (!o->auth_cookie)
5466 o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE, true, PA_NATIVE_COOKIE_LENGTH);
5467 }
5468 }
5469
5470 if (!o->auth_cookie)
5471 return -1;
5472
5473 } else
5474 o->auth_cookie = NULL;
5475
5476 return 0;
5477 }
5478
pa_native_connection_get_pstream(pa_native_connection * c)5479 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
5480 pa_native_connection_assert_ref(c);
5481
5482 return c->pstream;
5483 }
5484
pa_native_connection_get_client(pa_native_connection * c)5485 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
5486 pa_native_connection_assert_ref(c);
5487
5488 return c->client;
5489 }
5490