2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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/>.
30 #include <pulse/rtclock.h>
31 #include <pulse/timeval.h>
32 #include <pulse/version.h>
33 #include <pulse/utf8.h>
34 #include <pulse/util.h>
35 #include <pulse/xmalloc.h>
36 #include <pulse/internal.h>
38 #include <pulsecore/native-common.h>
39 #include <pulsecore/packet.h>
40 #include <pulsecore/client.h>
41 #include <pulsecore/source-output.h>
42 #include <pulsecore/sink-input.h>
43 #include <pulsecore/pstream.h>
44 #include <pulsecore/tagstruct.h>
45 #include <pulsecore/pdispatch.h>
46 #include <pulsecore/pstream-util.h>
47 #include <pulsecore/namereg.h>
48 #include <pulsecore/core-scache.h>
49 #include <pulsecore/core-subscribe.h>
50 #include <pulsecore/message-handler.h>
51 #include <pulsecore/log.h>
52 #include <pulsecore/mem.h>
53 #include <pulsecore/strlist.h>
54 #include <pulsecore/shared.h>
55 #include <pulsecore/sample-util.h>
56 #include <pulsecore/creds.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/ipacl.h>
59 #include <pulsecore/thread-mq.h>
60 #include <pulsecore/mem.h>
62 #include <pulsecore/cynara.h>
63 #include <pulsecore/iochannel.h>
66 #include "protocol-native.h"
68 /* #define PROTOCOL_NATIVE_DEBUG */
70 /* Kick a client if it doesn't authenticate within this time */
71 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
73 /* Don't accept more connection than this */
74 #define MAX_CONNECTIONS 64
76 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
77 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
78 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
79 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
81 struct pa_native_protocol;
83 typedef struct record_stream {
86 pa_native_connection *connection;
89 pa_source_output *source_output;
90 pa_memblockq *memblockq;
92 bool adjust_latency:1;
93 bool early_requests:1;
95 /* Requested buffer attributes */
96 pa_buffer_attr buffer_attr_req;
97 /* Fixed-up and adjusted buffer attributes */
98 pa_buffer_attr buffer_attr;
100 pa_atomic_t on_the_fly;
101 pa_usec_t configured_source_latency;
104 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
105 size_t on_the_fly_snapshot;
106 pa_usec_t current_monitor_latency;
107 pa_usec_t current_source_latency;
110 #define RECORD_STREAM(o) (record_stream_cast(o))
111 PA_DEFINE_PRIVATE_CLASS(record_stream, pa_msgobject);
113 typedef struct output_stream {
117 #define OUTPUT_STREAM(o) (output_stream_cast(o))
118 PA_DEFINE_PRIVATE_CLASS(output_stream, pa_msgobject);
120 typedef struct playback_stream {
121 output_stream parent;
123 pa_native_connection *connection;
126 pa_sink_input *sink_input;
127 pa_memblockq *memblockq;
129 bool adjust_latency:1;
130 bool early_requests:1;
133 bool drain_request:1;
137 /* Optimization to avoid too many rewinds with a lot of small blocks */
138 pa_atomic_t seek_or_post_in_queue;
142 pa_usec_t configured_sink_latency;
143 /* Requested buffer attributes */
144 pa_buffer_attr buffer_attr_req;
145 /* Fixed-up and adjusted buffer attributes */
146 pa_buffer_attr buffer_attr;
148 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
149 int64_t read_index, write_index;
150 size_t render_memblockq_length;
151 pa_usec_t current_sink_latency;
152 uint64_t playing_for, underrun_for;
155 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
156 PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
158 typedef struct upload_stream {
159 output_stream parent;
161 pa_native_connection *connection;
164 pa_memchunk memchunk;
167 pa_sample_spec sample_spec;
168 pa_channel_map channel_map;
169 pa_proplist *proplist;
172 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
173 PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
175 struct pa_native_connection {
177 pa_native_protocol *protocol;
178 pa_native_options *options;
183 /* R/W mempool, one per client connection, for srbchannel transport.
184 * Both server and client can write to this shm area.
186 * Note: This will be NULL if our connection with the client does
187 * not support srbchannels */
188 pa_mempool *rw_mempool;
190 pa_pdispatch *pdispatch;
191 pa_idxset *record_streams, *output_streams;
192 uint32_t rrobin_index;
193 pa_subscription *subscription;
194 pa_time_event *auth_timeout_event;
195 pa_srbchannel *srbpending;
198 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
199 PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
201 struct pa_native_protocol {
205 pa_idxset *connections;
208 pa_hook hooks[PA_NATIVE_HOOK_MAX];
210 pa_hashmap *extensions;
214 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
218 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
219 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
220 SINK_INPUT_MESSAGE_FLUSH,
221 SINK_INPUT_MESSAGE_TRIGGER,
222 SINK_INPUT_MESSAGE_SEEK,
223 SINK_INPUT_MESSAGE_PREBUF_FORCE,
224 SINK_INPUT_MESSAGE_UPDATE_LATENCY,
225 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
229 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
230 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
231 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
232 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
233 PLAYBACK_STREAM_MESSAGE_STARTED,
234 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH,
235 #ifdef TIZEN_EMPTY_POP
236 PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT
241 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
245 CONNECTION_MESSAGE_RELEASE,
246 CONNECTION_MESSAGE_REVOKE
249 static bool sink_input_process_underrun_cb(pa_sink_input *i);
250 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
251 static void sink_input_kill_cb(pa_sink_input *i);
252 static void sink_input_suspend_cb(pa_sink_input *i, pa_sink_state_t old_state, pa_suspend_cause_t old_suspend_cause);
253 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
254 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
255 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
256 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
257 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
259 static void native_connection_send_memblock(pa_native_connection *c);
260 static void playback_stream_request_bytes(struct playback_stream*s);
262 static void source_output_kill_cb(pa_source_output *o);
263 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
264 static void source_output_suspend_cb(pa_source_output *o, pa_source_state_t old_state, pa_suspend_cause_t old_suspend_cause);
265 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
266 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
267 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
269 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
270 static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
272 /* structure management */
274 /* Called from main context */
275 static void upload_stream_unlink(upload_stream *s) {
281 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
282 s->connection = NULL;
283 upload_stream_unref(s);
286 /* Called from main context */
287 static void upload_stream_free(pa_object *o) {
288 upload_stream *s = UPLOAD_STREAM(o);
291 upload_stream_unlink(s);
296 pa_proplist_free(s->proplist);
298 if (s->memchunk.memblock)
299 pa_memblock_unref(s->memchunk.memblock);
304 /* Called from main context */
305 static upload_stream* upload_stream_new(
306 pa_native_connection *c,
307 const pa_sample_spec *ss,
308 const pa_channel_map *map,
318 pa_assert(length > 0);
321 s = pa_msgobject_new(upload_stream);
322 s->parent.parent.parent.free = upload_stream_free;
324 s->sample_spec = *ss;
325 s->channel_map = *map;
326 s->name = pa_xstrdup(name);
327 pa_memchunk_reset(&s->memchunk);
329 s->proplist = pa_proplist_copy(p);
330 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
332 pa_idxset_put(c->output_streams, s, &s->index);
337 /* Called from main context */
338 static void record_stream_unlink(record_stream *s) {
344 if (s->source_output) {
345 pa_source_output_unlink(s->source_output);
346 pa_source_output_unref(s->source_output);
347 s->source_output = NULL;
350 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
351 s->connection = NULL;
352 record_stream_unref(s);
355 /* Called from main context */
356 static void record_stream_free(pa_object *o) {
357 record_stream *s = RECORD_STREAM(o);
360 record_stream_unlink(s);
362 pa_memblockq_free(s->memblockq);
366 /* Called from main context */
367 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
368 record_stream *s = RECORD_STREAM(o);
369 record_stream_assert_ref(s);
376 case RECORD_STREAM_MESSAGE_POST_DATA:
378 /* We try to keep up to date with how many bytes are
379 * currently on the fly */
380 pa_atomic_sub(&s->on_the_fly, chunk->length);
382 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
383 /* pa_log_warn("Failed to push data into output queue."); */
387 if (!pa_pstream_is_pending(s->connection->pstream))
388 native_connection_send_memblock(s->connection);
396 /* Called from main context */
397 static void fix_record_buffer_attr_pre(record_stream *s) {
400 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
404 /* This function will be called from the main thread, before as
405 * well as after the source output has been activated using
406 * pa_source_output_put()! That means it may not touch any
407 * ->thread_info data! */
409 frame_size = pa_frame_size(&s->source_output->sample_spec);
410 s->buffer_attr = s->buffer_attr_req;
412 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
413 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
414 if (s->buffer_attr.maxlength <= 0)
415 s->buffer_attr.maxlength = (uint32_t) frame_size;
417 if (s->buffer_attr.fragsize == (uint32_t) -1)
418 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
419 if (s->buffer_attr.fragsize <= 0)
420 s->buffer_attr.fragsize = (uint32_t) frame_size;
422 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
424 if (s->early_requests) {
426 /* In early request mode we need to emulate the classic
427 * fragment-based playback model. Unfortunately we have no
428 * mechanism to tell the source how often we want it to send us
429 * data. The next best thing we can do is to set the source's
430 * total buffer (i.e. its latency) to the fragment size. That
431 * way it will have to send data at least that often. */
433 source_usec = fragsize_usec;
435 } else if (s->adjust_latency) {
437 /* So, the user asked us to adjust the latency according to
438 * what the source can provide. We set the source to whatever
439 * latency it can provide that is closest to what we want, and
440 * let the client buffer be equally large. This does NOT mean
441 * that we are doing (2 * fragsize) bytes of buffering, since
442 * the client-side buffer is only data that is on the way to
445 source_usec = fragsize_usec;
449 /* Ok, the user didn't ask us to adjust the latency, hence we
452 source_usec = (pa_usec_t) -1;
455 if (source_usec != (pa_usec_t) -1)
456 s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
458 s->configured_source_latency = 0;
460 if (s->early_requests) {
462 /* Ok, we didn't necessarily get what we were asking for. We
463 * might still get the proper fragment interval, we just can't
466 if (fragsize_usec != s->configured_source_latency)
467 pa_log_debug("Could not configure a sufficiently low latency. Early requests might not be satisfied.");
469 } else if (s->adjust_latency) {
471 /* We keep the client buffer large enough to transfer one
472 * hardware-buffer-sized chunk at a time to the client. */
474 fragsize_usec = s->configured_source_latency;
477 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
478 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
480 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
482 if (s->buffer_attr.fragsize <= 0)
483 s->buffer_attr.fragsize = (uint32_t) frame_size;
486 /* Called from main context */
487 static void fix_record_buffer_attr_post(record_stream *s) {
492 /* This function will be called from the main thread, before as
493 * well as after the source output has been activated using
494 * pa_source_output_put()! That means it may not touch and
495 * ->thread_info data! */
497 base = pa_frame_size(&s->source_output->sample_spec);
499 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
500 if (s->buffer_attr.fragsize <= 0)
501 s->buffer_attr.fragsize = base;
503 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
504 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
507 #ifdef TIZEN_BUFFER_ATTR
508 static int update_buffer_attr(pa_proplist* proplist, pa_buffer_attr* ret_attr, bool is_playback_stream) {
509 const char* _propStr = NULL;
513 if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_MAXLENGTH)) == NULL) {
514 pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_MAXLENGTH);
517 if (pa_atoi(_propStr, (int32_t*)(&ret_attr->maxlength))) {
518 pa_log_error("failed to pa_atoi for maxlength");
522 if (is_playback_stream) {
524 if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_TLENGTH)) == NULL) {
525 pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_TLENGTH);
528 if (pa_atoi(_propStr, (int32_t*)(&ret_attr->tlength))) {
529 pa_log_error("failed to pa_atoi for tlength");
533 if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_PREBUF)) == NULL) {
534 pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_PREBUF);
537 if (pa_atoi(_propStr, (int32_t*)(&ret_attr->prebuf))) {
538 pa_log_error("failed to pa_atoi for prebuf");
542 if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_MINREQ)) == NULL) {
543 pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_MINREQ);
546 if (pa_atoi(_propStr, (int32_t*)(&ret_attr->minreq))) {
547 pa_log_error("failed to pa_atoi for minreq");
551 pa_log_info(" - props: maxlength(%d), tlength(%d), prebuf(%d), minreq(%d)",
552 ret_attr->maxlength, ret_attr->tlength, ret_attr->prebuf, ret_attr->minreq);
556 if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_FRAGSIZE)) == NULL) {
557 pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_FRAGSIZE);
560 if (pa_atoi(_propStr, (int32_t*)(&ret_attr->fragsize))) {
561 pa_log_error("failed to pa_atoi for fragsize");
565 pa_log_info(" - props: maxlength(%d), fragsize(%d)", ret_attr->maxlength, ret_attr->fragsize);
572 /* Called from main context */
573 static record_stream* record_stream_new(
574 pa_native_connection *c,
579 pa_buffer_attr *attr,
583 pa_source_output_flags_t flags,
587 bool relative_volume,
589 pa_sink_input *direct_on_input,
592 /* Note: This function takes ownership of the 'formats' param, so we need
593 * to take extra care to not leak it */
596 pa_source_output *source_output = NULL;
597 pa_source_output_new_data data;
598 char *memblockq_name;
605 pa_source_output_new_data_init(&data);
607 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
608 data.driver = __FILE__;
609 data.module = c->options->module;
610 data.client = c->client;
612 pa_source_output_new_data_set_source(&data, source, false, true);
613 if (pa_sample_spec_valid(ss))
614 pa_source_output_new_data_set_sample_spec(&data, ss);
615 if (pa_channel_map_valid(map))
616 pa_source_output_new_data_set_channel_map(&data, map);
618 pa_source_output_new_data_set_formats(&data, formats);
619 data.direct_on_input = direct_on_input;
621 pa_source_output_new_data_set_volume(&data, volume);
622 data.volume_is_absolute = !relative_volume;
623 data.save_volume = false;
626 pa_source_output_new_data_set_muted(&data, muted);
627 data.save_muted = false;
630 data.resample_method = PA_RESAMPLER_PEAKS;
633 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
635 #ifdef TIZEN_BUFFER_ATTR
637 pa_buffer_attr buffer_attr;
638 pa_log_info("*** update buffer attributes - record_stream_new()");
639 if (source_output && !update_buffer_attr(source_output->proplist, &buffer_attr, false)) {
640 pa_log_info(" - origins: maxlength(%d), fragsize(%d)", attr->maxlength, attr->fragsize);
641 if ((int)attr->maxlength >= 0)
642 buffer_attr.maxlength = attr->maxlength;
643 if ((int)attr->fragsize >= 0)
644 buffer_attr.fragsize = attr->fragsize;
646 pa_log_info(" - updated: maxlength(%d), fragsize(%d)", attr->maxlength, attr->fragsize);
651 pa_source_output_new_data_done(&data);
656 s = pa_msgobject_new(record_stream);
657 s->parent.parent.free = record_stream_free;
658 s->parent.process_msg = record_stream_process_msg;
660 s->source_output = source_output;
661 s->buffer_attr_req = *attr;
662 s->adjust_latency = adjust_latency;
663 s->early_requests = early_requests;
664 pa_atomic_store(&s->on_the_fly, 0);
666 s->source_output->parent.process_msg = source_output_process_msg;
667 s->source_output->push = source_output_push_cb;
668 s->source_output->kill = source_output_kill_cb;
669 s->source_output->get_latency = source_output_get_latency_cb;
670 s->source_output->moving = source_output_moving_cb;
671 s->source_output->suspend = source_output_suspend_cb;
672 s->source_output->send_event = source_output_send_event_cb;
673 s->source_output->userdata = s;
675 fix_record_buffer_attr_pre(s);
677 memblockq_name = pa_sprintf_malloc("native protocol record stream memblockq [%u]", s->source_output->index);
678 s->memblockq = pa_memblockq_new(
681 s->buffer_attr.maxlength,
683 &source_output->sample_spec,
688 pa_xfree(memblockq_name);
690 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
691 fix_record_buffer_attr_post(s);
693 *ss = s->source_output->sample_spec;
694 *map = s->source_output->channel_map;
696 pa_idxset_put(c->record_streams, s, &s->index);
698 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
699 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
700 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
701 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
703 pa_source_output_put(s->source_output);
707 /* Called from main context */
708 static void record_stream_send_killed(record_stream *r) {
710 record_stream_assert_ref(r);
712 t = pa_tagstruct_new();
713 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
714 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
715 pa_tagstruct_putu32(t, r->index);
716 pa_pstream_send_tagstruct(r->connection->pstream, t);
719 /* Called from main context */
720 static void playback_stream_unlink(playback_stream *s) {
727 pa_sink_input_unlink(s->sink_input);
728 pa_sink_input_unref(s->sink_input);
729 s->sink_input = NULL;
732 if (s->drain_request)
733 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
735 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
736 s->connection = NULL;
737 playback_stream_unref(s);
740 /* Called from main context */
741 static void playback_stream_free(pa_object* o) {
742 playback_stream *s = PLAYBACK_STREAM(o);
745 playback_stream_unlink(s);
747 pa_memblockq_free(s->memblockq);
751 /* Called from main context */
752 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
753 playback_stream *s = PLAYBACK_STREAM(o);
754 playback_stream_assert_ref(s);
761 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
766 if ((l = pa_atomic_load(&s->missing)) <= 0)
769 if (pa_atomic_cmpxchg(&s->missing, l, 0))
773 t = pa_tagstruct_new();
774 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
775 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
776 pa_tagstruct_putu32(t, s->index);
777 pa_tagstruct_putu32(t, (uint32_t) l);
778 pa_pstream_send_tagstruct(s->connection->pstream, t);
780 #ifdef PROTOCOL_NATIVE_DEBUG
781 pa_log("Requesting %lu bytes", (unsigned long) l);
786 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
789 #ifdef PROTOCOL_NATIVE_DEBUG
790 pa_log("signalling underflow");
793 /* Report that we're empty */
794 t = pa_tagstruct_new();
795 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
796 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
797 pa_tagstruct_putu32(t, s->index);
798 if (s->connection->version >= 23)
799 pa_tagstruct_puts64(t, offset);
800 pa_pstream_send_tagstruct(s->connection->pstream, t);
804 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
807 /* Notify the user we're overflowed*/
808 t = pa_tagstruct_new();
809 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
810 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
811 pa_tagstruct_putu32(t, s->index);
812 pa_pstream_send_tagstruct(s->connection->pstream, t);
816 case PLAYBACK_STREAM_MESSAGE_STARTED:
818 if (s->connection->version >= 13) {
821 /* Notify the user we started playback */
822 t = pa_tagstruct_new();
823 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
824 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
825 pa_tagstruct_putu32(t, s->index);
826 pa_pstream_send_tagstruct(s->connection->pstream, t);
831 #ifdef TIZEN_EMPTY_POP
832 case PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT: {
834 pa_proplist* pl = pa_proplist_new();
836 pa_log_info("received : PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT, send PA_COMMAND_PLAYBACK_STREAM_EVENT(%s)",
837 PA_STREAM_EVENT_POP_TIMEOUT);
839 t = pa_tagstruct_new();
840 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
841 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
842 pa_tagstruct_putu32(t, s->index);
843 pa_tagstruct_puts(t, PA_STREAM_EVENT_POP_TIMEOUT);
844 pa_tagstruct_put_proplist(t, pl);
845 pa_pstream_send_tagstruct(s->connection->pstream, t);
847 pa_proplist_free(pl);
852 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
853 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
856 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
858 s->buffer_attr.tlength = (uint32_t) offset;
860 if (s->connection->version >= 15) {
863 t = pa_tagstruct_new();
864 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
865 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
866 pa_tagstruct_putu32(t, s->index);
867 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
868 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
869 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
870 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
871 pa_tagstruct_put_usec(t, s->configured_sink_latency);
872 pa_pstream_send_tagstruct(s->connection->pstream, t);
881 /* Called from main context */
882 static void fix_playback_buffer_attr(playback_stream *s) {
883 size_t frame_size, max_prebuf;
884 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
888 #ifdef PROTOCOL_NATIVE_DEBUG
889 pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes",
890 (long) s->buffer_attr_req.maxlength,
891 (long) s->buffer_attr_req.tlength,
892 (long) s->buffer_attr_req.minreq,
893 (long) s->buffer_attr_req.prebuf);
895 pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms",
896 (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
897 (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
898 (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
899 (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC));
902 /* This function will be called from the main thread, before as
903 * well as after the sink input has been activated using
904 * pa_sink_input_put()! That means it may not touch any
905 * ->thread_info data, such as the memblockq! */
907 frame_size = pa_frame_size(&s->sink_input->sample_spec);
908 s->buffer_attr = s->buffer_attr_req;
910 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
911 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
912 if (s->buffer_attr.maxlength <= 0)
913 s->buffer_attr.maxlength = (uint32_t) frame_size;
915 if (s->buffer_attr.tlength == (uint32_t) -1)
916 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
917 if (s->buffer_attr.tlength <= 0)
918 s->buffer_attr.tlength = (uint32_t) frame_size;
919 if (s->buffer_attr.tlength > s->buffer_attr.maxlength)
920 s->buffer_attr.tlength = s->buffer_attr.maxlength;
922 if (s->buffer_attr.minreq == (uint32_t) -1) {
923 uint32_t process = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
924 /* With low-latency, tlength/4 gives a decent default in all of traditional, adjust latency and early request modes. */
925 uint32_t m = s->buffer_attr.tlength / 4;
928 s->buffer_attr.minreq = PA_MIN(process, m);
930 if (s->buffer_attr.minreq <= 0)
931 s->buffer_attr.minreq = (uint32_t) frame_size;
933 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
934 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
936 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
937 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
939 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
940 (double) tlength_usec / PA_USEC_PER_MSEC,
941 (double) minreq_usec / PA_USEC_PER_MSEC);
943 if (s->early_requests) {
945 /* In early request mode we need to emulate the classic
946 * fragment-based playback model. Unfortunately we have no
947 * mechanism to tell the sink how often we want to be queried
948 * for data. The next best thing we can do is to set the sink's
949 * total buffer (i.e. its latency) to the fragment size. That
950 * way it will have to query us at least that often. */
952 sink_usec = minreq_usec;
953 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
955 } else if (s->adjust_latency) {
957 /* So, the user asked us to adjust the latency of the stream
958 * buffer according to the what the sink can provide. The
959 * tlength passed in shall be the overall latency. Roughly
960 * half the latency will be spent on the hw buffer, the other
961 * half of it in the async buffer queue we maintain for each
962 * client. In between we'll have a safety space of size
963 * 2*minreq. Why the 2*minreq? When the hw buffer is completely
964 * empty and needs to be filled, then our buffer must have
965 * enough data to fulfill this request immediately and thus
966 * have at least the same tlength as the size of the hw
967 * buffer. It additionally needs space for 2 times minreq
968 * because if the buffer ran empty and a partial fillup
969 * happens immediately on the next iteration we need to be
970 * able to fulfill it and give the application also minreq
971 * time to fill it up again for the next request Makes 2 times
972 * minreq in plus.. */
974 if (tlength_usec > minreq_usec*2)
975 sink_usec = (tlength_usec - minreq_usec*2)/2;
979 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
983 /* Ok, the user didn't ask us to adjust the latency, but we
984 * still need to make sure that the parameters from the user
987 if (tlength_usec > minreq_usec*2)
988 sink_usec = (tlength_usec - minreq_usec*2);
992 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
995 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
997 if (s->early_requests) {
999 /* Ok, we didn't necessarily get what we were asking for. We
1000 * might still get the proper fragment interval, we just can't
1003 if (minreq_usec != s->configured_sink_latency)
1004 pa_log_debug("Could not configure a sufficiently low latency. Early requests might not be satisfied.");
1006 } else if (s->adjust_latency) {
1008 /* Ok, we didn't necessarily get what we were asking for, so
1009 * let's subtract from what we asked for for the remaining
1012 if (tlength_usec >= s->configured_sink_latency)
1013 tlength_usec -= s->configured_sink_latency;
1016 pa_log_debug("Requested latency=%0.2f ms, Received latency=%0.2f ms",
1017 (double) sink_usec / PA_USEC_PER_MSEC,
1018 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1020 /* FIXME: This is actually larger than necessary, since not all of
1021 * the sink latency is actually rewritable. */
1022 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
1023 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
1025 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
1026 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
1027 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
1029 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
1030 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
1031 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
1033 if (s->buffer_attr.minreq <= 0) {
1034 s->buffer_attr.minreq = (uint32_t) frame_size;
1035 s->buffer_attr.tlength += (uint32_t) frame_size*2;
1038 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
1039 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
1041 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
1043 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
1044 s->buffer_attr.prebuf > max_prebuf)
1045 s->buffer_attr.prebuf = max_prebuf;
1047 #ifdef PROTOCOL_NATIVE_DEBUG
1048 pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms",
1049 (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1050 (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1051 (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1052 (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC));
1056 /* Called from main context */
1057 static playback_stream* playback_stream_new(
1058 pa_native_connection *c,
1061 pa_channel_map *map,
1067 pa_sink_input_flags_t flags,
1069 bool adjust_latency,
1070 bool early_requests,
1071 bool relative_volume,
1076 /* Note: This function takes ownership of the 'formats' param, so we need
1077 * to take extra care to not leak it */
1079 playback_stream *ssync;
1080 playback_stream *s = NULL;
1081 pa_sink_input *sink_input = NULL;
1082 pa_memchunk silence;
1084 int64_t start_index;
1085 pa_sink_input_new_data data;
1086 char *memblockq_name;
1094 /* Find syncid group */
1095 PA_IDXSET_FOREACH(ssync, c->output_streams, idx) {
1097 if (!playback_stream_isinstance(ssync))
1100 if (ssync->syncid == syncid)
1104 /* Synced streams must connect to the same sink */
1108 sink = ssync->sink_input->sink;
1109 else if (sink != ssync->sink_input->sink) {
1110 *ret = PA_ERR_INVALID;
1115 pa_sink_input_new_data_init(&data);
1117 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1118 data.driver = __FILE__;
1119 data.module = c->options->module;
1120 data.client = c->client;
1122 pa_sink_input_new_data_set_sink(&data, sink, false, true);
1123 if (pa_sample_spec_valid(ss))
1124 pa_sink_input_new_data_set_sample_spec(&data, ss);
1125 if (pa_channel_map_valid(map))
1126 pa_sink_input_new_data_set_channel_map(&data, map);
1128 pa_sink_input_new_data_set_formats(&data, formats);
1129 /* Ownership transferred to new_data, so we don't free it ourselves */
1133 pa_sink_input_new_data_set_volume(&data, volume);
1134 data.volume_is_absolute = !relative_volume;
1135 data.save_volume = false;
1138 pa_sink_input_new_data_set_muted(&data, muted);
1139 data.save_muted = false;
1141 data.sync_base = ssync ? ssync->sink_input : NULL;
1144 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1146 #ifdef TIZEN_BUFFER_ATTR
1148 pa_buffer_attr buffer_attr;
1149 pa_log_info("*** update buffer attributes - playback_stream_new()");
1150 if (sink_input && !update_buffer_attr(sink_input->proplist, &buffer_attr, true)) {
1151 pa_log_info(" - origins: maxlength(%d), tlength(%d), prebuf(%d), minreq(%d)",
1152 a->maxlength, a->tlength, a->prebuf, a->minreq);
1153 if ((int)a->maxlength >= 0)
1154 buffer_attr.maxlength = a->maxlength;
1155 /* "tlength" is always set to default value from pa_stream_new_with_proplist_internal() in stream.c.
1156 but here we use tlength from stream-map.json except -1. */
1157 if ((int)buffer_attr.tlength == -1)
1158 buffer_attr.tlength = a->tlength;
1159 if ((int)a->prebuf >= 0)
1160 buffer_attr.prebuf = a->prebuf;
1161 if ((int)a->minreq >= 0)
1162 buffer_attr.minreq = a->minreq;
1164 pa_log_info(" - updated: maxlength(%d), tlength(%d), prebuf(%d), minreq(%d)",
1165 a->maxlength, a->tlength, a->prebuf, a->minreq);
1170 pa_sink_input_new_data_done(&data);
1175 s = pa_msgobject_new(playback_stream);
1176 s->parent.parent.parent.free = playback_stream_free;
1177 s->parent.parent.process_msg = playback_stream_process_msg;
1180 s->sink_input = sink_input;
1181 s->is_underrun = true;
1182 s->drain_request = false;
1183 pa_atomic_store(&s->missing, 0);
1184 s->buffer_attr_req = *a;
1185 s->adjust_latency = adjust_latency;
1186 s->early_requests = early_requests;
1187 pa_atomic_store(&s->seek_or_post_in_queue, 0);
1188 s->seek_windex = -1;
1190 s->sink_input->parent.process_msg = sink_input_process_msg;
1191 s->sink_input->pop = sink_input_pop_cb;
1192 s->sink_input->process_underrun = sink_input_process_underrun_cb;
1193 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1194 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1195 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1196 s->sink_input->kill = sink_input_kill_cb;
1197 s->sink_input->moving = sink_input_moving_cb;
1198 s->sink_input->suspend = sink_input_suspend_cb;
1199 s->sink_input->send_event = sink_input_send_event_cb;
1200 s->sink_input->userdata = s;
1202 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1204 fix_playback_buffer_attr(s);
1206 pa_sink_input_get_silence(sink_input, &silence);
1207 memblockq_name = pa_sprintf_malloc("native protocol playback stream memblockq [%u]", s->sink_input->index);
1208 s->memblockq = pa_memblockq_new(
1211 s->buffer_attr.maxlength,
1212 s->buffer_attr.tlength,
1213 &sink_input->sample_spec,
1214 s->buffer_attr.prebuf,
1215 s->buffer_attr.minreq,
1218 pa_xfree(memblockq_name);
1219 pa_memblock_unref(silence.memblock);
1221 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1223 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1225 #ifdef PROTOCOL_NATIVE_DEBUG
1226 pa_log("missing original: %li", (long int) *missing);
1229 *ss = s->sink_input->sample_spec;
1230 *map = s->sink_input->channel_map;
1232 pa_idxset_put(c->output_streams, s, &s->index);
1234 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1235 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1236 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1237 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1238 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1240 pa_sink_input_put(s->sink_input);
1244 pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
1249 /* Called from IO context */
1250 static void playback_stream_request_bytes(playback_stream *s) {
1253 playback_stream_assert_ref(s);
1255 m = pa_memblockq_pop_missing(s->memblockq);
1257 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1258 /* (unsigned long) m, */
1259 /* pa_memblockq_get_tlength(s->memblockq), */
1260 /* pa_memblockq_get_minreq(s->memblockq), */
1261 /* pa_memblockq_get_length(s->memblockq), */
1262 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1267 #ifdef PROTOCOL_NATIVE_DEBUG
1268 pa_log("request_bytes(%lu)", (unsigned long) m);
1271 if (pa_atomic_add(&s->missing, (int) m) <= 0)
1272 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1275 /* Called from main context */
1276 static void playback_stream_send_killed(playback_stream *p) {
1278 playback_stream_assert_ref(p);
1280 t = pa_tagstruct_new();
1281 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1282 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1283 pa_tagstruct_putu32(t, p->index);
1284 pa_pstream_send_tagstruct(p->connection->pstream, t);
1287 /* Called from main context */
1288 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1289 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1290 pa_native_connection_assert_ref(c);
1297 case CONNECTION_MESSAGE_REVOKE:
1298 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1301 case CONNECTION_MESSAGE_RELEASE:
1302 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1309 /* Called from main context */
1310 static void native_connection_unlink(pa_native_connection *c) {
1319 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1322 pa_native_options_unref(c->options);
1325 pa_srbchannel_free(c->srbpending);
1327 while ((r = pa_idxset_first(c->record_streams, NULL)))
1328 record_stream_unlink(r);
1330 while ((o = pa_idxset_first(c->output_streams, NULL)))
1331 if (playback_stream_isinstance(o))
1332 playback_stream_unlink(PLAYBACK_STREAM(o));
1334 upload_stream_unlink(UPLOAD_STREAM(o));
1336 if (c->subscription)
1337 pa_subscription_free(c->subscription);
1340 pa_pstream_unlink(c->pstream);
1342 if (c->auth_timeout_event) {
1343 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1344 c->auth_timeout_event = NULL;
1347 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1349 pa_native_connection_unref(c);
1352 /* Called from main context */
1353 static void native_connection_free(pa_object *o) {
1354 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1358 native_connection_unlink(c);
1360 pa_idxset_free(c->record_streams, NULL);
1361 pa_idxset_free(c->output_streams, NULL);
1363 pa_pdispatch_unref(c->pdispatch);
1364 pa_pstream_unref(c->pstream);
1366 pa_mempool_unref(c->rw_mempool);
1368 pa_client_free(c->client);
1373 /* Called from main context */
1374 static void native_connection_send_memblock(pa_native_connection *c) {
1378 start = PA_IDXSET_INVALID;
1382 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1385 if (start == PA_IDXSET_INVALID)
1386 start = c->rrobin_index;
1387 else if (start == c->rrobin_index)
1390 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1391 pa_memchunk schunk = chunk;
1393 if (schunk.length > r->buffer_attr.fragsize)
1394 schunk.length = r->buffer_attr.fragsize;
1396 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1398 pa_memblockq_drop(r->memblockq, schunk.length);
1399 pa_memblock_unref(schunk.memblock);
1406 /*** sink input callbacks ***/
1408 /* Called from thread context */
1409 static void handle_seek(playback_stream *s, int64_t indexw) {
1410 playback_stream_assert_ref(s);
1412 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1414 if (s->sink_input->thread_info.underrun_for > 0) {
1416 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1418 if (pa_memblockq_is_readable(s->memblockq)) {
1420 /* We just ended an underrun, let's ask the sink
1421 * for a complete rewind rewrite */
1423 pa_log_debug("Requesting rewind due to end of underrun.");
1424 pa_sink_input_request_rewind(s->sink_input,
1425 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1426 s->sink_input->thread_info.underrun_for),
1427 false, true, false);
1433 indexr = pa_memblockq_get_read_index(s->memblockq);
1435 if (indexw < indexr) {
1436 /* OK, the sink already asked for this data, so
1437 * let's have it ask us again */
1439 pa_log_debug("Requesting rewind due to rewrite.");
1440 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), true, false, false);
1444 playback_stream_request_bytes(s);
1447 static void flush_write_no_account(pa_memblockq *q) {
1448 pa_memblockq_flush_write(q, false);
1451 /* Called from thread context */
1452 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1453 pa_sink_input *i = PA_SINK_INPUT(o);
1456 pa_sink_input_assert_ref(i);
1457 s = PLAYBACK_STREAM(i->userdata);
1458 playback_stream_assert_ref(s);
1462 case SINK_INPUT_MESSAGE_SEEK:
1463 case SINK_INPUT_MESSAGE_POST_DATA: {
1464 int64_t windex = pa_memblockq_get_write_index(s->memblockq);
1466 if (code == SINK_INPUT_MESSAGE_SEEK) {
1467 /* The client side is incapable of accounting correctly
1468 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1469 * able to deal with that. */
1471 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1472 windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
1475 if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1476 if (pa_log_ratelimit(PA_LOG_WARN))
1477 pa_log_warn("Failed to push data into queue");
1478 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1479 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, true);
1482 /* If more data is in queue, we rewind later instead. */
1483 if (s->seek_windex != -1)
1484 windex = PA_MIN(windex, s->seek_windex);
1485 if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
1486 s->seek_windex = windex;
1488 s->seek_windex = -1;
1489 handle_seek(s, windex);
1494 case SINK_INPUT_MESSAGE_DRAIN:
1495 case SINK_INPUT_MESSAGE_FLUSH:
1496 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1497 case SINK_INPUT_MESSAGE_TRIGGER: {
1500 pa_sink_input *isync;
1501 void (*func)(pa_memblockq *bq);
1504 case SINK_INPUT_MESSAGE_FLUSH:
1505 func = flush_write_no_account;
1508 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1509 func = pa_memblockq_prebuf_force;
1512 case SINK_INPUT_MESSAGE_DRAIN:
1513 case SINK_INPUT_MESSAGE_TRIGGER:
1514 func = pa_memblockq_prebuf_disable;
1518 pa_assert_not_reached();
1521 windex = pa_memblockq_get_write_index(s->memblockq);
1523 handle_seek(s, windex);
1525 /* Do the same for all other members in the sync group */
1526 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1527 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1528 windex = pa_memblockq_get_write_index(ssync->memblockq);
1529 func(ssync->memblockq);
1530 handle_seek(ssync, windex);
1533 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1534 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1535 windex = pa_memblockq_get_write_index(ssync->memblockq);
1536 func(ssync->memblockq);
1537 handle_seek(ssync, windex);
1540 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1541 if (!pa_memblockq_is_readable(s->memblockq))
1542 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1544 s->drain_tag = PA_PTR_TO_UINT(userdata);
1545 s->drain_request = true;
1552 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1553 /* Atomically get a snapshot of all timing parameters... */
1554 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1555 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1556 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1557 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink, false);
1558 s->underrun_for = s->sink_input->thread_info.underrun_for;
1559 s->playing_for = s->sink_input->thread_info.playing_for;
1563 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1566 windex = pa_memblockq_get_write_index(s->memblockq);
1568 /* We enable prebuffering so that after CORKED -> RUNNING
1569 * transitions we don't have trouble with underruns in case the
1570 * buffer has too little data. This must not be done when draining
1571 * has been requested, however, otherwise the buffered audio would
1573 if (!s->drain_request)
1574 pa_memblockq_prebuf_force(s->memblockq);
1576 handle_seek(s, windex);
1578 /* Fall through to the default handler */
1582 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1583 pa_usec_t *r = userdata;
1585 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1587 /* Fall through, the default handler will add in the extra
1588 * latency added by the resampler */
1592 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1593 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1594 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1599 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1602 static bool handle_input_underrun(playback_stream *s, bool force) {
1605 if (pa_memblockq_is_readable(s->memblockq))
1608 if (!s->is_underrun)
1609 pa_log_debug("%s %s of '%s'", force ? "Actual" : "Implicit",
1610 s->drain_request ? "drain" : "underrun", pa_strnull(pa_proplist_gets(s->sink_input->proplist, PA_PROP_MEDIA_NAME)));
1612 send_drain = s->drain_request && (force || pa_sink_input_safe_to_remove(s->sink_input));
1615 s->drain_request = false;
1616 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);
1617 pa_log_debug("Drain acknowledged of '%s'", pa_strnull(pa_proplist_gets(s->sink_input->proplist, PA_PROP_MEDIA_NAME)));
1618 } else if (!s->is_underrun) {
1619 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);
1621 s->is_underrun = true;
1622 playback_stream_request_bytes(s);
1626 /* Called from thread context */
1627 static bool sink_input_process_underrun_cb(pa_sink_input *i) {
1630 pa_sink_input_assert_ref(i);
1631 s = PLAYBACK_STREAM(i->userdata);
1632 playback_stream_assert_ref(s);
1634 return handle_input_underrun(s, true);
1637 #ifdef TIZEN_EMPTY_POP
1638 static void _check_empty_pop_timeout(pa_sink_input *i) {
1639 playback_stream *s = PLAYBACK_STREAM(i->userdata);
1640 bool is_timeout = false;
1642 pa_sink_input_update_empty_pop(i, pa_memblockq_get_length(s->memblockq), &is_timeout);
1644 pa_log_warn("async msgq post : PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT");
1645 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s),
1646 PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT, NULL, 0, NULL, NULL);
1651 /* Called from thread context */
1652 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1655 pa_sink_input_assert_ref(i);
1656 s = PLAYBACK_STREAM(i->userdata);
1657 playback_stream_assert_ref(s);
1660 #ifdef PROTOCOL_NATIVE_DEBUG
1661 pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq));
1664 #ifdef TIZEN_EMPTY_POP
1665 /* If empty pops exceeds certain threshold, send message to client to handle this situation */
1666 /* FIXME: maybe we can use s->is_underrun to check.... */
1667 if (!i->is_virtual) /* skip for virtual stream */
1668 _check_empty_pop_timeout(i);
1671 if (!handle_input_underrun(s, false))
1672 s->is_underrun = false;
1674 /* This call will not fail with prebuf=0, hence we check for
1675 underrun explicitly in handle_input_underrun */
1676 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1679 chunk->length = PA_MIN(nbytes, chunk->length);
1681 if (i->thread_info.underrun_for > 0)
1682 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1684 pa_memblockq_drop(s->memblockq, chunk->length);
1685 playback_stream_request_bytes(s);
1690 /* Called from thread context */
1691 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1694 pa_sink_input_assert_ref(i);
1695 s = PLAYBACK_STREAM(i->userdata);
1696 playback_stream_assert_ref(s);
1698 /* If we are in an underrun, then we don't rewind */
1699 if (i->thread_info.underrun_for > 0)
1702 pa_memblockq_rewind(s->memblockq, nbytes);
1705 /* Called from thread context */
1706 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1709 pa_sink_input_assert_ref(i);
1710 s = PLAYBACK_STREAM(i->userdata);
1711 playback_stream_assert_ref(s);
1713 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1716 /* Called from thread context */
1717 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1719 size_t new_tlength, old_tlength;
1721 pa_sink_input_assert_ref(i);
1722 s = PLAYBACK_STREAM(i->userdata);
1723 playback_stream_assert_ref(s);
1725 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1726 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1728 if (old_tlength < new_tlength) {
1729 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1730 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1731 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1733 if (new_tlength == old_tlength)
1734 pa_log_debug("Failed to increase tlength");
1736 pa_log_debug("Notifying client about increased tlength");
1737 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);
1742 /* Called from main context */
1743 static void sink_input_kill_cb(pa_sink_input *i) {
1746 pa_sink_input_assert_ref(i);
1747 s = PLAYBACK_STREAM(i->userdata);
1748 playback_stream_assert_ref(s);
1750 playback_stream_send_killed(s);
1751 playback_stream_unlink(s);
1754 /* Called from main context */
1755 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1759 pa_sink_input_assert_ref(i);
1760 s = PLAYBACK_STREAM(i->userdata);
1761 playback_stream_assert_ref(s);
1763 if (s->connection->version < 15)
1766 t = pa_tagstruct_new();
1767 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1768 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1769 pa_tagstruct_putu32(t, s->index);
1770 pa_tagstruct_puts(t, event);
1771 pa_tagstruct_put_proplist(t, pl);
1772 pa_pstream_send_tagstruct(s->connection->pstream, t);
1775 /* Called from main context */
1776 static void sink_input_suspend_cb(pa_sink_input *i, pa_sink_state_t old_state, pa_suspend_cause_t old_suspend_cause) {
1781 pa_sink_input_assert_ref(i);
1783 /* State has not changed, nothing to do */
1784 if (old_state == i->sink->state)
1787 suspend = (i->sink->state == PA_SINK_SUSPENDED);
1789 s = PLAYBACK_STREAM(i->userdata);
1790 playback_stream_assert_ref(s);
1792 if (s->connection->version < 12)
1795 t = pa_tagstruct_new();
1796 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1797 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1798 pa_tagstruct_putu32(t, s->index);
1799 pa_tagstruct_put_boolean(t, suspend);
1800 pa_pstream_send_tagstruct(s->connection->pstream, t);
1803 /* Called from main context */
1804 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1808 pa_sink_input_assert_ref(i);
1809 s = PLAYBACK_STREAM(i->userdata);
1810 playback_stream_assert_ref(s);
1815 fix_playback_buffer_attr(s);
1816 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1817 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1819 if (s->connection->version < 12)
1822 t = pa_tagstruct_new();
1823 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1824 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1825 pa_tagstruct_putu32(t, s->index);
1826 pa_tagstruct_putu32(t, dest->index);
1827 pa_tagstruct_puts(t, dest->name);
1828 pa_tagstruct_put_boolean(t, dest->state == PA_SINK_SUSPENDED);
1830 if (s->connection->version >= 13) {
1831 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1832 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1833 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1834 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1835 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1838 pa_pstream_send_tagstruct(s->connection->pstream, t);
1841 /*** source_output callbacks ***/
1843 /* Called from thread context */
1844 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1845 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1848 pa_source_output_assert_ref(o);
1849 s = RECORD_STREAM(o->userdata);
1850 record_stream_assert_ref(s);
1853 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1854 /* Atomically get a snapshot of all timing parameters... */
1855 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of, false) : 0;
1856 s->current_source_latency = pa_source_get_latency_within_thread(o->source, false);
1857 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1861 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1864 /* Called from thread context */
1865 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1868 pa_source_output_assert_ref(o);
1869 s = RECORD_STREAM(o->userdata);
1870 record_stream_assert_ref(s);
1873 pa_atomic_add(&s->on_the_fly, chunk->length);
1874 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1877 static void source_output_kill_cb(pa_source_output *o) {
1880 pa_source_output_assert_ref(o);
1881 s = RECORD_STREAM(o->userdata);
1882 record_stream_assert_ref(s);
1884 record_stream_send_killed(s);
1885 record_stream_unlink(s);
1888 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1891 pa_source_output_assert_ref(o);
1892 s = RECORD_STREAM(o->userdata);
1893 record_stream_assert_ref(s);
1895 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1897 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1900 /* Called from main context */
1901 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1905 pa_source_output_assert_ref(o);
1906 s = RECORD_STREAM(o->userdata);
1907 record_stream_assert_ref(s);
1909 if (s->connection->version < 15)
1912 t = pa_tagstruct_new();
1913 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1914 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1915 pa_tagstruct_putu32(t, s->index);
1916 pa_tagstruct_puts(t, event);
1917 pa_tagstruct_put_proplist(t, pl);
1918 pa_pstream_send_tagstruct(s->connection->pstream, t);
1921 /* Called from main context */
1922 static void source_output_suspend_cb(pa_source_output *o, pa_source_state_t old_state, pa_suspend_cause_t old_suspend_cause) {
1927 pa_source_output_assert_ref(o);
1929 /* State has not changed, nothing to do */
1930 if (old_state == o->source->state)
1933 suspend = (o->source->state == PA_SOURCE_SUSPENDED);
1935 s = RECORD_STREAM(o->userdata);
1936 record_stream_assert_ref(s);
1938 if (s->connection->version < 12)
1941 t = pa_tagstruct_new();
1942 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1943 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1944 pa_tagstruct_putu32(t, s->index);
1945 pa_tagstruct_put_boolean(t, suspend);
1946 pa_pstream_send_tagstruct(s->connection->pstream, t);
1949 /* Called from main context */
1950 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1954 pa_source_output_assert_ref(o);
1955 s = RECORD_STREAM(o->userdata);
1956 record_stream_assert_ref(s);
1961 fix_record_buffer_attr_pre(s);
1962 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1963 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1964 fix_record_buffer_attr_post(s);
1966 if (s->connection->version < 12)
1969 t = pa_tagstruct_new();
1970 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1971 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1972 pa_tagstruct_putu32(t, s->index);
1973 pa_tagstruct_putu32(t, dest->index);
1974 pa_tagstruct_puts(t, dest->name);
1975 pa_tagstruct_put_boolean(t, dest->state == PA_SOURCE_SUSPENDED);
1977 if (s->connection->version >= 13) {
1978 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1979 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1980 pa_tagstruct_put_usec(t, s->configured_source_latency);
1983 pa_pstream_send_tagstruct(s->connection->pstream, t);
1986 /*** pdispatch callbacks ***/
1988 static void protocol_error(pa_native_connection *c) {
1989 pa_log("protocol error, kicking client");
1990 native_connection_unlink(c);
1994 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1995 if (!(expression)) { \
1996 pa_log_error("%s", #expression);\
1997 pa_pstream_send_error((pstream), (tag), (error)); \
2002 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
2003 if (!(expression)) { \
2004 pa_log_error("%s", #expression);\
2005 pa_pstream_send_error((pstream), (tag), (error)); \
2009 #else /* __TIZEN__ */
2010 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
2011 if (!(expression)) { \
2012 pa_pstream_send_error((pstream), (tag), (error)); \
2017 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
2018 if (!(expression)) { \
2019 pa_pstream_send_error((pstream), (tag), (error)); \
2023 #endif /* __TIZEN__ */
2025 static pa_tagstruct *reply_new(uint32_t tag) {
2026 pa_tagstruct *reply;
2028 reply = pa_tagstruct_new();
2029 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
2030 pa_tagstruct_putu32(reply, tag);
2034 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2035 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2037 uint32_t sink_index, syncid, missing = 0;
2038 pa_buffer_attr attr;
2039 const char *name = NULL, *sink_name;
2042 pa_tagstruct *reply;
2043 pa_sink *sink = NULL;
2051 fix_channels = false,
2053 variable_rate = false,
2055 adjust_latency = false,
2056 early_requests = false,
2057 dont_inhibit_auto_suspend = false,
2060 fail_on_suspend = false,
2061 relative_volume = false,
2062 passthrough = false;
2064 pa_sink_input_flags_t flags = 0;
2065 pa_proplist *p = NULL;
2066 int ret = PA_ERR_INVALID;
2067 uint8_t n_formats = 0;
2068 pa_format_info *format;
2069 pa_idxset *formats = NULL;
2072 pa_native_connection_assert_ref(c);
2074 memset(&attr, 0, sizeof(attr));
2076 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2079 PA_TAG_SAMPLE_SPEC, &ss,
2080 PA_TAG_CHANNEL_MAP, &map,
2081 PA_TAG_U32, &sink_index,
2082 PA_TAG_STRING, &sink_name,
2083 PA_TAG_U32, &attr.maxlength,
2084 PA_TAG_BOOLEAN, &corked,
2085 PA_TAG_U32, &attr.tlength,
2086 PA_TAG_U32, &attr.prebuf,
2087 PA_TAG_U32, &attr.minreq,
2088 PA_TAG_U32, &syncid,
2089 PA_TAG_CVOLUME, &volume,
2090 PA_TAG_INVALID) < 0) {
2097 pa_log_info("name:%s, sink_index:%u, sink_name:%s, corked:%u, syncid:%u",
2098 name, sink_index, sink_name, corked, syncid);
2101 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
2102 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID, finish);
2103 CHECK_VALIDITY_GOTO(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID, finish);
2104 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
2105 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
2107 p = pa_proplist_new();
2110 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2112 if (c->version >= 12) {
2113 /* Since 0.9.8 the user can ask for a couple of additional flags */
2115 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2116 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2117 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2118 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2119 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2120 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2121 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2128 if (c->version >= 13) {
2130 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
2131 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2132 pa_tagstruct_get_proplist(t, p) < 0) {
2139 if (c->version >= 14) {
2141 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2142 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2149 if (c->version >= 15) {
2151 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2152 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2153 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2160 if (c->version >= 17) {
2162 if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
2169 if (c->version >= 18) {
2171 if (pa_tagstruct_get_boolean(t, &passthrough) < 0 ) {
2177 if (c->version >= 21) {
2179 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2185 formats = pa_idxset_new(NULL, NULL);
2187 for (i = 0; i < n_formats; i++) {
2188 format = pa_format_info_new();
2189 if (pa_tagstruct_get_format_info(t, format) < 0) {
2191 pa_format_info_free(format);
2196 pa_idxset_put(formats, format, NULL);
2200 if (n_formats == 0) {
2201 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2202 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2203 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2205 PA_IDXSET_FOREACH(format, formats, i) {
2206 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2210 if (!pa_tagstruct_eof(t)) {
2215 if (sink_index != PA_INVALID_INDEX) {
2217 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
2219 pa_log_warn("[NOENTITY] ingoring given sink index %u ...", sink_index);
2221 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2226 } else if (sink_name) {
2228 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
2230 pa_log_warn("[NOENTITY] ingoring given sink name %s ...", sink_name);
2232 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2239 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
2240 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
2241 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
2242 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
2243 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
2244 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
2245 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
2246 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
2247 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2248 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
2249 (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0);
2251 /* Only since protocol version 15 there's a separate muted_set
2252 * flag. For older versions we synthesize it here */
2253 muted_set = muted_set || muted;
2255 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);
2256 /* We no longer own the formats idxset */
2259 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2261 reply = reply_new(tag);
2262 pa_tagstruct_putu32(reply, s->index);
2263 pa_assert(s->sink_input);
2264 pa_tagstruct_putu32(reply, s->sink_input->index);
2265 pa_tagstruct_putu32(reply, missing);
2267 #ifdef PROTOCOL_NATIVE_DEBUG
2268 pa_log("initial request is %u", missing);
2271 if (c->version >= 9) {
2272 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2274 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2275 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2276 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2277 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2280 if (c->version >= 12) {
2281 /* Since 0.9.8 we support sending the chosen sample
2282 * spec/channel map/device/suspend status back to the
2285 pa_tagstruct_put_sample_spec(reply, &ss);
2286 pa_tagstruct_put_channel_map(reply, &map);
2288 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2289 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2291 pa_tagstruct_put_boolean(reply, s->sink_input->sink->state == PA_SINK_SUSPENDED);
2294 if (c->version >= 13)
2295 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2297 if (c->version >= 21) {
2298 /* Send back the format we negotiated */
2299 if (s->sink_input->format)
2300 pa_tagstruct_put_format_info(reply, s->sink_input->format);
2302 pa_format_info *f = pa_format_info_new();
2303 pa_tagstruct_put_format_info(reply, f);
2304 pa_format_info_free(f);
2308 pa_pstream_send_tagstruct(c->pstream, reply);
2312 pa_proplist_free(p);
2314 pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
2317 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2318 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2321 pa_native_connection_assert_ref(c);
2324 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2325 !pa_tagstruct_eof(t)) {
2330 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2334 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2336 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2337 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2341 playback_stream_unlink(s);
2345 case PA_COMMAND_DELETE_RECORD_STREAM: {
2347 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2348 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2352 record_stream_unlink(s);
2356 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2359 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2360 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2364 upload_stream_unlink(s);
2369 pa_assert_not_reached();
2372 pa_pstream_send_simple_ack(c->pstream, tag);
2375 #ifdef TIZEN_SECURITY
2376 static int _get_connection_out_fd(pa_native_connection *c) {
2377 return pa_iochannel_get_send_fd(pa_pstream_get_iochannel(pa_native_connection_get_pstream(c)));
2380 static void command_check_privilege(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2381 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2382 const char *privilege;
2384 pa_native_connection_assert_ref(c);
2387 if (pa_tagstruct_gets(t, &privilege) < 0) {
2392 CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), privilege, -1), tag, PA_ERR_ACCESS);
2393 pa_pstream_send_simple_ack(c->pstream, tag);
2397 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2398 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2400 pa_buffer_attr attr;
2401 uint32_t source_index;
2402 const char *name = NULL, *source_name;
2405 pa_tagstruct *reply;
2406 pa_source *source = NULL;
2414 fix_channels = false,
2416 variable_rate = false,
2418 adjust_latency = false,
2419 peak_detect = false,
2420 early_requests = false,
2421 dont_inhibit_auto_suspend = false,
2424 fail_on_suspend = false,
2425 relative_volume = false,
2426 passthrough = false;
2428 pa_source_output_flags_t flags = 0;
2429 pa_proplist *p = NULL;
2430 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2431 pa_sink_input *direct_on_input = NULL;
2432 int ret = PA_ERR_INVALID;
2433 uint8_t n_formats = 0;
2434 pa_format_info *format;
2435 pa_idxset *formats = NULL;
2437 #ifdef TIZEN_SECURITY
2438 bool is_virtual_stream = false;
2439 bool is_remote_stream = false;
2442 pa_native_connection_assert_ref(c);
2445 memset(&attr, 0, sizeof(attr));
2447 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2448 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2449 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2450 pa_tagstruct_getu32(t, &source_index) < 0 ||
2451 pa_tagstruct_gets(t, &source_name) < 0 ||
2452 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2453 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2454 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2461 pa_log_info("name:%s, source_index:%u, source_name:%s, corked:%u",
2462 name, source_index, source_name, corked);
2465 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
2466 CHECK_VALIDITY_GOTO(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID, finish);
2467 CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID, finish);
2468 CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
2469 #ifdef TIZEN_SECURITY
2470 if ((pa_tagstruct_get_boolean(t, &is_virtual_stream) < 0)) {
2474 if ((pa_tagstruct_get_boolean(t, &is_remote_stream) < 0)) {
2478 pa_log_info("is virtual stream : %s, is remote stream : %s", pa_yes_no(is_virtual_stream), pa_yes_no(is_remote_stream));
2480 if (!is_virtual_stream && !is_remote_stream)
2481 CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), RECORDER_PRIVILEGE, -1), tag, PA_ERR_ACCESS);
2484 p = pa_proplist_new();
2487 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2489 if (c->version >= 12) {
2490 /* Since 0.9.8 the user can ask for a couple of additional flags */
2492 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2493 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2494 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2495 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2496 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2497 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2498 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2505 if (c->version >= 13) {
2507 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2508 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2509 pa_tagstruct_get_proplist(t, p) < 0 ||
2510 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2517 if (c->version >= 14) {
2519 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2525 if (c->version >= 15) {
2527 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2528 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2535 if (c->version >= 22) {
2536 /* For newer client versions (with per-source-output volumes), we try
2537 * to make the behaviour for playback and record streams the same. */
2540 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2546 formats = pa_idxset_new(NULL, NULL);
2548 for (i = 0; i < n_formats; i++) {
2549 format = pa_format_info_new();
2550 if (pa_tagstruct_get_format_info(t, format) < 0) {
2552 pa_format_info_free(format);
2557 pa_idxset_put(formats, format, NULL);
2560 if (pa_tagstruct_get_cvolume(t, &volume) < 0 ||
2561 pa_tagstruct_get_boolean(t, &muted) < 0 ||
2562 pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2563 pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2564 pa_tagstruct_get_boolean(t, &relative_volume) < 0 ||
2565 pa_tagstruct_get_boolean(t, &passthrough) < 0) {
2571 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
2574 if (n_formats == 0) {
2575 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2576 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2577 CHECK_VALIDITY_GOTO(c->pstream, c->version < 22 || (volume.channels == ss.channels), tag, PA_ERR_INVALID, finish);
2578 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2580 PA_IDXSET_FOREACH(format, formats, i) {
2581 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2585 if (!pa_tagstruct_eof(t)) {
2590 if (source_index != PA_INVALID_INDEX) {
2592 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2594 pa_log_warn("[NOENTITY] ingoring given source index %u ...", source_index);
2596 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2601 } else if (source_name) {
2603 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2605 pa_log_warn("[NOENTITY] ingoring given source name %s ...", source_name);
2607 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2613 if (direct_on_input_idx != PA_INVALID_INDEX) {
2615 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2616 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2622 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2623 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2624 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2625 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2626 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2627 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2628 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2629 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2630 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2631 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0) |
2632 (passthrough ? PA_SOURCE_OUTPUT_PASSTHROUGH : 0);
2634 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);
2635 /* We no longer own the formats idxset */
2638 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2640 reply = reply_new(tag);
2641 pa_tagstruct_putu32(reply, s->index);
2642 pa_assert(s->source_output);
2643 pa_tagstruct_putu32(reply, s->source_output->index);
2645 if (c->version >= 9) {
2646 /* Since 0.9 we support sending the buffer metrics back to the client */
2648 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2649 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2652 if (c->version >= 12) {
2653 /* Since 0.9.8 we support sending the chosen sample
2654 * spec/channel map/device/suspend status back to the
2657 pa_tagstruct_put_sample_spec(reply, &ss);
2658 pa_tagstruct_put_channel_map(reply, &map);
2660 pa_tagstruct_putu32(reply, s->source_output->source->index);
2661 pa_tagstruct_puts(reply, s->source_output->source->name);
2663 pa_tagstruct_put_boolean(reply, s->source_output->source->state == PA_SOURCE_SUSPENDED);
2666 if (c->version >= 13)
2667 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2669 if (c->version >= 22) {
2670 /* Send back the format we negotiated */
2671 if (s->source_output->format)
2672 pa_tagstruct_put_format_info(reply, s->source_output->format);
2674 pa_format_info *f = pa_format_info_new();
2675 pa_tagstruct_put_format_info(reply, f);
2676 pa_format_info_free(f);
2680 pa_pstream_send_tagstruct(c->pstream, reply);
2684 pa_proplist_free(p);
2686 pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
2689 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2690 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2693 pa_native_connection_assert_ref(c);
2696 if (!pa_tagstruct_eof(t)) {
2701 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2702 ret = pa_core_exit(c->protocol->core, false, 0);
2703 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2705 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2707 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2710 static void setup_srbchannel(pa_native_connection *c, pa_mem_type_t shm_type) {
2711 pa_srbchannel_template srbt;
2718 pa_log_debug("Disabling srbchannel, reason: No fd passing support");
2722 if (!c->options->srbchannel) {
2723 pa_log_debug("Disabling srbchannel, reason: Must be enabled by module parameter");
2727 if (c->version < 30) {
2728 pa_log_debug("Disabling srbchannel, reason: Protocol too old");
2732 if (!pa_pstream_get_shm(c->pstream)) {
2733 pa_log_debug("Disabling srbchannel, reason: No SHM support");
2737 if (c->rw_mempool) {
2738 pa_log_debug("Ignoring srbchannel setup, reason: received COMMAND_AUTH "
2743 if (!(c->rw_mempool = pa_mempool_new(shm_type, c->protocol->core->shm_size, true))) {
2744 pa_log_warn("Disabling srbchannel, reason: Failed to allocate shared "
2745 "writable memory pool.");
2749 if (shm_type == PA_MEM_TYPE_SHARED_MEMFD) {
2751 if (pa_pstream_register_memfd_mempool(c->pstream, c->rw_mempool, &reason)) {
2752 pa_log_warn("Disabling srbchannel, reason: Failed to register memfd mempool: %s", reason);
2756 pa_mempool_set_is_remote_writable(c->rw_mempool, true);
2758 srb = pa_srbchannel_new(c->protocol->core->mainloop, c->rw_mempool);
2760 pa_log_debug("Failed to create srbchannel");
2763 pa_log_debug("Enabling srbchannel...");
2764 pa_srbchannel_export(srb, &srbt);
2766 /* Send enable command to client */
2767 t = pa_tagstruct_new();
2768 pa_tagstruct_putu32(t, PA_COMMAND_ENABLE_SRBCHANNEL);
2769 pa_tagstruct_putu32(t, (size_t) srb); /* tag */
2770 fdlist[0] = srbt.readfd;
2771 fdlist[1] = srbt.writefd;
2772 pa_pstream_send_tagstruct_with_fds(c->pstream, t, 2, fdlist, false);
2774 /* Send ringbuffer memblock to client */
2775 mc.memblock = srbt.memblock;
2777 mc.length = pa_memblock_get_length(srbt.memblock);
2778 pa_pstream_send_memblock(c->pstream, 0, 0, 0, &mc);
2780 c->srbpending = srb;
2784 if (c->rw_mempool) {
2785 pa_mempool_unref(c->rw_mempool);
2786 c->rw_mempool = NULL;
2790 static void command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2791 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2793 if (tag != (uint32_t) (size_t) c->srbpending) {
2798 pa_log_debug("Client enabled srbchannel.");
2799 pa_pstream_set_srbchannel(c->pstream, c->srbpending);
2800 c->srbpending = NULL;
2803 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2804 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2806 bool memfd_on_remote = false, do_memfd = false;
2807 pa_tagstruct *reply;
2808 pa_mem_type_t shm_type;
2809 bool shm_on_remote = false, do_shm;
2811 pa_native_connection_assert_ref(c);
2814 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2815 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2816 !pa_tagstruct_eof(t)) {
2821 /* Minimum supported version */
2822 if (c->version < 8) {
2823 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2827 /* Starting with protocol version 13 the MSB of the version tag
2828 reflects if shm is available for this pa_native_connection or
2830 if ((c->version & PA_PROTOCOL_VERSION_MASK) >= 13) {
2831 shm_on_remote = !!(c->version & PA_PROTOCOL_FLAG_SHM);
2833 /* Starting with protocol version 31, the second MSB of the version
2834 * tag reflects whether memfd is supported on the other PA end. */
2835 if ((c->version & PA_PROTOCOL_VERSION_MASK) >= 31)
2836 memfd_on_remote = !!(c->version & PA_PROTOCOL_FLAG_MEMFD);
2838 /* Reserve the two most-significant _bytes_ of the version tag
2840 c->version &= PA_PROTOCOL_VERSION_MASK;
2843 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2845 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2847 if (!c->authorized) {
2848 bool success = false;
2851 const pa_creds *creds;
2853 if ((creds = pa_pdispatch_creds(pd))) {
2854 if (creds->uid == getuid())
2856 else if (c->options->auth_group) {
2860 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2861 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2862 else if (gid == creds->gid)
2866 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2867 pa_log_warn("Failed to check group membership.");
2873 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2874 (unsigned long) creds->uid,
2875 (unsigned long) creds->gid,
2880 if (!success && c->options->auth_cookie) {
2883 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2884 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2889 pa_log_warn("Denied access to client with invalid authentication data.");
2890 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2894 c->authorized = true;
2895 if (c->auth_timeout_event) {
2896 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2897 c->auth_timeout_event = NULL;
2901 /* Enable shared memory and memfd support if possible */
2903 pa_mempool_is_shared(c->protocol->core->mempool) &&
2906 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2909 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2914 /* Only enable SHM if both sides are owned by the same
2915 * user. This is a security measure because otherwise data
2916 * private to the user might leak. */
2918 const pa_creds *creds;
2919 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2924 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2925 pa_pstream_enable_shm(c->pstream, do_shm);
2927 /* Do not declare memfd support for 9.0 client libraries (protocol v31).
2929 * Although they support memfd transport, such 9.0 clients has an iochannel
2930 * bug that would break memfd audio if they're run in 32-bit mode over a
2931 * 64-bit kernel. Thus influence them to use the POSIX shared memory model
2932 * instead. Check commit 451d1d676237c81 for further details. */
2934 c->version >= 32 && do_shm && pa_mempool_is_memfd_backed(c->protocol->core->mempool);
2936 shm_type = PA_MEM_TYPE_PRIVATE;
2938 if (do_memfd && memfd_on_remote) {
2939 pa_pstream_enable_memfd(c->pstream);
2940 shm_type = PA_MEM_TYPE_SHARED_MEMFD;
2942 shm_type = PA_MEM_TYPE_SHARED_POSIX;
2944 pa_log_debug("Memfd possible: %s", pa_yes_no(pa_memfd_is_locally_supported()));
2945 pa_log_debug("Negotiated SHM type: %s", pa_mem_type_to_string(shm_type));
2948 reply = reply_new(tag);
2949 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0) |
2950 (do_memfd ? 0x40000000 : 0));
2954 /* SHM support is only enabled after both sides made sure they are the same user. */
2958 ucred.uid = getuid();
2959 ucred.gid = getgid();
2961 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2964 pa_pstream_send_tagstruct(c->pstream, reply);
2967 /* The client enables memfd transport on its pstream only after
2968 * inspecting our version flags to see if we support memfds too.
2970 * Thus register any pools after sending the server's version
2971 * flags and _never_ before it. */
2972 if (shm_type == PA_MEM_TYPE_SHARED_MEMFD) {
2975 if (pa_pstream_register_memfd_mempool(c->pstream, c->protocol->core->mempool, &reason))
2976 pa_log("Failed to register memfd mempool. Reason: %s", reason);
2979 setup_srbchannel(c, shm_type);
2982 static void command_register_memfd_shmid(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2983 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2985 pa_native_connection_assert_ref(c);
2988 if (pa_common_command_register_memfd_shmid(c->pstream, pd, c->version, command, t))
2992 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2993 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2994 const char *name = NULL;
2996 pa_tagstruct *reply;
2998 pa_native_connection_assert_ref(c);
3001 p = pa_proplist_new();
3003 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
3004 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
3005 !pa_tagstruct_eof(t)) {
3008 pa_proplist_free(p);
3013 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
3014 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
3015 pa_proplist_free(p);
3019 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
3020 pa_proplist_free(p);
3022 reply = reply_new(tag);
3024 if (c->version >= 13)
3025 pa_tagstruct_putu32(reply, c->client->index);
3027 pa_pstream_send_tagstruct(c->pstream, reply);
3030 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3031 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3033 uint32_t idx = PA_IDXSET_INVALID;
3035 pa_native_connection_assert_ref(c);
3038 if (pa_tagstruct_gets(t, &name) < 0 ||
3039 !pa_tagstruct_eof(t)) {
3044 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3045 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);
3047 if (command == PA_COMMAND_LOOKUP_SINK) {
3049 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
3053 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
3054 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
3055 idx = source->index;
3058 if (idx == PA_IDXSET_INVALID)
3059 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3061 pa_tagstruct *reply;
3062 reply = reply_new(tag);
3063 pa_tagstruct_putu32(reply, idx);
3064 pa_pstream_send_tagstruct(c->pstream, reply);
3068 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3069 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3073 pa_native_connection_assert_ref(c);
3076 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3077 !pa_tagstruct_eof(t)) {
3082 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3083 s = pa_idxset_get_by_index(c->output_streams, idx);
3084 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3085 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3087 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);
3090 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3091 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3092 pa_tagstruct *reply;
3093 const pa_mempool_stat *stat;
3095 pa_native_connection_assert_ref(c);
3098 if (!pa_tagstruct_eof(t)) {
3103 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3105 stat = pa_mempool_get_stat(c->protocol->core->mempool);
3107 reply = reply_new(tag);
3108 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
3109 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
3110 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
3111 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
3112 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
3113 pa_pstream_send_tagstruct(c->pstream, reply);
3116 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3117 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3118 pa_tagstruct *reply;
3120 struct timeval tv, now;
3123 pa_native_connection_assert_ref(c);
3126 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3127 pa_tagstruct_get_timeval(t, &tv) < 0 ||
3128 !pa_tagstruct_eof(t)) {
3133 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3134 s = pa_idxset_get_by_index(c->output_streams, idx);
3135 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3136 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3138 /* Get an atomic snapshot of all timing parameters */
3139 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);
3141 reply = reply_new(tag);
3142 pa_tagstruct_put_usec(reply,
3143 s->current_sink_latency +
3144 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
3145 pa_tagstruct_put_usec(reply, 0);
3146 pa_tagstruct_put_boolean(reply,
3147 s->playing_for > 0 &&
3148 s->sink_input->sink->state == PA_SINK_RUNNING &&
3149 s->sink_input->state == PA_SINK_INPUT_RUNNING);
3150 pa_tagstruct_put_timeval(reply, &tv);
3151 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
3152 pa_tagstruct_puts64(reply, s->write_index);
3153 pa_tagstruct_puts64(reply, s->read_index);
3155 if (c->version >= 13) {
3156 pa_tagstruct_putu64(reply, s->underrun_for);
3157 pa_tagstruct_putu64(reply, s->playing_for);
3160 pa_pstream_send_tagstruct(c->pstream, reply);
3163 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3164 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3165 pa_tagstruct *reply;
3167 struct timeval tv, now;
3170 pa_native_connection_assert_ref(c);
3173 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3174 pa_tagstruct_get_timeval(t, &tv) < 0 ||
3175 !pa_tagstruct_eof(t)) {
3180 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3181 s = pa_idxset_get_by_index(c->record_streams, idx);
3182 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3184 /* Get an atomic snapshot of all timing parameters */
3185 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);
3187 reply = reply_new(tag);
3188 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
3189 pa_tagstruct_put_usec(reply,
3190 s->current_source_latency +
3191 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->sample_spec));
3192 pa_tagstruct_put_boolean(reply,
3193 s->source_output->source->state == PA_SOURCE_RUNNING &&
3194 s->source_output->state == PA_SOURCE_OUTPUT_RUNNING);
3195 pa_tagstruct_put_timeval(reply, &tv);
3196 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
3197 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
3198 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
3199 pa_pstream_send_tagstruct(c->pstream, reply);
3202 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3203 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3206 const char *name = NULL;
3209 pa_tagstruct *reply;
3212 pa_native_connection_assert_ref(c);
3215 if (pa_tagstruct_gets(t, &name) < 0 ||
3216 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
3217 pa_tagstruct_get_channel_map(t, &map) < 0 ||
3218 pa_tagstruct_getu32(t, &length) < 0) {
3223 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3224 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
3225 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
3226 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
3227 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
3228 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
3230 p = pa_proplist_new();
3232 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
3233 !pa_tagstruct_eof(t)) {
3236 pa_proplist_free(p);
3240 if (c->version < 13)
3241 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
3243 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
3244 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
3246 if (!name || !pa_namereg_is_valid_name(name)) {
3247 pa_proplist_free(p);
3248 CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_INVALID);
3251 s = upload_stream_new(c, &ss, &map, name, length, p);
3252 pa_proplist_free(p);
3254 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
3256 reply = reply_new(tag);
3257 pa_tagstruct_putu32(reply, s->index);
3258 pa_tagstruct_putu32(reply, length);
3259 pa_pstream_send_tagstruct(c->pstream, reply);
3262 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3263 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3268 pa_native_connection_assert_ref(c);
3271 if (pa_tagstruct_getu32(t, &channel) < 0 ||
3272 !pa_tagstruct_eof(t)) {
3277 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3279 s = pa_idxset_get_by_index(c->output_streams, channel);
3280 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3281 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3283 if (!s->memchunk.memblock)
3284 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
3285 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
3286 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
3288 pa_pstream_send_simple_ack(c->pstream, tag);
3290 upload_stream_unlink(s);
3293 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3294 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3295 uint32_t sink_index;
3298 const char *name, *sink_name;
3301 pa_tagstruct *reply;
3303 pa_native_connection_assert_ref(c);
3306 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3308 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
3309 pa_tagstruct_gets(t, &sink_name) < 0 ||
3310 pa_tagstruct_getu32(t, &volume) < 0 ||
3311 pa_tagstruct_gets(t, &name) < 0) {
3316 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
3317 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
3318 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3319 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3321 if (sink_index != PA_INVALID_INDEX)
3322 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
3324 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
3326 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3328 p = pa_proplist_new();
3330 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
3331 !pa_tagstruct_eof(t)) {
3333 pa_proplist_free(p);
3337 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
3339 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
3340 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3341 pa_proplist_free(p);
3345 pa_proplist_free(p);
3347 reply = reply_new(tag);
3349 if (c->version >= 13)
3350 pa_tagstruct_putu32(reply, idx);
3352 pa_pstream_send_tagstruct(c->pstream, reply);
3355 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3356 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3359 pa_native_connection_assert_ref(c);
3362 if (pa_tagstruct_gets(t, &name) < 0 ||
3363 !pa_tagstruct_eof(t)) {
3368 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3369 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3371 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
3372 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3376 pa_pstream_send_simple_ack(c->pstream, tag);
3379 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
3382 pa_assert(original);
3386 if (c->version < 12) {
3387 /* Before protocol version 12 we didn't support S32 samples,
3388 * so we need to lie about this to the client */
3390 if (fixed->format == PA_SAMPLE_S32LE)
3391 fixed->format = PA_SAMPLE_FLOAT32LE;
3392 if (fixed->format == PA_SAMPLE_S32BE)
3393 fixed->format = PA_SAMPLE_FLOAT32BE;
3396 if (c->version < 15) {
3397 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
3398 fixed->format = PA_SAMPLE_FLOAT32LE;
3399 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
3400 fixed->format = PA_SAMPLE_FLOAT32BE;
3404 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
3405 pa_sample_spec fixed_ss;
3408 pa_sink_assert_ref(sink);
3410 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
3414 PA_TAG_U32, sink->index,
3415 PA_TAG_STRING, sink->name,
3416 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3417 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3418 PA_TAG_CHANNEL_MAP, &sink->channel_map,
3419 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
3420 PA_TAG_CVOLUME, pa_sink_get_volume(sink, false),
3421 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, false),
3422 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
3423 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
3424 PA_TAG_USEC, pa_sink_get_latency(sink),
3425 PA_TAG_STRING, sink->driver,
3426 PA_TAG_U32, sink->flags & PA_SINK_CLIENT_FLAGS_MASK,
3429 if (c->version >= 13) {
3430 pa_tagstruct_put_proplist(t, sink->proplist);
3431 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
3434 if (c->version >= 15) {
3435 pa_tagstruct_put_volume(t, sink->base_volume);
3436 if (PA_UNLIKELY(sink->state == PA_SINK_INVALID_STATE))
3437 pa_log_error("Internal sink state is invalid.");
3438 pa_tagstruct_putu32(t, sink->state);
3439 pa_tagstruct_putu32(t, sink->n_volume_steps);
3440 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
3443 if (c->version >= 16) {
3447 pa_tagstruct_putu32(t, pa_hashmap_size(sink->ports));
3449 PA_HASHMAP_FOREACH(p, sink->ports, state) {
3450 pa_tagstruct_puts(t, p->name);
3451 pa_tagstruct_puts(t, p->description);
3452 pa_tagstruct_putu32(t, p->priority);
3453 if (c->version >= 24) {
3454 pa_tagstruct_putu32(t, p->available);
3455 if (c->version >= 34) {
3456 pa_tagstruct_puts(t, p->availability_group);
3457 pa_tagstruct_putu32(t, p->type);
3462 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
3465 if (c->version >= 21) {
3468 pa_idxset *formats = pa_sink_get_formats(sink);
3470 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3471 PA_IDXSET_FOREACH(f, formats, i) {
3472 pa_tagstruct_put_format_info(t, f);
3475 pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
3479 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
3480 pa_sample_spec fixed_ss;
3483 pa_source_assert_ref(source);
3485 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
3489 PA_TAG_U32, source->index,
3490 PA_TAG_STRING, source->name,
3491 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3492 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3493 PA_TAG_CHANNEL_MAP, &source->channel_map,
3494 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
3495 PA_TAG_CVOLUME, pa_source_get_volume(source, false),
3496 PA_TAG_BOOLEAN, pa_source_get_mute(source, false),
3497 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
3498 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
3499 PA_TAG_USEC, pa_source_get_latency(source),
3500 PA_TAG_STRING, source->driver,
3501 PA_TAG_U32, source->flags & PA_SOURCE_CLIENT_FLAGS_MASK,
3504 if (c->version >= 13) {
3505 pa_tagstruct_put_proplist(t, source->proplist);
3506 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
3509 if (c->version >= 15) {
3510 pa_tagstruct_put_volume(t, source->base_volume);
3511 if (PA_UNLIKELY(source->state == PA_SOURCE_INVALID_STATE))
3512 pa_log_error("Internal source state is invalid.");
3513 pa_tagstruct_putu32(t, source->state);
3514 pa_tagstruct_putu32(t, source->n_volume_steps);
3515 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
3518 if (c->version >= 16) {
3522 pa_tagstruct_putu32(t, pa_hashmap_size(source->ports));
3524 PA_HASHMAP_FOREACH(p, source->ports, state) {
3525 pa_tagstruct_puts(t, p->name);
3526 pa_tagstruct_puts(t, p->description);
3527 pa_tagstruct_putu32(t, p->priority);
3528 if (c->version >= 24) {
3529 pa_tagstruct_putu32(t, p->available);
3530 if (c->version >= 34) {
3531 pa_tagstruct_puts(t, p->availability_group);
3532 pa_tagstruct_putu32(t, p->type);
3537 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
3540 if (c->version >= 22) {
3543 pa_idxset *formats = pa_source_get_formats(source);
3545 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3546 PA_IDXSET_FOREACH(f, formats, i) {
3547 pa_tagstruct_put_format_info(t, f);
3550 pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
3554 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
3558 pa_tagstruct_putu32(t, client->index);
3559 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
3560 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
3561 pa_tagstruct_puts(t, client->driver);
3563 if (c->version >= 13)
3564 pa_tagstruct_put_proplist(t, client->proplist);
3567 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
3570 pa_device_port *port;
3575 pa_tagstruct_putu32(t, card->index);
3576 pa_tagstruct_puts(t, card->name);
3577 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
3578 pa_tagstruct_puts(t, card->driver);
3580 pa_tagstruct_putu32(t, pa_hashmap_size(card->profiles));
3582 PA_HASHMAP_FOREACH(p, card->profiles, state) {
3583 pa_tagstruct_puts(t, p->name);
3584 pa_tagstruct_puts(t, p->description);
3585 pa_tagstruct_putu32(t, p->n_sinks);
3586 pa_tagstruct_putu32(t, p->n_sources);
3587 pa_tagstruct_putu32(t, p->priority);
3589 if (c->version >= 29)
3590 pa_tagstruct_putu32(t, (p->available != PA_AVAILABLE_NO));
3593 pa_tagstruct_puts(t, card->active_profile->name);
3594 pa_tagstruct_put_proplist(t, card->proplist);
3596 if (c->version < 26)
3599 pa_tagstruct_putu32(t, pa_hashmap_size(card->ports));
3601 PA_HASHMAP_FOREACH(port, card->ports, state) {
3604 pa_tagstruct_puts(t, port->name);
3605 pa_tagstruct_puts(t, port->description);
3606 pa_tagstruct_putu32(t, port->priority);
3607 pa_tagstruct_putu32(t, port->available);
3608 pa_tagstruct_putu8(t, port->direction);
3609 pa_tagstruct_put_proplist(t, port->proplist);
3611 pa_tagstruct_putu32(t, pa_hashmap_size(port->profiles));
3613 PA_HASHMAP_FOREACH(p, port->profiles, state2)
3614 pa_tagstruct_puts(t, p->name);
3616 if (c->version >= 27) {
3617 pa_tagstruct_puts64(t, port->latency_offset);
3618 if (c->version >= 34) {
3619 pa_tagstruct_puts(t, port->availability_group);
3620 pa_tagstruct_putu32(t, port->type);
3626 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3630 pa_tagstruct_putu32(t, module->index);
3631 pa_tagstruct_puts(t, module->name);
3632 pa_tagstruct_puts(t, module->argument);
3633 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3635 if (c->version < 15)
3636 pa_tagstruct_put_boolean(t, false); /* autoload is obsolete */
3638 if (c->version >= 15)
3639 pa_tagstruct_put_proplist(t, module->proplist);
3642 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3643 pa_sample_spec fixed_ss;
3644 pa_usec_t sink_latency;
3646 bool has_volume = false;
3649 pa_sink_input_assert_ref(s);
3651 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3653 has_volume = pa_sink_input_is_volume_readable(s);
3655 pa_sink_input_get_volume(s, &v, true);
3657 pa_cvolume_reset(&v, fixed_ss.channels);
3659 pa_tagstruct_putu32(t, s->index);
3660 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3661 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3662 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3663 pa_tagstruct_putu32(t, s->sink->index);
3664 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3665 pa_tagstruct_put_channel_map(t, &s->channel_map);
3666 pa_tagstruct_put_cvolume(t, &v);
3667 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3668 pa_tagstruct_put_usec(t, sink_latency);
3669 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3670 pa_tagstruct_puts(t, s->driver);
3671 if (c->version >= 11)
3672 pa_tagstruct_put_boolean(t, s->muted);
3673 if (c->version >= 13)
3674 pa_tagstruct_put_proplist(t, s->proplist);
3675 if (c->version >= 19)
3676 pa_tagstruct_put_boolean(t, s->state == PA_SINK_INPUT_CORKED);
3677 if (c->version >= 20) {
3678 pa_tagstruct_put_boolean(t, has_volume);
3679 pa_tagstruct_put_boolean(t, s->volume_writable);
3681 if (c->version >= 21)
3682 pa_tagstruct_put_format_info(t, s->format);
3685 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3686 pa_sample_spec fixed_ss;
3687 pa_usec_t source_latency;
3689 bool has_volume = false;
3692 pa_source_output_assert_ref(s);
3694 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3696 has_volume = pa_source_output_is_volume_readable(s);
3698 pa_source_output_get_volume(s, &v, true);
3700 pa_cvolume_reset(&v, fixed_ss.channels);
3702 pa_tagstruct_putu32(t, s->index);
3703 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3704 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3705 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3706 pa_tagstruct_putu32(t, s->source->index);
3707 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3708 pa_tagstruct_put_channel_map(t, &s->channel_map);
3709 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3710 pa_tagstruct_put_usec(t, source_latency);
3711 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3712 pa_tagstruct_puts(t, s->driver);
3713 if (c->version >= 13)
3714 pa_tagstruct_put_proplist(t, s->proplist);
3715 if (c->version >= 19)
3716 pa_tagstruct_put_boolean(t, s->state == PA_SOURCE_OUTPUT_CORKED);
3717 if (c->version >= 22) {
3718 pa_tagstruct_put_cvolume(t, &v);
3719 pa_tagstruct_put_boolean(t, s->muted);
3720 pa_tagstruct_put_boolean(t, has_volume);
3721 pa_tagstruct_put_boolean(t, s->volume_writable);
3722 pa_tagstruct_put_format_info(t, s->format);
3726 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3727 pa_sample_spec fixed_ss;
3733 if (e->memchunk.memblock)
3734 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3736 memset(&fixed_ss, 0, sizeof(fixed_ss));
3738 pa_tagstruct_putu32(t, e->index);
3739 pa_tagstruct_puts(t, e->name);
3741 if (e->volume_is_set)
3744 pa_cvolume_init(&v);
3746 pa_tagstruct_put_cvolume(t, &v);
3747 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3748 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3749 pa_tagstruct_put_channel_map(t, &e->channel_map);
3750 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3751 pa_tagstruct_put_boolean(t, e->lazy);
3752 pa_tagstruct_puts(t, e->filename);
3754 if (c->version >= 13)
3755 pa_tagstruct_put_proplist(t, e->proplist);
3758 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3759 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3761 pa_sink *sink = NULL;
3762 pa_source *source = NULL;
3763 pa_client *client = NULL;
3764 pa_card *card = NULL;
3765 pa_module *module = NULL;
3766 pa_sink_input *si = NULL;
3767 pa_source_output *so = NULL;
3768 pa_scache_entry *sce = NULL;
3769 const char *name = NULL;
3770 pa_tagstruct *reply;
3772 pa_native_connection_assert_ref(c);
3775 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3776 (command != PA_COMMAND_GET_CLIENT_INFO &&
3777 command != PA_COMMAND_GET_MODULE_INFO &&
3778 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3779 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3780 pa_tagstruct_gets(t, &name) < 0) ||
3781 !pa_tagstruct_eof(t)) {
3786 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3787 CHECK_VALIDITY(c->pstream, !name ||
3788 (command == PA_COMMAND_GET_SINK_INFO &&
3789 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3790 (command == PA_COMMAND_GET_SOURCE_INFO &&
3791 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3792 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3793 CHECK_VALIDITY(c->pstream, command == PA_COMMAND_GET_SINK_INFO ||
3794 command == PA_COMMAND_GET_SOURCE_INFO ||
3795 (idx != PA_INVALID_INDEX || name), tag, PA_ERR_INVALID);
3796 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3798 if (command == PA_COMMAND_GET_SINK_INFO) {
3799 if (idx != PA_INVALID_INDEX)
3800 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3802 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3803 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3804 if (idx != PA_INVALID_INDEX)
3805 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3807 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3808 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3809 if (idx != PA_INVALID_INDEX)
3810 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3812 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3813 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3814 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3815 else if (command == PA_COMMAND_GET_MODULE_INFO)
3816 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3817 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3818 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3819 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3820 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3822 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3823 if (idx != PA_INVALID_INDEX)
3824 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3826 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3829 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3830 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3834 reply = reply_new(tag);
3836 sink_fill_tagstruct(c, reply, sink);
3838 source_fill_tagstruct(c, reply, source);
3840 client_fill_tagstruct(c, reply, client);
3842 card_fill_tagstruct(c, reply, card);
3844 module_fill_tagstruct(c, reply, module);
3846 sink_input_fill_tagstruct(c, reply, si);
3848 source_output_fill_tagstruct(c, reply, so);
3850 scache_fill_tagstruct(c, reply, sce);
3851 pa_pstream_send_tagstruct(c->pstream, reply);
3854 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3855 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3859 pa_tagstruct *reply;
3861 pa_native_connection_assert_ref(c);
3864 if (!pa_tagstruct_eof(t)) {
3869 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3871 reply = reply_new(tag);
3873 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3874 i = c->protocol->core->sinks;
3875 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3876 i = c->protocol->core->sources;
3877 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3878 i = c->protocol->core->clients;
3879 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3880 i = c->protocol->core->cards;
3881 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3882 i = c->protocol->core->modules;
3883 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3884 i = c->protocol->core->sink_inputs;
3885 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3886 i = c->protocol->core->source_outputs;
3888 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3889 i = c->protocol->core->scache;
3893 PA_IDXSET_FOREACH(p, i, idx) {
3894 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3895 sink_fill_tagstruct(c, reply, p);
3896 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3897 source_fill_tagstruct(c, reply, p);
3898 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3899 client_fill_tagstruct(c, reply, p);
3900 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3901 card_fill_tagstruct(c, reply, p);
3902 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3903 module_fill_tagstruct(c, reply, p);
3904 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3905 sink_input_fill_tagstruct(c, reply, p);
3906 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3907 source_output_fill_tagstruct(c, reply, p);
3909 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3910 scache_fill_tagstruct(c, reply, p);
3915 pa_pstream_send_tagstruct(c->pstream, reply);
3918 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3919 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3920 pa_tagstruct *reply;
3921 pa_sample_spec fixed_ss;
3925 pa_native_connection_assert_ref(c);
3928 if (!pa_tagstruct_eof(t)) {
3933 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3935 reply = reply_new(tag);
3936 pa_tagstruct_puts(reply, PACKAGE_NAME);
3937 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3939 u = pa_get_user_name_malloc();
3940 pa_tagstruct_puts(reply, u);
3943 h = pa_get_host_name_malloc();
3944 pa_tagstruct_puts(reply, h);
3947 core = c->protocol->core;
3949 fixup_sample_spec(c, &fixed_ss, &core->default_sample_spec);
3950 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3952 pa_tagstruct_puts(reply, core->default_sink ? core->default_sink->name : NULL);
3953 pa_tagstruct_puts(reply, core->default_source ? core->default_source->name : NULL);
3955 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3957 if (c->version >= 15)
3958 pa_tagstruct_put_channel_map(reply, &core->default_channel_map);
3960 pa_pstream_send_tagstruct(c->pstream, reply);
3963 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3965 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3967 pa_native_connection_assert_ref(c);
3969 t = pa_tagstruct_new();
3970 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3971 pa_tagstruct_putu32(t, (uint32_t) -1);
3972 pa_tagstruct_putu32(t, e);
3973 pa_tagstruct_putu32(t, idx);
3974 pa_pstream_send_tagstruct(c->pstream, t);
3977 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3978 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3979 pa_subscription_mask_t m;
3981 pa_native_connection_assert_ref(c);
3984 if (pa_tagstruct_getu32(t, &m) < 0 ||
3985 !pa_tagstruct_eof(t)) {
3990 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3991 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3993 if (c->subscription)
3994 pa_subscription_free(c->subscription);
3997 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3998 pa_assert(c->subscription);
4000 c->subscription = NULL;
4002 pa_pstream_send_simple_ack(c->pstream, tag);
4005 #ifdef TIZEN_SECURITY
4006 static pid_t get_pid_to_skip(pa_sink_input *si, pa_source_output *so) {
4008 const char *pid_str = NULL;
4011 pid_str = pa_proplist_gets(si->proplist, PA_PROP_APPLICATION_PROCESS_ID);
4013 pid_str = pa_proplist_gets(so->proplist, PA_PROP_APPLICATION_PROCESS_ID);
4015 if (!pid_str || pa_atoi(pid_str, &pid) == -1)
4022 static void command_set_volume(
4029 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4032 pa_sink *sink = NULL;
4033 pa_source *source = NULL;
4034 pa_sink_input *si = NULL;
4035 pa_source_output *so = NULL;
4036 const char *name = NULL;
4037 const char *client_name;
4039 pa_native_connection_assert_ref(c);
4042 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4043 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
4044 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
4045 pa_tagstruct_get_cvolume(t, &volume) ||
4046 !pa_tagstruct_eof(t)) {
4051 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4052 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);
4053 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
4054 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
4057 case PA_COMMAND_SET_SINK_VOLUME:
4058 if (idx != PA_INVALID_INDEX)
4059 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4061 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4064 case PA_COMMAND_SET_SOURCE_VOLUME:
4065 if (idx != PA_INVALID_INDEX)
4066 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4068 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4071 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
4072 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4075 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME:
4076 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4080 pa_assert_not_reached();
4083 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
4084 #ifdef TIZEN_SECURITY
4085 CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), VOLUME_SET_PRIVILEGE, get_pid_to_skip(si, so)),
4086 tag, PA_ERR_ACCESS);
4088 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
4091 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
4093 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
4094 pa_sink_set_volume(sink, &volume, true, true);
4095 } else if (source) {
4096 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
4098 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
4099 pa_source_set_volume(source, &volume, true, true);
4101 CHECK_VALIDITY(c->pstream, si->volume_writable, tag, PA_ERR_BADSTATE);
4102 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
4104 pa_log_debug("Client %s changes volume of sink input %s.",
4106 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
4107 pa_sink_input_set_volume(si, &volume, true, true);
4109 CHECK_VALIDITY(c->pstream, so->volume_writable, tag, PA_ERR_BADSTATE);
4110 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &so->sample_spec), tag, PA_ERR_INVALID);
4112 pa_log_debug("Client %s changes volume of source output %s.",
4114 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
4115 pa_source_output_set_volume(so, &volume, true, true);
4118 pa_pstream_send_simple_ack(c->pstream, tag);
4121 static void command_set_mute(
4128 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4131 pa_sink *sink = NULL;
4132 pa_source *source = NULL;
4133 pa_sink_input *si = NULL;
4134 pa_source_output *so = NULL;
4135 const char *name = NULL, *client_name;
4137 pa_native_connection_assert_ref(c);
4140 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4141 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
4142 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
4143 pa_tagstruct_get_boolean(t, &mute) ||
4144 !pa_tagstruct_eof(t)) {
4149 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4150 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);
4151 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
4152 #ifdef TIZEN_SECURITY
4153 CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), VOLUME_SET_PRIVILEGE, -1),
4154 tag, PA_ERR_ACCESS);
4159 case PA_COMMAND_SET_SINK_MUTE:
4160 if (idx != PA_INVALID_INDEX)
4161 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4163 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4167 case PA_COMMAND_SET_SOURCE_MUTE:
4168 if (idx != PA_INVALID_INDEX)
4169 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4171 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4175 case PA_COMMAND_SET_SINK_INPUT_MUTE:
4176 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4179 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE:
4180 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4184 pa_assert_not_reached();
4187 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
4189 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
4192 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
4193 pa_sink_set_mute(sink, mute, true);
4194 } else if (source) {
4195 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
4196 pa_source_set_mute(source, mute, true);
4198 pa_log_debug("Client %s changes mute of sink input %s.",
4200 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
4201 pa_sink_input_set_mute(si, mute, true);
4203 pa_log_debug("Client %s changes mute of source output %s.",
4205 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
4206 pa_source_output_set_mute(so, mute, true);
4209 pa_pstream_send_simple_ack(c->pstream, tag);
4212 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4213 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4218 pa_native_connection_assert_ref(c);
4221 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4222 pa_tagstruct_get_boolean(t, &b) < 0 ||
4223 !pa_tagstruct_eof(t)) {
4228 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4229 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4230 s = pa_idxset_get_by_index(c->output_streams, idx);
4231 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4232 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4234 pa_sink_input_cork(s->sink_input, b);
4237 s->is_underrun = true;
4239 pa_pstream_send_simple_ack(c->pstream, tag);
4242 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4243 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4247 pa_native_connection_assert_ref(c);
4250 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4251 !pa_tagstruct_eof(t)) {
4256 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4257 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4258 s = pa_idxset_get_by_index(c->output_streams, idx);
4259 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4260 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4263 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
4264 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
4267 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
4268 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
4271 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
4272 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
4276 pa_assert_not_reached();
4279 pa_pstream_send_simple_ack(c->pstream, tag);
4282 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4283 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4288 pa_native_connection_assert_ref(c);
4291 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4292 pa_tagstruct_get_boolean(t, &b) < 0 ||
4293 !pa_tagstruct_eof(t)) {
4298 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4299 s = pa_idxset_get_by_index(c->record_streams, idx);
4300 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4302 pa_source_output_cork(s->source_output, b);
4303 pa_memblockq_prebuf_force(s->memblockq);
4304 pa_pstream_send_simple_ack(c->pstream, tag);
4307 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4308 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4312 pa_native_connection_assert_ref(c);
4315 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4316 !pa_tagstruct_eof(t)) {
4321 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4322 s = pa_idxset_get_by_index(c->record_streams, idx);
4323 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4325 pa_memblockq_flush_read(s->memblockq);
4326 pa_pstream_send_simple_ack(c->pstream, tag);
4329 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4330 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4333 pa_tagstruct *reply;
4335 pa_native_connection_assert_ref(c);
4338 memset(&a, 0, sizeof(a));
4340 if (pa_tagstruct_getu32(t, &idx) < 0) {
4345 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4347 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
4349 bool adjust_latency = false, early_requests = false;
4351 s = pa_idxset_get_by_index(c->output_streams, idx);
4352 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4353 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4355 if (pa_tagstruct_get(
4357 PA_TAG_U32, &a.maxlength,
4358 PA_TAG_U32, &a.tlength,
4359 PA_TAG_U32, &a.prebuf,
4360 PA_TAG_U32, &a.minreq,
4361 PA_TAG_INVALID) < 0 ||
4362 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
4363 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
4364 !pa_tagstruct_eof(t)) {
4369 s->adjust_latency = adjust_latency;
4370 s->early_requests = early_requests;
4371 s->buffer_attr_req = a;
4373 fix_playback_buffer_attr(s);
4374 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);
4376 reply = reply_new(tag);
4377 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
4378 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
4379 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
4380 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
4382 if (c->version >= 13)
4383 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
4387 bool adjust_latency = false, early_requests = false;
4388 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
4390 s = pa_idxset_get_by_index(c->record_streams, idx);
4391 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4393 if (pa_tagstruct_get(
4395 PA_TAG_U32, &a.maxlength,
4396 PA_TAG_U32, &a.fragsize,
4397 PA_TAG_INVALID) < 0 ||
4398 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
4399 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
4400 !pa_tagstruct_eof(t)) {
4405 s->adjust_latency = adjust_latency;
4406 s->early_requests = early_requests;
4407 s->buffer_attr_req = a;
4409 fix_record_buffer_attr_pre(s);
4410 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
4411 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
4412 fix_record_buffer_attr_post(s);
4414 reply = reply_new(tag);
4415 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
4416 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
4418 if (c->version >= 13)
4419 pa_tagstruct_put_usec(reply, s->configured_source_latency);
4422 pa_pstream_send_tagstruct(c->pstream, reply);
4425 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4426 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4430 pa_native_connection_assert_ref(c);
4433 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4434 pa_tagstruct_getu32(t, &rate) < 0 ||
4435 !pa_tagstruct_eof(t)) {
4440 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4441 CHECK_VALIDITY(c->pstream, pa_sample_rate_valid(rate), tag, PA_ERR_INVALID);
4443 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
4446 s = pa_idxset_get_by_index(c->output_streams, idx);
4447 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4448 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4450 pa_sink_input_set_rate(s->sink_input, rate);
4454 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
4456 s = pa_idxset_get_by_index(c->record_streams, idx);
4457 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4459 pa_source_output_set_rate(s->source_output, rate);
4462 pa_pstream_send_simple_ack(c->pstream, tag);
4465 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4466 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4471 pa_native_connection_assert_ref(c);
4474 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4476 p = pa_proplist_new();
4478 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
4480 if (pa_tagstruct_getu32(t, &mode) < 0 ||
4481 pa_tagstruct_get_proplist(t, p) < 0 ||
4482 !pa_tagstruct_eof(t)) {
4484 pa_proplist_free(p);
4490 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4491 pa_tagstruct_getu32(t, &mode) < 0 ||
4492 pa_tagstruct_get_proplist(t, p) < 0 ||
4493 !pa_tagstruct_eof(t)) {
4495 pa_proplist_free(p);
4500 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
4501 pa_proplist_free(p);
4502 CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_INVALID);
4505 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
4508 s = pa_idxset_get_by_index(c->output_streams, idx);
4509 if (!s || !playback_stream_isinstance(s)) {
4510 pa_proplist_free(p);
4511 CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_NOENTITY);
4513 pa_sink_input_update_proplist(s->sink_input, mode, p);
4515 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
4518 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
4519 pa_proplist_free(p);
4520 CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_NOENTITY);
4522 pa_source_output_update_proplist(s->source_output, mode, p);
4525 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
4527 pa_client_update_proplist(c->client, mode, p);
4530 pa_pstream_send_simple_ack(c->pstream, tag);
4531 pa_proplist_free(p);
4534 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4535 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4537 unsigned changed = 0;
4539 pa_strlist *l = NULL;
4541 pa_native_connection_assert_ref(c);
4544 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4546 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
4548 if (pa_tagstruct_getu32(t, &idx) < 0) {
4554 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4557 s = pa_idxset_get_by_index(c->output_streams, idx);
4558 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4559 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4561 p = s->sink_input->proplist;
4563 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4566 s = pa_idxset_get_by_index(c->record_streams, idx);
4567 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4569 p = s->source_output->proplist;
4571 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4573 p = c->client->proplist;
4579 if (pa_tagstruct_gets(t, &k) < 0) {
4588 l = pa_strlist_prepend(l, k);
4591 if (!pa_tagstruct_eof(t)) {
4600 l = pa_strlist_pop(l, &z);
4605 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
4609 pa_pstream_send_simple_ack(c->pstream, tag);
4612 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4615 s = pa_idxset_get_by_index(c->output_streams, idx);
4616 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
4618 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4621 s = pa_idxset_get_by_index(c->record_streams, idx);
4622 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
4625 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4626 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
4631 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4632 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4635 pa_native_connection_assert_ref(c);
4638 if (pa_tagstruct_gets(t, &s) < 0 ||
4639 !pa_tagstruct_eof(t)) {
4644 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4645 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
4647 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
4650 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
4651 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4653 pa_core_set_configured_default_source(c->protocol->core, source->name);
4656 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
4658 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
4659 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4661 pa_core_set_configured_default_sink(c->protocol->core, sink->name);
4664 pa_pstream_send_simple_ack(c->pstream, tag);
4667 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4668 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4672 pa_native_connection_assert_ref(c);
4675 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4676 pa_tagstruct_gets(t, &name) < 0 ||
4677 !pa_tagstruct_eof(t)) {
4682 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4683 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
4685 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
4688 s = pa_idxset_get_by_index(c->output_streams, idx);
4689 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4690 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4692 pa_sink_input_set_property(s->sink_input, PA_PROP_MEDIA_NAME, name);
4696 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4698 s = pa_idxset_get_by_index(c->record_streams, idx);
4699 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4701 pa_source_output_set_property(s->source_output, PA_PROP_MEDIA_NAME, name);
4704 pa_pstream_send_simple_ack(c->pstream, tag);
4707 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4708 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4711 pa_native_connection_assert_ref(c);
4714 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4715 !pa_tagstruct_eof(t)) {
4720 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4722 if (command == PA_COMMAND_KILL_CLIENT) {
4725 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4726 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4728 pa_native_connection_ref(c);
4729 pa_client_kill(client);
4731 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4734 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4735 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4737 pa_native_connection_ref(c);
4738 pa_sink_input_kill(s);
4740 pa_source_output *s;
4742 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4744 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4745 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4747 pa_native_connection_ref(c);
4748 pa_source_output_kill(s);
4751 pa_pstream_send_simple_ack(c->pstream, tag);
4752 pa_native_connection_unref(c);
4755 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4756 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4758 const char *name, *argument;
4759 pa_tagstruct *reply;
4761 pa_native_connection_assert_ref(c);
4764 if (pa_tagstruct_gets(t, &name) < 0 ||
4765 pa_tagstruct_gets(t, &argument) < 0 ||
4766 !pa_tagstruct_eof(t)) {
4771 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4772 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4773 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4775 if (pa_module_load(&m, c->protocol->core, name, argument) < 0) {
4776 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4780 reply = reply_new(tag);
4781 pa_tagstruct_putu32(reply, m->index);
4782 pa_pstream_send_tagstruct(c->pstream, reply);
4785 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4786 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4790 pa_native_connection_assert_ref(c);
4793 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4794 !pa_tagstruct_eof(t)) {
4799 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4800 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4801 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4803 pa_module_unload_request(m, false);
4804 pa_pstream_send_simple_ack(c->pstream, tag);
4807 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4808 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4809 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4810 const char *name_device = NULL;
4812 pa_native_connection_assert_ref(c);
4815 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4816 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4817 pa_tagstruct_gets(t, &name_device) < 0 ||
4818 !pa_tagstruct_eof(t)) {
4823 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4824 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4826 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);
4827 CHECK_VALIDITY(c->pstream, (idx_device != PA_INVALID_INDEX) ^ (name_device != NULL), tag, PA_ERR_INVALID);
4829 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4830 pa_sink_input *si = NULL;
4831 pa_sink *sink = NULL;
4833 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4835 if (idx_device != PA_INVALID_INDEX)
4836 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4838 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4840 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4842 if (pa_sink_input_move_to(si, sink, true) < 0) {
4843 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4847 pa_source_output *so = NULL;
4850 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4852 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4854 if (idx_device != PA_INVALID_INDEX)
4855 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4857 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4859 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4861 if (pa_source_output_move_to(so, source, true) < 0) {
4862 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4867 pa_pstream_send_simple_ack(c->pstream, tag);
4870 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4871 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4872 uint32_t idx = PA_INVALID_INDEX;
4873 const char *name = NULL;
4876 pa_native_connection_assert_ref(c);
4879 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4880 pa_tagstruct_gets(t, &name) < 0 ||
4881 pa_tagstruct_get_boolean(t, &b) < 0 ||
4882 !pa_tagstruct_eof(t)) {
4887 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4888 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);
4889 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
4891 if (command == PA_COMMAND_SUSPEND_SINK) {
4893 if (idx == PA_INVALID_INDEX && name && !*name) {
4895 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4897 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4898 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4902 pa_sink *sink = NULL;
4904 if (idx != PA_INVALID_INDEX)
4905 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4907 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4909 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4911 pa_log_debug("%s of sink %s requested by client %" PRIu32 ".",
4912 b ? "Suspending" : "Resuming", sink->name, c->client->index);
4914 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4915 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4921 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4923 if (idx == PA_INVALID_INDEX && name && !*name) {
4925 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4927 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4928 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4935 if (idx != PA_INVALID_INDEX)
4936 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4938 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4940 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4942 pa_log_debug("%s of source %s requested by client %" PRIu32 ".",
4943 b ? "Suspending" : "Resuming", source->name, c->client->index);
4945 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4946 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4952 pa_pstream_send_simple_ack(c->pstream, tag);
4955 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4956 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4957 uint32_t idx = PA_INVALID_INDEX;
4958 const char *name = NULL;
4960 pa_native_protocol_ext_cb_t cb;
4962 pa_native_connection_assert_ref(c);
4965 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4966 pa_tagstruct_gets(t, &name) < 0) {
4971 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4972 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4973 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
4975 if (idx != PA_INVALID_INDEX)
4976 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4978 PA_IDXSET_FOREACH(m, c->protocol->core->modules, idx)
4979 if (pa_streq(name, m->name))
4982 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4983 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4985 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4986 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4988 if (cb(c->protocol, m, c, tag, t) < 0)
4992 /* Send message to an object which registered a handler. Result must be returned as string. */
4993 static void command_send_object_message(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4994 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4995 const char *object_path = NULL;
4996 const char *message = NULL;
4997 const char *message_parameters = NULL;
4998 const char *client_name;
4999 char *response = NULL;
5001 pa_tagstruct *reply;
5003 pa_native_connection_assert_ref(c);
5006 if (pa_tagstruct_gets(t, &object_path) < 0 ||
5007 pa_tagstruct_gets(t, &message) < 0 ||
5008 pa_tagstruct_gets(t, &message_parameters) < 0 ||
5009 !pa_tagstruct_eof(t)) {
5014 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5015 CHECK_VALIDITY(c->pstream, object_path != NULL, tag, PA_ERR_INVALID);
5016 CHECK_VALIDITY(c->pstream, pa_utf8_valid(object_path), tag, PA_ERR_INVALID);
5017 CHECK_VALIDITY(c->pstream, message != NULL, tag, PA_ERR_INVALID);
5018 CHECK_VALIDITY(c->pstream, pa_utf8_valid(message), tag, PA_ERR_INVALID);
5019 if (message_parameters)
5020 CHECK_VALIDITY(c->pstream, pa_utf8_valid(message_parameters), tag, PA_ERR_INVALID);
5022 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
5023 pa_log_debug("Client %s sent message %s to path %s", client_name, message, object_path);
5024 if (message_parameters)
5025 pa_log_debug("Message parameters: %s", message_parameters);
5027 ret = pa_message_handler_send_message(c->protocol->core, object_path, message, message_parameters, &response);
5030 pa_pstream_send_error(c->pstream, tag, -ret);
5034 reply = reply_new(tag);
5035 pa_tagstruct_puts(reply, response);
5038 pa_pstream_send_tagstruct(c->pstream, reply);
5041 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5042 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5043 uint32_t idx = PA_INVALID_INDEX;
5044 const char *name = NULL, *profile_name = NULL;
5045 pa_card *card = NULL;
5046 pa_card_profile *profile;
5049 pa_native_connection_assert_ref(c);
5052 if (pa_tagstruct_getu32(t, &idx) < 0 ||
5053 pa_tagstruct_gets(t, &name) < 0 ||
5054 pa_tagstruct_gets(t, &profile_name) < 0 ||
5055 !pa_tagstruct_eof(t)) {
5060 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5061 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
5062 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
5063 CHECK_VALIDITY(c->pstream, profile_name, tag, PA_ERR_INVALID);
5065 if (idx != PA_INVALID_INDEX)
5066 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
5068 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
5070 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
5072 profile = pa_hashmap_get(card->profiles, profile_name);
5074 CHECK_VALIDITY(c->pstream, profile, tag, PA_ERR_NOENTITY);
5076 pa_log_info("Application \"%s\" requests card profile change. card = %s, profile = %s",
5077 pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_NAME)),
5081 if ((ret = pa_card_set_profile(card, profile, true)) < 0) {
5082 pa_pstream_send_error(c->pstream, tag, -ret);
5086 pa_pstream_send_simple_ack(c->pstream, tag);
5089 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5090 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5091 uint32_t idx = PA_INVALID_INDEX;
5092 const char *name = NULL, *port = NULL;
5095 pa_native_connection_assert_ref(c);
5098 if (pa_tagstruct_getu32(t, &idx) < 0 ||
5099 pa_tagstruct_gets(t, &name) < 0 ||
5100 pa_tagstruct_gets(t, &port) < 0 ||
5101 !pa_tagstruct_eof(t)) {
5106 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5107 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);
5108 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
5109 CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_INVALID);
5111 if (command == PA_COMMAND_SET_SINK_PORT) {
5114 if (idx != PA_INVALID_INDEX)
5115 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
5117 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
5119 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
5121 if ((ret = pa_sink_set_port(sink, port, true)) < 0) {
5122 pa_pstream_send_error(c->pstream, tag, -ret);
5128 pa_assert(command == PA_COMMAND_SET_SOURCE_PORT);
5130 if (idx != PA_INVALID_INDEX)
5131 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
5133 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
5135 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
5137 if ((ret = pa_source_set_port(source, port, true)) < 0) {
5138 pa_pstream_send_error(c->pstream, tag, -ret);
5143 pa_pstream_send_simple_ack(c->pstream, tag);
5146 static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5147 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5148 const char *port_name, *card_name;
5149 uint32_t idx = PA_INVALID_INDEX;
5151 pa_card *card = NULL;
5152 pa_device_port *port = NULL;
5154 pa_native_connection_assert_ref(c);
5157 if (pa_tagstruct_getu32(t, &idx) < 0 ||
5158 pa_tagstruct_gets(t, &card_name) < 0 ||
5159 pa_tagstruct_gets(t, &port_name) < 0 ||
5160 pa_tagstruct_gets64(t, &offset) < 0 ||
5161 !pa_tagstruct_eof(t)) {
5166 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5167 CHECK_VALIDITY(c->pstream, !card_name || pa_namereg_is_valid_name(card_name), tag, PA_ERR_INVALID);
5168 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (card_name != NULL), tag, PA_ERR_INVALID);
5169 CHECK_VALIDITY(c->pstream, port_name, tag, PA_ERR_INVALID);
5171 if (idx != PA_INVALID_INDEX)
5172 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
5174 card = pa_namereg_get(c->protocol->core, card_name, PA_NAMEREG_CARD);
5176 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
5178 port = pa_hashmap_get(card->ports, port_name);
5179 CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_NOENTITY);
5181 pa_device_port_set_latency_offset(port, offset);
5183 pa_pstream_send_simple_ack(c->pstream, tag);
5186 #ifdef TIZEN_PCM_DUMP
5187 static void command_set_pcm_dump(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5188 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5190 bool dump_type_enable;
5192 pa_native_connection_assert_ref(c);
5195 if (pa_tagstruct_getu32(t, &dump_type) < 0 ||
5196 pa_tagstruct_get_boolean(t, &dump_type_enable) < 0 ||
5197 !pa_tagstruct_eof(t)) {
5202 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5204 if (dump_type_enable)
5205 c->protocol->core->pcm_dump |= dump_type;
5207 c->protocol->core->pcm_dump &= ~dump_type;
5209 pa_pstream_send_simple_ack(c->pstream, tag);
5212 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
5213 [PA_COMMAND_ERROR] = NULL,
5214 [PA_COMMAND_TIMEOUT] = NULL,
5215 [PA_COMMAND_REPLY] = NULL,
5216 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
5217 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
5218 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
5219 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
5220 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
5221 [PA_COMMAND_AUTH] = command_auth,
5222 [PA_COMMAND_REQUEST] = NULL,
5223 [PA_COMMAND_EXIT] = command_exit,
5224 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
5225 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
5226 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
5227 [PA_COMMAND_STAT] = command_stat,
5228 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
5229 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
5230 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
5231 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
5232 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
5233 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
5234 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
5235 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
5236 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
5237 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
5238 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
5239 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
5240 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
5241 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
5242 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
5243 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
5244 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
5245 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
5246 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
5247 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
5248 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
5249 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
5250 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
5251 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
5252 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
5254 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
5255 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
5256 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
5257 [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = command_set_volume,
5259 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
5260 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
5261 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
5262 [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = command_set_mute,
5264 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
5265 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
5267 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
5268 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
5269 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
5270 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
5272 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
5273 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
5275 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
5276 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
5277 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
5278 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
5279 [PA_COMMAND_KILL_CLIENT] = command_kill,
5280 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
5281 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
5282 [PA_COMMAND_LOAD_MODULE] = command_load_module,
5283 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
5285 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
5286 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
5287 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
5288 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
5290 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
5291 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
5293 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
5294 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
5296 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
5297 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
5299 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
5300 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
5301 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
5303 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
5304 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
5305 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
5307 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
5309 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
5310 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
5312 [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = command_set_port_latency_offset,
5314 [PA_COMMAND_ENABLE_SRBCHANNEL] = command_enable_srbchannel,
5316 [PA_COMMAND_REGISTER_MEMFD_SHMID] = command_register_memfd_shmid,
5318 [PA_COMMAND_SEND_OBJECT_MESSAGE] = command_send_object_message,
5320 [PA_COMMAND_EXTENSION] = command_extension,
5321 #ifdef TIZEN_PCM_DUMP
5322 [PA_COMMAND_SET_PCM_DUMP] = command_set_pcm_dump,
5324 #ifdef TIZEN_SECURITY
5325 [PA_COMMAND_CHECK_PRIVILEGE] = command_check_privilege,
5329 /*** pstream callbacks ***/
5331 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, pa_cmsg_ancil_data *ancil_data, void *userdata) {
5332 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5336 pa_native_connection_assert_ref(c);
5338 if (pa_pdispatch_run(c->pdispatch, packet, ancil_data, c) < 0) {
5339 pa_log("invalid packet.");
5340 native_connection_unlink(c);
5344 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) {
5345 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5346 output_stream *stream;
5350 pa_native_connection_assert_ref(c);
5352 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
5353 pa_log_debug("Client sent block for invalid stream.");
5358 #ifdef PROTOCOL_NATIVE_DEBUG
5359 pa_log("got %lu bytes from client", (unsigned long) chunk->length);
5362 if (playback_stream_isinstance(stream)) {
5363 playback_stream *ps = PLAYBACK_STREAM(stream);
5365 size_t frame_size = pa_frame_size(&ps->sink_input->sample_spec);
5366 if (chunk->index % frame_size != 0 || chunk->length % frame_size != 0) {
5367 pa_log_warn("Client sent non-aligned memblock: index %d, length %d, frame size: %d",
5368 (int) chunk->index, (int) chunk->length, (int) frame_size);
5372 pa_atomic_inc(&ps->seek_or_post_in_queue);
5373 if (chunk->memblock) {
5374 if (seek != PA_SEEK_RELATIVE || offset != 0)
5375 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);
5377 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
5379 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);
5382 upload_stream *u = UPLOAD_STREAM(stream);
5385 if (!u->memchunk.memblock) {
5386 if (u->length == chunk->length && chunk->memblock) {
5387 u->memchunk = *chunk;
5388 pa_memblock_ref(u->memchunk.memblock);
5391 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
5392 u->memchunk.index = u->memchunk.length = 0;
5396 pa_assert(u->memchunk.memblock);
5399 if (l > chunk->length)
5404 dst = pa_memblock_acquire(u->memchunk.memblock);
5406 if (chunk->memblock) {
5408 src = pa_memblock_acquire(chunk->memblock);
5410 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
5411 (uint8_t*) src + chunk->index, l);
5413 pa_memblock_release(chunk->memblock);
5415 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
5417 pa_memblock_release(u->memchunk.memblock);
5419 u->memchunk.length += l;
5425 static void pstream_die_callback(pa_pstream *p, void *userdata) {
5426 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5429 pa_native_connection_assert_ref(c);
5431 native_connection_unlink(c);
5432 pa_log_info("Connection died.");
5435 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
5436 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5439 pa_native_connection_assert_ref(c);
5441 native_connection_send_memblock(c);
5444 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
5447 if (!(q = pa_thread_mq_get()))
5448 pa_pstream_send_revoke(p, block_id);
5450 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
5453 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
5456 if (!(q = pa_thread_mq_get()))
5457 pa_pstream_send_release(p, block_id);
5459 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
5462 /*** client callbacks ***/
5464 static void client_kill_cb(pa_client *c) {
5467 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
5468 pa_log_info("Connection killed.");
5471 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
5473 pa_native_connection *c;
5476 c = PA_NATIVE_CONNECTION(client->userdata);
5477 pa_native_connection_assert_ref(c);
5479 if (c->version < 15)
5482 t = pa_tagstruct_new();
5483 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
5484 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
5485 pa_tagstruct_puts(t, event);
5486 pa_tagstruct_put_proplist(t, pl);
5487 pa_pstream_send_tagstruct(c->pstream, t);
5490 /*** module entry points ***/
5492 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
5493 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5496 pa_native_connection_assert_ref(c);
5497 pa_assert(c->auth_timeout_event == e);
5499 if (!c->authorized) {
5500 native_connection_unlink(c);
5501 pa_log_info("Connection terminated due to authentication timeout.");
5506 void pa_native_protocol_dump_connections(pa_native_protocol *p) {
5507 pa_native_connection *c = NULL;
5512 pa_log_info("Dump status of current connections(%u)", pa_idxset_size(p->connections));
5514 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
5515 pa_client_dump_status(c->client);
5519 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
5520 pa_native_connection *c;
5523 pa_client_new_data data;
5530 pa_native_protocol_dump_connections(p);
5533 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
5534 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
5535 pa_iochannel_free(io);
5539 pa_client_new_data_init(&data);
5540 data.module = o->module;
5541 data.driver = __FILE__;
5542 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
5543 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
5544 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
5545 client = pa_client_new(p->core, &data);
5546 pa_client_new_data_done(&data);
5551 c = pa_msgobject_new(pa_native_connection);
5552 c->parent.parent.free = native_connection_free;
5553 c->parent.process_msg = native_connection_process_msg;
5555 c->options = pa_native_options_ref(o);
5556 c->authorized = false;
5557 c->srbpending = NULL;
5559 if (o->auth_anonymous) {
5560 pa_log_info("Client authenticated anonymously.");
5561 c->authorized = true;
5564 if (!c->authorized &&
5566 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
5568 pa_log_info("Client authenticated by IP ACL.");
5569 c->authorized = true;
5573 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
5575 c->auth_timeout_event = NULL;
5577 c->is_local = pa_iochannel_socket_is_local(io);
5581 c->client->kill = client_kill_cb;
5582 c->client->send_event = client_send_event_cb;
5583 c->client->userdata = c;
5585 c->rw_mempool = NULL;
5587 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
5588 pa_pstream_set_receive_packet_callback(c->pstream, pstream_packet_callback, c);
5589 pa_pstream_set_receive_memblock_callback(c->pstream, pstream_memblock_callback, c);
5590 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
5591 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
5592 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
5593 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
5595 c->pdispatch = pa_pdispatch_new(p->core->mainloop, true, command_table, PA_COMMAND_MAX);
5597 c->record_streams = pa_idxset_new(NULL, NULL);
5598 c->output_streams = pa_idxset_new(NULL, NULL);
5600 c->rrobin_index = PA_IDXSET_INVALID;
5601 c->subscription = NULL;
5603 pa_idxset_put(p->connections, c, NULL);
5606 if (pa_iochannel_creds_supported(io))
5607 pa_iochannel_creds_enable(io);
5610 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
5613 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
5614 pa_native_connection *c;
5620 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
5621 if (c->options->module == m)
5622 native_connection_unlink(c);
5625 static pa_native_protocol* native_protocol_new(pa_core *c) {
5626 pa_native_protocol *p;
5631 p = pa_xnew(pa_native_protocol, 1);
5634 p->connections = pa_idxset_new(NULL, NULL);
5638 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
5640 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
5641 pa_hook_init(&p->hooks[h], p);
5643 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
5648 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
5649 pa_native_protocol *p;
5651 if ((p = pa_shared_get(c, "native-protocol")))
5652 return pa_native_protocol_ref(p);
5654 return native_protocol_new(c);
5657 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
5659 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5666 void pa_native_protocol_unref(pa_native_protocol *p) {
5667 pa_native_connection *c;
5671 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5673 if (PA_REFCNT_DEC(p) > 0)
5676 while ((c = pa_idxset_first(p->connections, NULL)))
5677 native_connection_unlink(c);
5679 pa_idxset_free(p->connections, NULL);
5681 pa_strlist_free(p->servers);
5683 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
5684 pa_hook_done(&p->hooks[h]);
5686 pa_hashmap_free(p->extensions);
5688 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
5693 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
5695 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5698 p->servers = pa_strlist_prepend(p->servers, name);
5700 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5703 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
5705 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5708 p->servers = pa_strlist_remove(p->servers, name);
5710 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5713 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
5715 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5720 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
5722 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5727 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
5729 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5732 pa_assert(!pa_hashmap_get(p->extensions, m));
5734 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
5738 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
5740 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5743 pa_assert_se(pa_hashmap_remove(p->extensions, m));
5746 pa_native_options* pa_native_options_new(void) {
5747 pa_native_options *o;
5749 o = pa_xnew0(pa_native_options, 1);
5755 pa_native_options* pa_native_options_ref(pa_native_options *o) {
5757 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5764 void pa_native_options_unref(pa_native_options *o) {
5766 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5768 if (PA_REFCNT_DEC(o) > 0)
5771 pa_xfree(o->auth_group);
5774 pa_ip_acl_free(o->auth_ip_acl);
5777 pa_auth_cookie_unref(o->auth_cookie);
5782 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
5787 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5790 o->srbchannel = true;
5791 if (pa_modargs_get_value_boolean(ma, "srbchannel", &o->srbchannel) < 0) {
5792 pa_log("srbchannel= expects a boolean argument.");
5796 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
5797 pa_log("auth-anonymous= expects a boolean argument.");
5802 if (pa_modargs_get_value_boolean(ma, "auth-group-enable", &enabled) < 0) {
5803 pa_log("auth-group-enable= expects a boolean argument.");
5807 pa_xfree(o->auth_group);
5808 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
5812 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5815 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
5818 if (!(ipa = pa_ip_acl_new(acl))) {
5819 pa_log("Failed to parse IP ACL '%s'", acl);
5824 pa_ip_acl_free(o->auth_ip_acl);
5826 o->auth_ip_acl = ipa;
5830 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
5831 pa_log("auth-cookie-enabled= expects a boolean argument.");
5836 pa_auth_cookie_unref(o->auth_cookie);
5841 /* The new name for this is 'auth-cookie', for compat reasons
5842 * we check the old name too */
5843 cn = pa_modargs_get_value(ma, "auth-cookie", NULL);
5845 cn = pa_modargs_get_value(ma, "cookie", NULL);
5848 o->auth_cookie = pa_auth_cookie_get(c, cn, true, PA_NATIVE_COOKIE_LENGTH);
5850 o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE, false, PA_NATIVE_COOKIE_LENGTH);
5851 if (!o->auth_cookie) {
5852 char *fallback_path;
5854 if (pa_append_to_home_dir(PA_NATIVE_COOKIE_FILE_FALLBACK, &fallback_path) >= 0) {
5855 o->auth_cookie = pa_auth_cookie_get(c, fallback_path, false, PA_NATIVE_COOKIE_LENGTH);
5856 pa_xfree(fallback_path);
5859 if (!o->auth_cookie)
5860 o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE, true, PA_NATIVE_COOKIE_LENGTH);
5864 if (!o->auth_cookie)
5868 o->auth_cookie = NULL;
5873 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
5874 pa_native_connection_assert_ref(c);
5879 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
5880 pa_native_connection_assert_ref(c);