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);
1052 data.volume_is_absolute = TRUE;
1055 pa_sink_input_new_data_set_muted(&data, muted);
1056 data.sync_base = ssync ? ssync->sink_input : NULL;
1059 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1061 pa_sink_input_new_data_done(&data);
1066 s = pa_msgobject_new(playback_stream);
1067 s->parent.parent.parent.free = playback_stream_free;
1068 s->parent.parent.process_msg = playback_stream_process_msg;
1071 s->sink_input = sink_input;
1072 s->is_underrun = TRUE;
1073 s->drain_request = FALSE;
1074 pa_atomic_store(&s->missing, 0);
1075 s->buffer_attr = *a;
1076 s->adjust_latency = adjust_latency;
1077 s->early_requests = early_requests;
1079 s->sink_input->parent.process_msg = sink_input_process_msg;
1080 s->sink_input->pop = sink_input_pop_cb;
1081 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1082 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1083 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1084 s->sink_input->kill = sink_input_kill_cb;
1085 s->sink_input->moving = sink_input_moving_cb;
1086 s->sink_input->suspend = sink_input_suspend_cb;
1087 s->sink_input->send_event = sink_input_send_event_cb;
1088 s->sink_input->userdata = s;
1090 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1092 fix_playback_buffer_attr(s);
1094 pa_sink_input_get_silence(sink_input, &silence);
1095 s->memblockq = pa_memblockq_new(
1097 s->buffer_attr.maxlength,
1098 s->buffer_attr.tlength,
1099 pa_frame_size(&sink_input->sample_spec),
1100 s->buffer_attr.prebuf,
1101 s->buffer_attr.minreq,
1104 pa_memblock_unref(silence.memblock);
1106 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1108 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1110 *ss = s->sink_input->sample_spec;
1111 *map = s->sink_input->channel_map;
1113 pa_idxset_put(c->output_streams, s, &s->index);
1115 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1116 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1117 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1118 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1119 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1121 pa_sink_input_put(s->sink_input);
1125 /* Called from IO context */
1126 static void playback_stream_request_bytes(playback_stream *s) {
1128 int previous_missing;
1130 playback_stream_assert_ref(s);
1132 m = pa_memblockq_pop_missing(s->memblockq);
1134 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu)", */
1135 /* (unsigned long) m, */
1136 /* pa_memblockq_get_tlength(s->memblockq), */
1137 /* pa_memblockq_get_minreq(s->memblockq), */
1138 /* pa_memblockq_get_length(s->memblockq)); */
1143 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1145 previous_missing = pa_atomic_add(&s->missing, (int) m);
1146 minreq = pa_memblockq_get_minreq(s->memblockq);
1148 if (pa_memblockq_prebuf_active(s->memblockq) ||
1149 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1150 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1153 /* Called from main context */
1154 static void playback_stream_send_killed(playback_stream *p) {
1156 playback_stream_assert_ref(p);
1158 t = pa_tagstruct_new(NULL, 0);
1159 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1160 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1161 pa_tagstruct_putu32(t, p->index);
1162 pa_pstream_send_tagstruct(p->connection->pstream, t);
1165 /* Called from main context */
1166 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1167 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1168 pa_native_connection_assert_ref(c);
1175 case CONNECTION_MESSAGE_REVOKE:
1176 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1179 case CONNECTION_MESSAGE_RELEASE:
1180 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1187 /* Called from main context */
1188 static void native_connection_unlink(pa_native_connection *c) {
1197 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1200 pa_native_options_unref(c->options);
1202 while ((r = pa_idxset_first(c->record_streams, NULL)))
1203 record_stream_unlink(r);
1205 while ((o = pa_idxset_first(c->output_streams, NULL)))
1206 if (playback_stream_isinstance(o))
1207 playback_stream_unlink(PLAYBACK_STREAM(o));
1209 upload_stream_unlink(UPLOAD_STREAM(o));
1211 if (c->subscription)
1212 pa_subscription_free(c->subscription);
1215 pa_pstream_unlink(c->pstream);
1217 if (c->auth_timeout_event) {
1218 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1219 c->auth_timeout_event = NULL;
1222 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1224 pa_native_connection_unref(c);
1227 /* Called from main context */
1228 static void native_connection_free(pa_object *o) {
1229 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1233 native_connection_unlink(c);
1235 pa_idxset_free(c->record_streams, NULL, NULL);
1236 pa_idxset_free(c->output_streams, NULL, NULL);
1238 pa_pdispatch_unref(c->pdispatch);
1239 pa_pstream_unref(c->pstream);
1240 pa_client_free(c->client);
1245 /* Called from main context */
1246 static void native_connection_send_memblock(pa_native_connection *c) {
1250 start = PA_IDXSET_INVALID;
1254 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1257 if (start == PA_IDXSET_INVALID)
1258 start = c->rrobin_index;
1259 else if (start == c->rrobin_index)
1262 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1263 pa_memchunk schunk = chunk;
1265 if (schunk.length > r->buffer_attr.fragsize)
1266 schunk.length = r->buffer_attr.fragsize;
1268 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1270 pa_memblockq_drop(r->memblockq, schunk.length);
1271 pa_memblock_unref(schunk.memblock);
1278 /*** sink input callbacks ***/
1280 /* Called from thread context */
1281 static void handle_seek(playback_stream *s, int64_t indexw) {
1282 playback_stream_assert_ref(s);
1284 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1286 if (s->sink_input->thread_info.underrun_for > 0) {
1288 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1290 if (pa_memblockq_is_readable(s->memblockq)) {
1292 /* We just ended an underrun, let's ask the sink
1293 * for a complete rewind rewrite */
1295 pa_log_debug("Requesting rewind due to end of underrun.");
1296 pa_sink_input_request_rewind(s->sink_input,
1297 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1298 s->sink_input->thread_info.underrun_for),
1299 FALSE, TRUE, FALSE);
1305 indexr = pa_memblockq_get_read_index(s->memblockq);
1307 if (indexw < indexr) {
1308 /* OK, the sink already asked for this data, so
1309 * let's have it usk us again */
1311 pa_log_debug("Requesting rewind due to rewrite.");
1312 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1316 playback_stream_request_bytes(s);
1319 /* Called from thread context */
1320 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1321 pa_sink_input *i = PA_SINK_INPUT(o);
1324 pa_sink_input_assert_ref(i);
1325 s = PLAYBACK_STREAM(i->userdata);
1326 playback_stream_assert_ref(s);
1330 case SINK_INPUT_MESSAGE_SEEK: {
1333 windex = pa_memblockq_get_write_index(s->memblockq);
1335 /* The client side is incapable of accounting correctly
1336 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1337 * able to deal with that. */
1339 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1341 handle_seek(s, windex);
1345 case SINK_INPUT_MESSAGE_POST_DATA: {
1350 windex = pa_memblockq_get_write_index(s->memblockq);
1352 /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
1354 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1356 if (pa_log_ratelimit())
1357 pa_log_warn("Failed to push data into queue");
1358 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1359 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1362 handle_seek(s, windex);
1364 /* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1369 case SINK_INPUT_MESSAGE_DRAIN:
1370 case SINK_INPUT_MESSAGE_FLUSH:
1371 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1372 case SINK_INPUT_MESSAGE_TRIGGER: {
1375 pa_sink_input *isync;
1376 void (*func)(pa_memblockq *bq);
1379 case SINK_INPUT_MESSAGE_FLUSH:
1380 func = pa_memblockq_flush_write;
1383 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1384 func = pa_memblockq_prebuf_force;
1387 case SINK_INPUT_MESSAGE_DRAIN:
1388 case SINK_INPUT_MESSAGE_TRIGGER:
1389 func = pa_memblockq_prebuf_disable;
1393 pa_assert_not_reached();
1396 windex = pa_memblockq_get_write_index(s->memblockq);
1398 handle_seek(s, windex);
1400 /* Do the same for all other members in the sync group */
1401 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1402 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1403 windex = pa_memblockq_get_write_index(ssync->memblockq);
1404 func(ssync->memblockq);
1405 handle_seek(ssync, windex);
1408 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1409 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1410 windex = pa_memblockq_get_write_index(ssync->memblockq);
1411 func(ssync->memblockq);
1412 handle_seek(ssync, windex);
1415 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1416 if (!pa_memblockq_is_readable(s->memblockq))
1417 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1419 s->drain_tag = PA_PTR_TO_UINT(userdata);
1420 s->drain_request = TRUE;
1427 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1428 /* Atomically get a snapshot of all timing parameters... */
1429 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1430 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1431 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1432 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1433 s->underrun_for = s->sink_input->thread_info.underrun_for;
1434 s->playing_for = s->sink_input->thread_info.playing_for;
1438 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1441 windex = pa_memblockq_get_write_index(s->memblockq);
1443 pa_memblockq_prebuf_force(s->memblockq);
1445 handle_seek(s, windex);
1447 /* Fall through to the default handler */
1451 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1452 pa_usec_t *r = userdata;
1454 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1456 /* Fall through, the default handler will add in the extra
1457 * latency added by the resampler */
1461 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1462 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1463 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1468 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1471 /* Called from thread context */
1472 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1475 pa_sink_input_assert_ref(i);
1476 s = PLAYBACK_STREAM(i->userdata);
1477 playback_stream_assert_ref(s);
1480 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1482 if (pa_memblockq_is_readable(s->memblockq))
1483 s->is_underrun = FALSE;
1485 if (!s->is_underrun)
1486 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));
1488 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1489 s->drain_request = FALSE;
1490 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);
1491 } else if (!s->is_underrun)
1492 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1494 s->is_underrun = TRUE;
1496 playback_stream_request_bytes(s);
1499 /* This call will not fail with prebuf=0, hence we check for
1500 underrun explicitly above */
1501 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1504 chunk->length = PA_MIN(nbytes, chunk->length);
1506 if (i->thread_info.underrun_for > 0)
1507 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1509 pa_memblockq_drop(s->memblockq, chunk->length);
1510 playback_stream_request_bytes(s);
1515 /* Called from thread context */
1516 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1519 pa_sink_input_assert_ref(i);
1520 s = PLAYBACK_STREAM(i->userdata);
1521 playback_stream_assert_ref(s);
1523 /* If we are in an underrun, then we don't rewind */
1524 if (i->thread_info.underrun_for > 0)
1527 pa_memblockq_rewind(s->memblockq, nbytes);
1530 /* Called from thread context */
1531 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1534 pa_sink_input_assert_ref(i);
1535 s = PLAYBACK_STREAM(i->userdata);
1536 playback_stream_assert_ref(s);
1538 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1541 /* Called from thread context */
1542 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1544 size_t new_tlength, old_tlength;
1546 pa_sink_input_assert_ref(i);
1547 s = PLAYBACK_STREAM(i->userdata);
1548 playback_stream_assert_ref(s);
1550 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1551 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1553 if (old_tlength < new_tlength) {
1554 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1555 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1556 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1558 if (new_tlength == old_tlength)
1559 pa_log_debug("Failed to increase tlength");
1561 pa_log_debug("Notifying client about increased tlength");
1562 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);
1567 /* Called from main context */
1568 static void sink_input_kill_cb(pa_sink_input *i) {
1571 pa_sink_input_assert_ref(i);
1572 s = PLAYBACK_STREAM(i->userdata);
1573 playback_stream_assert_ref(s);
1575 playback_stream_send_killed(s);
1576 playback_stream_unlink(s);
1579 /* Called from main context */
1580 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1584 pa_sink_input_assert_ref(i);
1585 s = PLAYBACK_STREAM(i->userdata);
1586 playback_stream_assert_ref(s);
1588 if (s->connection->version < 15)
1591 t = pa_tagstruct_new(NULL, 0);
1592 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1593 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1594 pa_tagstruct_putu32(t, s->index);
1595 pa_tagstruct_puts(t, event);
1596 pa_tagstruct_put_proplist(t, pl);
1597 pa_pstream_send_tagstruct(s->connection->pstream, t);
1600 /* Called from main context */
1601 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1605 pa_sink_input_assert_ref(i);
1606 s = PLAYBACK_STREAM(i->userdata);
1607 playback_stream_assert_ref(s);
1609 if (s->connection->version < 12)
1612 t = pa_tagstruct_new(NULL, 0);
1613 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1614 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1615 pa_tagstruct_putu32(t, s->index);
1616 pa_tagstruct_put_boolean(t, suspend);
1617 pa_pstream_send_tagstruct(s->connection->pstream, t);
1620 /* Called from main context */
1621 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1625 pa_sink_input_assert_ref(i);
1626 s = PLAYBACK_STREAM(i->userdata);
1627 playback_stream_assert_ref(s);
1632 fix_playback_buffer_attr(s);
1633 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1634 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1636 if (s->connection->version < 12)
1639 t = pa_tagstruct_new(NULL, 0);
1640 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1641 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1642 pa_tagstruct_putu32(t, s->index);
1643 pa_tagstruct_putu32(t, dest->index);
1644 pa_tagstruct_puts(t, dest->name);
1645 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1647 if (s->connection->version >= 13) {
1648 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1649 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1650 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1651 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1652 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1655 pa_pstream_send_tagstruct(s->connection->pstream, t);
1658 /*** source_output callbacks ***/
1660 /* Called from thread context */
1661 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1662 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1665 pa_source_output_assert_ref(o);
1666 s = RECORD_STREAM(o->userdata);
1667 record_stream_assert_ref(s);
1670 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1671 /* Atomically get a snapshot of all timing parameters... */
1672 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1673 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1674 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1678 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1681 /* Called from thread context */
1682 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1685 pa_source_output_assert_ref(o);
1686 s = RECORD_STREAM(o->userdata);
1687 record_stream_assert_ref(s);
1690 pa_atomic_add(&s->on_the_fly, chunk->length);
1691 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1694 static void source_output_kill_cb(pa_source_output *o) {
1697 pa_source_output_assert_ref(o);
1698 s = RECORD_STREAM(o->userdata);
1699 record_stream_assert_ref(s);
1701 record_stream_send_killed(s);
1702 record_stream_unlink(s);
1705 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1708 pa_source_output_assert_ref(o);
1709 s = RECORD_STREAM(o->userdata);
1710 record_stream_assert_ref(s);
1712 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1714 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1717 /* Called from main context */
1718 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1722 pa_source_output_assert_ref(o);
1723 s = RECORD_STREAM(o->userdata);
1724 record_stream_assert_ref(s);
1726 if (s->connection->version < 15)
1729 t = pa_tagstruct_new(NULL, 0);
1730 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1731 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1732 pa_tagstruct_putu32(t, s->index);
1733 pa_tagstruct_puts(t, event);
1734 pa_tagstruct_put_proplist(t, pl);
1735 pa_pstream_send_tagstruct(s->connection->pstream, t);
1738 /* Called from main context */
1739 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1743 pa_source_output_assert_ref(o);
1744 s = RECORD_STREAM(o->userdata);
1745 record_stream_assert_ref(s);
1747 if (s->connection->version < 12)
1750 t = pa_tagstruct_new(NULL, 0);
1751 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1752 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1753 pa_tagstruct_putu32(t, s->index);
1754 pa_tagstruct_put_boolean(t, suspend);
1755 pa_pstream_send_tagstruct(s->connection->pstream, t);
1758 /* Called from main context */
1759 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1763 pa_source_output_assert_ref(o);
1764 s = RECORD_STREAM(o->userdata);
1765 record_stream_assert_ref(s);
1770 fix_record_buffer_attr_pre(s);
1771 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1772 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1773 fix_record_buffer_attr_post(s);
1775 if (s->connection->version < 12)
1778 t = pa_tagstruct_new(NULL, 0);
1779 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1780 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1781 pa_tagstruct_putu32(t, s->index);
1782 pa_tagstruct_putu32(t, dest->index);
1783 pa_tagstruct_puts(t, dest->name);
1784 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1786 if (s->connection->version >= 13) {
1787 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1788 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1789 pa_tagstruct_put_usec(t, s->configured_source_latency);
1792 pa_pstream_send_tagstruct(s->connection->pstream, t);
1795 /*** pdispatch callbacks ***/
1797 static void protocol_error(pa_native_connection *c) {
1798 pa_log("protocol error, kicking client");
1799 native_connection_unlink(c);
1802 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1803 if (!(expression)) { \
1804 pa_pstream_send_error((pstream), (tag), (error)); \
1809 static pa_tagstruct *reply_new(uint32_t tag) {
1810 pa_tagstruct *reply;
1812 reply = pa_tagstruct_new(NULL, 0);
1813 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1814 pa_tagstruct_putu32(reply, tag);
1818 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1819 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1821 uint32_t sink_index, syncid, missing;
1822 pa_buffer_attr attr;
1823 const char *name = NULL, *sink_name;
1826 pa_tagstruct *reply;
1827 pa_sink *sink = NULL;
1835 fix_channels = FALSE,
1837 variable_rate = FALSE,
1839 adjust_latency = FALSE,
1840 early_requests = FALSE,
1841 dont_inhibit_auto_suspend = FALSE,
1843 fail_on_suspend = FALSE;
1844 pa_sink_input_flags_t flags = 0;
1846 pa_bool_t volume_set = TRUE;
1847 int ret = PA_ERR_INVALID;
1849 pa_native_connection_assert_ref(c);
1851 memset(&attr, 0, sizeof(attr));
1853 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1856 PA_TAG_SAMPLE_SPEC, &ss,
1857 PA_TAG_CHANNEL_MAP, &map,
1858 PA_TAG_U32, &sink_index,
1859 PA_TAG_STRING, &sink_name,
1860 PA_TAG_U32, &attr.maxlength,
1861 PA_TAG_BOOLEAN, &corked,
1862 PA_TAG_U32, &attr.tlength,
1863 PA_TAG_U32, &attr.prebuf,
1864 PA_TAG_U32, &attr.minreq,
1865 PA_TAG_U32, &syncid,
1866 PA_TAG_CVOLUME, &volume,
1867 PA_TAG_INVALID) < 0) {
1873 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1874 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
1875 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
1876 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
1877 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
1878 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
1879 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
1880 CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID);
1882 p = pa_proplist_new();
1885 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1887 if (c->version >= 12) {
1888 /* Since 0.9.8 the user can ask for a couple of additional flags */
1890 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1891 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1892 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1893 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1894 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1895 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1896 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1899 pa_proplist_free(p);
1904 if (c->version >= 13) {
1906 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1907 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1908 pa_tagstruct_get_proplist(t, p) < 0) {
1910 pa_proplist_free(p);
1915 if (c->version >= 14) {
1917 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
1918 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
1920 pa_proplist_free(p);
1925 if (c->version >= 15) {
1927 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
1928 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
1929 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
1931 pa_proplist_free(p);
1936 if (!pa_tagstruct_eof(t)) {
1938 pa_proplist_free(p);
1942 if (sink_index != PA_INVALID_INDEX) {
1944 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
1945 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1946 pa_proplist_free(p);
1950 } else if (sink_name) {
1952 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
1953 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1954 pa_proplist_free(p);
1960 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
1961 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
1962 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
1963 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
1964 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
1965 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
1966 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
1967 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
1968 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
1969 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0);
1971 /* Only since protocol version 15 there's a seperate muted_set
1972 * flag. For older versions we synthesize it here */
1973 muted_set = muted_set || muted;
1975 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);
1976 pa_proplist_free(p);
1978 CHECK_VALIDITY(c->pstream, s, tag, ret);
1980 reply = reply_new(tag);
1981 pa_tagstruct_putu32(reply, s->index);
1982 pa_assert(s->sink_input);
1983 pa_tagstruct_putu32(reply, s->sink_input->index);
1984 pa_tagstruct_putu32(reply, missing);
1986 /* pa_log("initial request is %u", missing); */
1988 if (c->version >= 9) {
1989 /* Since 0.9.0 we support sending the buffer metrics back to the client */
1991 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
1992 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
1993 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
1994 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
1997 if (c->version >= 12) {
1998 /* Since 0.9.8 we support sending the chosen sample
1999 * spec/channel map/device/suspend status back to the
2002 pa_tagstruct_put_sample_spec(reply, &ss);
2003 pa_tagstruct_put_channel_map(reply, &map);
2005 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2006 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2008 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2011 if (c->version >= 13)
2012 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2014 pa_pstream_send_tagstruct(c->pstream, reply);
2017 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2018 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2021 pa_native_connection_assert_ref(c);
2024 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2025 !pa_tagstruct_eof(t)) {
2030 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2034 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2036 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2037 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2041 playback_stream_unlink(s);
2045 case PA_COMMAND_DELETE_RECORD_STREAM: {
2047 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2048 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2052 record_stream_unlink(s);
2056 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2059 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2060 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2064 upload_stream_unlink(s);
2069 pa_assert_not_reached();
2072 pa_pstream_send_simple_ack(c->pstream, tag);
2075 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2076 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2078 pa_buffer_attr attr;
2079 uint32_t source_index;
2080 const char *name = NULL, *source_name;
2083 pa_tagstruct *reply;
2084 pa_source *source = NULL;
2091 fix_channels = FALSE,
2093 variable_rate = FALSE,
2094 adjust_latency = FALSE,
2095 peak_detect = FALSE,
2096 early_requests = FALSE,
2097 dont_inhibit_auto_suspend = FALSE,
2098 fail_on_suspend = FALSE;
2099 pa_source_output_flags_t flags = 0;
2101 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2102 pa_sink_input *direct_on_input = NULL;
2103 int ret = PA_ERR_INVALID;
2105 pa_native_connection_assert_ref(c);
2108 memset(&attr, 0, sizeof(attr));
2110 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2111 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2112 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2113 pa_tagstruct_getu32(t, &source_index) < 0 ||
2114 pa_tagstruct_gets(t, &source_name) < 0 ||
2115 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2116 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2117 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2122 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2123 CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
2124 CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID);
2125 CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2126 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2127 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2128 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2130 p = pa_proplist_new();
2133 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2135 if (c->version >= 12) {
2136 /* Since 0.9.8 the user can ask for a couple of additional flags */
2138 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2139 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2140 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2141 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2142 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2143 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2144 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2147 pa_proplist_free(p);
2152 if (c->version >= 13) {
2154 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2155 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2156 pa_tagstruct_get_proplist(t, p) < 0 ||
2157 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2159 pa_proplist_free(p);
2164 if (c->version >= 14) {
2166 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2168 pa_proplist_free(p);
2173 if (c->version >= 15) {
2175 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2176 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2178 pa_proplist_free(p);
2183 if (!pa_tagstruct_eof(t)) {
2185 pa_proplist_free(p);
2189 if (source_index != PA_INVALID_INDEX) {
2191 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2192 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2193 pa_proplist_free(p);
2197 } else if (source_name) {
2199 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2200 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2201 pa_proplist_free(p);
2206 if (direct_on_input_idx != PA_INVALID_INDEX) {
2208 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2209 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2210 pa_proplist_free(p);
2216 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2217 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2218 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2219 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2220 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2221 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2222 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2223 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2224 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2225 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0);
2227 s = record_stream_new(c, source, &ss, &map, peak_detect, &attr, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
2228 pa_proplist_free(p);
2230 CHECK_VALIDITY(c->pstream, s, tag, ret);
2232 reply = reply_new(tag);
2233 pa_tagstruct_putu32(reply, s->index);
2234 pa_assert(s->source_output);
2235 pa_tagstruct_putu32(reply, s->source_output->index);
2237 if (c->version >= 9) {
2238 /* Since 0.9 we support sending the buffer metrics back to the client */
2240 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2241 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2244 if (c->version >= 12) {
2245 /* Since 0.9.8 we support sending the chosen sample
2246 * spec/channel map/device/suspend status back to the
2249 pa_tagstruct_put_sample_spec(reply, &ss);
2250 pa_tagstruct_put_channel_map(reply, &map);
2252 pa_tagstruct_putu32(reply, s->source_output->source->index);
2253 pa_tagstruct_puts(reply, s->source_output->source->name);
2255 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2258 if (c->version >= 13)
2259 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2261 pa_pstream_send_tagstruct(c->pstream, reply);
2264 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2265 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2268 pa_native_connection_assert_ref(c);
2271 if (!pa_tagstruct_eof(t)) {
2276 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2277 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2278 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2280 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2282 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2285 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2286 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2288 pa_tagstruct *reply;
2289 pa_bool_t shm_on_remote = FALSE, do_shm;
2291 pa_native_connection_assert_ref(c);
2294 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2295 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2296 !pa_tagstruct_eof(t)) {
2301 /* Minimum supported version */
2302 if (c->version < 8) {
2303 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2307 /* Starting with protocol version 13 the MSB of the version tag
2308 reflects if shm is available for this pa_native_connection or
2310 if (c->version >= 13) {
2311 shm_on_remote = !!(c->version & 0x80000000U);
2312 c->version &= 0x7FFFFFFFU;
2315 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2317 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2319 if (!c->authorized) {
2320 pa_bool_t success = FALSE;
2323 const pa_creds *creds;
2325 if ((creds = pa_pdispatch_creds(pd))) {
2326 if (creds->uid == getuid())
2328 else if (c->options->auth_group) {
2332 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2333 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2334 else if (gid == creds->gid)
2338 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2339 pa_log_warn("Failed to check group membership.");
2345 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2346 (unsigned long) creds->uid,
2347 (unsigned long) creds->gid,
2352 if (!success && c->options->auth_cookie) {
2355 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2356 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2361 pa_log_warn("Denied access to client with invalid authorization data.");
2362 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2366 c->authorized = TRUE;
2367 if (c->auth_timeout_event) {
2368 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2369 c->auth_timeout_event = NULL;
2373 /* Enable shared memory support if possible */
2375 pa_mempool_is_shared(c->protocol->core->mempool) &&
2378 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2381 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2386 /* Only enable SHM if both sides are owned by the same
2387 * user. This is a security measure because otherwise data
2388 * private to the user might leak. */
2390 const pa_creds *creds;
2391 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2396 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2397 pa_pstream_enable_shm(c->pstream, do_shm);
2399 reply = reply_new(tag);
2400 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2404 /* SHM support is only enabled after both sides made sure they are the same user. */
2408 ucred.uid = getuid();
2409 ucred.gid = getgid();
2411 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2414 pa_pstream_send_tagstruct(c->pstream, reply);
2418 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2419 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2420 const char *name = NULL;
2422 pa_tagstruct *reply;
2424 pa_native_connection_assert_ref(c);
2427 p = pa_proplist_new();
2429 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2430 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2431 !pa_tagstruct_eof(t)) {
2434 pa_proplist_free(p);
2439 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2440 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2441 pa_proplist_free(p);
2445 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2446 pa_proplist_free(p);
2448 reply = reply_new(tag);
2450 if (c->version >= 13)
2451 pa_tagstruct_putu32(reply, c->client->index);
2453 pa_pstream_send_tagstruct(c->pstream, reply);
2456 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2457 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2459 uint32_t idx = PA_IDXSET_INVALID;
2461 pa_native_connection_assert_ref(c);
2464 if (pa_tagstruct_gets(t, &name) < 0 ||
2465 !pa_tagstruct_eof(t)) {
2470 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2471 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);
2473 if (command == PA_COMMAND_LOOKUP_SINK) {
2475 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2479 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2480 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2481 idx = source->index;
2484 if (idx == PA_IDXSET_INVALID)
2485 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2487 pa_tagstruct *reply;
2488 reply = reply_new(tag);
2489 pa_tagstruct_putu32(reply, idx);
2490 pa_pstream_send_tagstruct(c->pstream, reply);
2494 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2495 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2499 pa_native_connection_assert_ref(c);
2502 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2503 !pa_tagstruct_eof(t)) {
2508 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2509 s = pa_idxset_get_by_index(c->output_streams, idx);
2510 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2511 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2513 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);
2516 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2517 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2518 pa_tagstruct *reply;
2519 const pa_mempool_stat *stat;
2521 pa_native_connection_assert_ref(c);
2524 if (!pa_tagstruct_eof(t)) {
2529 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2531 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2533 reply = reply_new(tag);
2534 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2535 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2536 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2537 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2538 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2539 pa_pstream_send_tagstruct(c->pstream, reply);
2542 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2543 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2544 pa_tagstruct *reply;
2546 struct timeval tv, now;
2549 pa_native_connection_assert_ref(c);
2552 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2553 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2554 !pa_tagstruct_eof(t)) {
2559 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2560 s = pa_idxset_get_by_index(c->output_streams, idx);
2561 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2562 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2564 /* Get an atomic snapshot of all timing parameters */
2565 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);
2567 reply = reply_new(tag);
2568 pa_tagstruct_put_usec(reply,
2569 s->current_sink_latency +
2570 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2571 pa_tagstruct_put_usec(reply, 0);
2572 pa_tagstruct_put_boolean(reply,
2573 s->playing_for > 0 &&
2574 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2575 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2576 pa_tagstruct_put_timeval(reply, &tv);
2577 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2578 pa_tagstruct_puts64(reply, s->write_index);
2579 pa_tagstruct_puts64(reply, s->read_index);
2581 if (c->version >= 13) {
2582 pa_tagstruct_putu64(reply, s->underrun_for);
2583 pa_tagstruct_putu64(reply, s->playing_for);
2586 pa_pstream_send_tagstruct(c->pstream, reply);
2589 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2590 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2591 pa_tagstruct *reply;
2593 struct timeval tv, now;
2596 pa_native_connection_assert_ref(c);
2599 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2600 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2601 !pa_tagstruct_eof(t)) {
2606 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2607 s = pa_idxset_get_by_index(c->record_streams, idx);
2608 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2610 /* Get an atomic snapshot of all timing parameters */
2611 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);
2613 reply = reply_new(tag);
2614 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2615 pa_tagstruct_put_usec(reply,
2616 s->current_source_latency +
2617 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->sample_spec));
2618 pa_tagstruct_put_boolean(reply,
2619 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2620 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2621 pa_tagstruct_put_timeval(reply, &tv);
2622 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2623 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2624 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2625 pa_pstream_send_tagstruct(c->pstream, reply);
2628 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2629 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2632 const char *name = NULL;
2635 pa_tagstruct *reply;
2638 pa_native_connection_assert_ref(c);
2641 if (pa_tagstruct_gets(t, &name) < 0 ||
2642 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2643 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2644 pa_tagstruct_getu32(t, &length) < 0) {
2649 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2650 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2651 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2652 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2653 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2654 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2656 p = pa_proplist_new();
2658 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2659 !pa_tagstruct_eof(t)) {
2662 pa_proplist_free(p);
2666 if (c->version < 13)
2667 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2669 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2670 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2672 if (!name || !pa_namereg_is_valid_name(name)) {
2673 pa_proplist_free(p);
2674 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2677 s = upload_stream_new(c, &ss, &map, name, length, p);
2678 pa_proplist_free(p);
2680 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2682 reply = reply_new(tag);
2683 pa_tagstruct_putu32(reply, s->index);
2684 pa_tagstruct_putu32(reply, length);
2685 pa_pstream_send_tagstruct(c->pstream, reply);
2688 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2689 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2694 pa_native_connection_assert_ref(c);
2697 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2698 !pa_tagstruct_eof(t)) {
2703 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2705 s = pa_idxset_get_by_index(c->output_streams, channel);
2706 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2707 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2709 if (!s->memchunk.memblock)
2710 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2711 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2712 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2714 pa_pstream_send_simple_ack(c->pstream, tag);
2716 upload_stream_unlink(s);
2719 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2720 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2721 uint32_t sink_index;
2724 const char *name, *sink_name;
2727 pa_tagstruct *reply;
2729 pa_native_connection_assert_ref(c);
2732 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2734 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2735 pa_tagstruct_gets(t, &sink_name) < 0 ||
2736 pa_tagstruct_getu32(t, &volume) < 0 ||
2737 pa_tagstruct_gets(t, &name) < 0) {
2742 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2743 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2744 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2745 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2747 if (sink_index != PA_INVALID_INDEX)
2748 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2750 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2752 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2754 p = pa_proplist_new();
2756 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2757 !pa_tagstruct_eof(t)) {
2759 pa_proplist_free(p);
2763 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2765 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2766 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2767 pa_proplist_free(p);
2771 pa_proplist_free(p);
2773 reply = reply_new(tag);
2775 if (c->version >= 13)
2776 pa_tagstruct_putu32(reply, idx);
2778 pa_pstream_send_tagstruct(c->pstream, reply);
2781 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2782 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2785 pa_native_connection_assert_ref(c);
2788 if (pa_tagstruct_gets(t, &name) < 0 ||
2789 !pa_tagstruct_eof(t)) {
2794 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2795 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2797 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
2798 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2802 pa_pstream_send_simple_ack(c->pstream, tag);
2805 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
2808 pa_assert(original);
2812 if (c->version < 12) {
2813 /* Before protocol version 12 we didn't support S32 samples,
2814 * so we need to lie about this to the client */
2816 if (fixed->format == PA_SAMPLE_S32LE)
2817 fixed->format = PA_SAMPLE_FLOAT32LE;
2818 if (fixed->format == PA_SAMPLE_S32BE)
2819 fixed->format = PA_SAMPLE_FLOAT32BE;
2822 if (c->version < 15) {
2823 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
2824 fixed->format = PA_SAMPLE_FLOAT32LE;
2825 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
2826 fixed->format = PA_SAMPLE_FLOAT32BE;
2830 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
2831 pa_sample_spec fixed_ss;
2834 pa_sink_assert_ref(sink);
2836 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
2840 PA_TAG_U32, sink->index,
2841 PA_TAG_STRING, sink->name,
2842 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2843 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2844 PA_TAG_CHANNEL_MAP, &sink->channel_map,
2845 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
2846 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
2847 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
2848 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
2849 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
2850 PA_TAG_USEC, pa_sink_get_latency(sink),
2851 PA_TAG_STRING, sink->driver,
2852 PA_TAG_U32, sink->flags,
2855 if (c->version >= 13) {
2856 pa_tagstruct_put_proplist(t, sink->proplist);
2857 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
2860 if (c->version >= 15) {
2861 pa_tagstruct_put_volume(t, sink->base_volume);
2862 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
2863 pa_log_error("Internal sink state is invalid.");
2864 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
2865 pa_tagstruct_putu32(t, sink->n_volume_steps);
2866 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
2869 if (c->version >= 16) {
2870 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
2876 PA_HASHMAP_FOREACH(p, sink->ports, state) {
2877 pa_tagstruct_puts(t, p->name);
2878 pa_tagstruct_puts(t, p->description);
2879 pa_tagstruct_putu32(t, p->priority);
2883 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
2887 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
2888 pa_sample_spec fixed_ss;
2891 pa_source_assert_ref(source);
2893 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
2897 PA_TAG_U32, source->index,
2898 PA_TAG_STRING, source->name,
2899 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2900 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2901 PA_TAG_CHANNEL_MAP, &source->channel_map,
2902 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
2903 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
2904 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
2905 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
2906 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
2907 PA_TAG_USEC, pa_source_get_latency(source),
2908 PA_TAG_STRING, source->driver,
2909 PA_TAG_U32, source->flags,
2912 if (c->version >= 13) {
2913 pa_tagstruct_put_proplist(t, source->proplist);
2914 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
2917 if (c->version >= 15) {
2918 pa_tagstruct_put_volume(t, source->base_volume);
2919 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
2920 pa_log_error("Internal source state is invalid.");
2921 pa_tagstruct_putu32(t, pa_source_get_state(source));
2922 pa_tagstruct_putu32(t, source->n_volume_steps);
2923 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
2926 if (c->version >= 16) {
2928 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
2930 if (source->ports) {
2934 PA_HASHMAP_FOREACH(p, source->ports, state) {
2935 pa_tagstruct_puts(t, p->name);
2936 pa_tagstruct_puts(t, p->description);
2937 pa_tagstruct_putu32(t, p->priority);
2941 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
2945 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
2949 pa_tagstruct_putu32(t, client->index);
2950 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
2951 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
2952 pa_tagstruct_puts(t, client->driver);
2954 if (c->version >= 13)
2955 pa_tagstruct_put_proplist(t, client->proplist);
2958 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
2965 pa_tagstruct_putu32(t, card->index);
2966 pa_tagstruct_puts(t, card->name);
2967 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
2968 pa_tagstruct_puts(t, card->driver);
2970 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
2972 if (card->profiles) {
2973 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
2974 pa_tagstruct_puts(t, p->name);
2975 pa_tagstruct_puts(t, p->description);
2976 pa_tagstruct_putu32(t, p->n_sinks);
2977 pa_tagstruct_putu32(t, p->n_sources);
2978 pa_tagstruct_putu32(t, p->priority);
2982 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
2983 pa_tagstruct_put_proplist(t, card->proplist);
2986 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
2990 pa_tagstruct_putu32(t, module->index);
2991 pa_tagstruct_puts(t, module->name);
2992 pa_tagstruct_puts(t, module->argument);
2993 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
2995 if (c->version < 15)
2996 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
2998 if (c->version >= 15)
2999 pa_tagstruct_put_proplist(t, module->proplist);
3002 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3003 pa_sample_spec fixed_ss;
3004 pa_usec_t sink_latency;
3008 pa_sink_input_assert_ref(s);
3010 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3012 pa_tagstruct_putu32(t, s->index);
3013 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3014 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3015 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3016 pa_tagstruct_putu32(t, s->sink->index);
3017 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3018 pa_tagstruct_put_channel_map(t, &s->channel_map);
3019 pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s, &v, TRUE));
3020 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3021 pa_tagstruct_put_usec(t, sink_latency);
3022 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3023 pa_tagstruct_puts(t, s->driver);
3024 if (c->version >= 11)
3025 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3026 if (c->version >= 13)
3027 pa_tagstruct_put_proplist(t, s->proplist);
3030 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3031 pa_sample_spec fixed_ss;
3032 pa_usec_t source_latency;
3035 pa_source_output_assert_ref(s);
3037 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3039 pa_tagstruct_putu32(t, s->index);
3040 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3041 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3042 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3043 pa_tagstruct_putu32(t, s->source->index);
3044 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3045 pa_tagstruct_put_channel_map(t, &s->channel_map);
3046 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3047 pa_tagstruct_put_usec(t, source_latency);
3048 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3049 pa_tagstruct_puts(t, s->driver);
3051 if (c->version >= 13)
3052 pa_tagstruct_put_proplist(t, s->proplist);
3055 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3056 pa_sample_spec fixed_ss;
3062 if (e->memchunk.memblock)
3063 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3065 memset(&fixed_ss, 0, sizeof(fixed_ss));
3067 pa_tagstruct_putu32(t, e->index);
3068 pa_tagstruct_puts(t, e->name);
3070 if (e->volume_is_set)
3073 pa_cvolume_init(&v);
3075 pa_tagstruct_put_cvolume(t, &v);
3076 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3077 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3078 pa_tagstruct_put_channel_map(t, &e->channel_map);
3079 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3080 pa_tagstruct_put_boolean(t, e->lazy);
3081 pa_tagstruct_puts(t, e->filename);
3083 if (c->version >= 13)
3084 pa_tagstruct_put_proplist(t, e->proplist);
3087 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3088 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3090 pa_sink *sink = NULL;
3091 pa_source *source = NULL;
3092 pa_client *client = NULL;
3093 pa_card *card = NULL;
3094 pa_module *module = NULL;
3095 pa_sink_input *si = NULL;
3096 pa_source_output *so = NULL;
3097 pa_scache_entry *sce = NULL;
3098 const char *name = NULL;
3099 pa_tagstruct *reply;
3101 pa_native_connection_assert_ref(c);
3104 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3105 (command != PA_COMMAND_GET_CLIENT_INFO &&
3106 command != PA_COMMAND_GET_MODULE_INFO &&
3107 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3108 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3109 pa_tagstruct_gets(t, &name) < 0) ||
3110 !pa_tagstruct_eof(t)) {
3115 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3116 CHECK_VALIDITY(c->pstream, !name ||
3117 (command == PA_COMMAND_GET_SINK_INFO &&
3118 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3119 (command == PA_COMMAND_GET_SOURCE_INFO &&
3120 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3121 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3122 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3123 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3124 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3126 if (command == PA_COMMAND_GET_SINK_INFO) {
3127 if (idx != PA_INVALID_INDEX)
3128 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3130 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3131 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3132 if (idx != PA_INVALID_INDEX)
3133 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3135 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3136 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3137 if (idx != PA_INVALID_INDEX)
3138 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3140 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3141 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3142 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3143 else if (command == PA_COMMAND_GET_MODULE_INFO)
3144 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3145 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3146 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3147 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3148 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3150 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3151 if (idx != PA_INVALID_INDEX)
3152 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3154 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3157 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3158 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3162 reply = reply_new(tag);
3164 sink_fill_tagstruct(c, reply, sink);
3166 source_fill_tagstruct(c, reply, source);
3168 client_fill_tagstruct(c, reply, client);
3170 card_fill_tagstruct(c, reply, card);
3172 module_fill_tagstruct(c, reply, module);
3174 sink_input_fill_tagstruct(c, reply, si);
3176 source_output_fill_tagstruct(c, reply, so);
3178 scache_fill_tagstruct(c, reply, sce);
3179 pa_pstream_send_tagstruct(c->pstream, reply);
3182 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3183 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3187 pa_tagstruct *reply;
3189 pa_native_connection_assert_ref(c);
3192 if (!pa_tagstruct_eof(t)) {
3197 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3199 reply = reply_new(tag);
3201 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3202 i = c->protocol->core->sinks;
3203 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3204 i = c->protocol->core->sources;
3205 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3206 i = c->protocol->core->clients;
3207 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3208 i = c->protocol->core->cards;
3209 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3210 i = c->protocol->core->modules;
3211 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3212 i = c->protocol->core->sink_inputs;
3213 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3214 i = c->protocol->core->source_outputs;
3216 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3217 i = c->protocol->core->scache;
3221 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3222 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3223 sink_fill_tagstruct(c, reply, p);
3224 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3225 source_fill_tagstruct(c, reply, p);
3226 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3227 client_fill_tagstruct(c, reply, p);
3228 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3229 card_fill_tagstruct(c, reply, p);
3230 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3231 module_fill_tagstruct(c, reply, p);
3232 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3233 sink_input_fill_tagstruct(c, reply, p);
3234 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3235 source_output_fill_tagstruct(c, reply, p);
3237 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3238 scache_fill_tagstruct(c, reply, p);
3243 pa_pstream_send_tagstruct(c->pstream, reply);
3246 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3247 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3248 pa_tagstruct *reply;
3250 pa_source *def_source;
3251 pa_sample_spec fixed_ss;
3254 pa_native_connection_assert_ref(c);
3257 if (!pa_tagstruct_eof(t)) {
3262 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3264 reply = reply_new(tag);
3265 pa_tagstruct_puts(reply, PACKAGE_NAME);
3266 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3268 u = pa_get_user_name_malloc();
3269 pa_tagstruct_puts(reply, u);
3272 h = pa_get_host_name_malloc();
3273 pa_tagstruct_puts(reply, h);
3276 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3277 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3279 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3280 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3281 def_source = pa_namereg_get_default_source(c->protocol->core);
3282 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3284 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3286 if (c->version >= 15)
3287 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3289 pa_pstream_send_tagstruct(c->pstream, reply);
3292 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3294 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3296 pa_native_connection_assert_ref(c);
3298 t = pa_tagstruct_new(NULL, 0);
3299 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3300 pa_tagstruct_putu32(t, (uint32_t) -1);
3301 pa_tagstruct_putu32(t, e);
3302 pa_tagstruct_putu32(t, idx);
3303 pa_pstream_send_tagstruct(c->pstream, t);
3306 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3307 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3308 pa_subscription_mask_t m;
3310 pa_native_connection_assert_ref(c);
3313 if (pa_tagstruct_getu32(t, &m) < 0 ||
3314 !pa_tagstruct_eof(t)) {
3319 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3320 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3322 if (c->subscription)
3323 pa_subscription_free(c->subscription);
3326 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3327 pa_assert(c->subscription);
3329 c->subscription = NULL;
3331 pa_pstream_send_simple_ack(c->pstream, tag);
3334 static void command_set_volume(
3341 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3344 pa_sink *sink = NULL;
3345 pa_source *source = NULL;
3346 pa_sink_input *si = NULL;
3347 const char *name = NULL;
3348 const char *client_name;
3350 pa_native_connection_assert_ref(c);
3353 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3354 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3355 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3356 pa_tagstruct_get_cvolume(t, &volume) ||
3357 !pa_tagstruct_eof(t)) {
3362 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3363 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);
3364 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3365 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3366 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3367 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3371 case PA_COMMAND_SET_SINK_VOLUME:
3372 if (idx != PA_INVALID_INDEX)
3373 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3375 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3378 case PA_COMMAND_SET_SOURCE_VOLUME:
3379 if (idx != PA_INVALID_INDEX)
3380 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3382 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3385 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3386 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3390 pa_assert_not_reached();
3393 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3395 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3398 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3400 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3401 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3402 } else if (source) {
3403 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3405 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3406 pa_source_set_volume(source, &volume, TRUE);
3408 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3410 pa_log_debug("Client %s changes volume of sink input %s.",
3412 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3413 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3416 pa_pstream_send_simple_ack(c->pstream, tag);
3419 static void command_set_mute(
3426 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3429 pa_sink *sink = NULL;
3430 pa_source *source = NULL;
3431 pa_sink_input *si = NULL;
3432 const char *name = NULL, *client_name;
3434 pa_native_connection_assert_ref(c);
3437 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3438 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3439 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3440 pa_tagstruct_get_boolean(t, &mute) ||
3441 !pa_tagstruct_eof(t)) {
3446 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3447 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);
3448 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3449 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3450 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3454 case PA_COMMAND_SET_SINK_MUTE:
3455 if (idx != PA_INVALID_INDEX)
3456 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3458 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3462 case PA_COMMAND_SET_SOURCE_MUTE:
3463 if (idx != PA_INVALID_INDEX)
3464 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3466 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3470 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3471 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3475 pa_assert_not_reached();
3478 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3480 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3483 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3484 pa_sink_set_mute(sink, mute, TRUE);
3485 } else if (source) {
3486 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3487 pa_source_set_mute(source, mute, TRUE);
3489 pa_log_debug("Client %s changes mute of sink input %s.",
3491 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3492 pa_sink_input_set_mute(si, mute, TRUE);
3495 pa_pstream_send_simple_ack(c->pstream, tag);
3498 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3499 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3504 pa_native_connection_assert_ref(c);
3507 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3508 pa_tagstruct_get_boolean(t, &b) < 0 ||
3509 !pa_tagstruct_eof(t)) {
3514 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3515 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3516 s = pa_idxset_get_by_index(c->output_streams, idx);
3517 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3518 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3520 pa_sink_input_cork(s->sink_input, b);
3523 s->is_underrun = TRUE;
3525 pa_pstream_send_simple_ack(c->pstream, tag);
3528 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3529 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3533 pa_native_connection_assert_ref(c);
3536 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3537 !pa_tagstruct_eof(t)) {
3542 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3543 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3544 s = pa_idxset_get_by_index(c->output_streams, idx);
3545 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3546 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3549 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3550 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3553 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3554 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3557 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3558 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3562 pa_assert_not_reached();
3565 pa_pstream_send_simple_ack(c->pstream, tag);
3568 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3569 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3574 pa_native_connection_assert_ref(c);
3577 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3578 pa_tagstruct_get_boolean(t, &b) < 0 ||
3579 !pa_tagstruct_eof(t)) {
3584 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3585 s = pa_idxset_get_by_index(c->record_streams, idx);
3586 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3588 pa_source_output_cork(s->source_output, b);
3589 pa_memblockq_prebuf_force(s->memblockq);
3590 pa_pstream_send_simple_ack(c->pstream, tag);
3593 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3594 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3598 pa_native_connection_assert_ref(c);
3601 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3602 !pa_tagstruct_eof(t)) {
3607 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3608 s = pa_idxset_get_by_index(c->record_streams, idx);
3609 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3611 pa_memblockq_flush_read(s->memblockq);
3612 pa_pstream_send_simple_ack(c->pstream, tag);
3615 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3616 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3619 pa_tagstruct *reply;
3621 pa_native_connection_assert_ref(c);
3624 memset(&a, 0, sizeof(a));
3626 if (pa_tagstruct_getu32(t, &idx) < 0) {
3631 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3633 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3635 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3637 s = pa_idxset_get_by_index(c->output_streams, idx);
3638 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3639 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3641 if (pa_tagstruct_get(
3643 PA_TAG_U32, &a.maxlength,
3644 PA_TAG_U32, &a.tlength,
3645 PA_TAG_U32, &a.prebuf,
3646 PA_TAG_U32, &a.minreq,
3647 PA_TAG_INVALID) < 0 ||
3648 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3649 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3650 !pa_tagstruct_eof(t)) {
3655 s->adjust_latency = adjust_latency;
3656 s->early_requests = early_requests;
3659 fix_playback_buffer_attr(s);
3660 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);
3662 reply = reply_new(tag);
3663 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3664 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3665 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3666 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3668 if (c->version >= 13)
3669 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3673 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3674 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3676 s = pa_idxset_get_by_index(c->record_streams, idx);
3677 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3679 if (pa_tagstruct_get(
3681 PA_TAG_U32, &a.maxlength,
3682 PA_TAG_U32, &a.fragsize,
3683 PA_TAG_INVALID) < 0 ||
3684 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3685 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3686 !pa_tagstruct_eof(t)) {
3691 s->adjust_latency = adjust_latency;
3692 s->early_requests = early_requests;
3695 fix_record_buffer_attr_pre(s);
3696 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3697 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3698 fix_record_buffer_attr_post(s);
3700 reply = reply_new(tag);
3701 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3702 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3704 if (c->version >= 13)
3705 pa_tagstruct_put_usec(reply, s->configured_source_latency);
3708 pa_pstream_send_tagstruct(c->pstream, reply);
3711 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3712 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3716 pa_native_connection_assert_ref(c);
3719 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3720 pa_tagstruct_getu32(t, &rate) < 0 ||
3721 !pa_tagstruct_eof(t)) {
3726 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3727 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
3729 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
3732 s = pa_idxset_get_by_index(c->output_streams, idx);
3733 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3734 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3736 pa_sink_input_set_rate(s->sink_input, rate);
3740 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
3742 s = pa_idxset_get_by_index(c->record_streams, idx);
3743 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3745 pa_source_output_set_rate(s->source_output, rate);
3748 pa_pstream_send_simple_ack(c->pstream, tag);
3751 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3752 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3757 pa_native_connection_assert_ref(c);
3760 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3762 p = pa_proplist_new();
3764 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
3766 if (pa_tagstruct_getu32(t, &mode) < 0 ||
3767 pa_tagstruct_get_proplist(t, p) < 0 ||
3768 !pa_tagstruct_eof(t)) {
3770 pa_proplist_free(p);
3776 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3777 pa_tagstruct_getu32(t, &mode) < 0 ||
3778 pa_tagstruct_get_proplist(t, p) < 0 ||
3779 !pa_tagstruct_eof(t)) {
3781 pa_proplist_free(p);
3786 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
3787 pa_proplist_free(p);
3788 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
3791 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
3794 s = pa_idxset_get_by_index(c->output_streams, idx);
3795 if (!s || !playback_stream_isinstance(s)) {
3796 pa_proplist_free(p);
3797 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3799 pa_sink_input_update_proplist(s->sink_input, mode, p);
3801 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
3804 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
3805 pa_proplist_free(p);
3806 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3808 pa_source_output_update_proplist(s->source_output, mode, p);
3811 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
3813 pa_client_update_proplist(c->client, mode, p);
3816 pa_pstream_send_simple_ack(c->pstream, tag);
3817 pa_proplist_free(p);
3820 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3821 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3823 unsigned changed = 0;
3825 pa_strlist *l = NULL;
3827 pa_native_connection_assert_ref(c);
3830 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3832 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
3834 if (pa_tagstruct_getu32(t, &idx) < 0) {
3840 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3843 s = pa_idxset_get_by_index(c->output_streams, idx);
3844 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3845 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3847 p = s->sink_input->proplist;
3849 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3852 s = pa_idxset_get_by_index(c->record_streams, idx);
3853 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3855 p = s->source_output->proplist;
3857 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3859 p = c->client->proplist;
3865 if (pa_tagstruct_gets(t, &k) < 0) {
3874 l = pa_strlist_prepend(l, k);
3877 if (!pa_tagstruct_eof(t)) {
3886 l = pa_strlist_pop(l, &z);
3891 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
3895 pa_pstream_send_simple_ack(c->pstream, tag);
3898 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3901 s = pa_idxset_get_by_index(c->output_streams, idx);
3902 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
3904 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3907 s = pa_idxset_get_by_index(c->record_streams, idx);
3908 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
3911 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3912 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
3917 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3918 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3921 pa_native_connection_assert_ref(c);
3924 if (pa_tagstruct_gets(t, &s) < 0 ||
3925 !pa_tagstruct_eof(t)) {
3930 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3931 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
3933 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
3936 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
3937 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
3939 pa_namereg_set_default_source(c->protocol->core, source);
3942 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
3944 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
3945 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3947 pa_namereg_set_default_sink(c->protocol->core, sink);
3950 pa_pstream_send_simple_ack(c->pstream, tag);
3953 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3954 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3958 pa_native_connection_assert_ref(c);
3961 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3962 pa_tagstruct_gets(t, &name) < 0 ||
3963 !pa_tagstruct_eof(t)) {
3968 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3969 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
3971 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
3974 s = pa_idxset_get_by_index(c->output_streams, idx);
3975 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3976 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3978 pa_sink_input_set_name(s->sink_input, name);
3982 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
3984 s = pa_idxset_get_by_index(c->record_streams, idx);
3985 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3987 pa_source_output_set_name(s->source_output, name);
3990 pa_pstream_send_simple_ack(c->pstream, tag);
3993 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3994 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3997 pa_native_connection_assert_ref(c);
4000 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4001 !pa_tagstruct_eof(t)) {
4006 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4008 if (command == PA_COMMAND_KILL_CLIENT) {
4011 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4012 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4014 pa_native_connection_ref(c);
4015 pa_client_kill(client);
4017 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4020 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4021 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4023 pa_native_connection_ref(c);
4024 pa_sink_input_kill(s);
4026 pa_source_output *s;
4028 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4030 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4031 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4033 pa_native_connection_ref(c);
4034 pa_source_output_kill(s);
4037 pa_pstream_send_simple_ack(c->pstream, tag);
4038 pa_native_connection_unref(c);
4041 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4042 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4044 const char *name, *argument;
4045 pa_tagstruct *reply;
4047 pa_native_connection_assert_ref(c);
4050 if (pa_tagstruct_gets(t, &name) < 0 ||
4051 pa_tagstruct_gets(t, &argument) < 0 ||
4052 !pa_tagstruct_eof(t)) {
4057 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4058 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4059 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4061 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4062 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4066 reply = reply_new(tag);
4067 pa_tagstruct_putu32(reply, m->index);
4068 pa_pstream_send_tagstruct(c->pstream, reply);
4071 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4072 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4076 pa_native_connection_assert_ref(c);
4079 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4080 !pa_tagstruct_eof(t)) {
4085 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4086 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4087 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4089 pa_module_unload_request(m, FALSE);
4090 pa_pstream_send_simple_ack(c->pstream, tag);
4093 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4094 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4095 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4096 const char *name_device = NULL;
4098 pa_native_connection_assert_ref(c);
4101 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4102 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4103 pa_tagstruct_gets(t, &name_device) < 0 ||
4104 !pa_tagstruct_eof(t)) {
4109 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4110 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4112 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);
4113 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4114 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4115 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4117 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4118 pa_sink_input *si = NULL;
4119 pa_sink *sink = NULL;
4121 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4123 if (idx_device != PA_INVALID_INDEX)
4124 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4126 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4128 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4130 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4131 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4135 pa_source_output *so = NULL;
4138 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4140 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4142 if (idx_device != PA_INVALID_INDEX)
4143 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4145 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4147 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4149 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4150 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4155 pa_pstream_send_simple_ack(c->pstream, tag);
4158 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4159 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4160 uint32_t idx = PA_INVALID_INDEX;
4161 const char *name = NULL;
4164 pa_native_connection_assert_ref(c);
4167 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4168 pa_tagstruct_gets(t, &name) < 0 ||
4169 pa_tagstruct_get_boolean(t, &b) < 0 ||
4170 !pa_tagstruct_eof(t)) {
4175 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4176 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);
4177 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4178 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4179 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4181 if (command == PA_COMMAND_SUSPEND_SINK) {
4183 if (idx == PA_INVALID_INDEX && name && !*name) {
4185 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4187 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4188 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4192 pa_sink *sink = NULL;
4194 if (idx != PA_INVALID_INDEX)
4195 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4197 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4199 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4201 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4202 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4208 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4210 if (idx == PA_INVALID_INDEX && name && !*name) {
4212 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4214 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4215 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4222 if (idx != PA_INVALID_INDEX)
4223 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4225 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4227 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4229 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4230 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4236 pa_pstream_send_simple_ack(c->pstream, tag);
4239 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4240 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4241 uint32_t idx = PA_INVALID_INDEX;
4242 const char *name = NULL;
4244 pa_native_protocol_ext_cb_t cb;
4246 pa_native_connection_assert_ref(c);
4249 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4250 pa_tagstruct_gets(t, &name) < 0) {
4255 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4256 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4257 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4258 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4259 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4261 if (idx != PA_INVALID_INDEX)
4262 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4264 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4265 if (strcmp(name, m->name) == 0)
4269 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4270 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4272 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4273 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4275 if (cb(c->protocol, m, c, tag, t) < 0)
4279 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4280 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4281 uint32_t idx = PA_INVALID_INDEX;
4282 const char *name = NULL, *profile = NULL;
4283 pa_card *card = NULL;
4286 pa_native_connection_assert_ref(c);
4289 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4290 pa_tagstruct_gets(t, &name) < 0 ||
4291 pa_tagstruct_gets(t, &profile) < 0 ||
4292 !pa_tagstruct_eof(t)) {
4297 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4298 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4299 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4300 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4301 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4303 if (idx != PA_INVALID_INDEX)
4304 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4306 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4308 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4310 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4311 pa_pstream_send_error(c->pstream, tag, -ret);
4315 pa_pstream_send_simple_ack(c->pstream, tag);
4318 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4319 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4320 uint32_t idx = PA_INVALID_INDEX;
4321 const char *name = NULL, *port = NULL;
4324 pa_native_connection_assert_ref(c);
4327 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4328 pa_tagstruct_gets(t, &name) < 0 ||
4329 pa_tagstruct_gets(t, &port) < 0 ||
4330 !pa_tagstruct_eof(t)) {
4335 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4336 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);
4337 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4338 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4339 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4341 if (command == PA_COMMAND_SET_SINK_PORT) {
4344 if (idx != PA_INVALID_INDEX)
4345 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4347 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4349 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4351 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4352 pa_pstream_send_error(c->pstream, tag, -ret);
4358 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4360 if (idx != PA_INVALID_INDEX)
4361 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4363 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4365 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4367 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4368 pa_pstream_send_error(c->pstream, tag, -ret);
4373 pa_pstream_send_simple_ack(c->pstream, tag);
4376 /*** pstream callbacks ***/
4378 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4379 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4383 pa_native_connection_assert_ref(c);
4385 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4386 pa_log("invalid packet.");
4387 native_connection_unlink(c);
4391 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) {
4392 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4393 output_stream *stream;
4397 pa_native_connection_assert_ref(c);
4399 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4400 pa_log_debug("Client sent block for invalid stream.");
4405 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4407 if (playback_stream_isinstance(stream)) {
4408 playback_stream *ps = PLAYBACK_STREAM(stream);
4410 if (chunk->memblock) {
4411 if (seek != PA_SEEK_RELATIVE || offset != 0)
4412 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);
4414 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4416 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);
4419 upload_stream *u = UPLOAD_STREAM(stream);
4422 if (!u->memchunk.memblock) {
4423 if (u->length == chunk->length && chunk->memblock) {
4424 u->memchunk = *chunk;
4425 pa_memblock_ref(u->memchunk.memblock);
4428 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4429 u->memchunk.index = u->memchunk.length = 0;
4433 pa_assert(u->memchunk.memblock);
4436 if (l > chunk->length)
4441 dst = pa_memblock_acquire(u->memchunk.memblock);
4443 if (chunk->memblock) {
4445 src = pa_memblock_acquire(chunk->memblock);
4447 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4448 (uint8_t*) src + chunk->index, l);
4450 pa_memblock_release(chunk->memblock);
4452 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4454 pa_memblock_release(u->memchunk.memblock);
4456 u->memchunk.length += l;
4462 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4463 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4466 pa_native_connection_assert_ref(c);
4468 native_connection_unlink(c);
4469 pa_log_info("Connection died.");
4472 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4473 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4476 pa_native_connection_assert_ref(c);
4478 native_connection_send_memblock(c);
4481 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4484 if (!(q = pa_thread_mq_get()))
4485 pa_pstream_send_revoke(p, block_id);
4487 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4490 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4493 if (!(q = pa_thread_mq_get()))
4494 pa_pstream_send_release(p, block_id);
4496 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4499 /*** client callbacks ***/
4501 static void client_kill_cb(pa_client *c) {
4504 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4505 pa_log_info("Connection killed.");
4508 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4510 pa_native_connection *c;
4513 c = PA_NATIVE_CONNECTION(client->userdata);
4514 pa_native_connection_assert_ref(c);
4516 if (c->version < 15)
4519 t = pa_tagstruct_new(NULL, 0);
4520 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4521 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4522 pa_tagstruct_puts(t, event);
4523 pa_tagstruct_put_proplist(t, pl);
4524 pa_pstream_send_tagstruct(c->pstream, t);
4527 /*** module entry points ***/
4529 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4530 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4533 pa_native_connection_assert_ref(c);
4534 pa_assert(c->auth_timeout_event == e);
4536 if (!c->authorized) {
4537 native_connection_unlink(c);
4538 pa_log_info("Connection terminated due to authentication timeout.");
4542 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4543 pa_native_connection *c;
4546 pa_client_new_data data;
4552 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4553 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4554 pa_iochannel_free(io);
4558 pa_client_new_data_init(&data);
4559 data.module = o->module;
4560 data.driver = __FILE__;
4561 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4562 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4563 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4564 client = pa_client_new(p->core, &data);
4565 pa_client_new_data_done(&data);
4570 c = pa_msgobject_new(pa_native_connection);
4571 c->parent.parent.free = native_connection_free;
4572 c->parent.process_msg = native_connection_process_msg;
4574 c->options = pa_native_options_ref(o);
4575 c->authorized = FALSE;
4577 if (o->auth_anonymous) {
4578 pa_log_info("Client authenticated anonymously.");
4579 c->authorized = TRUE;
4582 if (!c->authorized &&
4584 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4586 pa_log_info("Client authenticated by IP ACL.");
4587 c->authorized = TRUE;
4591 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4593 c->auth_timeout_event = NULL;
4595 c->is_local = pa_iochannel_socket_is_local(io);
4599 c->client->kill = client_kill_cb;
4600 c->client->send_event = client_send_event_cb;
4601 c->client->userdata = c;
4603 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4604 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4605 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4606 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4607 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4608 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4609 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4611 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4613 c->record_streams = pa_idxset_new(NULL, NULL);
4614 c->output_streams = pa_idxset_new(NULL, NULL);
4616 c->rrobin_index = PA_IDXSET_INVALID;
4617 c->subscription = NULL;
4619 pa_idxset_put(p->connections, c, NULL);
4622 if (pa_iochannel_creds_supported(io))
4623 pa_iochannel_creds_enable(io);
4626 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4629 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4630 pa_native_connection *c;
4636 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4637 if (c->options->module == m)
4638 native_connection_unlink(c);
4641 static pa_native_protocol* native_protocol_new(pa_core *c) {
4642 pa_native_protocol *p;
4647 p = pa_xnew(pa_native_protocol, 1);
4650 p->connections = pa_idxset_new(NULL, NULL);
4654 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4656 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4657 pa_hook_init(&p->hooks[h], p);
4659 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4664 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4665 pa_native_protocol *p;
4667 if ((p = pa_shared_get(c, "native-protocol")))
4668 return pa_native_protocol_ref(p);
4670 return native_protocol_new(c);
4673 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4675 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4682 void pa_native_protocol_unref(pa_native_protocol *p) {
4683 pa_native_connection *c;
4687 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4689 if (PA_REFCNT_DEC(p) > 0)
4692 while ((c = pa_idxset_first(p->connections, NULL)))
4693 native_connection_unlink(c);
4695 pa_idxset_free(p->connections, NULL, NULL);
4697 pa_strlist_free(p->servers);
4699 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4700 pa_hook_done(&p->hooks[h]);
4702 pa_hashmap_free(p->extensions, NULL, NULL);
4704 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4709 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
4711 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4714 p->servers = pa_strlist_prepend(p->servers, name);
4716 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4719 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
4721 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4724 p->servers = pa_strlist_remove(p->servers, name);
4726 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4729 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
4731 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4736 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
4738 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4743 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
4745 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4748 pa_assert(!pa_hashmap_get(p->extensions, m));
4750 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
4754 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
4756 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4759 pa_assert_se(pa_hashmap_remove(p->extensions, m));
4762 pa_native_options* pa_native_options_new(void) {
4763 pa_native_options *o;
4765 o = pa_xnew0(pa_native_options, 1);
4771 pa_native_options* pa_native_options_ref(pa_native_options *o) {
4773 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4780 void pa_native_options_unref(pa_native_options *o) {
4782 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4784 if (PA_REFCNT_DEC(o) > 0)
4787 pa_xfree(o->auth_group);
4790 pa_ip_acl_free(o->auth_ip_acl);
4793 pa_auth_cookie_unref(o->auth_cookie);
4798 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
4803 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4806 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
4807 pa_log("auth-anonymous= expects a boolean argument.");
4812 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
4813 pa_log("auth-group-enabled= expects a boolean argument.");
4817 pa_xfree(o->auth_group);
4818 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
4822 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4825 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
4828 if (!(ipa = pa_ip_acl_new(acl))) {
4829 pa_log("Failed to parse IP ACL '%s'", acl);
4834 pa_ip_acl_free(o->auth_ip_acl);
4836 o->auth_ip_acl = ipa;
4840 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
4841 pa_log("auth-cookie-enabled= expects a boolean argument.");
4846 pa_auth_cookie_unref(o->auth_cookie);
4851 /* The new name for this is 'auth-cookie', for compat reasons
4852 * we check the old name too */
4853 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
4854 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
4855 cn = PA_NATIVE_COOKIE_FILE;
4857 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
4861 o->auth_cookie = NULL;
4866 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
4867 pa_native_connection_assert_ref(c);
4872 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
4873 pa_native_connection_assert_ref(c);