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/rtclock.h>
33 #include <pulse/timeval.h>
34 #include <pulse/version.h>
35 #include <pulse/utf8.h>
36 #include <pulse/util.h>
37 #include <pulse/xmalloc.h>
39 #include <pulsecore/native-common.h>
40 #include <pulsecore/packet.h>
41 #include <pulsecore/client.h>
42 #include <pulsecore/source-output.h>
43 #include <pulsecore/sink-input.h>
44 #include <pulsecore/pstream.h>
45 #include <pulsecore/tagstruct.h>
46 #include <pulsecore/pdispatch.h>
47 #include <pulsecore/pstream-util.h>
48 #include <pulsecore/authkey.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/core-scache.h>
51 #include <pulsecore/core-subscribe.h>
52 #include <pulsecore/log.h>
53 #include <pulsecore/strlist.h>
54 #include <pulsecore/shared.h>
55 #include <pulsecore/sample-util.h>
56 #include <pulsecore/llist.h>
57 #include <pulsecore/creds.h>
58 #include <pulsecore/core-util.h>
59 #include <pulsecore/ipacl.h>
60 #include <pulsecore/thread-mq.h>
62 #include "protocol-native.h"
64 /* Kick a client if it doesn't authenticate within this time */
65 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
67 /* Don't accept more connection than this */
68 #define MAX_CONNECTIONS 64
70 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
71 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
72 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
73 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
75 struct pa_native_protocol;
77 typedef struct record_stream {
80 pa_native_connection *connection;
83 pa_source_output *source_output;
84 pa_memblockq *memblockq;
86 pa_bool_t adjust_latency:1;
87 pa_bool_t early_requests:1;
89 pa_buffer_attr buffer_attr;
91 pa_atomic_t on_the_fly;
92 pa_usec_t configured_source_latency;
95 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
96 size_t on_the_fly_snapshot;
97 pa_usec_t current_monitor_latency;
98 pa_usec_t current_source_latency;
101 #define RECORD_STREAM(o) (record_stream_cast(o))
102 PA_DEFINE_PRIVATE_CLASS(record_stream, pa_msgobject);
104 typedef struct output_stream {
108 #define OUTPUT_STREAM(o) (output_stream_cast(o))
109 PA_DEFINE_PRIVATE_CLASS(output_stream, pa_msgobject);
111 typedef struct playback_stream {
112 output_stream parent;
114 pa_native_connection *connection;
117 pa_sink_input *sink_input;
118 pa_memblockq *memblockq;
120 pa_bool_t adjust_latency:1;
121 pa_bool_t early_requests:1;
123 pa_bool_t is_underrun:1;
124 pa_bool_t drain_request:1;
129 pa_usec_t configured_sink_latency;
130 pa_buffer_attr buffer_attr;
132 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
133 int64_t read_index, write_index;
134 size_t render_memblockq_length;
135 pa_usec_t current_sink_latency;
136 uint64_t playing_for, underrun_for;
139 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
140 PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
142 typedef struct upload_stream {
143 output_stream parent;
145 pa_native_connection *connection;
148 pa_memchunk memchunk;
151 pa_sample_spec sample_spec;
152 pa_channel_map channel_map;
153 pa_proplist *proplist;
156 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
157 PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
159 struct pa_native_connection {
161 pa_native_protocol *protocol;
162 pa_native_options *options;
163 pa_bool_t authorized:1;
164 pa_bool_t is_local:1;
168 pa_pdispatch *pdispatch;
169 pa_idxset *record_streams, *output_streams;
170 uint32_t rrobin_index;
171 pa_subscription *subscription;
172 pa_time_event *auth_timeout_event;
175 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
176 PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
178 struct pa_native_protocol {
182 pa_idxset *connections;
185 pa_hook hooks[PA_NATIVE_HOOK_MAX];
187 pa_hashmap *extensions;
191 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
195 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
196 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
197 SINK_INPUT_MESSAGE_FLUSH,
198 SINK_INPUT_MESSAGE_TRIGGER,
199 SINK_INPUT_MESSAGE_SEEK,
200 SINK_INPUT_MESSAGE_PREBUF_FORCE,
201 SINK_INPUT_MESSAGE_UPDATE_LATENCY,
202 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
206 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
207 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
208 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
209 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
210 PLAYBACK_STREAM_MESSAGE_STARTED,
211 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
215 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
219 CONNECTION_MESSAGE_RELEASE,
220 CONNECTION_MESSAGE_REVOKE
223 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
224 static void sink_input_kill_cb(pa_sink_input *i);
225 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
226 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
227 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
228 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
229 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
230 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
232 static void native_connection_send_memblock(pa_native_connection *c);
233 static void playback_stream_request_bytes(struct playback_stream*s);
235 static void source_output_kill_cb(pa_source_output *o);
236 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
237 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend);
238 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
239 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
240 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
242 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
243 static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
245 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
246 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
247 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
248 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
249 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
250 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
251 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
252 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
253 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
254 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
255 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
256 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
257 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
258 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
259 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
260 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
261 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
262 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
263 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
264 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
265 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
266 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
267 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
268 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
269 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
270 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
271 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
272 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
273 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
274 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
275 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
276 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
277 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
278 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
279 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
280 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
281 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
282 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
283 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
285 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
286 [PA_COMMAND_ERROR] = NULL,
287 [PA_COMMAND_TIMEOUT] = NULL,
288 [PA_COMMAND_REPLY] = NULL,
289 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
290 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
291 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
292 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
293 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
294 [PA_COMMAND_AUTH] = command_auth,
295 [PA_COMMAND_REQUEST] = NULL,
296 [PA_COMMAND_EXIT] = command_exit,
297 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
298 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
299 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
300 [PA_COMMAND_STAT] = command_stat,
301 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
302 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
303 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
304 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
305 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
306 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
307 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
308 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
309 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
310 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
311 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
312 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
313 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
314 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
315 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
316 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
317 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
318 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
319 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
320 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
321 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
322 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
323 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
324 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
325 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
327 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
328 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
329 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
331 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
332 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
333 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
335 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
336 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
338 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
339 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
340 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
341 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
343 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
344 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
346 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
347 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
348 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
349 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
350 [PA_COMMAND_KILL_CLIENT] = command_kill,
351 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
352 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
353 [PA_COMMAND_LOAD_MODULE] = command_load_module,
354 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
356 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
357 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
358 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
359 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
361 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
362 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
364 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
365 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
367 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
368 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
370 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
371 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
372 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
374 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
375 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
376 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
378 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
380 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
381 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
383 [PA_COMMAND_EXTENSION] = command_extension
386 /* structure management */
388 /* Called from main context */
389 static void upload_stream_unlink(upload_stream *s) {
395 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
396 s->connection = NULL;
397 upload_stream_unref(s);
400 /* Called from main context */
401 static void upload_stream_free(pa_object *o) {
402 upload_stream *s = UPLOAD_STREAM(o);
405 upload_stream_unlink(s);
410 pa_proplist_free(s->proplist);
412 if (s->memchunk.memblock)
413 pa_memblock_unref(s->memchunk.memblock);
418 /* Called from main context */
419 static upload_stream* upload_stream_new(
420 pa_native_connection *c,
421 const pa_sample_spec *ss,
422 const pa_channel_map *map,
432 pa_assert(length > 0);
435 s = pa_msgobject_new(upload_stream);
436 s->parent.parent.parent.free = upload_stream_free;
438 s->sample_spec = *ss;
439 s->channel_map = *map;
440 s->name = pa_xstrdup(name);
441 pa_memchunk_reset(&s->memchunk);
443 s->proplist = pa_proplist_copy(p);
444 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
446 pa_idxset_put(c->output_streams, s, &s->index);
451 /* Called from main context */
452 static void record_stream_unlink(record_stream *s) {
458 if (s->source_output) {
459 pa_source_output_unlink(s->source_output);
460 pa_source_output_unref(s->source_output);
461 s->source_output = NULL;
464 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
465 s->connection = NULL;
466 record_stream_unref(s);
469 /* Called from main context */
470 static void record_stream_free(pa_object *o) {
471 record_stream *s = RECORD_STREAM(o);
474 record_stream_unlink(s);
476 pa_memblockq_free(s->memblockq);
480 /* Called from main context */
481 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
482 record_stream *s = RECORD_STREAM(o);
483 record_stream_assert_ref(s);
490 case RECORD_STREAM_MESSAGE_POST_DATA:
492 /* We try to keep up to date with how many bytes are
493 * currently on the fly */
494 pa_atomic_sub(&s->on_the_fly, chunk->length);
496 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
497 /* pa_log_warn("Failed to push data into output queue."); */
501 if (!pa_pstream_is_pending(s->connection->pstream))
502 native_connection_send_memblock(s->connection);
510 /* Called from main context */
511 static void fix_record_buffer_attr_pre(record_stream *s) {
514 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
518 /* This function will be called from the main thread, before as
519 * well as after the source output has been activated using
520 * pa_source_output_put()! That means it may not touch any
521 * ->thread_info data! */
523 frame_size = pa_frame_size(&s->source_output->sample_spec);
525 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
526 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
527 if (s->buffer_attr.maxlength <= 0)
528 s->buffer_attr.maxlength = (uint32_t) frame_size;
530 if (s->buffer_attr.fragsize == (uint32_t) -1)
531 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
532 if (s->buffer_attr.fragsize <= 0)
533 s->buffer_attr.fragsize = (uint32_t) frame_size;
535 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
537 if (s->early_requests) {
539 /* In early request mode we need to emulate the classic
540 * fragment-based playback model. We do this setting the source
541 * latency to the fragment size. */
543 source_usec = fragsize_usec;
545 } else if (s->adjust_latency) {
547 /* So, the user asked us to adjust the latency according to
548 * what the source can provide. Half the latency will be
549 * spent on the hw buffer, half of it in the async buffer
550 * queue we maintain for each client. */
552 source_usec = fragsize_usec/2;
556 /* Ok, the user didn't ask us to adjust the latency, hence we
559 source_usec = (pa_usec_t) -1;
562 if (source_usec != (pa_usec_t) -1)
563 s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
565 s->configured_source_latency = 0;
567 if (s->early_requests) {
569 /* Ok, we didn't necessarily get what we were asking for, so
570 * let's tell the user */
572 fragsize_usec = s->configured_source_latency;
574 } else if (s->adjust_latency) {
576 /* Now subtract what we actually got */
578 if (fragsize_usec >= s->configured_source_latency*2)
579 fragsize_usec -= s->configured_source_latency;
581 fragsize_usec = s->configured_source_latency;
584 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
585 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
587 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
589 if (s->buffer_attr.fragsize <= 0)
590 s->buffer_attr.fragsize = (uint32_t) frame_size;
593 /* Called from main context */
594 static void fix_record_buffer_attr_post(record_stream *s) {
599 /* This function will be called from the main thread, before as
600 * well as after the source output has been activated using
601 * pa_source_output_put()! That means it may not touch and
602 * ->thread_info data! */
604 base = pa_frame_size(&s->source_output->sample_spec);
606 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
607 if (s->buffer_attr.fragsize <= 0)
608 s->buffer_attr.fragsize = base;
610 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
611 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
614 /* Called from main context */
615 static record_stream* record_stream_new(
616 pa_native_connection *c,
620 pa_bool_t peak_detect,
621 pa_buffer_attr *attr,
622 pa_source_output_flags_t flags,
624 pa_bool_t adjust_latency,
625 pa_sink_input *direct_on_input,
626 pa_bool_t early_requests,
630 pa_source_output *source_output = NULL;
631 pa_source_output_new_data data;
638 pa_source_output_new_data_init(&data);
640 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
641 data.driver = __FILE__;
642 data.module = c->options->module;
643 data.client = c->client;
644 data.source = source;
645 data.direct_on_input = direct_on_input;
646 pa_source_output_new_data_set_sample_spec(&data, ss);
647 pa_source_output_new_data_set_channel_map(&data, map);
649 data.resample_method = PA_RESAMPLER_PEAKS;
652 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
654 pa_source_output_new_data_done(&data);
659 s = pa_msgobject_new(record_stream);
660 s->parent.parent.free = record_stream_free;
661 s->parent.process_msg = record_stream_process_msg;
663 s->source_output = source_output;
664 s->buffer_attr = *attr;
665 s->adjust_latency = adjust_latency;
666 s->early_requests = early_requests;
667 pa_atomic_store(&s->on_the_fly, 0);
669 s->source_output->parent.process_msg = source_output_process_msg;
670 s->source_output->push = source_output_push_cb;
671 s->source_output->kill = source_output_kill_cb;
672 s->source_output->get_latency = source_output_get_latency_cb;
673 s->source_output->moving = source_output_moving_cb;
674 s->source_output->suspend = source_output_suspend_cb;
675 s->source_output->send_event = source_output_send_event_cb;
676 s->source_output->userdata = s;
678 fix_record_buffer_attr_pre(s);
680 s->memblockq = pa_memblockq_new(
682 s->buffer_attr.maxlength,
684 pa_frame_size(&source_output->sample_spec),
690 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
691 fix_record_buffer_attr_post(s);
693 *ss = s->source_output->sample_spec;
694 *map = s->source_output->channel_map;
696 pa_idxset_put(c->record_streams, s, &s->index);
698 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
699 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
700 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
701 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
703 pa_source_output_put(s->source_output);
707 /* Called from main context */
708 static void record_stream_send_killed(record_stream *r) {
710 record_stream_assert_ref(r);
712 t = pa_tagstruct_new(NULL, 0);
713 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
714 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
715 pa_tagstruct_putu32(t, r->index);
716 pa_pstream_send_tagstruct(r->connection->pstream, t);
719 /* Called from main context */
720 static void playback_stream_unlink(playback_stream *s) {
727 pa_sink_input_unlink(s->sink_input);
728 pa_sink_input_unref(s->sink_input);
729 s->sink_input = NULL;
732 if (s->drain_request)
733 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
735 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
736 s->connection = NULL;
737 playback_stream_unref(s);
740 /* Called from main context */
741 static void playback_stream_free(pa_object* o) {
742 playback_stream *s = PLAYBACK_STREAM(o);
745 playback_stream_unlink(s);
747 pa_memblockq_free(s->memblockq);
751 /* Called from main context */
752 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
753 playback_stream *s = PLAYBACK_STREAM(o);
754 playback_stream_assert_ref(s);
761 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
766 if ((l = pa_atomic_load(&s->missing)) <= 0)
769 if (pa_atomic_cmpxchg(&s->missing, l, 0))
773 t = pa_tagstruct_new(NULL, 0);
774 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
775 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
776 pa_tagstruct_putu32(t, s->index);
777 pa_tagstruct_putu32(t, (uint32_t) l);
778 pa_pstream_send_tagstruct(s->connection->pstream, t);
780 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
784 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
787 /* pa_log("signalling underflow"); */
789 /* Report that we're empty */
790 t = pa_tagstruct_new(NULL, 0);
791 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
792 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
793 pa_tagstruct_putu32(t, s->index);
794 pa_pstream_send_tagstruct(s->connection->pstream, t);
798 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
801 /* Notify the user we're overflowed*/
802 t = pa_tagstruct_new(NULL, 0);
803 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
804 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
805 pa_tagstruct_putu32(t, s->index);
806 pa_pstream_send_tagstruct(s->connection->pstream, t);
810 case PLAYBACK_STREAM_MESSAGE_STARTED:
812 if (s->connection->version >= 13) {
815 /* Notify the user we started playback */
816 t = pa_tagstruct_new(NULL, 0);
817 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
818 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
819 pa_tagstruct_putu32(t, s->index);
820 pa_pstream_send_tagstruct(s->connection->pstream, t);
825 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
826 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
829 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
831 s->buffer_attr.tlength = (uint32_t) offset;
833 if (s->connection->version >= 15) {
836 t = pa_tagstruct_new(NULL, 0);
837 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
838 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
839 pa_tagstruct_putu32(t, s->index);
840 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
841 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
842 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
843 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
844 pa_tagstruct_put_usec(t, s->configured_sink_latency);
845 pa_pstream_send_tagstruct(s->connection->pstream, t);
854 /* Called from main context */
855 static void fix_playback_buffer_attr(playback_stream *s) {
856 size_t frame_size, max_prebuf;
857 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
861 /* This function will be called from the main thread, before as
862 * well as after the sink input has been activated using
863 * pa_sink_input_put()! That means it may not touch any
864 * ->thread_info data, such as the memblockq! */
866 frame_size = pa_frame_size(&s->sink_input->sample_spec);
868 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
869 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
870 if (s->buffer_attr.maxlength <= 0)
871 s->buffer_attr.maxlength = (uint32_t) frame_size;
873 if (s->buffer_attr.tlength == (uint32_t) -1)
874 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
875 if (s->buffer_attr.tlength <= 0)
876 s->buffer_attr.tlength = (uint32_t) frame_size;
878 if (s->buffer_attr.minreq == (uint32_t) -1)
879 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
880 if (s->buffer_attr.minreq <= 0)
881 s->buffer_attr.minreq = (uint32_t) frame_size;
883 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
884 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
886 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
887 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
889 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
890 (double) tlength_usec / PA_USEC_PER_MSEC,
891 (double) minreq_usec / PA_USEC_PER_MSEC);
893 if (s->early_requests) {
895 /* In early request mode we need to emulate the classic
896 * fragment-based playback model. We do this setting the sink
897 * latency to the fragment size. */
899 sink_usec = minreq_usec;
900 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
902 } else if (s->adjust_latency) {
904 /* So, the user asked us to adjust the latency of the stream
905 * buffer according to the what the sink can provide. The
906 * tlength passed in shall be the overall latency. Roughly
907 * half the latency will be spent on the hw buffer, the other
908 * half of it in the async buffer queue we maintain for each
909 * client. In between we'll have a safety space of size
910 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
911 * empty and needs to be filled, then our buffer must have
912 * enough data to fulfill this request immediatly and thus
913 * have at least the same tlength as the size of the hw
914 * buffer. It additionally needs space for 2 times minreq
915 * because if the buffer ran empty and a partial fillup
916 * happens immediately on the next iteration we need to be
917 * able to fulfill it and give the application also minreq
918 * time to fill it up again for the next request Makes 2 times
919 * minreq in plus.. */
921 if (tlength_usec > minreq_usec*2)
922 sink_usec = (tlength_usec - minreq_usec*2)/2;
926 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
930 /* Ok, the user didn't ask us to adjust the latency, but we
931 * still need to make sure that the parameters from the user
934 if (tlength_usec > minreq_usec*2)
935 sink_usec = (tlength_usec - minreq_usec*2);
939 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
942 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
944 if (s->early_requests) {
946 /* Ok, we didn't necessarily get what we were asking for, so
947 * let's tell the user */
949 minreq_usec = s->configured_sink_latency;
951 } else if (s->adjust_latency) {
953 /* Ok, we didn't necessarily get what we were asking for, so
954 * let's subtract from what we asked for for the remaining
957 if (tlength_usec >= s->configured_sink_latency)
958 tlength_usec -= s->configured_sink_latency;
961 /* FIXME: This is actually larger than necessary, since not all of
962 * the sink latency is actually rewritable. */
963 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
964 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
966 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
967 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
968 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
970 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
971 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
972 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
974 if (s->buffer_attr.minreq <= 0) {
975 s->buffer_attr.minreq = (uint32_t) frame_size;
976 s->buffer_attr.tlength += (uint32_t) frame_size*2;
979 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
980 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
982 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
984 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
985 s->buffer_attr.prebuf > max_prebuf)
986 s->buffer_attr.prebuf = max_prebuf;
989 /* Called from main context */
990 static playback_stream* playback_stream_new(
991 pa_native_connection *c,
1001 pa_sink_input_flags_t flags,
1003 pa_bool_t adjust_latency,
1004 pa_bool_t early_requests,
1007 playback_stream *s, *ssync;
1008 pa_sink_input *sink_input = NULL;
1009 pa_memchunk silence;
1011 int64_t start_index;
1012 pa_sink_input_new_data data;
1020 /* Find syncid group */
1021 for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) {
1023 if (!playback_stream_isinstance(ssync))
1026 if (ssync->syncid == syncid)
1030 /* Synced streams must connect to the same sink */
1034 sink = ssync->sink_input->sink;
1035 else if (sink != ssync->sink_input->sink) {
1036 *ret = PA_ERR_INVALID;
1041 pa_sink_input_new_data_init(&data);
1043 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1044 data.driver = __FILE__;
1045 data.module = c->options->module;
1046 data.client = c->client;
1048 pa_sink_input_new_data_set_sample_spec(&data, ss);
1049 pa_sink_input_new_data_set_channel_map(&data, map);
1051 pa_sink_input_new_data_set_volume(&data, volume);
1053 pa_sink_input_new_data_set_muted(&data, muted);
1054 data.sync_base = ssync ? ssync->sink_input : NULL;
1057 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1059 pa_sink_input_new_data_done(&data);
1064 s = pa_msgobject_new(playback_stream);
1065 s->parent.parent.parent.free = playback_stream_free;
1066 s->parent.parent.process_msg = playback_stream_process_msg;
1069 s->sink_input = sink_input;
1070 s->is_underrun = TRUE;
1071 s->drain_request = FALSE;
1072 pa_atomic_store(&s->missing, 0);
1073 s->buffer_attr = *a;
1074 s->adjust_latency = adjust_latency;
1075 s->early_requests = early_requests;
1077 s->sink_input->parent.process_msg = sink_input_process_msg;
1078 s->sink_input->pop = sink_input_pop_cb;
1079 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1080 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1081 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1082 s->sink_input->kill = sink_input_kill_cb;
1083 s->sink_input->moving = sink_input_moving_cb;
1084 s->sink_input->suspend = sink_input_suspend_cb;
1085 s->sink_input->send_event = sink_input_send_event_cb;
1086 s->sink_input->userdata = s;
1088 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1090 fix_playback_buffer_attr(s);
1092 pa_sink_input_get_silence(sink_input, &silence);
1093 s->memblockq = pa_memblockq_new(
1095 s->buffer_attr.maxlength,
1096 s->buffer_attr.tlength,
1097 pa_frame_size(&sink_input->sample_spec),
1098 s->buffer_attr.prebuf,
1099 s->buffer_attr.minreq,
1102 pa_memblock_unref(silence.memblock);
1104 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1106 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1108 *ss = s->sink_input->sample_spec;
1109 *map = s->sink_input->channel_map;
1111 pa_idxset_put(c->output_streams, s, &s->index);
1113 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1114 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1115 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1116 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1117 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1119 pa_sink_input_put(s->sink_input);
1123 /* Called from IO context */
1124 static void playback_stream_request_bytes(playback_stream *s) {
1126 int previous_missing;
1128 playback_stream_assert_ref(s);
1130 m = pa_memblockq_pop_missing(s->memblockq);
1132 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu)", */
1133 /* (unsigned long) m, */
1134 /* pa_memblockq_get_tlength(s->memblockq), */
1135 /* pa_memblockq_get_minreq(s->memblockq), */
1136 /* pa_memblockq_get_length(s->memblockq)); */
1141 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1143 previous_missing = pa_atomic_add(&s->missing, (int) m);
1144 minreq = pa_memblockq_get_minreq(s->memblockq);
1146 if (pa_memblockq_prebuf_active(s->memblockq) ||
1147 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1148 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1151 /* Called from main context */
1152 static void playback_stream_send_killed(playback_stream *p) {
1154 playback_stream_assert_ref(p);
1156 t = pa_tagstruct_new(NULL, 0);
1157 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1158 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1159 pa_tagstruct_putu32(t, p->index);
1160 pa_pstream_send_tagstruct(p->connection->pstream, t);
1163 /* Called from main context */
1164 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1165 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1166 pa_native_connection_assert_ref(c);
1173 case CONNECTION_MESSAGE_REVOKE:
1174 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1177 case CONNECTION_MESSAGE_RELEASE:
1178 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1185 /* Called from main context */
1186 static void native_connection_unlink(pa_native_connection *c) {
1195 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1198 pa_native_options_unref(c->options);
1200 while ((r = pa_idxset_first(c->record_streams, NULL)))
1201 record_stream_unlink(r);
1203 while ((o = pa_idxset_first(c->output_streams, NULL)))
1204 if (playback_stream_isinstance(o))
1205 playback_stream_unlink(PLAYBACK_STREAM(o));
1207 upload_stream_unlink(UPLOAD_STREAM(o));
1209 if (c->subscription)
1210 pa_subscription_free(c->subscription);
1213 pa_pstream_unlink(c->pstream);
1215 if (c->auth_timeout_event) {
1216 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1217 c->auth_timeout_event = NULL;
1220 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1222 pa_native_connection_unref(c);
1225 /* Called from main context */
1226 static void native_connection_free(pa_object *o) {
1227 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1231 native_connection_unlink(c);
1233 pa_idxset_free(c->record_streams, NULL, NULL);
1234 pa_idxset_free(c->output_streams, NULL, NULL);
1236 pa_pdispatch_unref(c->pdispatch);
1237 pa_pstream_unref(c->pstream);
1238 pa_client_free(c->client);
1243 /* Called from main context */
1244 static void native_connection_send_memblock(pa_native_connection *c) {
1248 start = PA_IDXSET_INVALID;
1252 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1255 if (start == PA_IDXSET_INVALID)
1256 start = c->rrobin_index;
1257 else if (start == c->rrobin_index)
1260 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1261 pa_memchunk schunk = chunk;
1263 if (schunk.length > r->buffer_attr.fragsize)
1264 schunk.length = r->buffer_attr.fragsize;
1266 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1268 pa_memblockq_drop(r->memblockq, schunk.length);
1269 pa_memblock_unref(schunk.memblock);
1276 /*** sink input callbacks ***/
1278 /* Called from thread context */
1279 static void handle_seek(playback_stream *s, int64_t indexw) {
1280 playback_stream_assert_ref(s);
1282 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1284 if (s->sink_input->thread_info.underrun_for > 0) {
1286 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1288 if (pa_memblockq_is_readable(s->memblockq)) {
1290 /* We just ended an underrun, let's ask the sink
1291 * for a complete rewind rewrite */
1293 pa_log_debug("Requesting rewind due to end of underrun.");
1294 pa_sink_input_request_rewind(s->sink_input,
1295 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1296 s->sink_input->thread_info.underrun_for),
1297 FALSE, TRUE, FALSE);
1303 indexr = pa_memblockq_get_read_index(s->memblockq);
1305 if (indexw < indexr) {
1306 /* OK, the sink already asked for this data, so
1307 * let's have it usk us again */
1309 pa_log_debug("Requesting rewind due to rewrite.");
1310 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1314 playback_stream_request_bytes(s);
1317 /* Called from thread context */
1318 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1319 pa_sink_input *i = PA_SINK_INPUT(o);
1322 pa_sink_input_assert_ref(i);
1323 s = PLAYBACK_STREAM(i->userdata);
1324 playback_stream_assert_ref(s);
1328 case SINK_INPUT_MESSAGE_SEEK: {
1331 windex = pa_memblockq_get_write_index(s->memblockq);
1333 /* The client side is incapable of accounting correctly
1334 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1335 * able to deal with that. */
1337 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1339 handle_seek(s, windex);
1343 case SINK_INPUT_MESSAGE_POST_DATA: {
1348 windex = pa_memblockq_get_write_index(s->memblockq);
1350 /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
1352 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1354 if (pa_log_ratelimit())
1355 pa_log_warn("Failed to push data into queue");
1356 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1357 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1360 handle_seek(s, windex);
1362 /* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1367 case SINK_INPUT_MESSAGE_DRAIN:
1368 case SINK_INPUT_MESSAGE_FLUSH:
1369 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1370 case SINK_INPUT_MESSAGE_TRIGGER: {
1373 pa_sink_input *isync;
1374 void (*func)(pa_memblockq *bq);
1377 case SINK_INPUT_MESSAGE_FLUSH:
1378 func = pa_memblockq_flush_write;
1381 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1382 func = pa_memblockq_prebuf_force;
1385 case SINK_INPUT_MESSAGE_DRAIN:
1386 case SINK_INPUT_MESSAGE_TRIGGER:
1387 func = pa_memblockq_prebuf_disable;
1391 pa_assert_not_reached();
1394 windex = pa_memblockq_get_write_index(s->memblockq);
1396 handle_seek(s, windex);
1398 /* Do the same for all other members in the sync group */
1399 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1400 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1401 windex = pa_memblockq_get_write_index(ssync->memblockq);
1402 func(ssync->memblockq);
1403 handle_seek(ssync, windex);
1406 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1407 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1408 windex = pa_memblockq_get_write_index(ssync->memblockq);
1409 func(ssync->memblockq);
1410 handle_seek(ssync, windex);
1413 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1414 if (!pa_memblockq_is_readable(s->memblockq))
1415 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1417 s->drain_tag = PA_PTR_TO_UINT(userdata);
1418 s->drain_request = TRUE;
1425 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1426 /* Atomically get a snapshot of all timing parameters... */
1427 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1428 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1429 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1430 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1431 s->underrun_for = s->sink_input->thread_info.underrun_for;
1432 s->playing_for = s->sink_input->thread_info.playing_for;
1436 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1439 windex = pa_memblockq_get_write_index(s->memblockq);
1441 pa_memblockq_prebuf_force(s->memblockq);
1443 handle_seek(s, windex);
1445 /* Fall through to the default handler */
1449 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1450 pa_usec_t *r = userdata;
1452 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1454 /* Fall through, the default handler will add in the extra
1455 * latency added by the resampler */
1459 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1460 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1461 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1466 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1469 /* Called from thread context */
1470 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1473 pa_sink_input_assert_ref(i);
1474 s = PLAYBACK_STREAM(i->userdata);
1475 playback_stream_assert_ref(s);
1478 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1480 if (pa_memblockq_is_readable(s->memblockq))
1481 s->is_underrun = FALSE;
1483 if (!s->is_underrun)
1484 pa_log_debug("Underrun on '%s', %lu bytes in queue.", pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)), (unsigned long) pa_memblockq_get_length(s->memblockq));
1486 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1487 s->drain_request = FALSE;
1488 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);
1489 } else if (!s->is_underrun)
1490 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1492 s->is_underrun = TRUE;
1494 playback_stream_request_bytes(s);
1497 /* This call will not fail with prebuf=0, hence we check for
1498 underrun explicitly above */
1499 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1502 chunk->length = PA_MIN(nbytes, chunk->length);
1504 if (i->thread_info.underrun_for > 0)
1505 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1507 pa_memblockq_drop(s->memblockq, chunk->length);
1508 playback_stream_request_bytes(s);
1513 /* Called from thread context */
1514 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1517 pa_sink_input_assert_ref(i);
1518 s = PLAYBACK_STREAM(i->userdata);
1519 playback_stream_assert_ref(s);
1521 /* If we are in an underrun, then we don't rewind */
1522 if (i->thread_info.underrun_for > 0)
1525 pa_memblockq_rewind(s->memblockq, nbytes);
1528 /* Called from thread context */
1529 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1532 pa_sink_input_assert_ref(i);
1533 s = PLAYBACK_STREAM(i->userdata);
1534 playback_stream_assert_ref(s);
1536 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1539 /* Called from thread context */
1540 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1542 size_t new_tlength, old_tlength;
1544 pa_sink_input_assert_ref(i);
1545 s = PLAYBACK_STREAM(i->userdata);
1546 playback_stream_assert_ref(s);
1548 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1549 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1551 if (old_tlength < new_tlength) {
1552 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1553 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1554 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1556 if (new_tlength == old_tlength)
1557 pa_log_debug("Failed to increase tlength");
1559 pa_log_debug("Notifying client about increased tlength");
1560 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH, NULL, pa_memblockq_get_tlength(s->memblockq), NULL, NULL);
1565 /* Called from main context */
1566 static void sink_input_kill_cb(pa_sink_input *i) {
1569 pa_sink_input_assert_ref(i);
1570 s = PLAYBACK_STREAM(i->userdata);
1571 playback_stream_assert_ref(s);
1573 playback_stream_send_killed(s);
1574 playback_stream_unlink(s);
1577 /* Called from main context */
1578 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1582 pa_sink_input_assert_ref(i);
1583 s = PLAYBACK_STREAM(i->userdata);
1584 playback_stream_assert_ref(s);
1586 if (s->connection->version < 15)
1589 t = pa_tagstruct_new(NULL, 0);
1590 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1591 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1592 pa_tagstruct_putu32(t, s->index);
1593 pa_tagstruct_puts(t, event);
1594 pa_tagstruct_put_proplist(t, pl);
1595 pa_pstream_send_tagstruct(s->connection->pstream, t);
1598 /* Called from main context */
1599 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1603 pa_sink_input_assert_ref(i);
1604 s = PLAYBACK_STREAM(i->userdata);
1605 playback_stream_assert_ref(s);
1607 if (s->connection->version < 12)
1610 t = pa_tagstruct_new(NULL, 0);
1611 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1612 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1613 pa_tagstruct_putu32(t, s->index);
1614 pa_tagstruct_put_boolean(t, suspend);
1615 pa_pstream_send_tagstruct(s->connection->pstream, t);
1618 /* Called from main context */
1619 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1623 pa_sink_input_assert_ref(i);
1624 s = PLAYBACK_STREAM(i->userdata);
1625 playback_stream_assert_ref(s);
1630 fix_playback_buffer_attr(s);
1631 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1632 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1634 if (s->connection->version < 12)
1637 t = pa_tagstruct_new(NULL, 0);
1638 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1639 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1640 pa_tagstruct_putu32(t, s->index);
1641 pa_tagstruct_putu32(t, dest->index);
1642 pa_tagstruct_puts(t, dest->name);
1643 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1645 if (s->connection->version >= 13) {
1646 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1647 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1648 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1649 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1650 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1653 pa_pstream_send_tagstruct(s->connection->pstream, t);
1656 /*** source_output callbacks ***/
1658 /* Called from thread context */
1659 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1660 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1663 pa_source_output_assert_ref(o);
1664 s = RECORD_STREAM(o->userdata);
1665 record_stream_assert_ref(s);
1668 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1669 /* Atomically get a snapshot of all timing parameters... */
1670 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1671 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1672 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1676 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1679 /* Called from thread context */
1680 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1683 pa_source_output_assert_ref(o);
1684 s = RECORD_STREAM(o->userdata);
1685 record_stream_assert_ref(s);
1688 pa_atomic_add(&s->on_the_fly, chunk->length);
1689 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1692 static void source_output_kill_cb(pa_source_output *o) {
1695 pa_source_output_assert_ref(o);
1696 s = RECORD_STREAM(o->userdata);
1697 record_stream_assert_ref(s);
1699 record_stream_send_killed(s);
1700 record_stream_unlink(s);
1703 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1706 pa_source_output_assert_ref(o);
1707 s = RECORD_STREAM(o->userdata);
1708 record_stream_assert_ref(s);
1710 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1712 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1715 /* Called from main context */
1716 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1720 pa_source_output_assert_ref(o);
1721 s = RECORD_STREAM(o->userdata);
1722 record_stream_assert_ref(s);
1724 if (s->connection->version < 15)
1727 t = pa_tagstruct_new(NULL, 0);
1728 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1729 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1730 pa_tagstruct_putu32(t, s->index);
1731 pa_tagstruct_puts(t, event);
1732 pa_tagstruct_put_proplist(t, pl);
1733 pa_pstream_send_tagstruct(s->connection->pstream, t);
1736 /* Called from main context */
1737 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1741 pa_source_output_assert_ref(o);
1742 s = RECORD_STREAM(o->userdata);
1743 record_stream_assert_ref(s);
1745 if (s->connection->version < 12)
1748 t = pa_tagstruct_new(NULL, 0);
1749 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1750 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1751 pa_tagstruct_putu32(t, s->index);
1752 pa_tagstruct_put_boolean(t, suspend);
1753 pa_pstream_send_tagstruct(s->connection->pstream, t);
1756 /* Called from main context */
1757 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1761 pa_source_output_assert_ref(o);
1762 s = RECORD_STREAM(o->userdata);
1763 record_stream_assert_ref(s);
1768 fix_record_buffer_attr_pre(s);
1769 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1770 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1771 fix_record_buffer_attr_post(s);
1773 if (s->connection->version < 12)
1776 t = pa_tagstruct_new(NULL, 0);
1777 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1778 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1779 pa_tagstruct_putu32(t, s->index);
1780 pa_tagstruct_putu32(t, dest->index);
1781 pa_tagstruct_puts(t, dest->name);
1782 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1784 if (s->connection->version >= 13) {
1785 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1786 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1787 pa_tagstruct_put_usec(t, s->configured_source_latency);
1790 pa_pstream_send_tagstruct(s->connection->pstream, t);
1793 /*** pdispatch callbacks ***/
1795 static void protocol_error(pa_native_connection *c) {
1796 pa_log("protocol error, kicking client");
1797 native_connection_unlink(c);
1800 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1801 if (!(expression)) { \
1802 pa_pstream_send_error((pstream), (tag), (error)); \
1807 static pa_tagstruct *reply_new(uint32_t tag) {
1808 pa_tagstruct *reply;
1810 reply = pa_tagstruct_new(NULL, 0);
1811 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1812 pa_tagstruct_putu32(reply, tag);
1816 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1817 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1819 uint32_t sink_index, syncid, missing;
1820 pa_buffer_attr attr;
1821 const char *name = NULL, *sink_name;
1824 pa_tagstruct *reply;
1825 pa_sink *sink = NULL;
1833 fix_channels = FALSE,
1835 variable_rate = FALSE,
1837 adjust_latency = FALSE,
1838 early_requests = FALSE,
1839 dont_inhibit_auto_suspend = FALSE,
1841 fail_on_suspend = FALSE;
1842 pa_sink_input_flags_t flags = 0;
1844 pa_bool_t volume_set = TRUE;
1845 int ret = PA_ERR_INVALID;
1847 pa_native_connection_assert_ref(c);
1849 memset(&attr, 0, sizeof(attr));
1851 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1854 PA_TAG_SAMPLE_SPEC, &ss,
1855 PA_TAG_CHANNEL_MAP, &map,
1856 PA_TAG_U32, &sink_index,
1857 PA_TAG_STRING, &sink_name,
1858 PA_TAG_U32, &attr.maxlength,
1859 PA_TAG_BOOLEAN, &corked,
1860 PA_TAG_U32, &attr.tlength,
1861 PA_TAG_U32, &attr.prebuf,
1862 PA_TAG_U32, &attr.minreq,
1863 PA_TAG_U32, &syncid,
1864 PA_TAG_CVOLUME, &volume,
1865 PA_TAG_INVALID) < 0) {
1871 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1872 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
1873 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
1874 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
1875 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
1876 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
1877 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
1878 CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID);
1880 p = pa_proplist_new();
1883 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1885 if (c->version >= 12) {
1886 /* Since 0.9.8 the user can ask for a couple of additional flags */
1888 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1889 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1890 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1891 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1892 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1893 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1894 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1897 pa_proplist_free(p);
1902 if (c->version >= 13) {
1904 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1905 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1906 pa_tagstruct_get_proplist(t, p) < 0) {
1908 pa_proplist_free(p);
1913 if (c->version >= 14) {
1915 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
1916 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
1918 pa_proplist_free(p);
1923 if (c->version >= 15) {
1925 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
1926 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
1927 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
1929 pa_proplist_free(p);
1934 if (!pa_tagstruct_eof(t)) {
1936 pa_proplist_free(p);
1940 if (sink_index != PA_INVALID_INDEX) {
1942 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
1943 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1944 pa_proplist_free(p);
1948 } else if (sink_name) {
1950 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
1951 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1952 pa_proplist_free(p);
1958 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
1959 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
1960 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
1961 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
1962 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
1963 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
1964 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
1965 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
1966 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
1967 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0);
1969 /* Only since protocol version 15 there's a seperate muted_set
1970 * flag. For older versions we synthesize it here */
1971 muted_set = muted_set || muted;
1973 s = playback_stream_new(c, sink, &ss, &map, &attr, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, &ret);
1974 pa_proplist_free(p);
1976 CHECK_VALIDITY(c->pstream, s, tag, ret);
1978 reply = reply_new(tag);
1979 pa_tagstruct_putu32(reply, s->index);
1980 pa_assert(s->sink_input);
1981 pa_tagstruct_putu32(reply, s->sink_input->index);
1982 pa_tagstruct_putu32(reply, missing);
1984 /* pa_log("initial request is %u", missing); */
1986 if (c->version >= 9) {
1987 /* Since 0.9.0 we support sending the buffer metrics back to the client */
1989 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
1990 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
1991 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
1992 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
1995 if (c->version >= 12) {
1996 /* Since 0.9.8 we support sending the chosen sample
1997 * spec/channel map/device/suspend status back to the
2000 pa_tagstruct_put_sample_spec(reply, &ss);
2001 pa_tagstruct_put_channel_map(reply, &map);
2003 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2004 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2006 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2009 if (c->version >= 13)
2010 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2012 pa_pstream_send_tagstruct(c->pstream, reply);
2015 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2016 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2019 pa_native_connection_assert_ref(c);
2022 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2023 !pa_tagstruct_eof(t)) {
2028 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2032 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2034 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2035 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2039 playback_stream_unlink(s);
2043 case PA_COMMAND_DELETE_RECORD_STREAM: {
2045 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2046 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2050 record_stream_unlink(s);
2054 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2057 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2058 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2062 upload_stream_unlink(s);
2067 pa_assert_not_reached();
2070 pa_pstream_send_simple_ack(c->pstream, tag);
2073 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2074 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2076 pa_buffer_attr attr;
2077 uint32_t source_index;
2078 const char *name = NULL, *source_name;
2081 pa_tagstruct *reply;
2082 pa_source *source = NULL;
2089 fix_channels = FALSE,
2091 variable_rate = FALSE,
2092 adjust_latency = FALSE,
2093 peak_detect = FALSE,
2094 early_requests = FALSE,
2095 dont_inhibit_auto_suspend = FALSE,
2096 fail_on_suspend = FALSE;
2097 pa_source_output_flags_t flags = 0;
2099 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2100 pa_sink_input *direct_on_input = NULL;
2101 int ret = PA_ERR_INVALID;
2103 pa_native_connection_assert_ref(c);
2106 memset(&attr, 0, sizeof(attr));
2108 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2109 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2110 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2111 pa_tagstruct_getu32(t, &source_index) < 0 ||
2112 pa_tagstruct_gets(t, &source_name) < 0 ||
2113 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2114 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2115 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2120 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2121 CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
2122 CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID);
2123 CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2124 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2125 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2126 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2128 p = pa_proplist_new();
2131 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2133 if (c->version >= 12) {
2134 /* Since 0.9.8 the user can ask for a couple of additional flags */
2136 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2137 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2138 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2139 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2140 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2141 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2142 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2145 pa_proplist_free(p);
2150 if (c->version >= 13) {
2152 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2153 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2154 pa_tagstruct_get_proplist(t, p) < 0 ||
2155 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2157 pa_proplist_free(p);
2162 if (c->version >= 14) {
2164 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2166 pa_proplist_free(p);
2171 if (c->version >= 15) {
2173 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2174 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2176 pa_proplist_free(p);
2181 if (!pa_tagstruct_eof(t)) {
2183 pa_proplist_free(p);
2187 if (source_index != PA_INVALID_INDEX) {
2189 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2190 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2191 pa_proplist_free(p);
2195 } else if (source_name) {
2197 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2198 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2199 pa_proplist_free(p);
2204 if (direct_on_input_idx != PA_INVALID_INDEX) {
2206 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2207 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2208 pa_proplist_free(p);
2214 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2215 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2216 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2217 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2218 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2219 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2220 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2221 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2222 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2223 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0);
2225 s = record_stream_new(c, source, &ss, &map, peak_detect, &attr, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
2226 pa_proplist_free(p);
2228 CHECK_VALIDITY(c->pstream, s, tag, ret);
2230 reply = reply_new(tag);
2231 pa_tagstruct_putu32(reply, s->index);
2232 pa_assert(s->source_output);
2233 pa_tagstruct_putu32(reply, s->source_output->index);
2235 if (c->version >= 9) {
2236 /* Since 0.9 we support sending the buffer metrics back to the client */
2238 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2239 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2242 if (c->version >= 12) {
2243 /* Since 0.9.8 we support sending the chosen sample
2244 * spec/channel map/device/suspend status back to the
2247 pa_tagstruct_put_sample_spec(reply, &ss);
2248 pa_tagstruct_put_channel_map(reply, &map);
2250 pa_tagstruct_putu32(reply, s->source_output->source->index);
2251 pa_tagstruct_puts(reply, s->source_output->source->name);
2253 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2256 if (c->version >= 13)
2257 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2259 pa_pstream_send_tagstruct(c->pstream, reply);
2262 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2263 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2266 pa_native_connection_assert_ref(c);
2269 if (!pa_tagstruct_eof(t)) {
2274 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2275 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2276 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2278 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2280 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2283 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2284 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2286 pa_tagstruct *reply;
2287 pa_bool_t shm_on_remote = FALSE, do_shm;
2289 pa_native_connection_assert_ref(c);
2292 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2293 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2294 !pa_tagstruct_eof(t)) {
2299 /* Minimum supported version */
2300 if (c->version < 8) {
2301 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2305 /* Starting with protocol version 13 the MSB of the version tag
2306 reflects if shm is available for this pa_native_connection or
2308 if (c->version >= 13) {
2309 shm_on_remote = !!(c->version & 0x80000000U);
2310 c->version &= 0x7FFFFFFFU;
2313 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2315 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2317 if (!c->authorized) {
2318 pa_bool_t success = FALSE;
2321 const pa_creds *creds;
2323 if ((creds = pa_pdispatch_creds(pd))) {
2324 if (creds->uid == getuid())
2326 else if (c->options->auth_group) {
2330 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2331 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2332 else if (gid == creds->gid)
2336 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2337 pa_log_warn("Failed to check group membership.");
2343 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2344 (unsigned long) creds->uid,
2345 (unsigned long) creds->gid,
2350 if (!success && c->options->auth_cookie) {
2353 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2354 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2359 pa_log_warn("Denied access to client with invalid authorization data.");
2360 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2364 c->authorized = TRUE;
2365 if (c->auth_timeout_event) {
2366 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2367 c->auth_timeout_event = NULL;
2371 /* Enable shared memory support if possible */
2373 pa_mempool_is_shared(c->protocol->core->mempool) &&
2376 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2379 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2384 /* Only enable SHM if both sides are owned by the same
2385 * user. This is a security measure because otherwise data
2386 * private to the user might leak. */
2388 const pa_creds *creds;
2389 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2394 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2395 pa_pstream_enable_shm(c->pstream, do_shm);
2397 reply = reply_new(tag);
2398 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2402 /* SHM support is only enabled after both sides made sure they are the same user. */
2406 ucred.uid = getuid();
2407 ucred.gid = getgid();
2409 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2412 pa_pstream_send_tagstruct(c->pstream, reply);
2416 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2417 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2418 const char *name = NULL;
2420 pa_tagstruct *reply;
2422 pa_native_connection_assert_ref(c);
2425 p = pa_proplist_new();
2427 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2428 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2429 !pa_tagstruct_eof(t)) {
2432 pa_proplist_free(p);
2437 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2438 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2439 pa_proplist_free(p);
2443 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2444 pa_proplist_free(p);
2446 reply = reply_new(tag);
2448 if (c->version >= 13)
2449 pa_tagstruct_putu32(reply, c->client->index);
2451 pa_pstream_send_tagstruct(c->pstream, reply);
2454 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2455 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2457 uint32_t idx = PA_IDXSET_INVALID;
2459 pa_native_connection_assert_ref(c);
2462 if (pa_tagstruct_gets(t, &name) < 0 ||
2463 !pa_tagstruct_eof(t)) {
2468 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2469 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_LOOKUP_SINK ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
2471 if (command == PA_COMMAND_LOOKUP_SINK) {
2473 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2477 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2478 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2479 idx = source->index;
2482 if (idx == PA_IDXSET_INVALID)
2483 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2485 pa_tagstruct *reply;
2486 reply = reply_new(tag);
2487 pa_tagstruct_putu32(reply, idx);
2488 pa_pstream_send_tagstruct(c->pstream, reply);
2492 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2493 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2497 pa_native_connection_assert_ref(c);
2500 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2501 !pa_tagstruct_eof(t)) {
2506 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2507 s = pa_idxset_get_by_index(c->output_streams, idx);
2508 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2509 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2511 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);
2514 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2515 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2516 pa_tagstruct *reply;
2517 const pa_mempool_stat *stat;
2519 pa_native_connection_assert_ref(c);
2522 if (!pa_tagstruct_eof(t)) {
2527 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2529 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2531 reply = reply_new(tag);
2532 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2533 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2534 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2535 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2536 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2537 pa_pstream_send_tagstruct(c->pstream, reply);
2540 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2541 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2542 pa_tagstruct *reply;
2544 struct timeval tv, now;
2547 pa_native_connection_assert_ref(c);
2550 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2551 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2552 !pa_tagstruct_eof(t)) {
2557 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2558 s = pa_idxset_get_by_index(c->output_streams, idx);
2559 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2560 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2562 /* Get an atomic snapshot of all timing parameters */
2563 pa_assert_se(pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0);
2565 reply = reply_new(tag);
2566 pa_tagstruct_put_usec(reply,
2567 s->current_sink_latency +
2568 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2569 pa_tagstruct_put_usec(reply, 0);
2570 pa_tagstruct_put_boolean(reply,
2571 s->playing_for > 0 &&
2572 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2573 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2574 pa_tagstruct_put_timeval(reply, &tv);
2575 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2576 pa_tagstruct_puts64(reply, s->write_index);
2577 pa_tagstruct_puts64(reply, s->read_index);
2579 if (c->version >= 13) {
2580 pa_tagstruct_putu64(reply, s->underrun_for);
2581 pa_tagstruct_putu64(reply, s->playing_for);
2584 pa_pstream_send_tagstruct(c->pstream, reply);
2587 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2588 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2589 pa_tagstruct *reply;
2591 struct timeval tv, now;
2594 pa_native_connection_assert_ref(c);
2597 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2598 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2599 !pa_tagstruct_eof(t)) {
2604 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2605 s = pa_idxset_get_by_index(c->record_streams, idx);
2606 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2608 /* Get an atomic snapshot of all timing parameters */
2609 pa_assert_se(pa_asyncmsgq_send(s->source_output->source->asyncmsgq, PA_MSGOBJECT(s->source_output), SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0);
2611 reply = reply_new(tag);
2612 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2613 pa_tagstruct_put_usec(reply,
2614 s->current_source_latency +
2615 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->sample_spec));
2616 pa_tagstruct_put_boolean(reply,
2617 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2618 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2619 pa_tagstruct_put_timeval(reply, &tv);
2620 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2621 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2622 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2623 pa_pstream_send_tagstruct(c->pstream, reply);
2626 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2627 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2630 const char *name = NULL;
2633 pa_tagstruct *reply;
2636 pa_native_connection_assert_ref(c);
2639 if (pa_tagstruct_gets(t, &name) < 0 ||
2640 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2641 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2642 pa_tagstruct_getu32(t, &length) < 0) {
2647 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2648 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2649 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2650 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2651 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2652 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2654 p = pa_proplist_new();
2656 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2657 !pa_tagstruct_eof(t)) {
2660 pa_proplist_free(p);
2664 if (c->version < 13)
2665 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2667 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2668 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2670 if (!name || !pa_namereg_is_valid_name(name)) {
2671 pa_proplist_free(p);
2672 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2675 s = upload_stream_new(c, &ss, &map, name, length, p);
2676 pa_proplist_free(p);
2678 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2680 reply = reply_new(tag);
2681 pa_tagstruct_putu32(reply, s->index);
2682 pa_tagstruct_putu32(reply, length);
2683 pa_pstream_send_tagstruct(c->pstream, reply);
2686 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2687 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2692 pa_native_connection_assert_ref(c);
2695 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2696 !pa_tagstruct_eof(t)) {
2701 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2703 s = pa_idxset_get_by_index(c->output_streams, channel);
2704 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2705 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2707 if (!s->memchunk.memblock)
2708 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2709 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2710 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2712 pa_pstream_send_simple_ack(c->pstream, tag);
2714 upload_stream_unlink(s);
2717 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2718 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2719 uint32_t sink_index;
2722 const char *name, *sink_name;
2725 pa_tagstruct *reply;
2727 pa_native_connection_assert_ref(c);
2730 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2732 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2733 pa_tagstruct_gets(t, &sink_name) < 0 ||
2734 pa_tagstruct_getu32(t, &volume) < 0 ||
2735 pa_tagstruct_gets(t, &name) < 0) {
2740 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2741 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2742 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2743 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2745 if (sink_index != PA_INVALID_INDEX)
2746 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2748 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2750 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2752 p = pa_proplist_new();
2754 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2755 !pa_tagstruct_eof(t)) {
2757 pa_proplist_free(p);
2761 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2763 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2764 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2765 pa_proplist_free(p);
2769 pa_proplist_free(p);
2771 reply = reply_new(tag);
2773 if (c->version >= 13)
2774 pa_tagstruct_putu32(reply, idx);
2776 pa_pstream_send_tagstruct(c->pstream, reply);
2779 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2780 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2783 pa_native_connection_assert_ref(c);
2786 if (pa_tagstruct_gets(t, &name) < 0 ||
2787 !pa_tagstruct_eof(t)) {
2792 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2793 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2795 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
2796 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2800 pa_pstream_send_simple_ack(c->pstream, tag);
2803 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
2806 pa_assert(original);
2810 if (c->version < 12) {
2811 /* Before protocol version 12 we didn't support S32 samples,
2812 * so we need to lie about this to the client */
2814 if (fixed->format == PA_SAMPLE_S32LE)
2815 fixed->format = PA_SAMPLE_FLOAT32LE;
2816 if (fixed->format == PA_SAMPLE_S32BE)
2817 fixed->format = PA_SAMPLE_FLOAT32BE;
2820 if (c->version < 15) {
2821 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
2822 fixed->format = PA_SAMPLE_FLOAT32LE;
2823 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
2824 fixed->format = PA_SAMPLE_FLOAT32BE;
2828 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
2829 pa_sample_spec fixed_ss;
2832 pa_sink_assert_ref(sink);
2834 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
2838 PA_TAG_U32, sink->index,
2839 PA_TAG_STRING, sink->name,
2840 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2841 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2842 PA_TAG_CHANNEL_MAP, &sink->channel_map,
2843 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
2844 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
2845 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
2846 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
2847 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
2848 PA_TAG_USEC, pa_sink_get_latency(sink),
2849 PA_TAG_STRING, sink->driver,
2850 PA_TAG_U32, sink->flags,
2853 if (c->version >= 13) {
2854 pa_tagstruct_put_proplist(t, sink->proplist);
2855 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
2858 if (c->version >= 15) {
2859 pa_tagstruct_put_volume(t, sink->base_volume);
2860 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
2861 pa_log_error("Internal sink state is invalid.");
2862 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
2863 pa_tagstruct_putu32(t, sink->n_volume_steps);
2864 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
2867 if (c->version >= 16) {
2868 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
2874 PA_HASHMAP_FOREACH(p, sink->ports, state) {
2875 pa_tagstruct_puts(t, p->name);
2876 pa_tagstruct_puts(t, p->description);
2877 pa_tagstruct_putu32(t, p->priority);
2881 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
2885 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
2886 pa_sample_spec fixed_ss;
2889 pa_source_assert_ref(source);
2891 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
2895 PA_TAG_U32, source->index,
2896 PA_TAG_STRING, source->name,
2897 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2898 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2899 PA_TAG_CHANNEL_MAP, &source->channel_map,
2900 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
2901 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
2902 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
2903 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
2904 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
2905 PA_TAG_USEC, pa_source_get_latency(source),
2906 PA_TAG_STRING, source->driver,
2907 PA_TAG_U32, source->flags,
2910 if (c->version >= 13) {
2911 pa_tagstruct_put_proplist(t, source->proplist);
2912 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
2915 if (c->version >= 15) {
2916 pa_tagstruct_put_volume(t, source->base_volume);
2917 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
2918 pa_log_error("Internal source state is invalid.");
2919 pa_tagstruct_putu32(t, pa_source_get_state(source));
2920 pa_tagstruct_putu32(t, source->n_volume_steps);
2921 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
2924 if (c->version >= 16) {
2926 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
2928 if (source->ports) {
2932 PA_HASHMAP_FOREACH(p, source->ports, state) {
2933 pa_tagstruct_puts(t, p->name);
2934 pa_tagstruct_puts(t, p->description);
2935 pa_tagstruct_putu32(t, p->priority);
2939 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
2943 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
2947 pa_tagstruct_putu32(t, client->index);
2948 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
2949 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
2950 pa_tagstruct_puts(t, client->driver);
2952 if (c->version >= 13)
2953 pa_tagstruct_put_proplist(t, client->proplist);
2956 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
2963 pa_tagstruct_putu32(t, card->index);
2964 pa_tagstruct_puts(t, card->name);
2965 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
2966 pa_tagstruct_puts(t, card->driver);
2968 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
2970 if (card->profiles) {
2971 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
2972 pa_tagstruct_puts(t, p->name);
2973 pa_tagstruct_puts(t, p->description);
2974 pa_tagstruct_putu32(t, p->n_sinks);
2975 pa_tagstruct_putu32(t, p->n_sources);
2976 pa_tagstruct_putu32(t, p->priority);
2980 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
2981 pa_tagstruct_put_proplist(t, card->proplist);
2984 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
2988 pa_tagstruct_putu32(t, module->index);
2989 pa_tagstruct_puts(t, module->name);
2990 pa_tagstruct_puts(t, module->argument);
2991 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
2993 if (c->version < 15)
2994 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
2996 if (c->version >= 15)
2997 pa_tagstruct_put_proplist(t, module->proplist);
3000 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3001 pa_sample_spec fixed_ss;
3002 pa_usec_t sink_latency;
3006 pa_sink_input_assert_ref(s);
3008 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3010 pa_tagstruct_putu32(t, s->index);
3011 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3012 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3013 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3014 pa_tagstruct_putu32(t, s->sink->index);
3015 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3016 pa_tagstruct_put_channel_map(t, &s->channel_map);
3017 pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s, &v, TRUE));
3018 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3019 pa_tagstruct_put_usec(t, sink_latency);
3020 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3021 pa_tagstruct_puts(t, s->driver);
3022 if (c->version >= 11)
3023 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3024 if (c->version >= 13)
3025 pa_tagstruct_put_proplist(t, s->proplist);
3028 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3029 pa_sample_spec fixed_ss;
3030 pa_usec_t source_latency;
3033 pa_source_output_assert_ref(s);
3035 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3037 pa_tagstruct_putu32(t, s->index);
3038 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3039 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3040 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3041 pa_tagstruct_putu32(t, s->source->index);
3042 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3043 pa_tagstruct_put_channel_map(t, &s->channel_map);
3044 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3045 pa_tagstruct_put_usec(t, source_latency);
3046 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3047 pa_tagstruct_puts(t, s->driver);
3049 if (c->version >= 13)
3050 pa_tagstruct_put_proplist(t, s->proplist);
3053 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3054 pa_sample_spec fixed_ss;
3060 if (e->memchunk.memblock)
3061 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3063 memset(&fixed_ss, 0, sizeof(fixed_ss));
3065 pa_tagstruct_putu32(t, e->index);
3066 pa_tagstruct_puts(t, e->name);
3068 if (e->volume_is_set)
3071 pa_cvolume_init(&v);
3073 pa_tagstruct_put_cvolume(t, &v);
3074 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3075 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3076 pa_tagstruct_put_channel_map(t, &e->channel_map);
3077 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3078 pa_tagstruct_put_boolean(t, e->lazy);
3079 pa_tagstruct_puts(t, e->filename);
3081 if (c->version >= 13)
3082 pa_tagstruct_put_proplist(t, e->proplist);
3085 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3086 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3088 pa_sink *sink = NULL;
3089 pa_source *source = NULL;
3090 pa_client *client = NULL;
3091 pa_card *card = NULL;
3092 pa_module *module = NULL;
3093 pa_sink_input *si = NULL;
3094 pa_source_output *so = NULL;
3095 pa_scache_entry *sce = NULL;
3096 const char *name = NULL;
3097 pa_tagstruct *reply;
3099 pa_native_connection_assert_ref(c);
3102 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3103 (command != PA_COMMAND_GET_CLIENT_INFO &&
3104 command != PA_COMMAND_GET_MODULE_INFO &&
3105 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3106 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3107 pa_tagstruct_gets(t, &name) < 0) ||
3108 !pa_tagstruct_eof(t)) {
3113 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3114 CHECK_VALIDITY(c->pstream, !name ||
3115 (command == PA_COMMAND_GET_SINK_INFO &&
3116 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3117 (command == PA_COMMAND_GET_SOURCE_INFO &&
3118 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3119 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3120 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3121 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3122 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3124 if (command == PA_COMMAND_GET_SINK_INFO) {
3125 if (idx != PA_INVALID_INDEX)
3126 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3128 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3129 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3130 if (idx != PA_INVALID_INDEX)
3131 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3133 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3134 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3135 if (idx != PA_INVALID_INDEX)
3136 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3138 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3139 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3140 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3141 else if (command == PA_COMMAND_GET_MODULE_INFO)
3142 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3143 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3144 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3145 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3146 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3148 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3149 if (idx != PA_INVALID_INDEX)
3150 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3152 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3155 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3156 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3160 reply = reply_new(tag);
3162 sink_fill_tagstruct(c, reply, sink);
3164 source_fill_tagstruct(c, reply, source);
3166 client_fill_tagstruct(c, reply, client);
3168 card_fill_tagstruct(c, reply, card);
3170 module_fill_tagstruct(c, reply, module);
3172 sink_input_fill_tagstruct(c, reply, si);
3174 source_output_fill_tagstruct(c, reply, so);
3176 scache_fill_tagstruct(c, reply, sce);
3177 pa_pstream_send_tagstruct(c->pstream, reply);
3180 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3181 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3185 pa_tagstruct *reply;
3187 pa_native_connection_assert_ref(c);
3190 if (!pa_tagstruct_eof(t)) {
3195 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3197 reply = reply_new(tag);
3199 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3200 i = c->protocol->core->sinks;
3201 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3202 i = c->protocol->core->sources;
3203 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3204 i = c->protocol->core->clients;
3205 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3206 i = c->protocol->core->cards;
3207 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3208 i = c->protocol->core->modules;
3209 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3210 i = c->protocol->core->sink_inputs;
3211 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3212 i = c->protocol->core->source_outputs;
3214 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3215 i = c->protocol->core->scache;
3219 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3220 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3221 sink_fill_tagstruct(c, reply, p);
3222 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3223 source_fill_tagstruct(c, reply, p);
3224 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3225 client_fill_tagstruct(c, reply, p);
3226 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3227 card_fill_tagstruct(c, reply, p);
3228 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3229 module_fill_tagstruct(c, reply, p);
3230 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3231 sink_input_fill_tagstruct(c, reply, p);
3232 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3233 source_output_fill_tagstruct(c, reply, p);
3235 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3236 scache_fill_tagstruct(c, reply, p);
3241 pa_pstream_send_tagstruct(c->pstream, reply);
3244 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3245 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3246 pa_tagstruct *reply;
3248 pa_source *def_source;
3249 pa_sample_spec fixed_ss;
3252 pa_native_connection_assert_ref(c);
3255 if (!pa_tagstruct_eof(t)) {
3260 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3262 reply = reply_new(tag);
3263 pa_tagstruct_puts(reply, PACKAGE_NAME);
3264 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3266 u = pa_get_user_name_malloc();
3267 pa_tagstruct_puts(reply, u);
3270 h = pa_get_host_name_malloc();
3271 pa_tagstruct_puts(reply, h);
3274 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3275 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3277 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3278 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3279 def_source = pa_namereg_get_default_source(c->protocol->core);
3280 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3282 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3284 if (c->version >= 15)
3285 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3287 pa_pstream_send_tagstruct(c->pstream, reply);
3290 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3292 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3294 pa_native_connection_assert_ref(c);
3296 t = pa_tagstruct_new(NULL, 0);
3297 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3298 pa_tagstruct_putu32(t, (uint32_t) -1);
3299 pa_tagstruct_putu32(t, e);
3300 pa_tagstruct_putu32(t, idx);
3301 pa_pstream_send_tagstruct(c->pstream, t);
3304 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3305 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3306 pa_subscription_mask_t m;
3308 pa_native_connection_assert_ref(c);
3311 if (pa_tagstruct_getu32(t, &m) < 0 ||
3312 !pa_tagstruct_eof(t)) {
3317 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3318 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3320 if (c->subscription)
3321 pa_subscription_free(c->subscription);
3324 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3325 pa_assert(c->subscription);
3327 c->subscription = NULL;
3329 pa_pstream_send_simple_ack(c->pstream, tag);
3332 static void command_set_volume(
3339 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3342 pa_sink *sink = NULL;
3343 pa_source *source = NULL;
3344 pa_sink_input *si = NULL;
3345 const char *name = NULL;
3346 const char *client_name;
3348 pa_native_connection_assert_ref(c);
3351 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3352 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3353 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3354 pa_tagstruct_get_cvolume(t, &volume) ||
3355 !pa_tagstruct_eof(t)) {
3360 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3361 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_VOLUME ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
3362 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3363 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3364 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3365 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3369 case PA_COMMAND_SET_SINK_VOLUME:
3370 if (idx != PA_INVALID_INDEX)
3371 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3373 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3376 case PA_COMMAND_SET_SOURCE_VOLUME:
3377 if (idx != PA_INVALID_INDEX)
3378 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3380 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3383 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3384 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3388 pa_assert_not_reached();
3391 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3393 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3396 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3398 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3399 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3400 } else if (source) {
3401 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3403 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3404 pa_source_set_volume(source, &volume, TRUE);
3406 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3408 pa_log_debug("Client %s changes volume of sink input %s.",
3410 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3411 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3414 pa_pstream_send_simple_ack(c->pstream, tag);
3417 static void command_set_mute(
3424 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3427 pa_sink *sink = NULL;
3428 pa_source *source = NULL;
3429 pa_sink_input *si = NULL;
3430 const char *name = NULL, *client_name;
3432 pa_native_connection_assert_ref(c);
3435 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3436 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3437 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3438 pa_tagstruct_get_boolean(t, &mute) ||
3439 !pa_tagstruct_eof(t)) {
3444 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3445 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_MUTE ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
3446 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3447 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3448 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3452 case PA_COMMAND_SET_SINK_MUTE:
3453 if (idx != PA_INVALID_INDEX)
3454 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3456 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3460 case PA_COMMAND_SET_SOURCE_MUTE:
3461 if (idx != PA_INVALID_INDEX)
3462 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3464 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3468 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3469 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3473 pa_assert_not_reached();
3476 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3478 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3481 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3482 pa_sink_set_mute(sink, mute, TRUE);
3483 } else if (source) {
3484 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3485 pa_source_set_mute(source, mute, TRUE);
3487 pa_log_debug("Client %s changes mute of sink input %s.",
3489 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3490 pa_sink_input_set_mute(si, mute, TRUE);
3493 pa_pstream_send_simple_ack(c->pstream, tag);
3496 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3497 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3502 pa_native_connection_assert_ref(c);
3505 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3506 pa_tagstruct_get_boolean(t, &b) < 0 ||
3507 !pa_tagstruct_eof(t)) {
3512 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3513 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3514 s = pa_idxset_get_by_index(c->output_streams, idx);
3515 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3516 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3518 pa_sink_input_cork(s->sink_input, b);
3521 s->is_underrun = TRUE;
3523 pa_pstream_send_simple_ack(c->pstream, tag);
3526 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3527 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3531 pa_native_connection_assert_ref(c);
3534 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3535 !pa_tagstruct_eof(t)) {
3540 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3541 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3542 s = pa_idxset_get_by_index(c->output_streams, idx);
3543 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3544 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3547 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3548 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3551 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3552 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3555 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3556 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3560 pa_assert_not_reached();
3563 pa_pstream_send_simple_ack(c->pstream, tag);
3566 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3567 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3572 pa_native_connection_assert_ref(c);
3575 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3576 pa_tagstruct_get_boolean(t, &b) < 0 ||
3577 !pa_tagstruct_eof(t)) {
3582 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3583 s = pa_idxset_get_by_index(c->record_streams, idx);
3584 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3586 pa_source_output_cork(s->source_output, b);
3587 pa_memblockq_prebuf_force(s->memblockq);
3588 pa_pstream_send_simple_ack(c->pstream, tag);
3591 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3592 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3596 pa_native_connection_assert_ref(c);
3599 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3600 !pa_tagstruct_eof(t)) {
3605 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3606 s = pa_idxset_get_by_index(c->record_streams, idx);
3607 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3609 pa_memblockq_flush_read(s->memblockq);
3610 pa_pstream_send_simple_ack(c->pstream, tag);
3613 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3614 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3617 pa_tagstruct *reply;
3619 pa_native_connection_assert_ref(c);
3622 memset(&a, 0, sizeof(a));
3624 if (pa_tagstruct_getu32(t, &idx) < 0) {
3629 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3631 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3633 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3635 s = pa_idxset_get_by_index(c->output_streams, idx);
3636 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3637 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3639 if (pa_tagstruct_get(
3641 PA_TAG_U32, &a.maxlength,
3642 PA_TAG_U32, &a.tlength,
3643 PA_TAG_U32, &a.prebuf,
3644 PA_TAG_U32, &a.minreq,
3645 PA_TAG_INVALID) < 0 ||
3646 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3647 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3648 !pa_tagstruct_eof(t)) {
3653 s->adjust_latency = adjust_latency;
3654 s->early_requests = early_requests;
3657 fix_playback_buffer_attr(s);
3658 pa_assert_se(pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR, NULL, 0, NULL) == 0);
3660 reply = reply_new(tag);
3661 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3662 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3663 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3664 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3666 if (c->version >= 13)
3667 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3671 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3672 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3674 s = pa_idxset_get_by_index(c->record_streams, idx);
3675 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3677 if (pa_tagstruct_get(
3679 PA_TAG_U32, &a.maxlength,
3680 PA_TAG_U32, &a.fragsize,
3681 PA_TAG_INVALID) < 0 ||
3682 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3683 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3684 !pa_tagstruct_eof(t)) {
3689 s->adjust_latency = adjust_latency;
3690 s->early_requests = early_requests;
3693 fix_record_buffer_attr_pre(s);
3694 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3695 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3696 fix_record_buffer_attr_post(s);
3698 reply = reply_new(tag);
3699 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3700 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3702 if (c->version >= 13)
3703 pa_tagstruct_put_usec(reply, s->configured_source_latency);
3706 pa_pstream_send_tagstruct(c->pstream, reply);
3709 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3710 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3714 pa_native_connection_assert_ref(c);
3717 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3718 pa_tagstruct_getu32(t, &rate) < 0 ||
3719 !pa_tagstruct_eof(t)) {
3724 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3725 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
3727 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
3730 s = pa_idxset_get_by_index(c->output_streams, idx);
3731 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3732 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3734 pa_sink_input_set_rate(s->sink_input, rate);
3738 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
3740 s = pa_idxset_get_by_index(c->record_streams, idx);
3741 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3743 pa_source_output_set_rate(s->source_output, rate);
3746 pa_pstream_send_simple_ack(c->pstream, tag);
3749 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3750 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3755 pa_native_connection_assert_ref(c);
3758 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3760 p = pa_proplist_new();
3762 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
3764 if (pa_tagstruct_getu32(t, &mode) < 0 ||
3765 pa_tagstruct_get_proplist(t, p) < 0 ||
3766 !pa_tagstruct_eof(t)) {
3768 pa_proplist_free(p);
3774 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3775 pa_tagstruct_getu32(t, &mode) < 0 ||
3776 pa_tagstruct_get_proplist(t, p) < 0 ||
3777 !pa_tagstruct_eof(t)) {
3779 pa_proplist_free(p);
3784 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
3785 pa_proplist_free(p);
3786 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
3789 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
3792 s = pa_idxset_get_by_index(c->output_streams, idx);
3793 if (!s || !playback_stream_isinstance(s)) {
3794 pa_proplist_free(p);
3795 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3797 pa_sink_input_update_proplist(s->sink_input, mode, p);
3799 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
3802 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
3803 pa_proplist_free(p);
3804 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3806 pa_source_output_update_proplist(s->source_output, mode, p);
3809 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
3811 pa_client_update_proplist(c->client, mode, p);
3814 pa_pstream_send_simple_ack(c->pstream, tag);
3815 pa_proplist_free(p);
3818 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3819 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3821 unsigned changed = 0;
3823 pa_strlist *l = NULL;
3825 pa_native_connection_assert_ref(c);
3828 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3830 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
3832 if (pa_tagstruct_getu32(t, &idx) < 0) {
3838 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3841 s = pa_idxset_get_by_index(c->output_streams, idx);
3842 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3843 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3845 p = s->sink_input->proplist;
3847 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3850 s = pa_idxset_get_by_index(c->record_streams, idx);
3851 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3853 p = s->source_output->proplist;
3855 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3857 p = c->client->proplist;
3863 if (pa_tagstruct_gets(t, &k) < 0) {
3872 l = pa_strlist_prepend(l, k);
3875 if (!pa_tagstruct_eof(t)) {
3884 l = pa_strlist_pop(l, &z);
3889 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
3893 pa_pstream_send_simple_ack(c->pstream, tag);
3896 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3899 s = pa_idxset_get_by_index(c->output_streams, idx);
3900 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
3902 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3905 s = pa_idxset_get_by_index(c->record_streams, idx);
3906 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
3909 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3910 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
3915 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3916 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3919 pa_native_connection_assert_ref(c);
3922 if (pa_tagstruct_gets(t, &s) < 0 ||
3923 !pa_tagstruct_eof(t)) {
3928 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3929 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
3931 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
3934 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
3935 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
3937 pa_namereg_set_default_source(c->protocol->core, source);
3940 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
3942 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
3943 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3945 pa_namereg_set_default_sink(c->protocol->core, sink);
3948 pa_pstream_send_simple_ack(c->pstream, tag);
3951 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3952 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3956 pa_native_connection_assert_ref(c);
3959 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3960 pa_tagstruct_gets(t, &name) < 0 ||
3961 !pa_tagstruct_eof(t)) {
3966 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3967 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
3969 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
3972 s = pa_idxset_get_by_index(c->output_streams, idx);
3973 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3974 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3976 pa_sink_input_set_name(s->sink_input, name);
3980 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
3982 s = pa_idxset_get_by_index(c->record_streams, idx);
3983 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3985 pa_source_output_set_name(s->source_output, name);
3988 pa_pstream_send_simple_ack(c->pstream, tag);
3991 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3992 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3995 pa_native_connection_assert_ref(c);
3998 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3999 !pa_tagstruct_eof(t)) {
4004 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4006 if (command == PA_COMMAND_KILL_CLIENT) {
4009 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4010 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4012 pa_native_connection_ref(c);
4013 pa_client_kill(client);
4015 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4018 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4019 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4021 pa_native_connection_ref(c);
4022 pa_sink_input_kill(s);
4024 pa_source_output *s;
4026 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4028 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4029 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4031 pa_native_connection_ref(c);
4032 pa_source_output_kill(s);
4035 pa_pstream_send_simple_ack(c->pstream, tag);
4036 pa_native_connection_unref(c);
4039 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4040 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4042 const char *name, *argument;
4043 pa_tagstruct *reply;
4045 pa_native_connection_assert_ref(c);
4048 if (pa_tagstruct_gets(t, &name) < 0 ||
4049 pa_tagstruct_gets(t, &argument) < 0 ||
4050 !pa_tagstruct_eof(t)) {
4055 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4056 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4057 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4059 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4060 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4064 reply = reply_new(tag);
4065 pa_tagstruct_putu32(reply, m->index);
4066 pa_pstream_send_tagstruct(c->pstream, reply);
4069 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4070 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4074 pa_native_connection_assert_ref(c);
4077 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4078 !pa_tagstruct_eof(t)) {
4083 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4084 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4085 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4087 pa_module_unload_request(m, FALSE);
4088 pa_pstream_send_simple_ack(c->pstream, tag);
4091 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4092 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4093 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4094 const char *name_device = NULL;
4096 pa_native_connection_assert_ref(c);
4099 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4100 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4101 pa_tagstruct_gets(t, &name_device) < 0 ||
4102 !pa_tagstruct_eof(t)) {
4107 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4108 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4110 CHECK_VALIDITY(c->pstream, !name_device || pa_namereg_is_valid_name_or_wildcard(name_device, command == PA_COMMAND_MOVE_SINK_INPUT ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
4111 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4112 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4113 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4115 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4116 pa_sink_input *si = NULL;
4117 pa_sink *sink = NULL;
4119 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4121 if (idx_device != PA_INVALID_INDEX)
4122 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4124 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4126 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4128 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4129 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4133 pa_source_output *so = NULL;
4136 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4138 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4140 if (idx_device != PA_INVALID_INDEX)
4141 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4143 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4145 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4147 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4148 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4153 pa_pstream_send_simple_ack(c->pstream, tag);
4156 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4157 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4158 uint32_t idx = PA_INVALID_INDEX;
4159 const char *name = NULL;
4162 pa_native_connection_assert_ref(c);
4165 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4166 pa_tagstruct_gets(t, &name) < 0 ||
4167 pa_tagstruct_get_boolean(t, &b) < 0 ||
4168 !pa_tagstruct_eof(t)) {
4173 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4174 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SUSPEND_SINK ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) || *name == 0, tag, PA_ERR_INVALID);
4175 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4176 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4177 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4179 if (command == PA_COMMAND_SUSPEND_SINK) {
4181 if (idx == PA_INVALID_INDEX && name && !*name) {
4183 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4185 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4186 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4190 pa_sink *sink = NULL;
4192 if (idx != PA_INVALID_INDEX)
4193 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4195 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4197 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4199 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4200 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4206 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4208 if (idx == PA_INVALID_INDEX && name && !*name) {
4210 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4212 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4213 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4220 if (idx != PA_INVALID_INDEX)
4221 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4223 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4225 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4227 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4228 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4234 pa_pstream_send_simple_ack(c->pstream, tag);
4237 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4238 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4239 uint32_t idx = PA_INVALID_INDEX;
4240 const char *name = NULL;
4242 pa_native_protocol_ext_cb_t cb;
4244 pa_native_connection_assert_ref(c);
4247 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4248 pa_tagstruct_gets(t, &name) < 0) {
4253 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4254 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4255 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4256 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4257 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4259 if (idx != PA_INVALID_INDEX)
4260 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4262 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4263 if (strcmp(name, m->name) == 0)
4267 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4268 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4270 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4271 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4273 if (cb(c->protocol, m, c, tag, t) < 0)
4277 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4278 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4279 uint32_t idx = PA_INVALID_INDEX;
4280 const char *name = NULL, *profile = NULL;
4281 pa_card *card = NULL;
4284 pa_native_connection_assert_ref(c);
4287 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4288 pa_tagstruct_gets(t, &name) < 0 ||
4289 pa_tagstruct_gets(t, &profile) < 0 ||
4290 !pa_tagstruct_eof(t)) {
4295 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4296 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4297 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4298 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4299 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4301 if (idx != PA_INVALID_INDEX)
4302 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4304 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4306 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4308 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4309 pa_pstream_send_error(c->pstream, tag, -ret);
4313 pa_pstream_send_simple_ack(c->pstream, tag);
4316 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4317 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4318 uint32_t idx = PA_INVALID_INDEX;
4319 const char *name = NULL, *port = NULL;
4322 pa_native_connection_assert_ref(c);
4325 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4326 pa_tagstruct_gets(t, &name) < 0 ||
4327 pa_tagstruct_gets(t, &port) < 0 ||
4328 !pa_tagstruct_eof(t)) {
4333 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4334 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_PORT ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
4335 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4336 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4337 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4339 if (command == PA_COMMAND_SET_SINK_PORT) {
4342 if (idx != PA_INVALID_INDEX)
4343 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4345 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4347 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4349 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4350 pa_pstream_send_error(c->pstream, tag, -ret);
4356 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4358 if (idx != PA_INVALID_INDEX)
4359 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4361 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4363 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4365 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4366 pa_pstream_send_error(c->pstream, tag, -ret);
4371 pa_pstream_send_simple_ack(c->pstream, tag);
4374 /*** pstream callbacks ***/
4376 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4377 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4381 pa_native_connection_assert_ref(c);
4383 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4384 pa_log("invalid packet.");
4385 native_connection_unlink(c);
4389 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) {
4390 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4391 output_stream *stream;
4395 pa_native_connection_assert_ref(c);
4397 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4398 pa_log_debug("Client sent block for invalid stream.");
4403 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4405 if (playback_stream_isinstance(stream)) {
4406 playback_stream *ps = PLAYBACK_STREAM(stream);
4408 if (chunk->memblock) {
4409 if (seek != PA_SEEK_RELATIVE || offset != 0)
4410 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);
4412 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4414 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);
4417 upload_stream *u = UPLOAD_STREAM(stream);
4420 if (!u->memchunk.memblock) {
4421 if (u->length == chunk->length && chunk->memblock) {
4422 u->memchunk = *chunk;
4423 pa_memblock_ref(u->memchunk.memblock);
4426 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4427 u->memchunk.index = u->memchunk.length = 0;
4431 pa_assert(u->memchunk.memblock);
4434 if (l > chunk->length)
4439 dst = pa_memblock_acquire(u->memchunk.memblock);
4441 if (chunk->memblock) {
4443 src = pa_memblock_acquire(chunk->memblock);
4445 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4446 (uint8_t*) src + chunk->index, l);
4448 pa_memblock_release(chunk->memblock);
4450 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4452 pa_memblock_release(u->memchunk.memblock);
4454 u->memchunk.length += l;
4460 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4461 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4464 pa_native_connection_assert_ref(c);
4466 native_connection_unlink(c);
4467 pa_log_info("Connection died.");
4470 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4471 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4474 pa_native_connection_assert_ref(c);
4476 native_connection_send_memblock(c);
4479 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4482 if (!(q = pa_thread_mq_get()))
4483 pa_pstream_send_revoke(p, block_id);
4485 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4488 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4491 if (!(q = pa_thread_mq_get()))
4492 pa_pstream_send_release(p, block_id);
4494 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4497 /*** client callbacks ***/
4499 static void client_kill_cb(pa_client *c) {
4502 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4503 pa_log_info("Connection killed.");
4506 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4508 pa_native_connection *c;
4511 c = PA_NATIVE_CONNECTION(client->userdata);
4512 pa_native_connection_assert_ref(c);
4514 if (c->version < 15)
4517 t = pa_tagstruct_new(NULL, 0);
4518 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4519 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4520 pa_tagstruct_puts(t, event);
4521 pa_tagstruct_put_proplist(t, pl);
4522 pa_pstream_send_tagstruct(c->pstream, t);
4525 /*** module entry points ***/
4527 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4528 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4531 pa_native_connection_assert_ref(c);
4532 pa_assert(c->auth_timeout_event == e);
4534 if (!c->authorized) {
4535 native_connection_unlink(c);
4536 pa_log_info("Connection terminated due to authentication timeout.");
4540 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4541 pa_native_connection *c;
4544 pa_client_new_data data;
4550 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4551 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4552 pa_iochannel_free(io);
4556 pa_client_new_data_init(&data);
4557 data.module = o->module;
4558 data.driver = __FILE__;
4559 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4560 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4561 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4562 client = pa_client_new(p->core, &data);
4563 pa_client_new_data_done(&data);
4568 c = pa_msgobject_new(pa_native_connection);
4569 c->parent.parent.free = native_connection_free;
4570 c->parent.process_msg = native_connection_process_msg;
4572 c->options = pa_native_options_ref(o);
4573 c->authorized = FALSE;
4575 if (o->auth_anonymous) {
4576 pa_log_info("Client authenticated anonymously.");
4577 c->authorized = TRUE;
4580 if (!c->authorized &&
4582 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4584 pa_log_info("Client authenticated by IP ACL.");
4585 c->authorized = TRUE;
4589 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4591 c->auth_timeout_event = NULL;
4593 c->is_local = pa_iochannel_socket_is_local(io);
4597 c->client->kill = client_kill_cb;
4598 c->client->send_event = client_send_event_cb;
4599 c->client->userdata = c;
4601 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4602 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4603 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4604 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4605 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4606 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4607 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4609 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4611 c->record_streams = pa_idxset_new(NULL, NULL);
4612 c->output_streams = pa_idxset_new(NULL, NULL);
4614 c->rrobin_index = PA_IDXSET_INVALID;
4615 c->subscription = NULL;
4617 pa_idxset_put(p->connections, c, NULL);
4620 if (pa_iochannel_creds_supported(io))
4621 pa_iochannel_creds_enable(io);
4624 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4627 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4628 pa_native_connection *c;
4634 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4635 if (c->options->module == m)
4636 native_connection_unlink(c);
4639 static pa_native_protocol* native_protocol_new(pa_core *c) {
4640 pa_native_protocol *p;
4645 p = pa_xnew(pa_native_protocol, 1);
4648 p->connections = pa_idxset_new(NULL, NULL);
4652 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4654 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4655 pa_hook_init(&p->hooks[h], p);
4657 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4662 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4663 pa_native_protocol *p;
4665 if ((p = pa_shared_get(c, "native-protocol")))
4666 return pa_native_protocol_ref(p);
4668 return native_protocol_new(c);
4671 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4673 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4680 void pa_native_protocol_unref(pa_native_protocol *p) {
4681 pa_native_connection *c;
4685 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4687 if (PA_REFCNT_DEC(p) > 0)
4690 while ((c = pa_idxset_first(p->connections, NULL)))
4691 native_connection_unlink(c);
4693 pa_idxset_free(p->connections, NULL, NULL);
4695 pa_strlist_free(p->servers);
4697 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4698 pa_hook_done(&p->hooks[h]);
4700 pa_hashmap_free(p->extensions, NULL, NULL);
4702 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4707 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
4709 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4712 p->servers = pa_strlist_prepend(p->servers, name);
4714 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4717 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
4719 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4722 p->servers = pa_strlist_remove(p->servers, name);
4724 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4727 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
4729 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4734 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
4736 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4741 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
4743 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4746 pa_assert(!pa_hashmap_get(p->extensions, m));
4748 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
4752 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
4754 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4757 pa_assert_se(pa_hashmap_remove(p->extensions, m));
4760 pa_native_options* pa_native_options_new(void) {
4761 pa_native_options *o;
4763 o = pa_xnew0(pa_native_options, 1);
4769 pa_native_options* pa_native_options_ref(pa_native_options *o) {
4771 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4778 void pa_native_options_unref(pa_native_options *o) {
4780 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4782 if (PA_REFCNT_DEC(o) > 0)
4785 pa_xfree(o->auth_group);
4788 pa_ip_acl_free(o->auth_ip_acl);
4791 pa_auth_cookie_unref(o->auth_cookie);
4796 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
4801 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4804 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
4805 pa_log("auth-anonymous= expects a boolean argument.");
4810 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
4811 pa_log("auth-group-enabled= expects a boolean argument.");
4815 pa_xfree(o->auth_group);
4816 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
4820 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4823 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
4826 if (!(ipa = pa_ip_acl_new(acl))) {
4827 pa_log("Failed to parse IP ACL '%s'", acl);
4832 pa_ip_acl_free(o->auth_ip_acl);
4834 o->auth_ip_acl = ipa;
4838 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
4839 pa_log("auth-cookie-enabled= expects a boolean argument.");
4844 pa_auth_cookie_unref(o->auth_cookie);
4849 /* The new name for this is 'auth-cookie', for compat reasons
4850 * we check the old name too */
4851 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
4852 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
4853 cn = PA_NATIVE_COOKIE_FILE;
4855 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
4859 o->auth_cookie = NULL;
4864 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
4865 pa_native_connection_assert_ref(c);
4870 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
4871 pa_native_connection_assert_ref(c);