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, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
32 #include <pulse/timeval.h>
33 #include <pulse/version.h>
34 #include <pulse/utf8.h>
35 #include <pulse/util.h>
36 #include <pulse/xmalloc.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/authkey.h>
48 #include <pulsecore/namereg.h>
49 #include <pulsecore/core-scache.h>
50 #include <pulsecore/core-subscribe.h>
51 #include <pulsecore/log.h>
52 #include <pulsecore/strlist.h>
53 #include <pulsecore/shared.h>
54 #include <pulsecore/sample-util.h>
55 #include <pulsecore/llist.h>
56 #include <pulsecore/creds.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/ipacl.h>
59 #include <pulsecore/thread-mq.h>
61 #include "protocol-native.h"
63 /* Kick a client if it doesn't authenticate within this time */
64 #define AUTH_TIMEOUT 60
66 /* Don't accept more connection than this */
67 #define MAX_CONNECTIONS 64
69 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
70 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
71 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
72 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
74 struct pa_native_protocol;
76 typedef struct record_stream {
79 pa_native_connection *connection;
82 pa_source_output *source_output;
83 pa_memblockq *memblockq;
85 pa_usec_t source_latency;
88 PA_DECLARE_CLASS(record_stream);
89 #define RECORD_STREAM(o) (record_stream_cast(o))
90 static PA_DEFINE_CHECK_TYPE(record_stream, pa_msgobject);
92 typedef struct output_stream {
96 PA_DECLARE_CLASS(output_stream);
97 #define OUTPUT_STREAM(o) (output_stream_cast(o))
98 static PA_DEFINE_CHECK_TYPE(output_stream, pa_msgobject);
100 typedef struct playback_stream {
101 output_stream parent;
103 pa_native_connection *connection;
106 pa_sink_input *sink_input;
107 pa_memblockq *memblockq;
108 pa_bool_t is_underrun:1;
109 pa_bool_t drain_request:1;
115 pa_usec_t sink_latency;
117 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
118 int64_t read_index, write_index;
119 size_t render_memblockq_length;
122 PA_DECLARE_CLASS(playback_stream);
123 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
124 static PA_DEFINE_CHECK_TYPE(playback_stream, output_stream);
126 typedef struct upload_stream {
127 output_stream parent;
129 pa_native_connection *connection;
132 pa_memchunk memchunk;
135 pa_sample_spec sample_spec;
136 pa_channel_map channel_map;
137 pa_proplist *proplist;
140 PA_DECLARE_CLASS(upload_stream);
141 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
142 static PA_DEFINE_CHECK_TYPE(upload_stream, output_stream);
144 struct pa_native_connection {
146 pa_native_protocol *protocol;
147 pa_native_options *options;
148 pa_bool_t authorized:1;
149 pa_bool_t is_local:1;
153 pa_pdispatch *pdispatch;
154 pa_idxset *record_streams, *output_streams;
155 uint32_t rrobin_index;
156 pa_subscription *subscription;
157 pa_time_event *auth_timeout_event;
160 PA_DECLARE_CLASS(pa_native_connection);
161 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
162 static PA_DEFINE_CHECK_TYPE(pa_native_connection, pa_msgobject);
164 struct pa_native_protocol {
168 pa_idxset *connections;
171 pa_hook hooks[PA_NATIVE_HOOK_MAX];
173 pa_hashmap *extensions;
177 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
178 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
179 SINK_INPUT_MESSAGE_FLUSH,
180 SINK_INPUT_MESSAGE_TRIGGER,
181 SINK_INPUT_MESSAGE_SEEK,
182 SINK_INPUT_MESSAGE_PREBUF_FORCE,
183 SINK_INPUT_MESSAGE_UPDATE_LATENCY
187 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
188 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
189 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
190 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
191 PLAYBACK_STREAM_MESSAGE_STARTED
195 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
199 CONNECTION_MESSAGE_RELEASE,
200 CONNECTION_MESSAGE_REVOKE
203 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
204 static void sink_input_kill_cb(pa_sink_input *i);
205 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
206 static void sink_input_moved_cb(pa_sink_input *i);
207 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
208 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
209 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
210 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
212 static void native_connection_send_memblock(pa_native_connection *c);
213 static void playback_stream_request_bytes(struct playback_stream*s);
215 static void source_output_kill_cb(pa_source_output *o);
216 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
217 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend);
218 static void source_output_moved_cb(pa_source_output *o);
219 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
220 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
222 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
224 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
225 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
226 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
227 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
228 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
229 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
230 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
231 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
232 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
233 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
234 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
235 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
236 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
237 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
238 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
239 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
240 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
241 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
242 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
243 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
244 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
245 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
246 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
247 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
248 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
249 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
250 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
251 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
252 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
253 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
254 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
255 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
256 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
257 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
258 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
259 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
260 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
261 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
263 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
264 [PA_COMMAND_ERROR] = NULL,
265 [PA_COMMAND_TIMEOUT] = NULL,
266 [PA_COMMAND_REPLY] = NULL,
267 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
268 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
269 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
270 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
271 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
272 [PA_COMMAND_AUTH] = command_auth,
273 [PA_COMMAND_REQUEST] = NULL,
274 [PA_COMMAND_EXIT] = command_exit,
275 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
276 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
277 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
278 [PA_COMMAND_STAT] = command_stat,
279 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
280 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
281 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
282 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
283 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
284 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
285 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
286 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
287 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
288 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
289 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
290 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
291 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
292 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
293 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
294 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
295 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
296 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
297 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
298 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
299 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
300 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
301 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
302 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
303 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
305 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
306 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
307 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
309 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
310 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
311 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
313 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
314 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
316 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
317 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
318 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
319 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
321 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
322 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
324 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
325 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
326 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
327 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
328 [PA_COMMAND_KILL_CLIENT] = command_kill,
329 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
330 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
331 [PA_COMMAND_LOAD_MODULE] = command_load_module,
332 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
334 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
335 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
336 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
337 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
339 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
340 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
342 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
343 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
345 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
346 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
348 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
349 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
350 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
352 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
353 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
354 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
356 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
358 [PA_COMMAND_EXTENSION] = command_extension
361 /* structure management */
363 static void upload_stream_unlink(upload_stream *s) {
369 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
370 s->connection = NULL;
371 upload_stream_unref(s);
374 static void upload_stream_free(pa_object *o) {
375 upload_stream *s = UPLOAD_STREAM(o);
378 upload_stream_unlink(s);
383 pa_proplist_free(s->proplist);
385 if (s->memchunk.memblock)
386 pa_memblock_unref(s->memchunk.memblock);
391 static upload_stream* upload_stream_new(
392 pa_native_connection *c,
393 const pa_sample_spec *ss,
394 const pa_channel_map *map,
404 pa_assert(length > 0);
407 s = pa_msgobject_new(upload_stream);
408 s->parent.parent.parent.free = upload_stream_free;
410 s->sample_spec = *ss;
411 s->channel_map = *map;
412 s->name = pa_xstrdup(name);
413 pa_memchunk_reset(&s->memchunk);
415 s->proplist = pa_proplist_copy(p);
416 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
418 pa_idxset_put(c->output_streams, s, &s->index);
423 static void record_stream_unlink(record_stream *s) {
429 if (s->source_output) {
430 pa_source_output_unlink(s->source_output);
431 pa_source_output_unref(s->source_output);
432 s->source_output = NULL;
435 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
436 s->connection = NULL;
437 record_stream_unref(s);
440 static void record_stream_free(pa_object *o) {
441 record_stream *s = RECORD_STREAM(o);
444 record_stream_unlink(s);
446 pa_memblockq_free(s->memblockq);
450 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
451 record_stream *s = RECORD_STREAM(o);
452 record_stream_assert_ref(s);
459 case RECORD_STREAM_MESSAGE_POST_DATA:
461 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
462 /* pa_log_warn("Failed to push data into output queue."); */
466 if (!pa_pstream_is_pending(s->connection->pstream))
467 native_connection_send_memblock(s->connection);
475 static void fix_record_buffer_attr_pre(
477 pa_bool_t adjust_latency,
478 pa_bool_t early_requests,
480 uint32_t *fragsize) {
483 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
486 pa_assert(maxlength);
489 frame_size = pa_frame_size(&s->source_output->sample_spec);
491 if (*maxlength == (uint32_t) -1 || *maxlength > MAX_MEMBLOCKQ_LENGTH)
492 *maxlength = MAX_MEMBLOCKQ_LENGTH;
494 *maxlength = (uint32_t) frame_size;
496 if (*fragsize == (uint32_t) -1)
497 *fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
499 *fragsize = (uint32_t) frame_size;
501 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(*fragsize, &s->source_output->sample_spec);
503 if (early_requests) {
505 /* In early request mode we need to emulate the classic
506 * fragment-based playback model. We do this setting the source
507 * latency to the fragment size. */
509 source_usec = fragsize_usec;
511 } else if (adjust_latency) {
513 /* So, the user asked us to adjust the latency according to
514 * what the source can provide. Half the latency will be
515 * spent on the hw buffer, half of it in the async buffer
516 * queue we maintain for each client. */
518 source_usec = fragsize_usec/2;
522 /* Ok, the user didn't ask us to adjust the latency, hence we
529 s->source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
531 s->source_latency = 0;
533 if (early_requests) {
535 /* Ok, we didn't necessarily get what we were asking for, so
536 * let's tell the user */
538 fragsize_usec = s->source_latency;
540 } else if (adjust_latency) {
542 /* Now subtract what we actually got */
544 if (fragsize_usec >= s->source_latency*2)
545 fragsize_usec -= s->source_latency;
547 fragsize_usec = s->source_latency;
550 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
551 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
553 *fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
556 *fragsize = (uint32_t) frame_size;
559 static void fix_record_buffer_attr_post(
562 uint32_t *fragsize) {
567 pa_assert(maxlength);
570 *maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq);
572 base = pa_frame_size(&s->source_output->sample_spec);
574 s->fragment_size = (*fragsize/base)*base;
575 if (s->fragment_size <= 0)
576 s->fragment_size = base;
578 if (s->fragment_size > *maxlength)
579 s->fragment_size = *maxlength;
581 *fragsize = (uint32_t) s->fragment_size;
584 static record_stream* record_stream_new(
585 pa_native_connection *c,
589 pa_bool_t peak_detect,
592 pa_source_output_flags_t flags,
594 pa_bool_t adjust_latency,
595 pa_sink_input *direct_on_input,
596 pa_bool_t early_requests,
600 pa_source_output *source_output = NULL;
602 pa_source_output_new_data data;
606 pa_assert(maxlength);
610 pa_source_output_new_data_init(&data);
612 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
613 data.driver = __FILE__;
614 data.module = c->options->module;
615 data.client = c->client;
616 data.source = source;
617 data.direct_on_input = direct_on_input;
618 pa_source_output_new_data_set_sample_spec(&data, ss);
619 pa_source_output_new_data_set_channel_map(&data, map);
621 data.resample_method = PA_RESAMPLER_PEAKS;
623 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data, flags);
625 pa_source_output_new_data_done(&data);
630 s = pa_msgobject_new(record_stream);
631 s->parent.parent.free = record_stream_free;
632 s->parent.process_msg = record_stream_process_msg;
634 s->source_output = source_output;
636 s->source_output->push = source_output_push_cb;
637 s->source_output->kill = source_output_kill_cb;
638 s->source_output->get_latency = source_output_get_latency_cb;
639 s->source_output->moved = source_output_moved_cb;
640 s->source_output->suspend = source_output_suspend_cb;
641 s->source_output->send_event = source_output_send_event_cb;
642 s->source_output->userdata = s;
644 fix_record_buffer_attr_pre(s, adjust_latency, early_requests, maxlength, fragsize);
646 s->memblockq = pa_memblockq_new(
650 base = pa_frame_size(&source_output->sample_spec),
656 fix_record_buffer_attr_post(s, maxlength, fragsize);
658 *ss = s->source_output->sample_spec;
659 *map = s->source_output->channel_map;
661 pa_idxset_put(c->record_streams, s, &s->index);
663 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
664 ((double) pa_bytes_to_usec(s->fragment_size, &source_output->sample_spec) + (double) s->source_latency) / PA_USEC_PER_MSEC,
665 (double) pa_bytes_to_usec(s->fragment_size, &source_output->sample_spec) / PA_USEC_PER_MSEC,
666 (double) s->source_latency / PA_USEC_PER_MSEC);
668 pa_source_output_put(s->source_output);
672 static void record_stream_send_killed(record_stream *r) {
674 record_stream_assert_ref(r);
676 t = pa_tagstruct_new(NULL, 0);
677 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
678 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
679 pa_tagstruct_putu32(t, r->index);
680 pa_pstream_send_tagstruct(r->connection->pstream, t);
683 static void playback_stream_unlink(playback_stream *s) {
690 pa_sink_input_unlink(s->sink_input);
691 pa_sink_input_unref(s->sink_input);
692 s->sink_input = NULL;
695 if (s->drain_request)
696 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
698 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
699 s->connection = NULL;
700 playback_stream_unref(s);
703 static void playback_stream_free(pa_object* o) {
704 playback_stream *s = PLAYBACK_STREAM(o);
707 playback_stream_unlink(s);
709 pa_memblockq_free(s->memblockq);
713 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
714 playback_stream *s = PLAYBACK_STREAM(o);
715 playback_stream_assert_ref(s);
721 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
726 if ((l = (uint32_t) pa_atomic_load(&s->missing)) <= 0)
729 if (pa_atomic_cmpxchg(&s->missing, (int) l, 0))
736 t = pa_tagstruct_new(NULL, 0);
737 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
738 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
739 pa_tagstruct_putu32(t, s->index);
740 pa_tagstruct_putu32(t, l);
741 pa_pstream_send_tagstruct(s->connection->pstream, t);
743 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
747 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
750 /* pa_log("signalling underflow"); */
752 /* Report that we're empty */
753 t = pa_tagstruct_new(NULL, 0);
754 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
755 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
756 pa_tagstruct_putu32(t, s->index);
757 pa_pstream_send_tagstruct(s->connection->pstream, t);
761 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
764 /* Notify the user we're overflowed*/
765 t = pa_tagstruct_new(NULL, 0);
766 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
767 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
768 pa_tagstruct_putu32(t, s->index);
769 pa_pstream_send_tagstruct(s->connection->pstream, t);
773 case PLAYBACK_STREAM_MESSAGE_STARTED:
775 if (s->connection->version >= 13) {
778 /* Notify the user we're overflowed*/
779 t = pa_tagstruct_new(NULL, 0);
780 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
781 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
782 pa_tagstruct_putu32(t, s->index);
783 pa_pstream_send_tagstruct(s->connection->pstream, t);
788 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
789 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
796 static void fix_playback_buffer_attr_pre(
798 pa_bool_t adjust_latency,
799 pa_bool_t early_requests,
806 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
809 pa_assert(maxlength);
814 frame_size = pa_frame_size(&s->sink_input->sample_spec);
816 if (*maxlength == (uint32_t) -1 || *maxlength > MAX_MEMBLOCKQ_LENGTH)
817 *maxlength = MAX_MEMBLOCKQ_LENGTH;
819 *maxlength = (uint32_t) frame_size;
821 if (*tlength == (uint32_t) -1)
822 *tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
824 *tlength = (uint32_t) frame_size;
826 if (*minreq == (uint32_t) -1)
827 *minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
829 *minreq = (uint32_t) frame_size;
831 if (*tlength < *minreq+frame_size)
832 *tlength = *minreq+(uint32_t) frame_size;
834 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(*tlength, &s->sink_input->sample_spec);
835 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(*minreq, &s->sink_input->sample_spec);
837 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
838 (double) tlength_usec / PA_USEC_PER_MSEC,
839 (double) minreq_usec / PA_USEC_PER_MSEC);
841 if (early_requests) {
843 /* In early request mode we need to emulate the classic
844 * fragment-based playback model. We do this setting the sink
845 * latency to the fragment size. */
847 sink_usec = minreq_usec;
849 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
851 } else if (adjust_latency) {
853 /* So, the user asked us to adjust the latency of the stream
854 * buffer according to the what the sink can provide. The
855 * tlength passed in shall be the overall latency. Roughly
856 * half the latency will be spent on the hw buffer, the other
857 * half of it in the async buffer queue we maintain for each
858 * client. In between we'll have a safety space of size
859 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
860 * empty and needs to be filled, then our buffer must have
861 * enough data to fulfill this request immediatly and thus
862 * have at least the same tlength as the size of the hw
863 * buffer. It additionally needs space for 2 times minreq
864 * because if the buffer ran empty and a partial fillup
865 * happens immediately on the next iteration we need to be
866 * able to fulfill it and give the application also minreq
867 * time to fill it up again for the next request Makes 2 times
868 * minreq in plus.. */
870 if (tlength_usec > minreq_usec*2)
871 sink_usec = (tlength_usec - minreq_usec*2)/2;
875 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
879 /* Ok, the user didn't ask us to adjust the latency, but we
880 * still need to make sure that the parameters from the user
883 if (tlength_usec > minreq_usec*2)
884 sink_usec = (tlength_usec - minreq_usec*2);
888 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
891 s->sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
893 if (early_requests) {
895 /* Ok, we didn't necessarily get what we were asking for, so
896 * let's tell the user */
898 minreq_usec = s->sink_latency;
900 } else if (adjust_latency) {
902 /* Ok, we didn't necessarily get what we were asking for, so
903 * let's subtract from what we asked for for the remaining
906 if (tlength_usec >= s->sink_latency)
907 tlength_usec -= s->sink_latency;
910 /* FIXME: This is actually larger than necessary, since not all of
911 * the sink latency is actually rewritable. */
912 if (tlength_usec < s->sink_latency + 2*minreq_usec)
913 tlength_usec = s->sink_latency + 2*minreq_usec;
915 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
916 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
917 *tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
919 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
920 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
921 *minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
924 *minreq = (uint32_t) frame_size;
925 *tlength += (uint32_t) frame_size*2;
928 if (*tlength <= *minreq)
929 *tlength = *minreq*2 + (uint32_t) frame_size;
931 if (*prebuf == (uint32_t) -1 || *prebuf > *tlength)
935 static void fix_playback_buffer_attr_post(
943 pa_assert(maxlength);
948 *maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq);
949 *tlength = (uint32_t) pa_memblockq_get_tlength(s->memblockq);
950 *prebuf = (uint32_t) pa_memblockq_get_prebuf(s->memblockq);
951 *minreq = (uint32_t) pa_memblockq_get_minreq(s->memblockq);
956 static playback_stream* playback_stream_new(
957 pa_native_connection *c,
970 pa_sink_input_flags_t flags,
972 pa_bool_t adjust_latency,
973 pa_bool_t early_requests,
976 playback_stream *s, *ssync;
977 pa_sink_input *sink_input = NULL;
981 pa_sink_input_new_data data;
985 pa_assert(maxlength);
993 /* Find syncid group */
994 for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) {
996 if (!playback_stream_isinstance(ssync))
999 if (ssync->syncid == syncid)
1003 /* Synced streams must connect to the same sink */
1007 sink = ssync->sink_input->sink;
1008 else if (sink != ssync->sink_input->sink) {
1009 *ret = PA_ERR_INVALID;
1014 pa_sink_input_new_data_init(&data);
1016 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1017 data.driver = __FILE__;
1018 data.module = c->options->module;
1019 data.client = c->client;
1021 pa_sink_input_new_data_set_sample_spec(&data, ss);
1022 pa_sink_input_new_data_set_channel_map(&data, map);
1024 pa_sink_input_new_data_set_volume(&data, volume);
1026 pa_sink_input_new_data_set_muted(&data, muted);
1027 data.sync_base = ssync ? ssync->sink_input : NULL;
1029 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data, flags);
1031 pa_sink_input_new_data_done(&data);
1036 s = pa_msgobject_new(playback_stream);
1037 s->parent.parent.parent.free = playback_stream_free;
1038 s->parent.parent.process_msg = playback_stream_process_msg;
1041 s->sink_input = sink_input;
1042 s->is_underrun = TRUE;
1043 s->drain_request = FALSE;
1044 pa_atomic_store(&s->missing, 0);
1046 s->sink_input->parent.process_msg = sink_input_process_msg;
1047 s->sink_input->pop = sink_input_pop_cb;
1048 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1049 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1050 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1051 s->sink_input->kill = sink_input_kill_cb;
1052 s->sink_input->moved = sink_input_moved_cb;
1053 s->sink_input->suspend = sink_input_suspend_cb;
1054 s->sink_input->send_event = sink_input_send_event_cb;
1055 s->sink_input->userdata = s;
1057 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1059 fix_playback_buffer_attr_pre(s, adjust_latency, early_requests, maxlength, tlength, prebuf, minreq);
1060 pa_sink_input_get_silence(sink_input, &silence);
1062 s->memblockq = pa_memblockq_new(
1066 pa_frame_size(&sink_input->sample_spec),
1072 pa_memblock_unref(silence.memblock);
1073 fix_playback_buffer_attr_post(s, maxlength, tlength, prebuf, minreq);
1075 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1077 *ss = s->sink_input->sample_spec;
1078 *map = s->sink_input->channel_map;
1080 pa_idxset_put(c->output_streams, s, &s->index);
1082 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1083 ((double) pa_bytes_to_usec(*tlength, &sink_input->sample_spec) + (double) s->sink_latency) / PA_USEC_PER_MSEC,
1084 (double) pa_bytes_to_usec(*tlength-*minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1085 (double) pa_bytes_to_usec(*minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1086 (double) s->sink_latency / PA_USEC_PER_MSEC);
1088 pa_sink_input_put(s->sink_input);
1092 /* Called from thread context */
1093 static void playback_stream_request_bytes(playback_stream *s) {
1094 size_t m, previous_missing;
1096 playback_stream_assert_ref(s);
1098 m = pa_memblockq_pop_missing(s->memblockq);
1103 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1105 previous_missing = (size_t) pa_atomic_add(&s->missing, (int) m);
1107 if (pa_memblockq_prebuf_active(s->memblockq) ||
1108 (previous_missing < s->minreq && previous_missing+m >= s->minreq))
1109 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1113 static void playback_stream_send_killed(playback_stream *p) {
1115 playback_stream_assert_ref(p);
1117 t = pa_tagstruct_new(NULL, 0);
1118 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1119 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1120 pa_tagstruct_putu32(t, p->index);
1121 pa_pstream_send_tagstruct(p->connection->pstream, t);
1124 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1125 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1126 pa_native_connection_assert_ref(c);
1133 case CONNECTION_MESSAGE_REVOKE:
1134 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1137 case CONNECTION_MESSAGE_RELEASE:
1138 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1145 static void native_connection_unlink(pa_native_connection *c) {
1154 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1157 pa_native_options_unref(c->options);
1159 while ((r = pa_idxset_first(c->record_streams, NULL)))
1160 record_stream_unlink(r);
1162 while ((o = pa_idxset_first(c->output_streams, NULL)))
1163 if (playback_stream_isinstance(o))
1164 playback_stream_unlink(PLAYBACK_STREAM(o));
1166 upload_stream_unlink(UPLOAD_STREAM(o));
1168 if (c->subscription)
1169 pa_subscription_free(c->subscription);
1172 pa_pstream_unlink(c->pstream);
1174 if (c->auth_timeout_event) {
1175 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1176 c->auth_timeout_event = NULL;
1179 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1181 pa_native_connection_unref(c);
1184 static void native_connection_free(pa_object *o) {
1185 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1189 native_connection_unlink(c);
1191 pa_idxset_free(c->record_streams, NULL, NULL);
1192 pa_idxset_free(c->output_streams, NULL, NULL);
1194 pa_pdispatch_unref(c->pdispatch);
1195 pa_pstream_unref(c->pstream);
1196 pa_client_free(c->client);
1201 static void native_connection_send_memblock(pa_native_connection *c) {
1205 start = PA_IDXSET_INVALID;
1209 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1212 if (start == PA_IDXSET_INVALID)
1213 start = c->rrobin_index;
1214 else if (start == c->rrobin_index)
1217 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1218 pa_memchunk schunk = chunk;
1220 if (schunk.length > r->fragment_size)
1221 schunk.length = r->fragment_size;
1223 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1225 pa_memblockq_drop(r->memblockq, schunk.length);
1226 pa_memblock_unref(schunk.memblock);
1233 /*** sink input callbacks ***/
1235 static void handle_seek(playback_stream *s, int64_t indexw) {
1236 playback_stream_assert_ref(s);
1238 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1240 if (s->sink_input->thread_info.underrun_for > 0) {
1242 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1244 if (pa_memblockq_is_readable(s->memblockq)) {
1246 /* We just ended an underrun, let's ask the sink
1247 * for a complete rewind rewrite */
1249 pa_log_debug("Requesting rewind due to end of underrun.");
1250 pa_sink_input_request_rewind(s->sink_input,
1251 (size_t) (s->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : s->sink_input->thread_info.underrun_for),
1252 FALSE, TRUE, FALSE);
1258 indexr = pa_memblockq_get_read_index(s->memblockq);
1260 if (indexw < indexr) {
1261 /* OK, the sink already asked for this data, so
1262 * let's have it usk us again */
1264 pa_log_debug("Requesting rewind due to rewrite.");
1265 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1269 playback_stream_request_bytes(s);
1272 /* Called from thread context */
1273 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1274 pa_sink_input *i = PA_SINK_INPUT(o);
1277 pa_sink_input_assert_ref(i);
1278 s = PLAYBACK_STREAM(i->userdata);
1279 playback_stream_assert_ref(s);
1283 case SINK_INPUT_MESSAGE_SEEK: {
1286 windex = pa_memblockq_get_write_index(s->memblockq);
1287 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata));
1289 handle_seek(s, windex);
1293 case SINK_INPUT_MESSAGE_POST_DATA: {
1298 windex = pa_memblockq_get_write_index(s->memblockq);
1300 /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
1302 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1303 pa_log_warn("Failed to push data into queue");
1304 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1305 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE);
1308 handle_seek(s, windex);
1310 /* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1315 case SINK_INPUT_MESSAGE_DRAIN:
1316 case SINK_INPUT_MESSAGE_FLUSH:
1317 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1318 case SINK_INPUT_MESSAGE_TRIGGER: {
1321 pa_sink_input *isync;
1322 void (*func)(pa_memblockq *bq);
1325 case SINK_INPUT_MESSAGE_FLUSH:
1326 func = pa_memblockq_flush_write;
1329 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1330 func = pa_memblockq_prebuf_force;
1333 case SINK_INPUT_MESSAGE_DRAIN:
1334 case SINK_INPUT_MESSAGE_TRIGGER:
1335 func = pa_memblockq_prebuf_disable;
1339 pa_assert_not_reached();
1342 windex = pa_memblockq_get_write_index(s->memblockq);
1344 handle_seek(s, windex);
1346 /* Do the same for all other members in the sync group */
1347 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1348 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1349 windex = pa_memblockq_get_write_index(ssync->memblockq);
1350 func(ssync->memblockq);
1351 handle_seek(ssync, windex);
1354 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1355 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1356 windex = pa_memblockq_get_write_index(ssync->memblockq);
1357 func(ssync->memblockq);
1358 handle_seek(ssync, windex);
1361 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1362 if (!pa_memblockq_is_readable(s->memblockq))
1363 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1365 s->drain_tag = PA_PTR_TO_UINT(userdata);
1366 s->drain_request = TRUE;
1373 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1375 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1376 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1377 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1380 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1383 windex = pa_memblockq_get_write_index(s->memblockq);
1385 pa_memblockq_prebuf_force(s->memblockq);
1387 handle_seek(s, windex);
1389 /* Fall through to the default handler */
1393 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1394 pa_usec_t *r = userdata;
1396 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1398 /* Fall through, the default handler will add in the extra
1399 * latency added by the resampler */
1404 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1407 /* Called from thread context */
1408 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1411 pa_sink_input_assert_ref(i);
1412 s = PLAYBACK_STREAM(i->userdata);
1413 playback_stream_assert_ref(s);
1416 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1418 if (pa_memblockq_is_readable(s->memblockq))
1419 s->is_underrun = FALSE;
1421 /* pa_log("%s, UNDERRUN: %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1423 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1424 s->drain_request = FALSE;
1425 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);
1426 } else if (!s->is_underrun)
1427 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1429 s->is_underrun = TRUE;
1431 playback_stream_request_bytes(s);
1434 /* This call will not fail with prebuf=0, hence we check for
1435 underrun explicitly above */
1436 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1439 chunk->length = PA_MIN(nbytes, chunk->length);
1441 if (i->thread_info.underrun_for > 0)
1442 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1444 pa_memblockq_drop(s->memblockq, chunk->length);
1445 playback_stream_request_bytes(s);
1450 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1453 pa_sink_input_assert_ref(i);
1454 s = PLAYBACK_STREAM(i->userdata);
1455 playback_stream_assert_ref(s);
1457 /* If we are in an underrun, then we don't rewind */
1458 if (i->thread_info.underrun_for > 0)
1461 pa_memblockq_rewind(s->memblockq, nbytes);
1464 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1467 pa_sink_input_assert_ref(i);
1468 s = PLAYBACK_STREAM(i->userdata);
1469 playback_stream_assert_ref(s);
1471 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1474 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1478 pa_sink_input_assert_ref(i);
1479 s = PLAYBACK_STREAM(i->userdata);
1480 playback_stream_assert_ref(s);
1482 tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1484 if (pa_memblockq_get_tlength(s->memblockq) < tlength)
1485 pa_memblockq_set_tlength(s->memblockq, tlength);
1488 /* Called from main context */
1489 static void sink_input_kill_cb(pa_sink_input *i) {
1492 pa_sink_input_assert_ref(i);
1493 s = PLAYBACK_STREAM(i->userdata);
1494 playback_stream_assert_ref(s);
1496 playback_stream_send_killed(s);
1497 playback_stream_unlink(s);
1500 /* Called from main context */
1501 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1505 pa_sink_input_assert_ref(i);
1506 s = PLAYBACK_STREAM(i->userdata);
1507 playback_stream_assert_ref(s);
1509 if (s->connection->version < 15)
1512 t = pa_tagstruct_new(NULL, 0);
1513 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1514 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1515 pa_tagstruct_putu32(t, s->index);
1516 pa_tagstruct_puts(t, event);
1517 pa_tagstruct_put_proplist(t, pl);
1518 pa_pstream_send_tagstruct(s->connection->pstream, t);
1521 /* Called from main context */
1522 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1526 pa_sink_input_assert_ref(i);
1527 s = PLAYBACK_STREAM(i->userdata);
1528 playback_stream_assert_ref(s);
1530 if (s->connection->version < 12)
1533 t = pa_tagstruct_new(NULL, 0);
1534 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1535 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1536 pa_tagstruct_putu32(t, s->index);
1537 pa_tagstruct_put_boolean(t, suspend);
1538 pa_pstream_send_tagstruct(s->connection->pstream, t);
1541 /* Called from main context */
1542 static void sink_input_moved_cb(pa_sink_input *i) {
1545 uint32_t maxlength, tlength, prebuf, minreq;
1547 pa_sink_input_assert_ref(i);
1548 s = PLAYBACK_STREAM(i->userdata);
1549 playback_stream_assert_ref(s);
1551 maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq);
1552 tlength = (uint32_t) pa_memblockq_get_tlength(s->memblockq);
1553 prebuf = (uint32_t) pa_memblockq_get_prebuf(s->memblockq);
1554 minreq = (uint32_t) pa_memblockq_get_minreq(s->memblockq);
1556 fix_playback_buffer_attr_pre(s, TRUE, FALSE, &maxlength, &tlength, &prebuf, &minreq);
1557 pa_memblockq_set_maxlength(s->memblockq, maxlength);
1558 pa_memblockq_set_tlength(s->memblockq, tlength);
1559 pa_memblockq_set_prebuf(s->memblockq, prebuf);
1560 pa_memblockq_set_minreq(s->memblockq, minreq);
1561 fix_playback_buffer_attr_post(s, &maxlength, &tlength, &prebuf, &minreq);
1563 if (s->connection->version < 12)
1566 t = pa_tagstruct_new(NULL, 0);
1567 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1568 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1569 pa_tagstruct_putu32(t, s->index);
1570 pa_tagstruct_putu32(t, i->sink->index);
1571 pa_tagstruct_puts(t, i->sink->name);
1572 pa_tagstruct_put_boolean(t, pa_sink_get_state(i->sink) == PA_SINK_SUSPENDED);
1574 if (s->connection->version >= 13) {
1575 pa_tagstruct_putu32(t, maxlength);
1576 pa_tagstruct_putu32(t, tlength);
1577 pa_tagstruct_putu32(t, prebuf);
1578 pa_tagstruct_putu32(t, minreq);
1579 pa_tagstruct_put_usec(t, s->sink_latency);
1582 pa_pstream_send_tagstruct(s->connection->pstream, t);
1585 /*** source_output callbacks ***/
1587 /* Called from thread context */
1588 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1591 pa_source_output_assert_ref(o);
1592 s = RECORD_STREAM(o->userdata);
1593 record_stream_assert_ref(s);
1596 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1599 static void source_output_kill_cb(pa_source_output *o) {
1602 pa_source_output_assert_ref(o);
1603 s = RECORD_STREAM(o->userdata);
1604 record_stream_assert_ref(s);
1606 record_stream_send_killed(s);
1607 record_stream_unlink(s);
1610 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1613 pa_source_output_assert_ref(o);
1614 s = RECORD_STREAM(o->userdata);
1615 record_stream_assert_ref(s);
1617 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1619 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1622 /* Called from main context */
1623 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1627 pa_source_output_assert_ref(o);
1628 s = RECORD_STREAM(o->userdata);
1629 record_stream_assert_ref(s);
1631 if (s->connection->version < 15)
1634 t = pa_tagstruct_new(NULL, 0);
1635 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1636 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1637 pa_tagstruct_putu32(t, s->index);
1638 pa_tagstruct_puts(t, event);
1639 pa_tagstruct_put_proplist(t, pl);
1640 pa_pstream_send_tagstruct(s->connection->pstream, t);
1643 /* Called from main context */
1644 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1648 pa_source_output_assert_ref(o);
1649 s = RECORD_STREAM(o->userdata);
1650 record_stream_assert_ref(s);
1652 if (s->connection->version < 12)
1655 t = pa_tagstruct_new(NULL, 0);
1656 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1657 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1658 pa_tagstruct_putu32(t, s->index);
1659 pa_tagstruct_put_boolean(t, suspend);
1660 pa_pstream_send_tagstruct(s->connection->pstream, t);
1663 /* Called from main context */
1664 static void source_output_moved_cb(pa_source_output *o) {
1667 uint32_t maxlength, fragsize;
1669 pa_source_output_assert_ref(o);
1670 s = RECORD_STREAM(o->userdata);
1671 record_stream_assert_ref(s);
1673 fragsize = (uint32_t) s->fragment_size;
1674 maxlength = (uint32_t) pa_memblockq_get_length(s->memblockq);
1676 fix_record_buffer_attr_pre(s, TRUE, FALSE, &maxlength, &fragsize);
1677 pa_memblockq_set_maxlength(s->memblockq, maxlength);
1678 fix_record_buffer_attr_post(s, &maxlength, &fragsize);
1680 if (s->connection->version < 12)
1683 t = pa_tagstruct_new(NULL, 0);
1684 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1685 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1686 pa_tagstruct_putu32(t, s->index);
1687 pa_tagstruct_putu32(t, o->source->index);
1688 pa_tagstruct_puts(t, o->source->name);
1689 pa_tagstruct_put_boolean(t, pa_source_get_state(o->source) == PA_SOURCE_SUSPENDED);
1691 if (s->connection->version >= 13) {
1692 pa_tagstruct_putu32(t, maxlength);
1693 pa_tagstruct_putu32(t, fragsize);
1694 pa_tagstruct_put_usec(t, s->source_latency);
1697 pa_pstream_send_tagstruct(s->connection->pstream, t);
1700 /*** pdispatch callbacks ***/
1702 static void protocol_error(pa_native_connection *c) {
1703 pa_log("protocol error, kicking client");
1704 native_connection_unlink(c);
1707 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1708 if (!(expression)) { \
1709 pa_pstream_send_error((pstream), (tag), (error)); \
1714 static pa_tagstruct *reply_new(uint32_t tag) {
1715 pa_tagstruct *reply;
1717 reply = pa_tagstruct_new(NULL, 0);
1718 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1719 pa_tagstruct_putu32(reply, tag);
1723 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1724 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1726 uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid, missing;
1727 const char *name = NULL, *sink_name;
1730 pa_tagstruct *reply;
1731 pa_sink *sink = NULL;
1739 fix_channels = FALSE,
1741 variable_rate = FALSE,
1743 adjust_latency = FALSE,
1744 early_requests = FALSE,
1745 dont_inhibit_auto_suspend = FALSE,
1747 fail_on_suspend = FALSE;
1748 pa_sink_input_flags_t flags = 0;
1750 pa_bool_t volume_set = TRUE;
1751 int ret = PA_ERR_INVALID;
1753 pa_native_connection_assert_ref(c);
1756 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1759 PA_TAG_SAMPLE_SPEC, &ss,
1760 PA_TAG_CHANNEL_MAP, &map,
1761 PA_TAG_U32, &sink_index,
1762 PA_TAG_STRING, &sink_name,
1763 PA_TAG_U32, &maxlength,
1764 PA_TAG_BOOLEAN, &corked,
1765 PA_TAG_U32, &tlength,
1766 PA_TAG_U32, &prebuf,
1767 PA_TAG_U32, &minreq,
1768 PA_TAG_U32, &syncid,
1769 PA_TAG_CVOLUME, &volume,
1770 PA_TAG_INVALID) < 0) {
1776 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1777 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name(sink_name), tag, PA_ERR_INVALID);
1778 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
1779 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
1780 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
1781 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
1782 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
1783 CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID);
1785 p = pa_proplist_new();
1788 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1790 if (c->version >= 12) {
1791 /* Since 0.9.8 the user can ask for a couple of additional flags */
1793 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1794 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1795 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1796 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1797 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1798 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1799 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1802 pa_proplist_free(p);
1807 if (c->version >= 13) {
1809 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1810 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1811 pa_tagstruct_get_proplist(t, p) < 0) {
1813 pa_proplist_free(p);
1818 if (c->version >= 14) {
1820 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
1821 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
1823 pa_proplist_free(p);
1828 if (c->version >= 15) {
1830 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
1831 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
1832 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
1834 pa_proplist_free(p);
1839 if (!pa_tagstruct_eof(t)) {
1841 pa_proplist_free(p);
1845 if (sink_index != PA_INVALID_INDEX) {
1847 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
1848 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1849 pa_proplist_free(p);
1853 } else if (sink_name) {
1855 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
1856 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1857 pa_proplist_free(p);
1863 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
1864 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
1865 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
1866 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
1867 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
1868 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
1869 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
1870 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
1871 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
1872 (fail_on_suspend ? PA_SINK_INPUT_FAIL_ON_SUSPEND : 0);
1874 /* Only since protocol version 15 there's a seperate muted_set
1875 * flag. For older versions we synthesize it here */
1876 muted_set = muted_set || muted;
1878 s = playback_stream_new(c, sink, &ss, &map, &maxlength, &tlength, &prebuf, &minreq, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, &ret);
1879 pa_proplist_free(p);
1881 CHECK_VALIDITY(c->pstream, s, tag, ret);
1883 reply = reply_new(tag);
1884 pa_tagstruct_putu32(reply, s->index);
1885 pa_assert(s->sink_input);
1886 pa_tagstruct_putu32(reply, s->sink_input->index);
1887 pa_tagstruct_putu32(reply, missing);
1889 /* pa_log("initial request is %u", missing); */
1891 if (c->version >= 9) {
1892 /* Since 0.9.0 we support sending the buffer metrics back to the client */
1894 pa_tagstruct_putu32(reply, (uint32_t) maxlength);
1895 pa_tagstruct_putu32(reply, (uint32_t) tlength);
1896 pa_tagstruct_putu32(reply, (uint32_t) prebuf);
1897 pa_tagstruct_putu32(reply, (uint32_t) minreq);
1900 if (c->version >= 12) {
1901 /* Since 0.9.8 we support sending the chosen sample
1902 * spec/channel map/device/suspend status back to the
1905 pa_tagstruct_put_sample_spec(reply, &ss);
1906 pa_tagstruct_put_channel_map(reply, &map);
1908 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
1909 pa_tagstruct_puts(reply, s->sink_input->sink->name);
1911 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
1914 if (c->version >= 13)
1915 pa_tagstruct_put_usec(reply, s->sink_latency);
1917 pa_pstream_send_tagstruct(c->pstream, reply);
1920 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1921 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1924 pa_native_connection_assert_ref(c);
1927 if (pa_tagstruct_getu32(t, &channel) < 0 ||
1928 !pa_tagstruct_eof(t)) {
1933 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1937 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
1939 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
1940 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
1944 playback_stream_unlink(s);
1948 case PA_COMMAND_DELETE_RECORD_STREAM: {
1950 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
1951 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
1955 record_stream_unlink(s);
1959 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
1962 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
1963 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
1967 upload_stream_unlink(s);
1972 pa_assert_not_reached();
1975 pa_pstream_send_simple_ack(c->pstream, tag);
1978 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1979 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1981 uint32_t maxlength, fragment_size;
1982 uint32_t source_index;
1983 const char *name = NULL, *source_name;
1986 pa_tagstruct *reply;
1987 pa_source *source = NULL;
1994 fix_channels = FALSE,
1996 variable_rate = FALSE,
1997 adjust_latency = FALSE,
1998 peak_detect = FALSE,
1999 early_requests = FALSE,
2000 dont_inhibit_auto_suspend = FALSE,
2001 fail_on_suspend = FALSE;
2002 pa_source_output_flags_t flags = 0;
2004 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2005 pa_sink_input *direct_on_input = NULL;
2006 int ret = PA_ERR_INVALID;
2008 pa_native_connection_assert_ref(c);
2011 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2012 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2013 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2014 pa_tagstruct_getu32(t, &source_index) < 0 ||
2015 pa_tagstruct_gets(t, &source_name) < 0 ||
2016 pa_tagstruct_getu32(t, &maxlength) < 0 ||
2017 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2018 pa_tagstruct_getu32(t, &fragment_size) < 0) {
2023 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2024 CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name(source_name), tag, PA_ERR_INVALID);
2025 CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID);
2026 CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2027 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2028 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2029 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2031 p = pa_proplist_new();
2034 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2036 if (c->version >= 12) {
2037 /* Since 0.9.8 the user can ask for a couple of additional flags */
2039 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2040 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2041 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2042 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2043 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2044 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2045 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2048 pa_proplist_free(p);
2053 if (c->version >= 13) {
2055 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2056 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2057 pa_tagstruct_get_proplist(t, p) < 0 ||
2058 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2060 pa_proplist_free(p);
2065 if (c->version >= 14) {
2067 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2069 pa_proplist_free(p);
2074 if (c->version >= 15) {
2076 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2077 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2079 pa_proplist_free(p);
2084 if (!pa_tagstruct_eof(t)) {
2086 pa_proplist_free(p);
2090 if (source_index != PA_INVALID_INDEX) {
2092 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2093 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2094 pa_proplist_free(p);
2098 } else if (source_name) {
2100 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2101 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2102 pa_proplist_free(p);
2107 if (direct_on_input_idx != PA_INVALID_INDEX) {
2109 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2110 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2111 pa_proplist_free(p);
2117 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2118 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2119 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2120 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2121 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2122 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2123 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2124 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2125 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2126 (fail_on_suspend ? PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND : 0);
2128 s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
2129 pa_proplist_free(p);
2131 CHECK_VALIDITY(c->pstream, s, tag, ret);
2133 reply = reply_new(tag);
2134 pa_tagstruct_putu32(reply, s->index);
2135 pa_assert(s->source_output);
2136 pa_tagstruct_putu32(reply, s->source_output->index);
2138 if (c->version >= 9) {
2139 /* Since 0.9 we support sending the buffer metrics back to the client */
2141 pa_tagstruct_putu32(reply, (uint32_t) maxlength);
2142 pa_tagstruct_putu32(reply, (uint32_t) fragment_size);
2145 if (c->version >= 12) {
2146 /* Since 0.9.8 we support sending the chosen sample
2147 * spec/channel map/device/suspend status back to the
2150 pa_tagstruct_put_sample_spec(reply, &ss);
2151 pa_tagstruct_put_channel_map(reply, &map);
2153 pa_tagstruct_putu32(reply, s->source_output->source->index);
2154 pa_tagstruct_puts(reply, s->source_output->source->name);
2156 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2159 if (c->version >= 13)
2160 pa_tagstruct_put_usec(reply, s->source_latency);
2162 pa_pstream_send_tagstruct(c->pstream, reply);
2165 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2166 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2169 pa_native_connection_assert_ref(c);
2172 if (!pa_tagstruct_eof(t)) {
2177 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2178 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2179 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2181 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2184 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2185 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2187 pa_tagstruct *reply;
2188 pa_bool_t shm_on_remote = FALSE, do_shm;
2190 pa_native_connection_assert_ref(c);
2193 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2194 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2195 !pa_tagstruct_eof(t)) {
2200 /* Minimum supported version */
2201 if (c->version < 8) {
2202 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2206 /* Starting with protocol version 13 the MSB of the version tag
2207 reflects if shm is available for this pa_native_connection or
2209 if (c->version >= 13) {
2210 shm_on_remote = !!(c->version & 0x80000000U);
2211 c->version &= 0x7FFFFFFFU;
2214 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2216 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2218 if (!c->authorized) {
2219 pa_bool_t success = FALSE;
2222 const pa_creds *creds;
2224 if ((creds = pa_pdispatch_creds(pd))) {
2225 if (creds->uid == getuid())
2227 else if (c->options->auth_group) {
2231 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2232 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2233 else if (gid == creds->gid)
2237 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2238 pa_log_warn("Failed to check group membership.");
2244 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2245 (unsigned long) creds->uid,
2246 (unsigned long) creds->gid,
2251 if (!success && c->options->auth_cookie) {
2254 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2255 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2260 pa_log_warn("Denied access to client with invalid authorization data.");
2261 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2265 c->authorized = TRUE;
2266 if (c->auth_timeout_event) {
2267 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2268 c->auth_timeout_event = NULL;
2272 /* Enable shared memory support if possible */
2274 pa_mempool_is_shared(c->protocol->core->mempool) &&
2277 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2280 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2285 /* Only enable SHM if both sides are owned by the same
2286 * user. This is a security measure because otherwise data
2287 * private to the user might leak. */
2289 const pa_creds *creds;
2290 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2295 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2296 pa_pstream_enable_shm(c->pstream, do_shm);
2298 reply = reply_new(tag);
2299 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2303 /* SHM support is only enabled after both sides made sure they are the same user. */
2307 ucred.uid = getuid();
2308 ucred.gid = getgid();
2310 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2313 pa_pstream_send_tagstruct(c->pstream, reply);
2317 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2318 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2319 const char *name = NULL;
2321 pa_tagstruct *reply;
2323 pa_native_connection_assert_ref(c);
2326 p = pa_proplist_new();
2328 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2329 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2330 !pa_tagstruct_eof(t)) {
2333 pa_proplist_free(p);
2338 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2339 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2340 pa_proplist_free(p);
2344 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2345 pa_proplist_free(p);
2347 reply = reply_new(tag);
2349 if (c->version >= 13)
2350 pa_tagstruct_putu32(reply, c->client->index);
2352 pa_pstream_send_tagstruct(c->pstream, reply);
2355 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2356 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2358 uint32_t idx = PA_IDXSET_INVALID;
2360 pa_native_connection_assert_ref(c);
2363 if (pa_tagstruct_gets(t, &name) < 0 ||
2364 !pa_tagstruct_eof(t)) {
2369 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2370 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2372 if (command == PA_COMMAND_LOOKUP_SINK) {
2374 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2378 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2379 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2380 idx = source->index;
2383 if (idx == PA_IDXSET_INVALID)
2384 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2386 pa_tagstruct *reply;
2387 reply = reply_new(tag);
2388 pa_tagstruct_putu32(reply, idx);
2389 pa_pstream_send_tagstruct(c->pstream, reply);
2393 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2394 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2398 pa_native_connection_assert_ref(c);
2401 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2402 !pa_tagstruct_eof(t)) {
2407 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2408 s = pa_idxset_get_by_index(c->output_streams, idx);
2409 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2410 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2412 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);
2415 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2416 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2417 pa_tagstruct *reply;
2418 const pa_mempool_stat *stat;
2420 pa_native_connection_assert_ref(c);
2423 if (!pa_tagstruct_eof(t)) {
2428 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2430 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2432 reply = reply_new(tag);
2433 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2434 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2435 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2436 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2437 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2438 pa_pstream_send_tagstruct(c->pstream, reply);
2441 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2442 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2443 pa_tagstruct *reply;
2445 struct timeval tv, now;
2449 pa_native_connection_assert_ref(c);
2452 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2453 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2454 !pa_tagstruct_eof(t)) {
2459 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2460 s = pa_idxset_get_by_index(c->output_streams, idx);
2461 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2462 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2463 CHECK_VALIDITY(c->pstream, pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0, tag, PA_ERR_NOENTITY)
2465 reply = reply_new(tag);
2467 latency = pa_sink_get_latency(s->sink_input->sink);
2468 latency += pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sample_spec);
2470 pa_tagstruct_put_usec(reply, latency);
2472 pa_tagstruct_put_usec(reply, 0);
2473 pa_tagstruct_put_boolean(reply, s->sink_input->thread_info.playing_for > 0);
2474 pa_tagstruct_put_timeval(reply, &tv);
2475 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2476 pa_tagstruct_puts64(reply, s->write_index);
2477 pa_tagstruct_puts64(reply, s->read_index);
2479 if (c->version >= 13) {
2480 pa_tagstruct_putu64(reply, s->sink_input->thread_info.underrun_for);
2481 pa_tagstruct_putu64(reply, s->sink_input->thread_info.playing_for);
2484 pa_pstream_send_tagstruct(c->pstream, reply);
2487 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2488 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2489 pa_tagstruct *reply;
2491 struct timeval tv, now;
2494 pa_native_connection_assert_ref(c);
2497 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2498 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2499 !pa_tagstruct_eof(t)) {
2504 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2505 s = pa_idxset_get_by_index(c->record_streams, idx);
2506 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2508 reply = reply_new(tag);
2509 pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0);
2510 pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source));
2511 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING);
2512 pa_tagstruct_put_timeval(reply, &tv);
2513 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2514 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2515 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2516 pa_pstream_send_tagstruct(c->pstream, reply);
2519 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2520 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2523 const char *name = NULL;
2526 pa_tagstruct *reply;
2529 pa_native_connection_assert_ref(c);
2532 if (pa_tagstruct_gets(t, &name) < 0 ||
2533 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2534 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2535 pa_tagstruct_getu32(t, &length) < 0) {
2540 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2541 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2542 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2543 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2544 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2545 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2547 p = pa_proplist_new();
2549 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2550 !pa_tagstruct_eof(t)) {
2553 pa_proplist_free(p);
2557 if (c->version < 13)
2558 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2560 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2561 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2563 if (!name || !pa_namereg_is_valid_name(name)) {
2564 pa_proplist_free(p);
2565 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2568 s = upload_stream_new(c, &ss, &map, name, length, p);
2569 pa_proplist_free(p);
2571 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2573 reply = reply_new(tag);
2574 pa_tagstruct_putu32(reply, s->index);
2575 pa_tagstruct_putu32(reply, length);
2576 pa_pstream_send_tagstruct(c->pstream, reply);
2579 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2580 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2585 pa_native_connection_assert_ref(c);
2588 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2589 !pa_tagstruct_eof(t)) {
2594 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2596 s = pa_idxset_get_by_index(c->output_streams, channel);
2597 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2598 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2600 if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2601 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2603 pa_pstream_send_simple_ack(c->pstream, tag);
2605 upload_stream_unlink(s);
2608 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2609 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2610 uint32_t sink_index;
2613 const char *name, *sink_name;
2616 pa_tagstruct *reply;
2618 pa_native_connection_assert_ref(c);
2621 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2623 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2624 pa_tagstruct_gets(t, &sink_name) < 0 ||
2625 pa_tagstruct_getu32(t, &volume) < 0 ||
2626 pa_tagstruct_gets(t, &name) < 0) {
2631 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name(sink_name), tag, PA_ERR_INVALID);
2632 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2633 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2634 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2636 if (sink_index != PA_INVALID_INDEX)
2637 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2639 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2641 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2643 p = pa_proplist_new();
2645 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2646 !pa_tagstruct_eof(t)) {
2648 pa_proplist_free(p);
2652 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2654 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2655 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2656 pa_proplist_free(p);
2660 pa_proplist_free(p);
2662 reply = reply_new(tag);
2664 if (c->version >= 13)
2665 pa_tagstruct_putu32(reply, idx);
2667 pa_pstream_send_tagstruct(c->pstream, reply);
2670 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2671 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2674 pa_native_connection_assert_ref(c);
2677 if (pa_tagstruct_gets(t, &name) < 0 ||
2678 !pa_tagstruct_eof(t)) {
2683 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2684 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2686 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
2687 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2691 pa_pstream_send_simple_ack(c->pstream, tag);
2694 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
2697 pa_assert(original);
2701 if (c->version < 12) {
2702 /* Before protocol version 12 we didn't support S32 samples,
2703 * so we need to lie about this to the client */
2705 if (fixed->format == PA_SAMPLE_S32LE)
2706 fixed->format = PA_SAMPLE_FLOAT32LE;
2707 if (fixed->format == PA_SAMPLE_S32BE)
2708 fixed->format = PA_SAMPLE_FLOAT32BE;
2711 if (c->version < 15) {
2712 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
2713 fixed->format = PA_SAMPLE_FLOAT32LE;
2714 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
2715 fixed->format = PA_SAMPLE_FLOAT32BE;
2719 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
2720 pa_sample_spec fixed_ss;
2723 pa_sink_assert_ref(sink);
2725 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
2729 PA_TAG_U32, sink->index,
2730 PA_TAG_STRING, sink->name,
2731 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2732 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2733 PA_TAG_CHANNEL_MAP, &sink->channel_map,
2734 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
2735 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
2736 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
2737 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
2738 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
2739 PA_TAG_USEC, pa_sink_get_latency(sink),
2740 PA_TAG_STRING, sink->driver,
2741 PA_TAG_U32, sink->flags,
2744 if (c->version >= 13) {
2745 pa_tagstruct_put_proplist(t, sink->proplist);
2746 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
2749 if (c->version >= 15) {
2750 pa_tagstruct_put_volume(t, sink->base_volume);
2751 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
2752 pa_log_error("Internal sink state is invalid.");
2753 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
2754 pa_tagstruct_putu32(t, sink->n_volume_steps);
2755 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
2759 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
2760 pa_sample_spec fixed_ss;
2763 pa_source_assert_ref(source);
2765 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
2769 PA_TAG_U32, source->index,
2770 PA_TAG_STRING, source->name,
2771 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2772 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2773 PA_TAG_CHANNEL_MAP, &source->channel_map,
2774 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
2775 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
2776 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
2777 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
2778 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
2779 PA_TAG_USEC, pa_source_get_latency(source),
2780 PA_TAG_STRING, source->driver,
2781 PA_TAG_U32, source->flags,
2784 if (c->version >= 13) {
2785 pa_tagstruct_put_proplist(t, source->proplist);
2786 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
2789 if (c->version >= 15) {
2790 pa_tagstruct_put_volume(t, source->base_volume);
2791 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
2792 pa_log_error("Internal source state is invalid.");
2793 pa_tagstruct_putu32(t, pa_source_get_state(source));
2794 pa_tagstruct_putu32(t, source->n_volume_steps);
2795 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
2799 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
2803 pa_tagstruct_putu32(t, client->index);
2804 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
2805 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
2806 pa_tagstruct_puts(t, client->driver);
2808 if (c->version >= 13)
2809 pa_tagstruct_put_proplist(t, client->proplist);
2812 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
2819 pa_tagstruct_putu32(t, card->index);
2820 pa_tagstruct_puts(t, card->name);
2821 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
2822 pa_tagstruct_puts(t, card->driver);
2824 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
2826 if (card->profiles) {
2827 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
2828 pa_tagstruct_puts(t, p->name);
2829 pa_tagstruct_puts(t, p->description);
2830 pa_tagstruct_putu32(t, p->n_sinks);
2831 pa_tagstruct_putu32(t, p->n_sources);
2832 pa_tagstruct_putu32(t, p->priority);
2836 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
2837 pa_tagstruct_put_proplist(t, card->proplist);
2840 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
2844 pa_tagstruct_putu32(t, module->index);
2845 pa_tagstruct_puts(t, module->name);
2846 pa_tagstruct_puts(t, module->argument);
2847 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
2849 if (c->version < 15)
2850 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
2852 if (c->version >= 15)
2853 pa_tagstruct_put_proplist(t, module->proplist);
2856 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
2857 pa_sample_spec fixed_ss;
2858 pa_usec_t sink_latency;
2861 pa_sink_input_assert_ref(s);
2863 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
2865 pa_tagstruct_putu32(t, s->index);
2866 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
2867 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
2868 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
2869 pa_tagstruct_putu32(t, s->sink->index);
2870 pa_tagstruct_put_sample_spec(t, &fixed_ss);
2871 pa_tagstruct_put_channel_map(t, &s->channel_map);
2872 pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s));
2873 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
2874 pa_tagstruct_put_usec(t, sink_latency);
2875 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
2876 pa_tagstruct_puts(t, s->driver);
2877 if (c->version >= 11)
2878 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
2879 if (c->version >= 13)
2880 pa_tagstruct_put_proplist(t, s->proplist);
2883 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
2884 pa_sample_spec fixed_ss;
2885 pa_usec_t source_latency;
2888 pa_source_output_assert_ref(s);
2890 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
2892 pa_tagstruct_putu32(t, s->index);
2893 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
2894 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
2895 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
2896 pa_tagstruct_putu32(t, s->source->index);
2897 pa_tagstruct_put_sample_spec(t, &fixed_ss);
2898 pa_tagstruct_put_channel_map(t, &s->channel_map);
2899 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
2900 pa_tagstruct_put_usec(t, source_latency);
2901 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
2902 pa_tagstruct_puts(t, s->driver);
2904 if (c->version >= 13)
2905 pa_tagstruct_put_proplist(t, s->proplist);
2908 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
2909 pa_sample_spec fixed_ss;
2915 if (e->memchunk.memblock)
2916 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
2918 memset(&fixed_ss, 0, sizeof(fixed_ss));
2920 pa_tagstruct_putu32(t, e->index);
2921 pa_tagstruct_puts(t, e->name);
2923 if (e->volume_is_set)
2926 pa_cvolume_init(&v);
2928 pa_tagstruct_put_cvolume(t, &v);
2929 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
2930 pa_tagstruct_put_sample_spec(t, &fixed_ss);
2931 pa_tagstruct_put_channel_map(t, &e->channel_map);
2932 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
2933 pa_tagstruct_put_boolean(t, e->lazy);
2934 pa_tagstruct_puts(t, e->filename);
2936 if (c->version >= 13)
2937 pa_tagstruct_put_proplist(t, e->proplist);
2940 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2941 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2943 pa_sink *sink = NULL;
2944 pa_source *source = NULL;
2945 pa_client *client = NULL;
2946 pa_card *card = NULL;
2947 pa_module *module = NULL;
2948 pa_sink_input *si = NULL;
2949 pa_source_output *so = NULL;
2950 pa_scache_entry *sce = NULL;
2951 const char *name = NULL;
2952 pa_tagstruct *reply;
2954 pa_native_connection_assert_ref(c);
2957 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2958 (command != PA_COMMAND_GET_CLIENT_INFO &&
2959 command != PA_COMMAND_GET_MODULE_INFO &&
2960 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
2961 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
2962 pa_tagstruct_gets(t, &name) < 0) ||
2963 !pa_tagstruct_eof(t)) {
2968 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2969 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2970 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
2971 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
2972 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2974 if (command == PA_COMMAND_GET_SINK_INFO) {
2975 if (idx != PA_INVALID_INDEX)
2976 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
2978 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
2979 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
2980 if (idx != PA_INVALID_INDEX)
2981 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
2983 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
2984 } else if (command == PA_COMMAND_GET_CARD_INFO) {
2985 if (idx != PA_INVALID_INDEX)
2986 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
2988 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
2989 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
2990 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
2991 else if (command == PA_COMMAND_GET_MODULE_INFO)
2992 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
2993 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
2994 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
2995 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
2996 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
2998 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
2999 if (idx != PA_INVALID_INDEX)
3000 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3002 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3005 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3006 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3010 reply = reply_new(tag);
3012 sink_fill_tagstruct(c, reply, sink);
3014 source_fill_tagstruct(c, reply, source);
3016 client_fill_tagstruct(c, reply, client);
3018 card_fill_tagstruct(c, reply, card);
3020 module_fill_tagstruct(c, reply, module);
3022 sink_input_fill_tagstruct(c, reply, si);
3024 source_output_fill_tagstruct(c, reply, so);
3026 scache_fill_tagstruct(c, reply, sce);
3027 pa_pstream_send_tagstruct(c->pstream, reply);
3030 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3031 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3035 pa_tagstruct *reply;
3037 pa_native_connection_assert_ref(c);
3040 if (!pa_tagstruct_eof(t)) {
3045 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3047 reply = reply_new(tag);
3049 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3050 i = c->protocol->core->sinks;
3051 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3052 i = c->protocol->core->sources;
3053 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3054 i = c->protocol->core->clients;
3055 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3056 i = c->protocol->core->cards;
3057 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3058 i = c->protocol->core->modules;
3059 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3060 i = c->protocol->core->sink_inputs;
3061 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3062 i = c->protocol->core->source_outputs;
3064 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3065 i = c->protocol->core->scache;
3069 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3070 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3071 sink_fill_tagstruct(c, reply, p);
3072 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3073 source_fill_tagstruct(c, reply, p);
3074 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3075 client_fill_tagstruct(c, reply, p);
3076 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3077 card_fill_tagstruct(c, reply, p);
3078 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3079 module_fill_tagstruct(c, reply, p);
3080 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3081 sink_input_fill_tagstruct(c, reply, p);
3082 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3083 source_output_fill_tagstruct(c, reply, p);
3085 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3086 scache_fill_tagstruct(c, reply, p);
3091 pa_pstream_send_tagstruct(c->pstream, reply);
3094 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3095 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3096 pa_tagstruct *reply;
3099 pa_source *def_source;
3100 pa_sample_spec fixed_ss;
3102 pa_native_connection_assert_ref(c);
3105 if (!pa_tagstruct_eof(t)) {
3110 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3112 reply = reply_new(tag);
3113 pa_tagstruct_puts(reply, PACKAGE_NAME);
3114 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3115 pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt)));
3116 pa_tagstruct_puts(reply, pa_get_host_name(txt, sizeof(txt)));
3118 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3119 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3121 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3122 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3123 def_source = pa_namereg_get_default_source(c->protocol->core);
3124 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3126 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3128 if (c->version >= 15)
3129 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3131 pa_pstream_send_tagstruct(c->pstream, reply);
3134 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3136 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3138 pa_native_connection_assert_ref(c);
3140 t = pa_tagstruct_new(NULL, 0);
3141 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3142 pa_tagstruct_putu32(t, (uint32_t) -1);
3143 pa_tagstruct_putu32(t, e);
3144 pa_tagstruct_putu32(t, idx);
3145 pa_pstream_send_tagstruct(c->pstream, t);
3148 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3149 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3150 pa_subscription_mask_t m;
3152 pa_native_connection_assert_ref(c);
3155 if (pa_tagstruct_getu32(t, &m) < 0 ||
3156 !pa_tagstruct_eof(t)) {
3161 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3162 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3164 if (c->subscription)
3165 pa_subscription_free(c->subscription);
3168 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3169 pa_assert(c->subscription);
3171 c->subscription = NULL;
3173 pa_pstream_send_simple_ack(c->pstream, tag);
3176 static void command_set_volume(
3183 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3186 pa_sink *sink = NULL;
3187 pa_source *source = NULL;
3188 pa_sink_input *si = NULL;
3189 const char *name = NULL;
3191 pa_native_connection_assert_ref(c);
3194 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3195 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3196 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3197 pa_tagstruct_get_cvolume(t, &volume) ||
3198 !pa_tagstruct_eof(t)) {
3203 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3204 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3205 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3206 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3207 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3208 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3212 case PA_COMMAND_SET_SINK_VOLUME:
3213 if (idx != PA_INVALID_INDEX)
3214 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3216 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3219 case PA_COMMAND_SET_SOURCE_VOLUME:
3220 if (idx != PA_INVALID_INDEX)
3221 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3223 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3226 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3227 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3231 pa_assert_not_reached();
3234 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3237 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3239 pa_source_set_volume(source, &volume);
3241 pa_sink_input_set_volume(si, &volume, TRUE);
3243 pa_pstream_send_simple_ack(c->pstream, tag);
3246 static void command_set_mute(
3253 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3256 pa_sink *sink = NULL;
3257 pa_source *source = NULL;
3258 pa_sink_input *si = NULL;
3259 const char *name = NULL;
3261 pa_native_connection_assert_ref(c);
3264 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3265 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3266 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3267 pa_tagstruct_get_boolean(t, &mute) ||
3268 !pa_tagstruct_eof(t)) {
3273 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3274 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3275 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3276 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3277 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3281 case PA_COMMAND_SET_SINK_MUTE:
3283 if (idx != PA_INVALID_INDEX)
3284 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3286 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3290 case PA_COMMAND_SET_SOURCE_MUTE:
3291 if (idx != PA_INVALID_INDEX)
3292 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3294 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3298 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3299 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3303 pa_assert_not_reached();
3306 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3309 pa_sink_set_mute(sink, mute);
3311 pa_source_set_mute(source, mute);
3313 pa_sink_input_set_mute(si, mute, TRUE);
3315 pa_pstream_send_simple_ack(c->pstream, tag);
3318 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3319 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3324 pa_native_connection_assert_ref(c);
3327 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3328 pa_tagstruct_get_boolean(t, &b) < 0 ||
3329 !pa_tagstruct_eof(t)) {
3334 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3335 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3336 s = pa_idxset_get_by_index(c->output_streams, idx);
3337 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3338 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3340 pa_sink_input_cork(s->sink_input, b);
3343 s->is_underrun = TRUE;
3345 pa_pstream_send_simple_ack(c->pstream, tag);
3348 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3349 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3353 pa_native_connection_assert_ref(c);
3356 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3357 !pa_tagstruct_eof(t)) {
3362 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3363 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3364 s = pa_idxset_get_by_index(c->output_streams, idx);
3365 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3366 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3369 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3370 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3373 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3374 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3377 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3378 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3382 pa_assert_not_reached();
3385 pa_pstream_send_simple_ack(c->pstream, tag);
3388 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3389 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3394 pa_native_connection_assert_ref(c);
3397 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3398 pa_tagstruct_get_boolean(t, &b) < 0 ||
3399 !pa_tagstruct_eof(t)) {
3404 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3405 s = pa_idxset_get_by_index(c->record_streams, idx);
3406 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3408 pa_source_output_cork(s->source_output, b);
3409 pa_memblockq_prebuf_force(s->memblockq);
3410 pa_pstream_send_simple_ack(c->pstream, tag);
3413 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3414 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3418 pa_native_connection_assert_ref(c);
3421 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3422 !pa_tagstruct_eof(t)) {
3427 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3428 s = pa_idxset_get_by_index(c->record_streams, idx);
3429 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3431 pa_memblockq_flush_read(s->memblockq);
3432 pa_pstream_send_simple_ack(c->pstream, tag);
3435 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3436 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3438 uint32_t maxlength, tlength, prebuf, minreq, fragsize;
3439 pa_tagstruct *reply;
3441 pa_native_connection_assert_ref(c);
3444 if (pa_tagstruct_getu32(t, &idx) < 0) {
3449 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3451 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3453 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3455 s = pa_idxset_get_by_index(c->output_streams, idx);
3456 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3457 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3459 if (pa_tagstruct_get(
3461 PA_TAG_U32, &maxlength,
3462 PA_TAG_U32, &tlength,
3463 PA_TAG_U32, &prebuf,
3464 PA_TAG_U32, &minreq,
3465 PA_TAG_INVALID) < 0 ||
3466 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3467 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3468 !pa_tagstruct_eof(t)) {
3473 fix_playback_buffer_attr_pre(s, adjust_latency, early_requests, &maxlength, &tlength, &prebuf, &minreq);
3474 pa_memblockq_set_maxlength(s->memblockq, maxlength);
3475 pa_memblockq_set_tlength(s->memblockq, tlength);
3476 pa_memblockq_set_prebuf(s->memblockq, prebuf);
3477 pa_memblockq_set_minreq(s->memblockq, minreq);
3478 fix_playback_buffer_attr_post(s, &maxlength, &tlength, &prebuf, &minreq);
3480 reply = reply_new(tag);
3481 pa_tagstruct_putu32(reply, maxlength);
3482 pa_tagstruct_putu32(reply, tlength);
3483 pa_tagstruct_putu32(reply, prebuf);
3484 pa_tagstruct_putu32(reply, minreq);
3486 if (c->version >= 13)
3487 pa_tagstruct_put_usec(reply, s->sink_latency);
3491 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3492 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3494 s = pa_idxset_get_by_index(c->record_streams, idx);
3495 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3497 if (pa_tagstruct_get(
3499 PA_TAG_U32, &maxlength,
3500 PA_TAG_U32, &fragsize,
3501 PA_TAG_INVALID) < 0 ||
3502 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3503 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3504 !pa_tagstruct_eof(t)) {
3509 fix_record_buffer_attr_pre(s, adjust_latency, early_requests, &maxlength, &fragsize);
3510 pa_memblockq_set_maxlength(s->memblockq, maxlength);
3511 fix_record_buffer_attr_post(s, &maxlength, &fragsize);
3513 reply = reply_new(tag);
3514 pa_tagstruct_putu32(reply, maxlength);
3515 pa_tagstruct_putu32(reply, fragsize);
3517 if (c->version >= 13)
3518 pa_tagstruct_put_usec(reply, s->source_latency);
3521 pa_pstream_send_tagstruct(c->pstream, reply);
3524 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3525 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3529 pa_native_connection_assert_ref(c);
3532 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3533 pa_tagstruct_getu32(t, &rate) < 0 ||
3534 !pa_tagstruct_eof(t)) {
3539 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3540 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
3542 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
3545 s = pa_idxset_get_by_index(c->output_streams, idx);
3546 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3547 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3549 pa_sink_input_set_rate(s->sink_input, rate);
3553 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
3555 s = pa_idxset_get_by_index(c->record_streams, idx);
3556 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3558 pa_source_output_set_rate(s->source_output, rate);
3561 pa_pstream_send_simple_ack(c->pstream, tag);
3564 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3565 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3570 pa_native_connection_assert_ref(c);
3573 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3575 p = pa_proplist_new();
3577 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
3579 if (pa_tagstruct_getu32(t, &mode) < 0 ||
3580 pa_tagstruct_get_proplist(t, p) < 0 ||
3581 !pa_tagstruct_eof(t)) {
3583 pa_proplist_free(p);
3589 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3590 pa_tagstruct_getu32(t, &mode) < 0 ||
3591 pa_tagstruct_get_proplist(t, p) < 0 ||
3592 !pa_tagstruct_eof(t)) {
3594 pa_proplist_free(p);
3599 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
3600 pa_proplist_free(p);
3601 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
3604 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
3607 s = pa_idxset_get_by_index(c->output_streams, idx);
3608 if (!s || !playback_stream_isinstance(s)) {
3609 pa_proplist_free(p);
3610 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3612 pa_sink_input_update_proplist(s->sink_input, mode, p);
3614 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
3617 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
3618 pa_proplist_free(p);
3619 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3621 pa_source_output_update_proplist(s->source_output, mode, p);
3624 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
3626 pa_client_update_proplist(c->client, mode, p);
3629 pa_pstream_send_simple_ack(c->pstream, tag);
3630 pa_proplist_free(p);
3633 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3634 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3636 unsigned changed = 0;
3638 pa_strlist *l = NULL;
3640 pa_native_connection_assert_ref(c);
3643 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3645 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
3647 if (pa_tagstruct_getu32(t, &idx) < 0) {
3653 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3656 s = pa_idxset_get_by_index(c->output_streams, idx);
3657 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3658 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3660 p = s->sink_input->proplist;
3662 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3665 s = pa_idxset_get_by_index(c->record_streams, idx);
3666 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3668 p = s->source_output->proplist;
3670 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3672 p = c->client->proplist;
3678 if (pa_tagstruct_gets(t, &k) < 0) {
3687 l = pa_strlist_prepend(l, k);
3690 if (!pa_tagstruct_eof(t)) {
3699 l = pa_strlist_pop(l, &z);
3704 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
3708 pa_pstream_send_simple_ack(c->pstream, tag);
3711 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3714 s = pa_idxset_get_by_index(c->output_streams, idx);
3715 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
3717 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3720 s = pa_idxset_get_by_index(c->record_streams, idx);
3721 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
3724 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3725 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
3730 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3731 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3734 pa_native_connection_assert_ref(c);
3737 if (pa_tagstruct_gets(t, &s) < 0 ||
3738 !pa_tagstruct_eof(t)) {
3743 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3744 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
3746 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
3749 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
3750 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
3752 pa_namereg_set_default_source(c->protocol->core, source);
3755 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
3757 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
3758 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3760 pa_namereg_set_default_sink(c->protocol->core, sink);
3763 pa_pstream_send_simple_ack(c->pstream, tag);
3766 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3767 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3771 pa_native_connection_assert_ref(c);
3774 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3775 pa_tagstruct_gets(t, &name) < 0 ||
3776 !pa_tagstruct_eof(t)) {
3781 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3782 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
3784 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
3787 s = pa_idxset_get_by_index(c->output_streams, idx);
3788 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3789 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3791 pa_sink_input_set_name(s->sink_input, name);
3795 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
3797 s = pa_idxset_get_by_index(c->record_streams, idx);
3798 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3800 pa_source_output_set_name(s->source_output, name);
3803 pa_pstream_send_simple_ack(c->pstream, tag);
3806 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3807 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3810 pa_native_connection_assert_ref(c);
3813 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3814 !pa_tagstruct_eof(t)) {
3819 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3821 if (command == PA_COMMAND_KILL_CLIENT) {
3824 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3825 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
3827 pa_native_connection_ref(c);
3828 pa_client_kill(client);
3830 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
3833 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3834 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3836 pa_native_connection_ref(c);
3837 pa_sink_input_kill(s);
3839 pa_source_output *s;
3841 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
3843 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3844 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3846 pa_native_connection_ref(c);
3847 pa_source_output_kill(s);
3850 pa_pstream_send_simple_ack(c->pstream, tag);
3851 pa_native_connection_unref(c);
3854 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3855 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3857 const char *name, *argument;
3858 pa_tagstruct *reply;
3860 pa_native_connection_assert_ref(c);
3863 if (pa_tagstruct_gets(t, &name) < 0 ||
3864 pa_tagstruct_gets(t, &argument) < 0 ||
3865 !pa_tagstruct_eof(t)) {
3870 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3871 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
3872 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
3874 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
3875 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
3879 reply = reply_new(tag);
3880 pa_tagstruct_putu32(reply, m->index);
3881 pa_pstream_send_tagstruct(c->pstream, reply);
3884 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3885 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3889 pa_native_connection_assert_ref(c);
3892 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3893 !pa_tagstruct_eof(t)) {
3898 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3899 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3900 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
3902 pa_module_unload_request(m, FALSE);
3903 pa_pstream_send_simple_ack(c->pstream, tag);
3906 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3907 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3908 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
3909 const char *name_device = NULL;
3911 pa_native_connection_assert_ref(c);
3914 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3915 pa_tagstruct_getu32(t, &idx_device) < 0 ||
3916 pa_tagstruct_gets(t, &name_device) < 0 ||
3917 !pa_tagstruct_eof(t)) {
3922 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3923 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3925 CHECK_VALIDITY(c->pstream, !name_device || pa_namereg_is_valid_name(name_device), tag, PA_ERR_INVALID);
3926 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
3927 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
3928 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3930 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
3931 pa_sink_input *si = NULL;
3932 pa_sink *sink = NULL;
3934 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3936 if (idx_device != PA_INVALID_INDEX)
3937 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
3939 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
3941 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
3943 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
3944 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
3948 pa_source_output *so = NULL;
3951 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
3953 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3955 if (idx_device != PA_INVALID_INDEX)
3956 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
3958 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
3960 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
3962 if (pa_source_output_move_to(so, source, TRUE) < 0) {
3963 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
3968 pa_pstream_send_simple_ack(c->pstream, tag);
3971 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3972 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3973 uint32_t idx = PA_INVALID_INDEX;
3974 const char *name = NULL;
3977 pa_native_connection_assert_ref(c);
3980 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3981 pa_tagstruct_gets(t, &name) < 0 ||
3982 pa_tagstruct_get_boolean(t, &b) < 0 ||
3983 !pa_tagstruct_eof(t)) {
3988 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3989 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name) || *name == 0, tag, PA_ERR_INVALID);
3990 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3991 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3992 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3994 if (command == PA_COMMAND_SUSPEND_SINK) {
3996 if (idx == PA_INVALID_INDEX && name && !*name) {
3998 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4000 if (pa_sink_suspend_all(c->protocol->core, b) < 0) {
4001 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4005 pa_sink *sink = NULL;
4007 if (idx != PA_INVALID_INDEX)
4008 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4010 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4012 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4014 if (pa_sink_suspend(sink, b) < 0) {
4015 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4021 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4023 if (idx == PA_INVALID_INDEX && name && !*name) {
4025 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4027 if (pa_source_suspend_all(c->protocol->core, b) < 0) {
4028 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4035 if (idx != PA_INVALID_INDEX)
4036 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4038 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4040 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4042 if (pa_source_suspend(source, b) < 0) {
4043 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4049 pa_pstream_send_simple_ack(c->pstream, tag);
4052 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4053 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4054 uint32_t idx = PA_INVALID_INDEX;
4055 const char *name = NULL;
4057 pa_native_protocol_ext_cb_t cb;
4059 pa_native_connection_assert_ref(c);
4062 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4063 pa_tagstruct_gets(t, &name) < 0) {
4068 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4069 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4070 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4071 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4072 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4074 if (idx != PA_INVALID_INDEX)
4075 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4077 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4078 if (strcmp(name, m->name) == 0)
4082 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4083 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4085 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4086 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4088 if (cb(c->protocol, m, c, tag, t) < 0)
4092 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4093 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4094 uint32_t idx = PA_INVALID_INDEX;
4095 const char *name = NULL, *profile = NULL;
4096 pa_card *card = NULL;
4098 pa_native_connection_assert_ref(c);
4101 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4102 pa_tagstruct_gets(t, &name) < 0 ||
4103 pa_tagstruct_gets(t, &profile) < 0 ||
4104 !pa_tagstruct_eof(t)) {
4109 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4110 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4111 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4112 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4113 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4115 if (idx != PA_INVALID_INDEX)
4116 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4118 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4120 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4122 if (pa_card_set_profile(card, profile) < 0) {
4123 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4127 pa_pstream_send_simple_ack(c->pstream, tag);
4130 /*** pstream callbacks ***/
4132 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4133 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4137 pa_native_connection_assert_ref(c);
4139 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4140 pa_log("invalid packet.");
4141 native_connection_unlink(c);
4145 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) {
4146 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4147 output_stream *stream;
4151 pa_native_connection_assert_ref(c);
4153 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4154 pa_log("client sent block for invalid stream.");
4159 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4161 if (playback_stream_isinstance(stream)) {
4162 playback_stream *ps = PLAYBACK_STREAM(stream);
4164 if (chunk->memblock) {
4165 if (seek != PA_SEEK_RELATIVE || offset != 0)
4166 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, NULL, NULL);
4168 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4170 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);
4173 upload_stream *u = UPLOAD_STREAM(stream);
4176 if (!u->memchunk.memblock) {
4177 if (u->length == chunk->length && chunk->memblock) {
4178 u->memchunk = *chunk;
4179 pa_memblock_ref(u->memchunk.memblock);
4182 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4183 u->memchunk.index = u->memchunk.length = 0;
4187 pa_assert(u->memchunk.memblock);
4190 if (l > chunk->length)
4195 dst = pa_memblock_acquire(u->memchunk.memblock);
4197 if (chunk->memblock) {
4199 src = pa_memblock_acquire(chunk->memblock);
4201 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4202 (uint8_t*) src + chunk->index, l);
4204 pa_memblock_release(chunk->memblock);
4206 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4208 pa_memblock_release(u->memchunk.memblock);
4210 u->memchunk.length += l;
4216 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4217 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4220 pa_native_connection_assert_ref(c);
4222 native_connection_unlink(c);
4223 pa_log_info("Connection died.");
4226 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4227 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4230 pa_native_connection_assert_ref(c);
4232 native_connection_send_memblock(c);
4235 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4238 if (!(q = pa_thread_mq_get()))
4239 pa_pstream_send_revoke(p, block_id);
4241 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4244 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4247 if (!(q = pa_thread_mq_get()))
4248 pa_pstream_send_release(p, block_id);
4250 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4253 /*** client callbacks ***/
4255 static void client_kill_cb(pa_client *c) {
4258 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4259 pa_log_info("Connection killed.");
4262 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4264 pa_native_connection *c;
4267 c = PA_NATIVE_CONNECTION(client->userdata);
4268 pa_native_connection_assert_ref(c);
4270 if (c->version < 15)
4273 t = pa_tagstruct_new(NULL, 0);
4274 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4275 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4276 pa_tagstruct_puts(t, event);
4277 pa_tagstruct_put_proplist(t, pl);
4278 pa_pstream_send_tagstruct(c->pstream, t);
4281 /*** module entry points ***/
4283 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
4284 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4288 pa_native_connection_assert_ref(c);
4289 pa_assert(c->auth_timeout_event == e);
4291 if (!c->authorized) {
4292 native_connection_unlink(c);
4293 pa_log_info("Connection terminated due to authentication timeout.");
4297 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4298 pa_native_connection *c;
4301 pa_client_new_data data;
4307 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4308 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4309 pa_iochannel_free(io);
4313 pa_client_new_data_init(&data);
4314 data.module = o->module;
4315 data.driver = __FILE__;
4316 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4317 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4318 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4319 client = pa_client_new(p->core, &data);
4320 pa_client_new_data_done(&data);
4325 c = pa_msgobject_new(pa_native_connection);
4326 c->parent.parent.free = native_connection_free;
4327 c->parent.process_msg = native_connection_process_msg;
4329 c->options = pa_native_options_ref(o);
4330 c->authorized = FALSE;
4332 if (o->auth_anonymous) {
4333 pa_log_info("Client authenticated anonymously.");
4334 c->authorized = TRUE;
4337 if (!c->authorized &&
4339 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4341 pa_log_info("Client authenticated by IP ACL.");
4342 c->authorized = TRUE;
4345 if (!c->authorized) {
4347 pa_gettimeofday(&tv);
4348 tv.tv_sec += AUTH_TIMEOUT;
4349 c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c);
4351 c->auth_timeout_event = NULL;
4353 c->is_local = pa_iochannel_socket_is_local(io);
4357 c->client->kill = client_kill_cb;
4358 c->client->send_event = client_send_event_cb;
4359 c->client->userdata = c;
4361 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4362 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4363 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4364 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4365 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4366 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4367 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4369 c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX);
4371 c->record_streams = pa_idxset_new(NULL, NULL);
4372 c->output_streams = pa_idxset_new(NULL, NULL);
4374 c->rrobin_index = PA_IDXSET_INVALID;
4375 c->subscription = NULL;
4377 pa_idxset_put(p->connections, c, NULL);
4380 if (pa_iochannel_creds_supported(io))
4381 pa_iochannel_creds_enable(io);
4384 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4387 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4388 pa_native_connection *c;
4394 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4395 if (c->options->module == m)
4396 native_connection_unlink(c);
4399 static pa_native_protocol* native_protocol_new(pa_core *c) {
4400 pa_native_protocol *p;
4405 p = pa_xnew(pa_native_protocol, 1);
4408 p->connections = pa_idxset_new(NULL, NULL);
4412 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4414 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4415 pa_hook_init(&p->hooks[h], p);
4417 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4422 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4423 pa_native_protocol *p;
4425 if ((p = pa_shared_get(c, "native-protocol")))
4426 return pa_native_protocol_ref(p);
4428 return native_protocol_new(c);
4431 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4433 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4440 void pa_native_protocol_unref(pa_native_protocol *p) {
4441 pa_native_connection *c;
4445 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4447 if (PA_REFCNT_DEC(p) > 0)
4450 while ((c = pa_idxset_first(p->connections, NULL)))
4451 native_connection_unlink(c);
4453 pa_idxset_free(p->connections, NULL, NULL);
4455 pa_strlist_free(p->servers);
4457 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4458 pa_hook_done(&p->hooks[h]);
4460 pa_hashmap_free(p->extensions, NULL, NULL);
4462 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4467 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
4469 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4472 p->servers = pa_strlist_prepend(p->servers, name);
4474 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4477 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
4479 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4482 p->servers = pa_strlist_remove(p->servers, name);
4484 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4487 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
4489 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4494 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
4496 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4501 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
4503 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4506 pa_assert(!pa_hashmap_get(p->extensions, m));
4508 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
4512 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
4514 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4517 pa_assert_se(pa_hashmap_remove(p->extensions, m));
4520 pa_native_options* pa_native_options_new(void) {
4521 pa_native_options *o;
4523 o = pa_xnew0(pa_native_options, 1);
4529 pa_native_options* pa_native_options_ref(pa_native_options *o) {
4531 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4538 void pa_native_options_unref(pa_native_options *o) {
4540 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4542 if (PA_REFCNT_DEC(o) > 0)
4545 pa_xfree(o->auth_group);
4548 pa_ip_acl_free(o->auth_ip_acl);
4551 pa_auth_cookie_unref(o->auth_cookie);
4556 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
4561 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4564 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
4565 pa_log("auth-anonymous= expects a boolean argument.");
4570 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
4571 pa_log("auth-group-enabled= expects a boolean argument.");
4575 pa_xfree(o->auth_group);
4576 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
4580 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4583 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
4586 if (!(ipa = pa_ip_acl_new(acl))) {
4587 pa_log("Failed to parse IP ACL '%s'", acl);
4592 pa_ip_acl_free(o->auth_ip_acl);
4594 o->auth_ip_acl = ipa;
4598 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
4599 pa_log("auth-cookie-enabled= expects a boolean argument.");
4604 pa_auth_cookie_unref(o->auth_cookie);
4609 /* The new name for this is 'auth-cookie', for compat reasons
4610 * we check the old name too */
4611 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
4612 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
4613 cn = PA_NATIVE_COOKIE_FILE;
4615 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
4619 o->auth_cookie = NULL;
4624 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
4625 pa_native_connection_assert_ref(c);