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;
128 /* Optimization to avoid too many rewinds with a lot of small blocks */
129 pa_atomic_t seek_or_post_in_queue;
133 pa_usec_t configured_sink_latency;
134 pa_buffer_attr buffer_attr;
136 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
137 int64_t read_index, write_index;
138 size_t render_memblockq_length;
139 pa_usec_t current_sink_latency;
140 uint64_t playing_for, underrun_for;
143 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
144 PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
146 typedef struct upload_stream {
147 output_stream parent;
149 pa_native_connection *connection;
152 pa_memchunk memchunk;
155 pa_sample_spec sample_spec;
156 pa_channel_map channel_map;
157 pa_proplist *proplist;
160 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
161 PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
163 struct pa_native_connection {
165 pa_native_protocol *protocol;
166 pa_native_options *options;
167 pa_bool_t authorized:1;
168 pa_bool_t is_local:1;
172 pa_pdispatch *pdispatch;
173 pa_idxset *record_streams, *output_streams;
174 uint32_t rrobin_index;
175 pa_subscription *subscription;
176 pa_time_event *auth_timeout_event;
179 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
180 PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
182 struct pa_native_protocol {
186 pa_idxset *connections;
189 pa_hook hooks[PA_NATIVE_HOOK_MAX];
191 pa_hashmap *extensions;
195 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
199 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
200 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
201 SINK_INPUT_MESSAGE_FLUSH,
202 SINK_INPUT_MESSAGE_TRIGGER,
203 SINK_INPUT_MESSAGE_SEEK,
204 SINK_INPUT_MESSAGE_PREBUF_FORCE,
205 SINK_INPUT_MESSAGE_UPDATE_LATENCY,
206 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
210 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
211 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
212 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
213 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
214 PLAYBACK_STREAM_MESSAGE_STARTED,
215 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
219 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
223 CONNECTION_MESSAGE_RELEASE,
224 CONNECTION_MESSAGE_REVOKE
227 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
228 static void sink_input_kill_cb(pa_sink_input *i);
229 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
230 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
231 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
232 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
233 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
234 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
236 static void native_connection_send_memblock(pa_native_connection *c);
237 static void playback_stream_request_bytes(struct playback_stream*s);
239 static void source_output_kill_cb(pa_source_output *o);
240 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
241 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend);
242 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
243 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
244 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
246 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
247 static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
249 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
250 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
251 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
252 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
253 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
254 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
255 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
256 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
257 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
258 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
259 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
260 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
261 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
262 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
263 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
264 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
265 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
266 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
267 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
268 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
269 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
270 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
271 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
272 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
273 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
274 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
275 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
276 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
277 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
278 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
279 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
280 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
281 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
282 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
283 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
284 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
285 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
286 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
287 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
289 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
290 [PA_COMMAND_ERROR] = NULL,
291 [PA_COMMAND_TIMEOUT] = NULL,
292 [PA_COMMAND_REPLY] = NULL,
293 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
294 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
295 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
296 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
297 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
298 [PA_COMMAND_AUTH] = command_auth,
299 [PA_COMMAND_REQUEST] = NULL,
300 [PA_COMMAND_EXIT] = command_exit,
301 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
302 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
303 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
304 [PA_COMMAND_STAT] = command_stat,
305 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
306 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
307 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
308 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
309 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
310 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
311 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
312 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
313 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
314 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
315 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
316 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
317 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
318 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
319 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
320 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
321 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
322 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
323 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
324 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
325 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
326 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
327 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
328 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
329 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
331 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
332 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
333 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
335 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
336 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
337 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
339 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
340 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
342 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
343 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
344 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
345 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
347 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
348 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
350 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
351 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
352 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
353 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
354 [PA_COMMAND_KILL_CLIENT] = command_kill,
355 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
356 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
357 [PA_COMMAND_LOAD_MODULE] = command_load_module,
358 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
360 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
361 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
362 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
363 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
365 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
366 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
368 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
369 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
371 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
372 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
374 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
375 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
376 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
378 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
379 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
380 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
382 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
384 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
385 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
387 [PA_COMMAND_EXTENSION] = command_extension
390 /* structure management */
392 /* Called from main context */
393 static void upload_stream_unlink(upload_stream *s) {
399 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
400 s->connection = NULL;
401 upload_stream_unref(s);
404 /* Called from main context */
405 static void upload_stream_free(pa_object *o) {
406 upload_stream *s = UPLOAD_STREAM(o);
409 upload_stream_unlink(s);
414 pa_proplist_free(s->proplist);
416 if (s->memchunk.memblock)
417 pa_memblock_unref(s->memchunk.memblock);
422 /* Called from main context */
423 static upload_stream* upload_stream_new(
424 pa_native_connection *c,
425 const pa_sample_spec *ss,
426 const pa_channel_map *map,
436 pa_assert(length > 0);
439 s = pa_msgobject_new(upload_stream);
440 s->parent.parent.parent.free = upload_stream_free;
442 s->sample_spec = *ss;
443 s->channel_map = *map;
444 s->name = pa_xstrdup(name);
445 pa_memchunk_reset(&s->memchunk);
447 s->proplist = pa_proplist_copy(p);
448 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
450 pa_idxset_put(c->output_streams, s, &s->index);
455 /* Called from main context */
456 static void record_stream_unlink(record_stream *s) {
462 if (s->source_output) {
463 pa_source_output_unlink(s->source_output);
464 pa_source_output_unref(s->source_output);
465 s->source_output = NULL;
468 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
469 s->connection = NULL;
470 record_stream_unref(s);
473 /* Called from main context */
474 static void record_stream_free(pa_object *o) {
475 record_stream *s = RECORD_STREAM(o);
478 record_stream_unlink(s);
480 pa_memblockq_free(s->memblockq);
484 /* Called from main context */
485 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
486 record_stream *s = RECORD_STREAM(o);
487 record_stream_assert_ref(s);
494 case RECORD_STREAM_MESSAGE_POST_DATA:
496 /* We try to keep up to date with how many bytes are
497 * currently on the fly */
498 pa_atomic_sub(&s->on_the_fly, chunk->length);
500 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
501 /* pa_log_warn("Failed to push data into output queue."); */
505 if (!pa_pstream_is_pending(s->connection->pstream))
506 native_connection_send_memblock(s->connection);
514 /* Called from main context */
515 static void fix_record_buffer_attr_pre(record_stream *s) {
518 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
522 /* This function will be called from the main thread, before as
523 * well as after the source output has been activated using
524 * pa_source_output_put()! That means it may not touch any
525 * ->thread_info data! */
527 frame_size = pa_frame_size(&s->source_output->sample_spec);
529 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
530 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
531 if (s->buffer_attr.maxlength <= 0)
532 s->buffer_attr.maxlength = (uint32_t) frame_size;
534 if (s->buffer_attr.fragsize == (uint32_t) -1)
535 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
536 if (s->buffer_attr.fragsize <= 0)
537 s->buffer_attr.fragsize = (uint32_t) frame_size;
539 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
541 if (s->early_requests) {
543 /* In early request mode we need to emulate the classic
544 * fragment-based playback model. We do this setting the source
545 * latency to the fragment size. */
547 source_usec = fragsize_usec;
549 } else if (s->adjust_latency) {
551 /* So, the user asked us to adjust the latency according to
552 * what the source can provide. Half the latency will be
553 * spent on the hw buffer, half of it in the async buffer
554 * queue we maintain for each client. */
556 source_usec = fragsize_usec/2;
560 /* Ok, the user didn't ask us to adjust the latency, hence we
563 source_usec = (pa_usec_t) -1;
566 if (source_usec != (pa_usec_t) -1)
567 s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
569 s->configured_source_latency = 0;
571 if (s->early_requests) {
573 /* Ok, we didn't necessarily get what we were asking for, so
574 * let's tell the user */
576 fragsize_usec = s->configured_source_latency;
578 } else if (s->adjust_latency) {
580 /* Now subtract what we actually got */
582 if (fragsize_usec >= s->configured_source_latency*2)
583 fragsize_usec -= s->configured_source_latency;
585 fragsize_usec = s->configured_source_latency;
588 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
589 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
591 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
593 if (s->buffer_attr.fragsize <= 0)
594 s->buffer_attr.fragsize = (uint32_t) frame_size;
597 /* Called from main context */
598 static void fix_record_buffer_attr_post(record_stream *s) {
603 /* This function will be called from the main thread, before as
604 * well as after the source output has been activated using
605 * pa_source_output_put()! That means it may not touch and
606 * ->thread_info data! */
608 base = pa_frame_size(&s->source_output->sample_spec);
610 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
611 if (s->buffer_attr.fragsize <= 0)
612 s->buffer_attr.fragsize = base;
614 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
615 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
618 /* Called from main context */
619 static record_stream* record_stream_new(
620 pa_native_connection *c,
624 pa_bool_t peak_detect,
625 pa_buffer_attr *attr,
626 pa_source_output_flags_t flags,
628 pa_bool_t adjust_latency,
629 pa_sink_input *direct_on_input,
630 pa_bool_t early_requests,
634 pa_source_output *source_output = NULL;
635 pa_source_output_new_data data;
642 pa_source_output_new_data_init(&data);
644 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
645 data.driver = __FILE__;
646 data.module = c->options->module;
647 data.client = c->client;
648 data.source = source;
649 data.direct_on_input = direct_on_input;
650 pa_source_output_new_data_set_sample_spec(&data, ss);
651 pa_source_output_new_data_set_channel_map(&data, map);
653 data.resample_method = PA_RESAMPLER_PEAKS;
656 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
658 pa_source_output_new_data_done(&data);
663 s = pa_msgobject_new(record_stream);
664 s->parent.parent.free = record_stream_free;
665 s->parent.process_msg = record_stream_process_msg;
667 s->source_output = source_output;
668 s->buffer_attr = *attr;
669 s->adjust_latency = adjust_latency;
670 s->early_requests = early_requests;
671 pa_atomic_store(&s->on_the_fly, 0);
673 s->source_output->parent.process_msg = source_output_process_msg;
674 s->source_output->push = source_output_push_cb;
675 s->source_output->kill = source_output_kill_cb;
676 s->source_output->get_latency = source_output_get_latency_cb;
677 s->source_output->moving = source_output_moving_cb;
678 s->source_output->suspend = source_output_suspend_cb;
679 s->source_output->send_event = source_output_send_event_cb;
680 s->source_output->userdata = s;
682 fix_record_buffer_attr_pre(s);
684 s->memblockq = pa_memblockq_new(
686 s->buffer_attr.maxlength,
688 pa_frame_size(&source_output->sample_spec),
694 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
695 fix_record_buffer_attr_post(s);
697 *ss = s->source_output->sample_spec;
698 *map = s->source_output->channel_map;
700 pa_idxset_put(c->record_streams, s, &s->index);
702 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
703 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
704 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
705 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
707 pa_source_output_put(s->source_output);
711 /* Called from main context */
712 static void record_stream_send_killed(record_stream *r) {
714 record_stream_assert_ref(r);
716 t = pa_tagstruct_new(NULL, 0);
717 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
718 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
719 pa_tagstruct_putu32(t, r->index);
720 pa_pstream_send_tagstruct(r->connection->pstream, t);
723 /* Called from main context */
724 static void playback_stream_unlink(playback_stream *s) {
731 pa_sink_input_unlink(s->sink_input);
732 pa_sink_input_unref(s->sink_input);
733 s->sink_input = NULL;
736 if (s->drain_request)
737 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
739 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
740 s->connection = NULL;
741 playback_stream_unref(s);
744 /* Called from main context */
745 static void playback_stream_free(pa_object* o) {
746 playback_stream *s = PLAYBACK_STREAM(o);
749 playback_stream_unlink(s);
751 pa_memblockq_free(s->memblockq);
755 /* Called from main context */
756 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
757 playback_stream *s = PLAYBACK_STREAM(o);
758 playback_stream_assert_ref(s);
765 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
770 if ((l = pa_atomic_load(&s->missing)) <= 0)
773 if (pa_atomic_cmpxchg(&s->missing, l, 0))
777 t = pa_tagstruct_new(NULL, 0);
778 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
779 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
780 pa_tagstruct_putu32(t, s->index);
781 pa_tagstruct_putu32(t, (uint32_t) l);
782 pa_pstream_send_tagstruct(s->connection->pstream, t);
784 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
788 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
791 /* pa_log("signalling underflow"); */
793 /* Report that we're empty */
794 t = pa_tagstruct_new(NULL, 0);
795 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
796 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
797 pa_tagstruct_putu32(t, s->index);
798 pa_pstream_send_tagstruct(s->connection->pstream, t);
802 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
805 /* Notify the user we're overflowed*/
806 t = pa_tagstruct_new(NULL, 0);
807 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
808 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
809 pa_tagstruct_putu32(t, s->index);
810 pa_pstream_send_tagstruct(s->connection->pstream, t);
814 case PLAYBACK_STREAM_MESSAGE_STARTED:
816 if (s->connection->version >= 13) {
819 /* Notify the user we started playback */
820 t = pa_tagstruct_new(NULL, 0);
821 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
822 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
823 pa_tagstruct_putu32(t, s->index);
824 pa_pstream_send_tagstruct(s->connection->pstream, t);
829 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
830 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
833 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
835 s->buffer_attr.tlength = (uint32_t) offset;
837 if (s->connection->version >= 15) {
840 t = pa_tagstruct_new(NULL, 0);
841 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
842 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
843 pa_tagstruct_putu32(t, s->index);
844 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
845 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
846 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
847 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
848 pa_tagstruct_put_usec(t, s->configured_sink_latency);
849 pa_pstream_send_tagstruct(s->connection->pstream, t);
858 /* Called from main context */
859 static void fix_playback_buffer_attr(playback_stream *s) {
860 size_t frame_size, max_prebuf;
861 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
865 /* pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", */
866 /* (long) s->buffer_attr.maxlength, */
867 /* (long) s->buffer_attr.tlength, */
868 /* (long) s->buffer_attr.minreq, */
869 /* (long) s->buffer_attr.prebuf); */
871 /* pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
872 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
873 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
874 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
875 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
877 /* This function will be called from the main thread, before as
878 * well as after the sink input has been activated using
879 * pa_sink_input_put()! That means it may not touch any
880 * ->thread_info data, such as the memblockq! */
882 frame_size = pa_frame_size(&s->sink_input->sample_spec);
884 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
885 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
886 if (s->buffer_attr.maxlength <= 0)
887 s->buffer_attr.maxlength = (uint32_t) frame_size;
889 if (s->buffer_attr.tlength == (uint32_t) -1)
890 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
891 if (s->buffer_attr.tlength <= 0)
892 s->buffer_attr.tlength = (uint32_t) frame_size;
894 if (s->buffer_attr.minreq == (uint32_t) -1)
895 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
896 if (s->buffer_attr.minreq <= 0)
897 s->buffer_attr.minreq = (uint32_t) frame_size;
899 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
900 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
902 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
903 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
905 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
906 (double) tlength_usec / PA_USEC_PER_MSEC,
907 (double) minreq_usec / PA_USEC_PER_MSEC);
909 if (s->early_requests) {
911 /* In early request mode we need to emulate the classic
912 * fragment-based playback model. We do this setting the sink
913 * latency to the fragment size. */
915 sink_usec = minreq_usec;
916 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
918 } else if (s->adjust_latency) {
920 /* So, the user asked us to adjust the latency of the stream
921 * buffer according to the what the sink can provide. The
922 * tlength passed in shall be the overall latency. Roughly
923 * half the latency will be spent on the hw buffer, the other
924 * half of it in the async buffer queue we maintain for each
925 * client. In between we'll have a safety space of size
926 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
927 * empty and needs to be filled, then our buffer must have
928 * enough data to fulfill this request immediatly and thus
929 * have at least the same tlength as the size of the hw
930 * buffer. It additionally needs space for 2 times minreq
931 * because if the buffer ran empty and a partial fillup
932 * happens immediately on the next iteration we need to be
933 * able to fulfill it and give the application also minreq
934 * time to fill it up again for the next request Makes 2 times
935 * minreq in plus.. */
937 if (tlength_usec > minreq_usec*2)
938 sink_usec = (tlength_usec - minreq_usec*2)/2;
942 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
946 /* Ok, the user didn't ask us to adjust the latency, but we
947 * still need to make sure that the parameters from the user
950 if (tlength_usec > minreq_usec*2)
951 sink_usec = (tlength_usec - minreq_usec*2);
955 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
958 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
960 if (s->early_requests) {
962 /* Ok, we didn't necessarily get what we were asking for, so
963 * let's tell the user */
965 minreq_usec = s->configured_sink_latency;
967 } else if (s->adjust_latency) {
969 /* Ok, we didn't necessarily get what we were asking for, so
970 * let's subtract from what we asked for for the remaining
973 if (tlength_usec >= s->configured_sink_latency)
974 tlength_usec -= s->configured_sink_latency;
977 /* FIXME: This is actually larger than necessary, since not all of
978 * the sink latency is actually rewritable. */
979 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
980 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
982 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
983 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
984 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
986 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
987 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
988 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
990 if (s->buffer_attr.minreq <= 0) {
991 s->buffer_attr.minreq = (uint32_t) frame_size;
992 s->buffer_attr.tlength += (uint32_t) frame_size*2;
995 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
996 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
998 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
1000 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
1001 s->buffer_attr.prebuf > max_prebuf)
1002 s->buffer_attr.prebuf = max_prebuf;
1004 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1005 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1006 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1007 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1008 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1011 /* Called from main context */
1012 static playback_stream* playback_stream_new(
1013 pa_native_connection *c,
1016 pa_channel_map *map,
1020 pa_bool_t muted_set,
1023 pa_sink_input_flags_t flags,
1025 pa_bool_t adjust_latency,
1026 pa_bool_t early_requests,
1027 pa_bool_t relative_volume,
1030 playback_stream *s, *ssync;
1031 pa_sink_input *sink_input = NULL;
1032 pa_memchunk silence;
1034 int64_t start_index;
1035 pa_sink_input_new_data data;
1043 /* Find syncid group */
1044 PA_IDXSET_FOREACH(ssync, c->output_streams, idx) {
1046 if (!playback_stream_isinstance(ssync))
1049 if (ssync->syncid == syncid)
1053 /* Synced streams must connect to the same sink */
1057 sink = ssync->sink_input->sink;
1058 else if (sink != ssync->sink_input->sink) {
1059 *ret = PA_ERR_INVALID;
1064 pa_sink_input_new_data_init(&data);
1066 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1067 data.driver = __FILE__;
1068 data.module = c->options->module;
1069 data.client = c->client;
1072 data.save_sink = TRUE;
1074 pa_sink_input_new_data_set_sample_spec(&data, ss);
1075 pa_sink_input_new_data_set_channel_map(&data, map);
1077 pa_sink_input_new_data_set_volume(&data, volume);
1078 data.volume_is_absolute = !relative_volume;
1079 data.save_volume = TRUE;
1082 pa_sink_input_new_data_set_muted(&data, muted);
1083 data.save_muted = TRUE;
1085 data.sync_base = ssync ? ssync->sink_input : NULL;
1088 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1090 pa_sink_input_new_data_done(&data);
1095 s = pa_msgobject_new(playback_stream);
1096 s->parent.parent.parent.free = playback_stream_free;
1097 s->parent.parent.process_msg = playback_stream_process_msg;
1100 s->sink_input = sink_input;
1101 s->is_underrun = TRUE;
1102 s->drain_request = FALSE;
1103 pa_atomic_store(&s->missing, 0);
1104 s->buffer_attr = *a;
1105 s->adjust_latency = adjust_latency;
1106 s->early_requests = early_requests;
1107 pa_atomic_store(&s->seek_or_post_in_queue, 0);
1108 s->seek_windex = -1;
1110 s->sink_input->parent.process_msg = sink_input_process_msg;
1111 s->sink_input->pop = sink_input_pop_cb;
1112 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1113 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1114 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1115 s->sink_input->kill = sink_input_kill_cb;
1116 s->sink_input->moving = sink_input_moving_cb;
1117 s->sink_input->suspend = sink_input_suspend_cb;
1118 s->sink_input->send_event = sink_input_send_event_cb;
1119 s->sink_input->userdata = s;
1121 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1123 fix_playback_buffer_attr(s);
1125 pa_sink_input_get_silence(sink_input, &silence);
1126 s->memblockq = pa_memblockq_new(
1128 s->buffer_attr.maxlength,
1129 s->buffer_attr.tlength,
1130 pa_frame_size(&sink_input->sample_spec),
1131 s->buffer_attr.prebuf,
1132 s->buffer_attr.minreq,
1135 pa_memblock_unref(silence.memblock);
1137 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1139 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1141 /* pa_log("missing original: %li", (long int) *missing); */
1143 *ss = s->sink_input->sample_spec;
1144 *map = s->sink_input->channel_map;
1146 pa_idxset_put(c->output_streams, s, &s->index);
1148 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1149 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1150 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1151 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1152 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1154 pa_sink_input_put(s->sink_input);
1158 /* Called from IO context */
1159 static void playback_stream_request_bytes(playback_stream *s) {
1161 int previous_missing;
1163 playback_stream_assert_ref(s);
1165 m = pa_memblockq_pop_missing(s->memblockq);
1167 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1168 /* (unsigned long) m, */
1169 /* pa_memblockq_get_tlength(s->memblockq), */
1170 /* pa_memblockq_get_minreq(s->memblockq), */
1171 /* pa_memblockq_get_length(s->memblockq), */
1172 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1177 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1179 previous_missing = pa_atomic_add(&s->missing, (int) m);
1180 minreq = pa_memblockq_get_minreq(s->memblockq);
1182 if (pa_memblockq_prebuf_active(s->memblockq) ||
1183 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1184 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1187 /* Called from main context */
1188 static void playback_stream_send_killed(playback_stream *p) {
1190 playback_stream_assert_ref(p);
1192 t = pa_tagstruct_new(NULL, 0);
1193 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1194 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1195 pa_tagstruct_putu32(t, p->index);
1196 pa_pstream_send_tagstruct(p->connection->pstream, t);
1199 /* Called from main context */
1200 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1201 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1202 pa_native_connection_assert_ref(c);
1209 case CONNECTION_MESSAGE_REVOKE:
1210 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1213 case CONNECTION_MESSAGE_RELEASE:
1214 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1221 /* Called from main context */
1222 static void native_connection_unlink(pa_native_connection *c) {
1231 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1234 pa_native_options_unref(c->options);
1236 while ((r = pa_idxset_first(c->record_streams, NULL)))
1237 record_stream_unlink(r);
1239 while ((o = pa_idxset_first(c->output_streams, NULL)))
1240 if (playback_stream_isinstance(o))
1241 playback_stream_unlink(PLAYBACK_STREAM(o));
1243 upload_stream_unlink(UPLOAD_STREAM(o));
1245 if (c->subscription)
1246 pa_subscription_free(c->subscription);
1249 pa_pstream_unlink(c->pstream);
1251 if (c->auth_timeout_event) {
1252 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1253 c->auth_timeout_event = NULL;
1256 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1258 pa_native_connection_unref(c);
1261 /* Called from main context */
1262 static void native_connection_free(pa_object *o) {
1263 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1267 native_connection_unlink(c);
1269 pa_idxset_free(c->record_streams, NULL, NULL);
1270 pa_idxset_free(c->output_streams, NULL, NULL);
1272 pa_pdispatch_unref(c->pdispatch);
1273 pa_pstream_unref(c->pstream);
1274 pa_client_free(c->client);
1279 /* Called from main context */
1280 static void native_connection_send_memblock(pa_native_connection *c) {
1284 start = PA_IDXSET_INVALID;
1288 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1291 if (start == PA_IDXSET_INVALID)
1292 start = c->rrobin_index;
1293 else if (start == c->rrobin_index)
1296 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1297 pa_memchunk schunk = chunk;
1299 if (schunk.length > r->buffer_attr.fragsize)
1300 schunk.length = r->buffer_attr.fragsize;
1302 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1304 pa_memblockq_drop(r->memblockq, schunk.length);
1305 pa_memblock_unref(schunk.memblock);
1312 /*** sink input callbacks ***/
1314 /* Called from thread context */
1315 static void handle_seek(playback_stream *s, int64_t indexw) {
1316 playback_stream_assert_ref(s);
1318 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1320 if (s->sink_input->thread_info.underrun_for > 0) {
1322 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1324 if (pa_memblockq_is_readable(s->memblockq)) {
1326 /* We just ended an underrun, let's ask the sink
1327 * for a complete rewind rewrite */
1329 pa_log_debug("Requesting rewind due to end of underrun.");
1330 pa_sink_input_request_rewind(s->sink_input,
1331 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1332 s->sink_input->thread_info.underrun_for),
1333 FALSE, TRUE, FALSE);
1339 indexr = pa_memblockq_get_read_index(s->memblockq);
1341 if (indexw < indexr) {
1342 /* OK, the sink already asked for this data, so
1343 * let's have it usk us again */
1345 pa_log_debug("Requesting rewind due to rewrite.");
1346 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1350 playback_stream_request_bytes(s);
1353 static void flush_write_no_account(pa_memblockq *q) {
1354 pa_memblockq_flush_write(q, FALSE);
1357 /* Called from thread context */
1358 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1359 pa_sink_input *i = PA_SINK_INPUT(o);
1362 pa_sink_input_assert_ref(i);
1363 s = PLAYBACK_STREAM(i->userdata);
1364 playback_stream_assert_ref(s);
1368 case SINK_INPUT_MESSAGE_SEEK:
1369 case SINK_INPUT_MESSAGE_POST_DATA: {
1370 int64_t windex = pa_memblockq_get_write_index(s->memblockq);
1372 if (code == SINK_INPUT_MESSAGE_SEEK) {
1373 /* The client side is incapable of accounting correctly
1374 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1375 * able to deal with that. */
1377 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1378 windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
1381 if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1382 if (pa_log_ratelimit(PA_LOG_WARN))
1383 pa_log_warn("Failed to push data into queue");
1384 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1385 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1388 /* If more data is in queue, we rewind later instead. */
1389 if (s->seek_windex != -1)
1390 windex = PA_MIN(windex, s->seek_windex);
1391 if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
1392 s->seek_windex = windex;
1394 s->seek_windex = -1;
1395 handle_seek(s, windex);
1400 case SINK_INPUT_MESSAGE_DRAIN:
1401 case SINK_INPUT_MESSAGE_FLUSH:
1402 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1403 case SINK_INPUT_MESSAGE_TRIGGER: {
1406 pa_sink_input *isync;
1407 void (*func)(pa_memblockq *bq);
1410 case SINK_INPUT_MESSAGE_FLUSH:
1411 func = flush_write_no_account;
1414 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1415 func = pa_memblockq_prebuf_force;
1418 case SINK_INPUT_MESSAGE_DRAIN:
1419 case SINK_INPUT_MESSAGE_TRIGGER:
1420 func = pa_memblockq_prebuf_disable;
1424 pa_assert_not_reached();
1427 windex = pa_memblockq_get_write_index(s->memblockq);
1429 handle_seek(s, windex);
1431 /* Do the same for all other members in the sync group */
1432 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1433 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1434 windex = pa_memblockq_get_write_index(ssync->memblockq);
1435 func(ssync->memblockq);
1436 handle_seek(ssync, windex);
1439 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1440 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1441 windex = pa_memblockq_get_write_index(ssync->memblockq);
1442 func(ssync->memblockq);
1443 handle_seek(ssync, windex);
1446 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1447 if (!pa_memblockq_is_readable(s->memblockq))
1448 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1450 s->drain_tag = PA_PTR_TO_UINT(userdata);
1451 s->drain_request = TRUE;
1458 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1459 /* Atomically get a snapshot of all timing parameters... */
1460 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1461 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1462 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1463 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1464 s->underrun_for = s->sink_input->thread_info.underrun_for;
1465 s->playing_for = s->sink_input->thread_info.playing_for;
1469 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1472 windex = pa_memblockq_get_write_index(s->memblockq);
1474 pa_memblockq_prebuf_force(s->memblockq);
1476 handle_seek(s, windex);
1478 /* Fall through to the default handler */
1482 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1483 pa_usec_t *r = userdata;
1485 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1487 /* Fall through, the default handler will add in the extra
1488 * latency added by the resampler */
1492 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1493 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1494 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1499 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1502 /* Called from thread context */
1503 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1506 pa_sink_input_assert_ref(i);
1507 s = PLAYBACK_STREAM(i->userdata);
1508 playback_stream_assert_ref(s);
1511 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1513 if (pa_memblockq_is_readable(s->memblockq))
1514 s->is_underrun = FALSE;
1516 if (!s->is_underrun)
1517 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));
1519 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1520 s->drain_request = FALSE;
1521 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);
1522 } else if (!s->is_underrun)
1523 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1525 s->is_underrun = TRUE;
1527 playback_stream_request_bytes(s);
1530 /* This call will not fail with prebuf=0, hence we check for
1531 underrun explicitly above */
1532 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1535 chunk->length = PA_MIN(nbytes, chunk->length);
1537 if (i->thread_info.underrun_for > 0)
1538 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1540 pa_memblockq_drop(s->memblockq, chunk->length);
1541 playback_stream_request_bytes(s);
1546 /* Called from thread context */
1547 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1550 pa_sink_input_assert_ref(i);
1551 s = PLAYBACK_STREAM(i->userdata);
1552 playback_stream_assert_ref(s);
1554 /* If we are in an underrun, then we don't rewind */
1555 if (i->thread_info.underrun_for > 0)
1558 pa_memblockq_rewind(s->memblockq, nbytes);
1561 /* Called from thread context */
1562 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1565 pa_sink_input_assert_ref(i);
1566 s = PLAYBACK_STREAM(i->userdata);
1567 playback_stream_assert_ref(s);
1569 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1572 /* Called from thread context */
1573 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1575 size_t new_tlength, old_tlength;
1577 pa_sink_input_assert_ref(i);
1578 s = PLAYBACK_STREAM(i->userdata);
1579 playback_stream_assert_ref(s);
1581 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1582 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1584 if (old_tlength < new_tlength) {
1585 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1586 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1587 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1589 if (new_tlength == old_tlength)
1590 pa_log_debug("Failed to increase tlength");
1592 pa_log_debug("Notifying client about increased tlength");
1593 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);
1598 /* Called from main context */
1599 static void sink_input_kill_cb(pa_sink_input *i) {
1602 pa_sink_input_assert_ref(i);
1603 s = PLAYBACK_STREAM(i->userdata);
1604 playback_stream_assert_ref(s);
1606 playback_stream_send_killed(s);
1607 playback_stream_unlink(s);
1610 /* Called from main context */
1611 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1615 pa_sink_input_assert_ref(i);
1616 s = PLAYBACK_STREAM(i->userdata);
1617 playback_stream_assert_ref(s);
1619 if (s->connection->version < 15)
1622 t = pa_tagstruct_new(NULL, 0);
1623 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1624 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1625 pa_tagstruct_putu32(t, s->index);
1626 pa_tagstruct_puts(t, event);
1627 pa_tagstruct_put_proplist(t, pl);
1628 pa_pstream_send_tagstruct(s->connection->pstream, t);
1631 /* Called from main context */
1632 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1636 pa_sink_input_assert_ref(i);
1637 s = PLAYBACK_STREAM(i->userdata);
1638 playback_stream_assert_ref(s);
1640 if (s->connection->version < 12)
1643 t = pa_tagstruct_new(NULL, 0);
1644 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1645 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1646 pa_tagstruct_putu32(t, s->index);
1647 pa_tagstruct_put_boolean(t, suspend);
1648 pa_pstream_send_tagstruct(s->connection->pstream, t);
1651 /* Called from main context */
1652 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1656 pa_sink_input_assert_ref(i);
1657 s = PLAYBACK_STREAM(i->userdata);
1658 playback_stream_assert_ref(s);
1663 fix_playback_buffer_attr(s);
1664 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1665 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1667 if (s->connection->version < 12)
1670 t = pa_tagstruct_new(NULL, 0);
1671 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1672 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1673 pa_tagstruct_putu32(t, s->index);
1674 pa_tagstruct_putu32(t, dest->index);
1675 pa_tagstruct_puts(t, dest->name);
1676 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1678 if (s->connection->version >= 13) {
1679 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1680 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1681 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1682 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1683 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1686 pa_pstream_send_tagstruct(s->connection->pstream, t);
1689 /*** source_output callbacks ***/
1691 /* Called from thread context */
1692 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1693 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1696 pa_source_output_assert_ref(o);
1697 s = RECORD_STREAM(o->userdata);
1698 record_stream_assert_ref(s);
1701 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1702 /* Atomically get a snapshot of all timing parameters... */
1703 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1704 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1705 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1709 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1712 /* Called from thread context */
1713 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1716 pa_source_output_assert_ref(o);
1717 s = RECORD_STREAM(o->userdata);
1718 record_stream_assert_ref(s);
1721 pa_atomic_add(&s->on_the_fly, chunk->length);
1722 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1725 static void source_output_kill_cb(pa_source_output *o) {
1728 pa_source_output_assert_ref(o);
1729 s = RECORD_STREAM(o->userdata);
1730 record_stream_assert_ref(s);
1732 record_stream_send_killed(s);
1733 record_stream_unlink(s);
1736 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1739 pa_source_output_assert_ref(o);
1740 s = RECORD_STREAM(o->userdata);
1741 record_stream_assert_ref(s);
1743 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1745 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1748 /* Called from main context */
1749 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1753 pa_source_output_assert_ref(o);
1754 s = RECORD_STREAM(o->userdata);
1755 record_stream_assert_ref(s);
1757 if (s->connection->version < 15)
1760 t = pa_tagstruct_new(NULL, 0);
1761 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1762 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1763 pa_tagstruct_putu32(t, s->index);
1764 pa_tagstruct_puts(t, event);
1765 pa_tagstruct_put_proplist(t, pl);
1766 pa_pstream_send_tagstruct(s->connection->pstream, t);
1769 /* Called from main context */
1770 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1774 pa_source_output_assert_ref(o);
1775 s = RECORD_STREAM(o->userdata);
1776 record_stream_assert_ref(s);
1778 if (s->connection->version < 12)
1781 t = pa_tagstruct_new(NULL, 0);
1782 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1783 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1784 pa_tagstruct_putu32(t, s->index);
1785 pa_tagstruct_put_boolean(t, suspend);
1786 pa_pstream_send_tagstruct(s->connection->pstream, t);
1789 /* Called from main context */
1790 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1794 pa_source_output_assert_ref(o);
1795 s = RECORD_STREAM(o->userdata);
1796 record_stream_assert_ref(s);
1801 fix_record_buffer_attr_pre(s);
1802 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1803 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1804 fix_record_buffer_attr_post(s);
1806 if (s->connection->version < 12)
1809 t = pa_tagstruct_new(NULL, 0);
1810 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1811 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1812 pa_tagstruct_putu32(t, s->index);
1813 pa_tagstruct_putu32(t, dest->index);
1814 pa_tagstruct_puts(t, dest->name);
1815 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1817 if (s->connection->version >= 13) {
1818 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1819 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1820 pa_tagstruct_put_usec(t, s->configured_source_latency);
1823 pa_pstream_send_tagstruct(s->connection->pstream, t);
1826 /*** pdispatch callbacks ***/
1828 static void protocol_error(pa_native_connection *c) {
1829 pa_log("protocol error, kicking client");
1830 native_connection_unlink(c);
1833 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1834 if (!(expression)) { \
1835 pa_pstream_send_error((pstream), (tag), (error)); \
1840 static pa_tagstruct *reply_new(uint32_t tag) {
1841 pa_tagstruct *reply;
1843 reply = pa_tagstruct_new(NULL, 0);
1844 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1845 pa_tagstruct_putu32(reply, tag);
1849 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1850 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1852 uint32_t sink_index, syncid, missing;
1853 pa_buffer_attr attr;
1854 const char *name = NULL, *sink_name;
1857 pa_tagstruct *reply;
1858 pa_sink *sink = NULL;
1866 fix_channels = FALSE,
1868 variable_rate = FALSE,
1870 adjust_latency = FALSE,
1871 early_requests = FALSE,
1872 dont_inhibit_auto_suspend = FALSE,
1874 fail_on_suspend = FALSE,
1875 relative_volume = FALSE,
1876 passthrough = FALSE;
1878 pa_sink_input_flags_t flags = 0;
1880 pa_bool_t volume_set = TRUE;
1881 int ret = PA_ERR_INVALID;
1883 pa_native_connection_assert_ref(c);
1885 memset(&attr, 0, sizeof(attr));
1887 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1890 PA_TAG_SAMPLE_SPEC, &ss,
1891 PA_TAG_CHANNEL_MAP, &map,
1892 PA_TAG_U32, &sink_index,
1893 PA_TAG_STRING, &sink_name,
1894 PA_TAG_U32, &attr.maxlength,
1895 PA_TAG_BOOLEAN, &corked,
1896 PA_TAG_U32, &attr.tlength,
1897 PA_TAG_U32, &attr.prebuf,
1898 PA_TAG_U32, &attr.minreq,
1899 PA_TAG_U32, &syncid,
1900 PA_TAG_CVOLUME, &volume,
1901 PA_TAG_INVALID) < 0) {
1907 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1908 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
1909 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
1910 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
1911 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
1912 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
1913 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
1914 CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID);
1916 p = pa_proplist_new();
1919 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1921 if (c->version >= 12) {
1922 /* Since 0.9.8 the user can ask for a couple of additional flags */
1924 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1925 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1926 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1927 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1928 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1929 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1930 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1933 pa_proplist_free(p);
1938 if (c->version >= 13) {
1940 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1941 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1942 pa_tagstruct_get_proplist(t, p) < 0) {
1944 pa_proplist_free(p);
1949 if (c->version >= 14) {
1951 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
1952 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
1954 pa_proplist_free(p);
1959 if (c->version >= 15) {
1961 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
1962 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
1963 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
1965 pa_proplist_free(p);
1970 if (c->version >= 17) {
1972 if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
1974 pa_proplist_free(p);
1979 if (c->version >= 18) {
1981 if (pa_tagstruct_get_boolean(t, &passthrough) < 0 ) {
1983 pa_proplist_free(p);
1988 if (!pa_tagstruct_eof(t)) {
1990 pa_proplist_free(p);
1994 if (sink_index != PA_INVALID_INDEX) {
1996 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
1997 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1998 pa_proplist_free(p);
2002 } else if (sink_name) {
2004 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
2005 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2006 pa_proplist_free(p);
2012 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
2013 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
2014 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
2015 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
2016 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
2017 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
2018 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
2019 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
2020 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2021 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
2022 (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0);
2024 /* Only since protocol version 15 there's a seperate muted_set
2025 * flag. For older versions we synthesize it here */
2026 muted_set = muted_set || muted;
2028 s = playback_stream_new(c, sink, &ss, &map, &attr, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, relative_volume, &ret);
2029 pa_proplist_free(p);
2031 CHECK_VALIDITY(c->pstream, s, tag, ret);
2033 reply = reply_new(tag);
2034 pa_tagstruct_putu32(reply, s->index);
2035 pa_assert(s->sink_input);
2036 pa_tagstruct_putu32(reply, s->sink_input->index);
2037 pa_tagstruct_putu32(reply, missing);
2039 /* pa_log("initial request is %u", missing); */
2041 if (c->version >= 9) {
2042 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2044 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2045 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2046 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2047 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2050 if (c->version >= 12) {
2051 /* Since 0.9.8 we support sending the chosen sample
2052 * spec/channel map/device/suspend status back to the
2055 pa_tagstruct_put_sample_spec(reply, &ss);
2056 pa_tagstruct_put_channel_map(reply, &map);
2058 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2059 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2061 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2064 if (c->version >= 13)
2065 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2067 pa_pstream_send_tagstruct(c->pstream, reply);
2070 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2071 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2074 pa_native_connection_assert_ref(c);
2077 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2078 !pa_tagstruct_eof(t)) {
2083 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2087 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2089 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2090 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2094 playback_stream_unlink(s);
2098 case PA_COMMAND_DELETE_RECORD_STREAM: {
2100 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2101 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2105 record_stream_unlink(s);
2109 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2112 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2113 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2117 upload_stream_unlink(s);
2122 pa_assert_not_reached();
2125 pa_pstream_send_simple_ack(c->pstream, tag);
2128 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2129 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2131 pa_buffer_attr attr;
2132 uint32_t source_index;
2133 const char *name = NULL, *source_name;
2136 pa_tagstruct *reply;
2137 pa_source *source = NULL;
2144 fix_channels = FALSE,
2146 variable_rate = FALSE,
2147 adjust_latency = FALSE,
2148 peak_detect = FALSE,
2149 early_requests = FALSE,
2150 dont_inhibit_auto_suspend = FALSE,
2151 fail_on_suspend = FALSE;
2152 pa_source_output_flags_t flags = 0;
2154 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2155 pa_sink_input *direct_on_input = NULL;
2156 int ret = PA_ERR_INVALID;
2158 pa_native_connection_assert_ref(c);
2161 memset(&attr, 0, sizeof(attr));
2163 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2164 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2165 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2166 pa_tagstruct_getu32(t, &source_index) < 0 ||
2167 pa_tagstruct_gets(t, &source_name) < 0 ||
2168 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2169 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2170 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2175 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2176 CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
2177 CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID);
2178 CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2179 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2180 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2181 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2183 p = pa_proplist_new();
2186 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2188 if (c->version >= 12) {
2189 /* Since 0.9.8 the user can ask for a couple of additional flags */
2191 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2192 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2193 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2194 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2195 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2196 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2197 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2200 pa_proplist_free(p);
2205 if (c->version >= 13) {
2207 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2208 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2209 pa_tagstruct_get_proplist(t, p) < 0 ||
2210 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2212 pa_proplist_free(p);
2217 if (c->version >= 14) {
2219 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2221 pa_proplist_free(p);
2226 if (c->version >= 15) {
2228 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2229 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2231 pa_proplist_free(p);
2236 if (!pa_tagstruct_eof(t)) {
2238 pa_proplist_free(p);
2242 if (source_index != PA_INVALID_INDEX) {
2244 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2245 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2246 pa_proplist_free(p);
2250 } else if (source_name) {
2252 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2253 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2254 pa_proplist_free(p);
2259 if (direct_on_input_idx != PA_INVALID_INDEX) {
2261 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2262 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2263 pa_proplist_free(p);
2269 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2270 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2271 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2272 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2273 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2274 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2275 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2276 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2277 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2278 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0);
2280 s = record_stream_new(c, source, &ss, &map, peak_detect, &attr, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
2281 pa_proplist_free(p);
2283 CHECK_VALIDITY(c->pstream, s, tag, ret);
2285 reply = reply_new(tag);
2286 pa_tagstruct_putu32(reply, s->index);
2287 pa_assert(s->source_output);
2288 pa_tagstruct_putu32(reply, s->source_output->index);
2290 if (c->version >= 9) {
2291 /* Since 0.9 we support sending the buffer metrics back to the client */
2293 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2294 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2297 if (c->version >= 12) {
2298 /* Since 0.9.8 we support sending the chosen sample
2299 * spec/channel map/device/suspend status back to the
2302 pa_tagstruct_put_sample_spec(reply, &ss);
2303 pa_tagstruct_put_channel_map(reply, &map);
2305 pa_tagstruct_putu32(reply, s->source_output->source->index);
2306 pa_tagstruct_puts(reply, s->source_output->source->name);
2308 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2311 if (c->version >= 13)
2312 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2314 pa_pstream_send_tagstruct(c->pstream, reply);
2317 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2318 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2321 pa_native_connection_assert_ref(c);
2324 if (!pa_tagstruct_eof(t)) {
2329 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2330 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2331 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2333 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2335 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2338 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2339 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2341 pa_tagstruct *reply;
2342 pa_bool_t shm_on_remote = FALSE, do_shm;
2344 pa_native_connection_assert_ref(c);
2347 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2348 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2349 !pa_tagstruct_eof(t)) {
2354 /* Minimum supported version */
2355 if (c->version < 8) {
2356 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2360 /* Starting with protocol version 13 the MSB of the version tag
2361 reflects if shm is available for this pa_native_connection or
2363 if (c->version >= 13) {
2364 shm_on_remote = !!(c->version & 0x80000000U);
2365 c->version &= 0x7FFFFFFFU;
2368 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2370 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2372 if (!c->authorized) {
2373 pa_bool_t success = FALSE;
2376 const pa_creds *creds;
2378 if ((creds = pa_pdispatch_creds(pd))) {
2379 if (creds->uid == getuid())
2381 else if (c->options->auth_group) {
2385 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2386 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2387 else if (gid == creds->gid)
2391 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2392 pa_log_warn("Failed to check group membership.");
2398 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2399 (unsigned long) creds->uid,
2400 (unsigned long) creds->gid,
2405 if (!success && c->options->auth_cookie) {
2408 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2409 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2414 pa_log_warn("Denied access to client with invalid authorization data.");
2415 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2419 c->authorized = TRUE;
2420 if (c->auth_timeout_event) {
2421 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2422 c->auth_timeout_event = NULL;
2426 /* Enable shared memory support if possible */
2428 pa_mempool_is_shared(c->protocol->core->mempool) &&
2431 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2434 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2439 /* Only enable SHM if both sides are owned by the same
2440 * user. This is a security measure because otherwise data
2441 * private to the user might leak. */
2443 const pa_creds *creds;
2444 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2449 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2450 pa_pstream_enable_shm(c->pstream, do_shm);
2452 reply = reply_new(tag);
2453 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2457 /* SHM support is only enabled after both sides made sure they are the same user. */
2461 ucred.uid = getuid();
2462 ucred.gid = getgid();
2464 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2467 pa_pstream_send_tagstruct(c->pstream, reply);
2471 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2472 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2473 const char *name = NULL;
2475 pa_tagstruct *reply;
2477 pa_native_connection_assert_ref(c);
2480 p = pa_proplist_new();
2482 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2483 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2484 !pa_tagstruct_eof(t)) {
2487 pa_proplist_free(p);
2492 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2493 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2494 pa_proplist_free(p);
2498 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2499 pa_proplist_free(p);
2501 reply = reply_new(tag);
2503 if (c->version >= 13)
2504 pa_tagstruct_putu32(reply, c->client->index);
2506 pa_pstream_send_tagstruct(c->pstream, reply);
2509 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2510 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2512 uint32_t idx = PA_IDXSET_INVALID;
2514 pa_native_connection_assert_ref(c);
2517 if (pa_tagstruct_gets(t, &name) < 0 ||
2518 !pa_tagstruct_eof(t)) {
2523 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2524 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);
2526 if (command == PA_COMMAND_LOOKUP_SINK) {
2528 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2532 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2533 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2534 idx = source->index;
2537 if (idx == PA_IDXSET_INVALID)
2538 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2540 pa_tagstruct *reply;
2541 reply = reply_new(tag);
2542 pa_tagstruct_putu32(reply, idx);
2543 pa_pstream_send_tagstruct(c->pstream, reply);
2547 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2548 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2552 pa_native_connection_assert_ref(c);
2555 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2556 !pa_tagstruct_eof(t)) {
2561 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2562 s = pa_idxset_get_by_index(c->output_streams, idx);
2563 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2564 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2566 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);
2569 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2570 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2571 pa_tagstruct *reply;
2572 const pa_mempool_stat *stat;
2574 pa_native_connection_assert_ref(c);
2577 if (!pa_tagstruct_eof(t)) {
2582 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2584 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2586 reply = reply_new(tag);
2587 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2588 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2589 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2590 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2591 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2592 pa_pstream_send_tagstruct(c->pstream, reply);
2595 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2596 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2597 pa_tagstruct *reply;
2599 struct timeval tv, now;
2602 pa_native_connection_assert_ref(c);
2605 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2606 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2607 !pa_tagstruct_eof(t)) {
2612 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2613 s = pa_idxset_get_by_index(c->output_streams, idx);
2614 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2615 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2617 /* Get an atomic snapshot of all timing parameters */
2618 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);
2620 reply = reply_new(tag);
2621 pa_tagstruct_put_usec(reply,
2622 s->current_sink_latency +
2623 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2624 pa_tagstruct_put_usec(reply, 0);
2625 pa_tagstruct_put_boolean(reply,
2626 s->playing_for > 0 &&
2627 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2628 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2629 pa_tagstruct_put_timeval(reply, &tv);
2630 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2631 pa_tagstruct_puts64(reply, s->write_index);
2632 pa_tagstruct_puts64(reply, s->read_index);
2634 if (c->version >= 13) {
2635 pa_tagstruct_putu64(reply, s->underrun_for);
2636 pa_tagstruct_putu64(reply, s->playing_for);
2639 pa_pstream_send_tagstruct(c->pstream, reply);
2642 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2643 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2644 pa_tagstruct *reply;
2646 struct timeval tv, now;
2649 pa_native_connection_assert_ref(c);
2652 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2653 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2654 !pa_tagstruct_eof(t)) {
2659 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2660 s = pa_idxset_get_by_index(c->record_streams, idx);
2661 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2663 /* Get an atomic snapshot of all timing parameters */
2664 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);
2666 reply = reply_new(tag);
2667 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2668 pa_tagstruct_put_usec(reply,
2669 s->current_source_latency +
2670 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec));
2671 pa_tagstruct_put_boolean(reply,
2672 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2673 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2674 pa_tagstruct_put_timeval(reply, &tv);
2675 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2676 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2677 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2678 pa_pstream_send_tagstruct(c->pstream, reply);
2681 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2682 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2685 const char *name = NULL;
2688 pa_tagstruct *reply;
2691 pa_native_connection_assert_ref(c);
2694 if (pa_tagstruct_gets(t, &name) < 0 ||
2695 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2696 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2697 pa_tagstruct_getu32(t, &length) < 0) {
2702 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2703 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2704 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2705 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2706 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2707 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2709 p = pa_proplist_new();
2711 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2712 !pa_tagstruct_eof(t)) {
2715 pa_proplist_free(p);
2719 if (c->version < 13)
2720 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2722 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2723 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2725 if (!name || !pa_namereg_is_valid_name(name)) {
2726 pa_proplist_free(p);
2727 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2730 s = upload_stream_new(c, &ss, &map, name, length, p);
2731 pa_proplist_free(p);
2733 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2735 reply = reply_new(tag);
2736 pa_tagstruct_putu32(reply, s->index);
2737 pa_tagstruct_putu32(reply, length);
2738 pa_pstream_send_tagstruct(c->pstream, reply);
2741 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2742 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2747 pa_native_connection_assert_ref(c);
2750 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2751 !pa_tagstruct_eof(t)) {
2756 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2758 s = pa_idxset_get_by_index(c->output_streams, channel);
2759 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2760 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2762 if (!s->memchunk.memblock)
2763 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2764 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2765 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2767 pa_pstream_send_simple_ack(c->pstream, tag);
2769 upload_stream_unlink(s);
2772 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2773 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2774 uint32_t sink_index;
2777 const char *name, *sink_name;
2780 pa_tagstruct *reply;
2782 pa_native_connection_assert_ref(c);
2785 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2787 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2788 pa_tagstruct_gets(t, &sink_name) < 0 ||
2789 pa_tagstruct_getu32(t, &volume) < 0 ||
2790 pa_tagstruct_gets(t, &name) < 0) {
2795 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2796 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2797 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2798 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2800 if (sink_index != PA_INVALID_INDEX)
2801 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2803 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2805 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2807 p = pa_proplist_new();
2809 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2810 !pa_tagstruct_eof(t)) {
2812 pa_proplist_free(p);
2816 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2818 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2819 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2820 pa_proplist_free(p);
2824 pa_proplist_free(p);
2826 reply = reply_new(tag);
2828 if (c->version >= 13)
2829 pa_tagstruct_putu32(reply, idx);
2831 pa_pstream_send_tagstruct(c->pstream, reply);
2834 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2835 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2838 pa_native_connection_assert_ref(c);
2841 if (pa_tagstruct_gets(t, &name) < 0 ||
2842 !pa_tagstruct_eof(t)) {
2847 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2848 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2850 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
2851 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2855 pa_pstream_send_simple_ack(c->pstream, tag);
2858 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
2861 pa_assert(original);
2865 if (c->version < 12) {
2866 /* Before protocol version 12 we didn't support S32 samples,
2867 * so we need to lie about this to the client */
2869 if (fixed->format == PA_SAMPLE_S32LE)
2870 fixed->format = PA_SAMPLE_FLOAT32LE;
2871 if (fixed->format == PA_SAMPLE_S32BE)
2872 fixed->format = PA_SAMPLE_FLOAT32BE;
2875 if (c->version < 15) {
2876 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
2877 fixed->format = PA_SAMPLE_FLOAT32LE;
2878 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
2879 fixed->format = PA_SAMPLE_FLOAT32BE;
2883 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
2884 pa_sample_spec fixed_ss;
2887 pa_sink_assert_ref(sink);
2889 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
2893 PA_TAG_U32, sink->index,
2894 PA_TAG_STRING, sink->name,
2895 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2896 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2897 PA_TAG_CHANNEL_MAP, &sink->channel_map,
2898 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
2899 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
2900 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
2901 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
2902 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
2903 PA_TAG_USEC, pa_sink_get_latency(sink),
2904 PA_TAG_STRING, sink->driver,
2905 PA_TAG_U32, sink->flags,
2908 if (c->version >= 13) {
2909 pa_tagstruct_put_proplist(t, sink->proplist);
2910 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
2913 if (c->version >= 15) {
2914 pa_tagstruct_put_volume(t, sink->base_volume);
2915 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
2916 pa_log_error("Internal sink state is invalid.");
2917 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
2918 pa_tagstruct_putu32(t, sink->n_volume_steps);
2919 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
2922 if (c->version >= 16) {
2923 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
2929 PA_HASHMAP_FOREACH(p, sink->ports, state) {
2930 pa_tagstruct_puts(t, p->name);
2931 pa_tagstruct_puts(t, p->description);
2932 pa_tagstruct_putu32(t, p->priority);
2936 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
2940 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
2941 pa_sample_spec fixed_ss;
2944 pa_source_assert_ref(source);
2946 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
2950 PA_TAG_U32, source->index,
2951 PA_TAG_STRING, source->name,
2952 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2953 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2954 PA_TAG_CHANNEL_MAP, &source->channel_map,
2955 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
2956 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
2957 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
2958 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
2959 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
2960 PA_TAG_USEC, pa_source_get_latency(source),
2961 PA_TAG_STRING, source->driver,
2962 PA_TAG_U32, source->flags,
2965 if (c->version >= 13) {
2966 pa_tagstruct_put_proplist(t, source->proplist);
2967 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
2970 if (c->version >= 15) {
2971 pa_tagstruct_put_volume(t, source->base_volume);
2972 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
2973 pa_log_error("Internal source state is invalid.");
2974 pa_tagstruct_putu32(t, pa_source_get_state(source));
2975 pa_tagstruct_putu32(t, source->n_volume_steps);
2976 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
2979 if (c->version >= 16) {
2981 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
2983 if (source->ports) {
2987 PA_HASHMAP_FOREACH(p, source->ports, state) {
2988 pa_tagstruct_puts(t, p->name);
2989 pa_tagstruct_puts(t, p->description);
2990 pa_tagstruct_putu32(t, p->priority);
2994 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
2998 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
3002 pa_tagstruct_putu32(t, client->index);
3003 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
3004 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
3005 pa_tagstruct_puts(t, client->driver);
3007 if (c->version >= 13)
3008 pa_tagstruct_put_proplist(t, client->proplist);
3011 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
3018 pa_tagstruct_putu32(t, card->index);
3019 pa_tagstruct_puts(t, card->name);
3020 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
3021 pa_tagstruct_puts(t, card->driver);
3023 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
3025 if (card->profiles) {
3026 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
3027 pa_tagstruct_puts(t, p->name);
3028 pa_tagstruct_puts(t, p->description);
3029 pa_tagstruct_putu32(t, p->n_sinks);
3030 pa_tagstruct_putu32(t, p->n_sources);
3031 pa_tagstruct_putu32(t, p->priority);
3035 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
3036 pa_tagstruct_put_proplist(t, card->proplist);
3039 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3043 pa_tagstruct_putu32(t, module->index);
3044 pa_tagstruct_puts(t, module->name);
3045 pa_tagstruct_puts(t, module->argument);
3046 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3048 if (c->version < 15)
3049 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
3051 if (c->version >= 15)
3052 pa_tagstruct_put_proplist(t, module->proplist);
3055 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3056 pa_sample_spec fixed_ss;
3057 pa_usec_t sink_latency;
3059 pa_bool_t has_volume = FALSE;
3062 pa_sink_input_assert_ref(s);
3064 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3066 has_volume = pa_sink_input_is_volume_readable(s);
3068 pa_sink_input_get_volume(s, &v, TRUE);
3070 pa_cvolume_reset(&v, fixed_ss.channels);
3072 pa_tagstruct_putu32(t, s->index);
3073 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3074 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3075 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3076 pa_tagstruct_putu32(t, s->sink->index);
3077 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3078 pa_tagstruct_put_channel_map(t, &s->channel_map);
3079 pa_tagstruct_put_cvolume(t, &v);
3080 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3081 pa_tagstruct_put_usec(t, sink_latency);
3082 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3083 pa_tagstruct_puts(t, s->driver);
3084 if (c->version >= 11)
3085 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3086 if (c->version >= 13)
3087 pa_tagstruct_put_proplist(t, s->proplist);
3088 if (c->version >= 19)
3089 pa_tagstruct_put_boolean(t, (pa_sink_input_get_state(s) == PA_SINK_INPUT_CORKED));
3090 if (c->version >= 20) {
3091 pa_tagstruct_put_boolean(t, has_volume);
3092 pa_tagstruct_put_boolean(t, has_volume ? !pa_sink_input_is_volume_writable(s) : FALSE);
3096 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3097 pa_sample_spec fixed_ss;
3098 pa_usec_t source_latency;
3101 pa_source_output_assert_ref(s);
3103 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3105 pa_tagstruct_putu32(t, s->index);
3106 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3107 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3108 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3109 pa_tagstruct_putu32(t, s->source->index);
3110 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3111 pa_tagstruct_put_channel_map(t, &s->channel_map);
3112 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3113 pa_tagstruct_put_usec(t, source_latency);
3114 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3115 pa_tagstruct_puts(t, s->driver);
3116 if (c->version >= 13)
3117 pa_tagstruct_put_proplist(t, s->proplist);
3118 if (c->version >= 19)
3119 pa_tagstruct_put_boolean(t, (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_CORKED));
3122 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3123 pa_sample_spec fixed_ss;
3129 if (e->memchunk.memblock)
3130 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3132 memset(&fixed_ss, 0, sizeof(fixed_ss));
3134 pa_tagstruct_putu32(t, e->index);
3135 pa_tagstruct_puts(t, e->name);
3137 if (e->volume_is_set)
3140 pa_cvolume_init(&v);
3142 pa_tagstruct_put_cvolume(t, &v);
3143 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3144 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3145 pa_tagstruct_put_channel_map(t, &e->channel_map);
3146 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3147 pa_tagstruct_put_boolean(t, e->lazy);
3148 pa_tagstruct_puts(t, e->filename);
3150 if (c->version >= 13)
3151 pa_tagstruct_put_proplist(t, e->proplist);
3154 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3155 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3157 pa_sink *sink = NULL;
3158 pa_source *source = NULL;
3159 pa_client *client = NULL;
3160 pa_card *card = NULL;
3161 pa_module *module = NULL;
3162 pa_sink_input *si = NULL;
3163 pa_source_output *so = NULL;
3164 pa_scache_entry *sce = NULL;
3165 const char *name = NULL;
3166 pa_tagstruct *reply;
3168 pa_native_connection_assert_ref(c);
3171 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3172 (command != PA_COMMAND_GET_CLIENT_INFO &&
3173 command != PA_COMMAND_GET_MODULE_INFO &&
3174 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3175 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3176 pa_tagstruct_gets(t, &name) < 0) ||
3177 !pa_tagstruct_eof(t)) {
3182 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3183 CHECK_VALIDITY(c->pstream, !name ||
3184 (command == PA_COMMAND_GET_SINK_INFO &&
3185 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3186 (command == PA_COMMAND_GET_SOURCE_INFO &&
3187 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3188 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3189 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3190 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3191 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3193 if (command == PA_COMMAND_GET_SINK_INFO) {
3194 if (idx != PA_INVALID_INDEX)
3195 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3197 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3198 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3199 if (idx != PA_INVALID_INDEX)
3200 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3202 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3203 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3204 if (idx != PA_INVALID_INDEX)
3205 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3207 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3208 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3209 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3210 else if (command == PA_COMMAND_GET_MODULE_INFO)
3211 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3212 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3213 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3214 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3215 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3217 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3218 if (idx != PA_INVALID_INDEX)
3219 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3221 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3224 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3225 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3229 reply = reply_new(tag);
3231 sink_fill_tagstruct(c, reply, sink);
3233 source_fill_tagstruct(c, reply, source);
3235 client_fill_tagstruct(c, reply, client);
3237 card_fill_tagstruct(c, reply, card);
3239 module_fill_tagstruct(c, reply, module);
3241 sink_input_fill_tagstruct(c, reply, si);
3243 source_output_fill_tagstruct(c, reply, so);
3245 scache_fill_tagstruct(c, reply, sce);
3246 pa_pstream_send_tagstruct(c->pstream, reply);
3249 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3250 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3254 pa_tagstruct *reply;
3256 pa_native_connection_assert_ref(c);
3259 if (!pa_tagstruct_eof(t)) {
3264 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3266 reply = reply_new(tag);
3268 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3269 i = c->protocol->core->sinks;
3270 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3271 i = c->protocol->core->sources;
3272 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3273 i = c->protocol->core->clients;
3274 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3275 i = c->protocol->core->cards;
3276 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3277 i = c->protocol->core->modules;
3278 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3279 i = c->protocol->core->sink_inputs;
3280 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3281 i = c->protocol->core->source_outputs;
3283 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3284 i = c->protocol->core->scache;
3288 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3289 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3290 sink_fill_tagstruct(c, reply, p);
3291 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3292 source_fill_tagstruct(c, reply, p);
3293 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3294 client_fill_tagstruct(c, reply, p);
3295 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3296 card_fill_tagstruct(c, reply, p);
3297 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3298 module_fill_tagstruct(c, reply, p);
3299 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3300 sink_input_fill_tagstruct(c, reply, p);
3301 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3302 source_output_fill_tagstruct(c, reply, p);
3304 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3305 scache_fill_tagstruct(c, reply, p);
3310 pa_pstream_send_tagstruct(c->pstream, reply);
3313 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3314 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3315 pa_tagstruct *reply;
3317 pa_source *def_source;
3318 pa_sample_spec fixed_ss;
3321 pa_native_connection_assert_ref(c);
3324 if (!pa_tagstruct_eof(t)) {
3329 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3331 reply = reply_new(tag);
3332 pa_tagstruct_puts(reply, PACKAGE_NAME);
3333 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3335 u = pa_get_user_name_malloc();
3336 pa_tagstruct_puts(reply, u);
3339 h = pa_get_host_name_malloc();
3340 pa_tagstruct_puts(reply, h);
3343 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3344 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3346 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3347 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3348 def_source = pa_namereg_get_default_source(c->protocol->core);
3349 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3351 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3353 if (c->version >= 15)
3354 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3356 pa_pstream_send_tagstruct(c->pstream, reply);
3359 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3361 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3363 pa_native_connection_assert_ref(c);
3365 t = pa_tagstruct_new(NULL, 0);
3366 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3367 pa_tagstruct_putu32(t, (uint32_t) -1);
3368 pa_tagstruct_putu32(t, e);
3369 pa_tagstruct_putu32(t, idx);
3370 pa_pstream_send_tagstruct(c->pstream, t);
3373 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3374 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3375 pa_subscription_mask_t m;
3377 pa_native_connection_assert_ref(c);
3380 if (pa_tagstruct_getu32(t, &m) < 0 ||
3381 !pa_tagstruct_eof(t)) {
3386 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3387 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3389 if (c->subscription)
3390 pa_subscription_free(c->subscription);
3393 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3394 pa_assert(c->subscription);
3396 c->subscription = NULL;
3398 pa_pstream_send_simple_ack(c->pstream, tag);
3401 static void command_set_volume(
3408 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3411 pa_sink *sink = NULL;
3412 pa_source *source = NULL;
3413 pa_sink_input *si = NULL;
3414 const char *name = NULL;
3415 const char *client_name;
3417 pa_native_connection_assert_ref(c);
3420 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3421 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3422 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3423 pa_tagstruct_get_cvolume(t, &volume) ||
3424 !pa_tagstruct_eof(t)) {
3429 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3430 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);
3431 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3432 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3433 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3434 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3438 case PA_COMMAND_SET_SINK_VOLUME:
3439 if (idx != PA_INVALID_INDEX)
3440 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3442 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3445 case PA_COMMAND_SET_SOURCE_VOLUME:
3446 if (idx != PA_INVALID_INDEX)
3447 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3449 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3452 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3453 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3457 pa_assert_not_reached();
3460 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3462 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3465 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3467 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3468 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3469 } else if (source) {
3470 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3472 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3473 pa_source_set_volume(source, &volume, TRUE);
3475 CHECK_VALIDITY(c->pstream, pa_sink_input_is_volume_writable(si), tag, PA_ERR_INVALID);
3476 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3478 pa_log_debug("Client %s changes volume of sink input %s.",
3480 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3481 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3484 pa_pstream_send_simple_ack(c->pstream, tag);
3487 static void command_set_mute(
3494 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3497 pa_sink *sink = NULL;
3498 pa_source *source = NULL;
3499 pa_sink_input *si = NULL;
3500 const char *name = NULL, *client_name;
3502 pa_native_connection_assert_ref(c);
3505 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3506 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3507 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3508 pa_tagstruct_get_boolean(t, &mute) ||
3509 !pa_tagstruct_eof(t)) {
3514 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3515 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);
3516 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3517 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3518 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3522 case PA_COMMAND_SET_SINK_MUTE:
3523 if (idx != PA_INVALID_INDEX)
3524 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3526 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3530 case PA_COMMAND_SET_SOURCE_MUTE:
3531 if (idx != PA_INVALID_INDEX)
3532 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3534 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3538 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3539 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3543 pa_assert_not_reached();
3546 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3548 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3551 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3552 pa_sink_set_mute(sink, mute, TRUE);
3553 } else if (source) {
3554 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3555 pa_source_set_mute(source, mute, TRUE);
3557 pa_log_debug("Client %s changes mute of sink input %s.",
3559 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3560 pa_sink_input_set_mute(si, mute, TRUE);
3563 pa_pstream_send_simple_ack(c->pstream, tag);
3566 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3567 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3572 pa_native_connection_assert_ref(c);
3575 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3576 pa_tagstruct_get_boolean(t, &b) < 0 ||
3577 !pa_tagstruct_eof(t)) {
3582 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3583 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3584 s = pa_idxset_get_by_index(c->output_streams, idx);
3585 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3586 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3588 pa_sink_input_cork(s->sink_input, b);
3591 s->is_underrun = TRUE;
3593 pa_pstream_send_simple_ack(c->pstream, tag);
3596 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3597 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3601 pa_native_connection_assert_ref(c);
3604 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3605 !pa_tagstruct_eof(t)) {
3610 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3611 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3612 s = pa_idxset_get_by_index(c->output_streams, idx);
3613 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3614 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3617 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3618 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3621 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3622 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3625 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3626 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3630 pa_assert_not_reached();
3633 pa_pstream_send_simple_ack(c->pstream, tag);
3636 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3637 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3642 pa_native_connection_assert_ref(c);
3645 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3646 pa_tagstruct_get_boolean(t, &b) < 0 ||
3647 !pa_tagstruct_eof(t)) {
3652 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3653 s = pa_idxset_get_by_index(c->record_streams, idx);
3654 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3656 pa_source_output_cork(s->source_output, b);
3657 pa_memblockq_prebuf_force(s->memblockq);
3658 pa_pstream_send_simple_ack(c->pstream, tag);
3661 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3662 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3666 pa_native_connection_assert_ref(c);
3669 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3670 !pa_tagstruct_eof(t)) {
3675 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3676 s = pa_idxset_get_by_index(c->record_streams, idx);
3677 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3679 pa_memblockq_flush_read(s->memblockq);
3680 pa_pstream_send_simple_ack(c->pstream, tag);
3683 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3684 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3687 pa_tagstruct *reply;
3689 pa_native_connection_assert_ref(c);
3692 memset(&a, 0, sizeof(a));
3694 if (pa_tagstruct_getu32(t, &idx) < 0) {
3699 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3701 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3703 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3705 s = pa_idxset_get_by_index(c->output_streams, idx);
3706 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3707 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3709 if (pa_tagstruct_get(
3711 PA_TAG_U32, &a.maxlength,
3712 PA_TAG_U32, &a.tlength,
3713 PA_TAG_U32, &a.prebuf,
3714 PA_TAG_U32, &a.minreq,
3715 PA_TAG_INVALID) < 0 ||
3716 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3717 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3718 !pa_tagstruct_eof(t)) {
3723 s->adjust_latency = adjust_latency;
3724 s->early_requests = early_requests;
3727 fix_playback_buffer_attr(s);
3728 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);
3730 reply = reply_new(tag);
3731 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3732 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3733 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3734 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3736 if (c->version >= 13)
3737 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3741 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3742 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3744 s = pa_idxset_get_by_index(c->record_streams, idx);
3745 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3747 if (pa_tagstruct_get(
3749 PA_TAG_U32, &a.maxlength,
3750 PA_TAG_U32, &a.fragsize,
3751 PA_TAG_INVALID) < 0 ||
3752 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3753 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3754 !pa_tagstruct_eof(t)) {
3759 s->adjust_latency = adjust_latency;
3760 s->early_requests = early_requests;
3763 fix_record_buffer_attr_pre(s);
3764 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3765 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3766 fix_record_buffer_attr_post(s);
3768 reply = reply_new(tag);
3769 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3770 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3772 if (c->version >= 13)
3773 pa_tagstruct_put_usec(reply, s->configured_source_latency);
3776 pa_pstream_send_tagstruct(c->pstream, reply);
3779 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3780 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3784 pa_native_connection_assert_ref(c);
3787 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3788 pa_tagstruct_getu32(t, &rate) < 0 ||
3789 !pa_tagstruct_eof(t)) {
3794 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3795 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
3797 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
3800 s = pa_idxset_get_by_index(c->output_streams, idx);
3801 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3802 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3804 pa_sink_input_set_rate(s->sink_input, rate);
3808 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
3810 s = pa_idxset_get_by_index(c->record_streams, idx);
3811 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3813 pa_source_output_set_rate(s->source_output, rate);
3816 pa_pstream_send_simple_ack(c->pstream, tag);
3819 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3820 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3825 pa_native_connection_assert_ref(c);
3828 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3830 p = pa_proplist_new();
3832 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
3834 if (pa_tagstruct_getu32(t, &mode) < 0 ||
3835 pa_tagstruct_get_proplist(t, p) < 0 ||
3836 !pa_tagstruct_eof(t)) {
3838 pa_proplist_free(p);
3844 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3845 pa_tagstruct_getu32(t, &mode) < 0 ||
3846 pa_tagstruct_get_proplist(t, p) < 0 ||
3847 !pa_tagstruct_eof(t)) {
3849 pa_proplist_free(p);
3854 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
3855 pa_proplist_free(p);
3856 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
3859 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
3862 s = pa_idxset_get_by_index(c->output_streams, idx);
3863 if (!s || !playback_stream_isinstance(s)) {
3864 pa_proplist_free(p);
3865 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3867 pa_sink_input_update_proplist(s->sink_input, mode, p);
3869 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
3872 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
3873 pa_proplist_free(p);
3874 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3876 pa_source_output_update_proplist(s->source_output, mode, p);
3879 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
3881 pa_client_update_proplist(c->client, mode, p);
3884 pa_pstream_send_simple_ack(c->pstream, tag);
3885 pa_proplist_free(p);
3888 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3889 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3891 unsigned changed = 0;
3893 pa_strlist *l = NULL;
3895 pa_native_connection_assert_ref(c);
3898 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3900 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
3902 if (pa_tagstruct_getu32(t, &idx) < 0) {
3908 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3911 s = pa_idxset_get_by_index(c->output_streams, idx);
3912 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3913 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3915 p = s->sink_input->proplist;
3917 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3920 s = pa_idxset_get_by_index(c->record_streams, idx);
3921 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3923 p = s->source_output->proplist;
3925 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3927 p = c->client->proplist;
3933 if (pa_tagstruct_gets(t, &k) < 0) {
3942 l = pa_strlist_prepend(l, k);
3945 if (!pa_tagstruct_eof(t)) {
3954 l = pa_strlist_pop(l, &z);
3959 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
3963 pa_pstream_send_simple_ack(c->pstream, tag);
3966 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3969 s = pa_idxset_get_by_index(c->output_streams, idx);
3970 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
3972 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3975 s = pa_idxset_get_by_index(c->record_streams, idx);
3976 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
3979 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3980 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
3985 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3986 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3989 pa_native_connection_assert_ref(c);
3992 if (pa_tagstruct_gets(t, &s) < 0 ||
3993 !pa_tagstruct_eof(t)) {
3998 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3999 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
4001 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
4004 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
4005 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4007 pa_namereg_set_default_source(c->protocol->core, source);
4010 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
4012 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
4013 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4015 pa_namereg_set_default_sink(c->protocol->core, sink);
4018 pa_pstream_send_simple_ack(c->pstream, tag);
4021 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4022 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4026 pa_native_connection_assert_ref(c);
4029 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4030 pa_tagstruct_gets(t, &name) < 0 ||
4031 !pa_tagstruct_eof(t)) {
4036 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4037 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
4039 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
4042 s = pa_idxset_get_by_index(c->output_streams, idx);
4043 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4044 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4046 pa_sink_input_set_name(s->sink_input, name);
4050 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4052 s = pa_idxset_get_by_index(c->record_streams, idx);
4053 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4055 pa_source_output_set_name(s->source_output, name);
4058 pa_pstream_send_simple_ack(c->pstream, tag);
4061 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4062 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4065 pa_native_connection_assert_ref(c);
4068 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4069 !pa_tagstruct_eof(t)) {
4074 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4076 if (command == PA_COMMAND_KILL_CLIENT) {
4079 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4080 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4082 pa_native_connection_ref(c);
4083 pa_client_kill(client);
4085 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4088 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4089 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4091 pa_native_connection_ref(c);
4092 pa_sink_input_kill(s);
4094 pa_source_output *s;
4096 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4098 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4099 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4101 pa_native_connection_ref(c);
4102 pa_source_output_kill(s);
4105 pa_pstream_send_simple_ack(c->pstream, tag);
4106 pa_native_connection_unref(c);
4109 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4110 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4112 const char *name, *argument;
4113 pa_tagstruct *reply;
4115 pa_native_connection_assert_ref(c);
4118 if (pa_tagstruct_gets(t, &name) < 0 ||
4119 pa_tagstruct_gets(t, &argument) < 0 ||
4120 !pa_tagstruct_eof(t)) {
4125 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4126 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4127 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4129 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4130 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4134 reply = reply_new(tag);
4135 pa_tagstruct_putu32(reply, m->index);
4136 pa_pstream_send_tagstruct(c->pstream, reply);
4139 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4140 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4144 pa_native_connection_assert_ref(c);
4147 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4148 !pa_tagstruct_eof(t)) {
4153 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4154 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4155 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4157 pa_module_unload_request(m, FALSE);
4158 pa_pstream_send_simple_ack(c->pstream, tag);
4161 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4162 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4163 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4164 const char *name_device = NULL;
4166 pa_native_connection_assert_ref(c);
4169 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4170 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4171 pa_tagstruct_gets(t, &name_device) < 0 ||
4172 !pa_tagstruct_eof(t)) {
4177 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4178 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4180 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);
4181 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4182 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4183 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4185 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4186 pa_sink_input *si = NULL;
4187 pa_sink *sink = NULL;
4189 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4191 if (idx_device != PA_INVALID_INDEX)
4192 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4194 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4196 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4198 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4199 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4203 pa_source_output *so = NULL;
4206 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4208 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4210 if (idx_device != PA_INVALID_INDEX)
4211 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4213 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4215 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4217 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4218 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4223 pa_pstream_send_simple_ack(c->pstream, tag);
4226 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4227 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4228 uint32_t idx = PA_INVALID_INDEX;
4229 const char *name = NULL;
4232 pa_native_connection_assert_ref(c);
4235 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4236 pa_tagstruct_gets(t, &name) < 0 ||
4237 pa_tagstruct_get_boolean(t, &b) < 0 ||
4238 !pa_tagstruct_eof(t)) {
4243 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4244 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);
4245 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4246 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4247 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4249 if (command == PA_COMMAND_SUSPEND_SINK) {
4251 if (idx == PA_INVALID_INDEX && name && !*name) {
4253 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4255 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4256 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4260 pa_sink *sink = NULL;
4262 if (idx != PA_INVALID_INDEX)
4263 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4265 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4267 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4269 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4270 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4276 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4278 if (idx == PA_INVALID_INDEX && name && !*name) {
4280 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4282 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4283 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4290 if (idx != PA_INVALID_INDEX)
4291 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4293 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4295 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4297 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4298 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4304 pa_pstream_send_simple_ack(c->pstream, tag);
4307 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4308 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4309 uint32_t idx = PA_INVALID_INDEX;
4310 const char *name = NULL;
4312 pa_native_protocol_ext_cb_t cb;
4314 pa_native_connection_assert_ref(c);
4317 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4318 pa_tagstruct_gets(t, &name) < 0) {
4323 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4324 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4325 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4326 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4327 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4329 if (idx != PA_INVALID_INDEX)
4330 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4332 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4333 if (strcmp(name, m->name) == 0)
4337 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4338 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4340 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4341 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4343 if (cb(c->protocol, m, c, tag, t) < 0)
4347 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4348 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4349 uint32_t idx = PA_INVALID_INDEX;
4350 const char *name = NULL, *profile = NULL;
4351 pa_card *card = NULL;
4354 pa_native_connection_assert_ref(c);
4357 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4358 pa_tagstruct_gets(t, &name) < 0 ||
4359 pa_tagstruct_gets(t, &profile) < 0 ||
4360 !pa_tagstruct_eof(t)) {
4365 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4366 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4367 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4368 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4369 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4371 if (idx != PA_INVALID_INDEX)
4372 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4374 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4376 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4378 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4379 pa_pstream_send_error(c->pstream, tag, -ret);
4383 pa_pstream_send_simple_ack(c->pstream, tag);
4386 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4387 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4388 uint32_t idx = PA_INVALID_INDEX;
4389 const char *name = NULL, *port = NULL;
4392 pa_native_connection_assert_ref(c);
4395 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4396 pa_tagstruct_gets(t, &name) < 0 ||
4397 pa_tagstruct_gets(t, &port) < 0 ||
4398 !pa_tagstruct_eof(t)) {
4403 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4404 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);
4405 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4406 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4407 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4409 if (command == PA_COMMAND_SET_SINK_PORT) {
4412 if (idx != PA_INVALID_INDEX)
4413 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4415 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4417 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4419 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4420 pa_pstream_send_error(c->pstream, tag, -ret);
4426 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4428 if (idx != PA_INVALID_INDEX)
4429 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4431 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4433 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4435 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4436 pa_pstream_send_error(c->pstream, tag, -ret);
4441 pa_pstream_send_simple_ack(c->pstream, tag);
4444 /*** pstream callbacks ***/
4446 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4447 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4451 pa_native_connection_assert_ref(c);
4453 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4454 pa_log("invalid packet.");
4455 native_connection_unlink(c);
4459 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) {
4460 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4461 output_stream *stream;
4465 pa_native_connection_assert_ref(c);
4467 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4468 pa_log_debug("Client sent block for invalid stream.");
4473 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4475 if (playback_stream_isinstance(stream)) {
4476 playback_stream *ps = PLAYBACK_STREAM(stream);
4478 pa_atomic_inc(&ps->seek_or_post_in_queue);
4479 if (chunk->memblock) {
4480 if (seek != PA_SEEK_RELATIVE || offset != 0)
4481 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, chunk, NULL);
4483 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4485 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);
4488 upload_stream *u = UPLOAD_STREAM(stream);
4491 if (!u->memchunk.memblock) {
4492 if (u->length == chunk->length && chunk->memblock) {
4493 u->memchunk = *chunk;
4494 pa_memblock_ref(u->memchunk.memblock);
4497 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4498 u->memchunk.index = u->memchunk.length = 0;
4502 pa_assert(u->memchunk.memblock);
4505 if (l > chunk->length)
4510 dst = pa_memblock_acquire(u->memchunk.memblock);
4512 if (chunk->memblock) {
4514 src = pa_memblock_acquire(chunk->memblock);
4516 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4517 (uint8_t*) src + chunk->index, l);
4519 pa_memblock_release(chunk->memblock);
4521 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4523 pa_memblock_release(u->memchunk.memblock);
4525 u->memchunk.length += l;
4531 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4532 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4535 pa_native_connection_assert_ref(c);
4537 native_connection_unlink(c);
4538 pa_log_info("Connection died.");
4541 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4542 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4545 pa_native_connection_assert_ref(c);
4547 native_connection_send_memblock(c);
4550 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4553 if (!(q = pa_thread_mq_get()))
4554 pa_pstream_send_revoke(p, block_id);
4556 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4559 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4562 if (!(q = pa_thread_mq_get()))
4563 pa_pstream_send_release(p, block_id);
4565 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4568 /*** client callbacks ***/
4570 static void client_kill_cb(pa_client *c) {
4573 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4574 pa_log_info("Connection killed.");
4577 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4579 pa_native_connection *c;
4582 c = PA_NATIVE_CONNECTION(client->userdata);
4583 pa_native_connection_assert_ref(c);
4585 if (c->version < 15)
4588 t = pa_tagstruct_new(NULL, 0);
4589 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4590 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4591 pa_tagstruct_puts(t, event);
4592 pa_tagstruct_put_proplist(t, pl);
4593 pa_pstream_send_tagstruct(c->pstream, t);
4596 /*** module entry points ***/
4598 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4599 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4602 pa_native_connection_assert_ref(c);
4603 pa_assert(c->auth_timeout_event == e);
4605 if (!c->authorized) {
4606 native_connection_unlink(c);
4607 pa_log_info("Connection terminated due to authentication timeout.");
4611 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4612 pa_native_connection *c;
4615 pa_client_new_data data;
4621 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4622 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4623 pa_iochannel_free(io);
4627 pa_client_new_data_init(&data);
4628 data.module = o->module;
4629 data.driver = __FILE__;
4630 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4631 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4632 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4633 client = pa_client_new(p->core, &data);
4634 pa_client_new_data_done(&data);
4639 c = pa_msgobject_new(pa_native_connection);
4640 c->parent.parent.free = native_connection_free;
4641 c->parent.process_msg = native_connection_process_msg;
4643 c->options = pa_native_options_ref(o);
4644 c->authorized = FALSE;
4646 if (o->auth_anonymous) {
4647 pa_log_info("Client authenticated anonymously.");
4648 c->authorized = TRUE;
4651 if (!c->authorized &&
4653 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4655 pa_log_info("Client authenticated by IP ACL.");
4656 c->authorized = TRUE;
4660 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4662 c->auth_timeout_event = NULL;
4664 c->is_local = pa_iochannel_socket_is_local(io);
4668 c->client->kill = client_kill_cb;
4669 c->client->send_event = client_send_event_cb;
4670 c->client->userdata = c;
4672 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4673 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4674 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4675 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4676 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4677 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4678 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4680 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4682 c->record_streams = pa_idxset_new(NULL, NULL);
4683 c->output_streams = pa_idxset_new(NULL, NULL);
4685 c->rrobin_index = PA_IDXSET_INVALID;
4686 c->subscription = NULL;
4688 pa_idxset_put(p->connections, c, NULL);
4691 if (pa_iochannel_creds_supported(io))
4692 pa_iochannel_creds_enable(io);
4695 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4698 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4699 pa_native_connection *c;
4705 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4706 if (c->options->module == m)
4707 native_connection_unlink(c);
4710 static pa_native_protocol* native_protocol_new(pa_core *c) {
4711 pa_native_protocol *p;
4716 p = pa_xnew(pa_native_protocol, 1);
4719 p->connections = pa_idxset_new(NULL, NULL);
4723 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4725 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4726 pa_hook_init(&p->hooks[h], p);
4728 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4733 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4734 pa_native_protocol *p;
4736 if ((p = pa_shared_get(c, "native-protocol")))
4737 return pa_native_protocol_ref(p);
4739 return native_protocol_new(c);
4742 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4744 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4751 void pa_native_protocol_unref(pa_native_protocol *p) {
4752 pa_native_connection *c;
4756 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4758 if (PA_REFCNT_DEC(p) > 0)
4761 while ((c = pa_idxset_first(p->connections, NULL)))
4762 native_connection_unlink(c);
4764 pa_idxset_free(p->connections, NULL, NULL);
4766 pa_strlist_free(p->servers);
4768 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4769 pa_hook_done(&p->hooks[h]);
4771 pa_hashmap_free(p->extensions, NULL, NULL);
4773 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4778 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
4780 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4783 p->servers = pa_strlist_prepend(p->servers, name);
4785 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4788 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
4790 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4793 p->servers = pa_strlist_remove(p->servers, name);
4795 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4798 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
4800 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4805 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
4807 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4812 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
4814 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4817 pa_assert(!pa_hashmap_get(p->extensions, m));
4819 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
4823 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
4825 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4828 pa_assert_se(pa_hashmap_remove(p->extensions, m));
4831 pa_native_options* pa_native_options_new(void) {
4832 pa_native_options *o;
4834 o = pa_xnew0(pa_native_options, 1);
4840 pa_native_options* pa_native_options_ref(pa_native_options *o) {
4842 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4849 void pa_native_options_unref(pa_native_options *o) {
4851 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4853 if (PA_REFCNT_DEC(o) > 0)
4856 pa_xfree(o->auth_group);
4859 pa_ip_acl_free(o->auth_ip_acl);
4862 pa_auth_cookie_unref(o->auth_cookie);
4867 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
4872 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4875 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
4876 pa_log("auth-anonymous= expects a boolean argument.");
4881 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
4882 pa_log("auth-group-enabled= expects a boolean argument.");
4886 pa_xfree(o->auth_group);
4887 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
4891 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4894 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
4897 if (!(ipa = pa_ip_acl_new(acl))) {
4898 pa_log("Failed to parse IP ACL '%s'", acl);
4903 pa_ip_acl_free(o->auth_ip_acl);
4905 o->auth_ip_acl = ipa;
4909 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
4910 pa_log("auth-cookie-enabled= expects a boolean argument.");
4915 pa_auth_cookie_unref(o->auth_cookie);
4920 /* The new name for this is 'auth-cookie', for compat reasons
4921 * we check the old name too */
4922 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
4923 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
4924 cn = PA_NATIVE_COOKIE_FILE;
4926 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
4930 o->auth_cookie = NULL;
4935 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
4936 pa_native_connection_assert_ref(c);
4941 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
4942 pa_native_connection_assert_ref(c);