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>
38 #include <pulse/internal.h>
40 #include <pulsecore/native-common.h>
41 #include <pulsecore/packet.h>
42 #include <pulsecore/client.h>
43 #include <pulsecore/source-output.h>
44 #include <pulsecore/sink-input.h>
45 #include <pulsecore/pstream.h>
46 #include <pulsecore/tagstruct.h>
47 #include <pulsecore/pdispatch.h>
48 #include <pulsecore/pstream-util.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/creds.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/ipacl.h>
59 #include <pulsecore/thread-mq.h>
61 #include "protocol-native.h"
63 /* Kick a client if it doesn't authenticate within this time */
64 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
66 /* Don't accept more connection than this */
67 #define MAX_CONNECTIONS 64
69 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
70 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
71 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
72 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
74 struct pa_native_protocol;
76 typedef struct record_stream {
79 pa_native_connection *connection;
82 pa_source_output *source_output;
83 pa_memblockq *memblockq;
85 pa_bool_t adjust_latency:1;
86 pa_bool_t early_requests:1;
88 /* Requested buffer attributes */
89 pa_buffer_attr buffer_attr_req;
90 /* Fixed-up and adjusted buffer attributes */
91 pa_buffer_attr buffer_attr;
93 pa_atomic_t on_the_fly;
94 pa_usec_t configured_source_latency;
97 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
98 size_t on_the_fly_snapshot;
99 pa_usec_t current_monitor_latency;
100 pa_usec_t current_source_latency;
103 #define RECORD_STREAM(o) (record_stream_cast(o))
104 PA_DEFINE_PRIVATE_CLASS(record_stream, pa_msgobject);
106 typedef struct output_stream {
110 #define OUTPUT_STREAM(o) (output_stream_cast(o))
111 PA_DEFINE_PRIVATE_CLASS(output_stream, pa_msgobject);
113 typedef struct playback_stream {
114 output_stream parent;
116 pa_native_connection *connection;
119 pa_sink_input *sink_input;
120 pa_memblockq *memblockq;
122 pa_bool_t adjust_latency:1;
123 pa_bool_t early_requests:1;
125 pa_bool_t is_underrun:1;
126 pa_bool_t drain_request:1;
130 /* Optimization to avoid too many rewinds with a lot of small blocks */
131 pa_atomic_t seek_or_post_in_queue;
135 pa_usec_t configured_sink_latency;
136 /* Requested buffer attributes */
137 pa_buffer_attr buffer_attr_req;
138 /* Fixed-up and adjusted buffer attributes */
139 pa_buffer_attr buffer_attr;
141 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
142 int64_t read_index, write_index;
143 size_t render_memblockq_length;
144 pa_usec_t current_sink_latency;
145 uint64_t playing_for, underrun_for;
148 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
149 PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
151 typedef struct upload_stream {
152 output_stream parent;
154 pa_native_connection *connection;
157 pa_memchunk memchunk;
160 pa_sample_spec sample_spec;
161 pa_channel_map channel_map;
162 pa_proplist *proplist;
165 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
166 PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
168 struct pa_native_connection {
170 pa_native_protocol *protocol;
171 pa_native_options *options;
172 pa_bool_t authorized:1;
173 pa_bool_t is_local:1;
177 pa_pdispatch *pdispatch;
178 pa_idxset *record_streams, *output_streams;
179 uint32_t rrobin_index;
180 pa_subscription *subscription;
181 pa_time_event *auth_timeout_event;
184 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
185 PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
187 struct pa_native_protocol {
191 pa_idxset *connections;
194 pa_hook hooks[PA_NATIVE_HOOK_MAX];
196 pa_hashmap *extensions;
200 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
204 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
205 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
206 SINK_INPUT_MESSAGE_FLUSH,
207 SINK_INPUT_MESSAGE_TRIGGER,
208 SINK_INPUT_MESSAGE_SEEK,
209 SINK_INPUT_MESSAGE_PREBUF_FORCE,
210 SINK_INPUT_MESSAGE_UPDATE_LATENCY,
211 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
215 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
216 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
217 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
218 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
219 PLAYBACK_STREAM_MESSAGE_STARTED,
220 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
224 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
228 CONNECTION_MESSAGE_RELEASE,
229 CONNECTION_MESSAGE_REVOKE
232 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
233 static void sink_input_kill_cb(pa_sink_input *i);
234 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
235 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
236 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
237 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
238 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
239 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
241 static void native_connection_send_memblock(pa_native_connection *c);
242 static void playback_stream_request_bytes(struct playback_stream*s);
244 static void source_output_kill_cb(pa_source_output *o);
245 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
246 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend);
247 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
248 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
249 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
251 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
252 static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
254 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
255 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
256 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
257 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
258 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
259 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
260 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
261 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
262 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
263 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
264 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
265 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
266 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
267 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
268 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
269 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
270 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
271 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
272 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
273 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
274 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
275 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
276 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
277 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
278 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
279 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
280 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
281 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
282 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
283 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
284 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
285 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
286 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
287 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
288 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
289 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
290 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
291 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
292 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
294 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
295 [PA_COMMAND_ERROR] = NULL,
296 [PA_COMMAND_TIMEOUT] = NULL,
297 [PA_COMMAND_REPLY] = NULL,
298 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
299 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
300 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
301 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
302 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
303 [PA_COMMAND_AUTH] = command_auth,
304 [PA_COMMAND_REQUEST] = NULL,
305 [PA_COMMAND_EXIT] = command_exit,
306 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
307 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
308 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
309 [PA_COMMAND_STAT] = command_stat,
310 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
311 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
312 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
313 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
314 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
315 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
316 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
317 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
318 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
319 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
320 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
321 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
322 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
323 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
324 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
325 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
326 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
327 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
328 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
329 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
330 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
331 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
332 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
333 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
334 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
336 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
337 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
338 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
339 [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = command_set_volume,
341 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
342 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
343 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
344 [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = command_set_mute,
346 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
347 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
349 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
350 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
351 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
352 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
354 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
355 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
357 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
358 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
359 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
360 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
361 [PA_COMMAND_KILL_CLIENT] = command_kill,
362 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
363 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
364 [PA_COMMAND_LOAD_MODULE] = command_load_module,
365 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
367 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
368 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
369 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
370 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
372 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
373 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
375 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
376 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
378 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
379 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
381 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
382 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
383 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
385 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
386 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
387 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
389 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
391 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
392 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
394 [PA_COMMAND_EXTENSION] = command_extension
397 /* structure management */
399 /* Called from main context */
400 static void upload_stream_unlink(upload_stream *s) {
406 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
407 s->connection = NULL;
408 upload_stream_unref(s);
411 /* Called from main context */
412 static void upload_stream_free(pa_object *o) {
413 upload_stream *s = UPLOAD_STREAM(o);
416 upload_stream_unlink(s);
421 pa_proplist_free(s->proplist);
423 if (s->memchunk.memblock)
424 pa_memblock_unref(s->memchunk.memblock);
429 /* Called from main context */
430 static upload_stream* upload_stream_new(
431 pa_native_connection *c,
432 const pa_sample_spec *ss,
433 const pa_channel_map *map,
443 pa_assert(length > 0);
446 s = pa_msgobject_new(upload_stream);
447 s->parent.parent.parent.free = upload_stream_free;
449 s->sample_spec = *ss;
450 s->channel_map = *map;
451 s->name = pa_xstrdup(name);
452 pa_memchunk_reset(&s->memchunk);
454 s->proplist = pa_proplist_copy(p);
455 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
457 pa_idxset_put(c->output_streams, s, &s->index);
462 /* Called from main context */
463 static void record_stream_unlink(record_stream *s) {
469 if (s->source_output) {
470 pa_source_output_unlink(s->source_output);
471 pa_source_output_unref(s->source_output);
472 s->source_output = NULL;
475 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
476 s->connection = NULL;
477 record_stream_unref(s);
480 /* Called from main context */
481 static void record_stream_free(pa_object *o) {
482 record_stream *s = RECORD_STREAM(o);
485 record_stream_unlink(s);
487 pa_memblockq_free(s->memblockq);
491 /* Called from main context */
492 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
493 record_stream *s = RECORD_STREAM(o);
494 record_stream_assert_ref(s);
501 case RECORD_STREAM_MESSAGE_POST_DATA:
503 /* We try to keep up to date with how many bytes are
504 * currently on the fly */
505 pa_atomic_sub(&s->on_the_fly, chunk->length);
507 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
508 /* pa_log_warn("Failed to push data into output queue."); */
512 if (!pa_pstream_is_pending(s->connection->pstream))
513 native_connection_send_memblock(s->connection);
521 /* Called from main context */
522 static void fix_record_buffer_attr_pre(record_stream *s) {
525 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
529 /* This function will be called from the main thread, before as
530 * well as after the source output has been activated using
531 * pa_source_output_put()! That means it may not touch any
532 * ->thread_info data! */
534 frame_size = pa_frame_size(&s->source_output->sample_spec);
535 s->buffer_attr = s->buffer_attr_req;
537 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
538 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
539 if (s->buffer_attr.maxlength <= 0)
540 s->buffer_attr.maxlength = (uint32_t) frame_size;
542 if (s->buffer_attr.fragsize == (uint32_t) -1)
543 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
544 if (s->buffer_attr.fragsize <= 0)
545 s->buffer_attr.fragsize = (uint32_t) frame_size;
547 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
549 if (s->early_requests) {
551 /* In early request mode we need to emulate the classic
552 * fragment-based playback model. We do this setting the source
553 * latency to the fragment size. */
555 source_usec = fragsize_usec;
557 } else if (s->adjust_latency) {
559 /* So, the user asked us to adjust the latency according to
560 * what the source can provide. Half the latency will be
561 * spent on the hw buffer, half of it in the async buffer
562 * queue we maintain for each client. */
564 source_usec = fragsize_usec/2;
568 /* Ok, the user didn't ask us to adjust the latency, hence we
571 source_usec = (pa_usec_t) -1;
574 if (source_usec != (pa_usec_t) -1)
575 s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
577 s->configured_source_latency = 0;
579 if (s->early_requests) {
581 /* Ok, we didn't necessarily get what we were asking for, so
582 * let's tell the user */
584 fragsize_usec = s->configured_source_latency;
586 } else if (s->adjust_latency) {
588 /* Now subtract what we actually got */
590 if (fragsize_usec >= s->configured_source_latency*2)
591 fragsize_usec -= s->configured_source_latency;
593 fragsize_usec = s->configured_source_latency;
596 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
597 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
599 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
601 if (s->buffer_attr.fragsize <= 0)
602 s->buffer_attr.fragsize = (uint32_t) frame_size;
605 /* Called from main context */
606 static void fix_record_buffer_attr_post(record_stream *s) {
611 /* This function will be called from the main thread, before as
612 * well as after the source output has been activated using
613 * pa_source_output_put()! That means it may not touch and
614 * ->thread_info data! */
616 base = pa_frame_size(&s->source_output->sample_spec);
618 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
619 if (s->buffer_attr.fragsize <= 0)
620 s->buffer_attr.fragsize = base;
622 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
623 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
626 /* Called from main context */
627 static record_stream* record_stream_new(
628 pa_native_connection *c,
633 pa_buffer_attr *attr,
637 pa_source_output_flags_t flags,
639 pa_bool_t adjust_latency,
640 pa_bool_t early_requests,
641 pa_bool_t relative_volume,
642 pa_bool_t peak_detect,
643 pa_sink_input *direct_on_input,
647 pa_source_output *source_output = NULL;
648 pa_source_output_new_data data;
655 pa_source_output_new_data_init(&data);
657 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
658 data.driver = __FILE__;
659 data.module = c->options->module;
660 data.client = c->client;
662 pa_source_output_new_data_set_source(&data, source, TRUE);
663 if (pa_sample_spec_valid(ss))
664 pa_source_output_new_data_set_sample_spec(&data, ss);
665 if (pa_channel_map_valid(map))
666 pa_source_output_new_data_set_channel_map(&data, map);
668 pa_source_output_new_data_set_formats(&data, formats);
669 data.direct_on_input = direct_on_input;
671 pa_source_output_new_data_set_volume(&data, volume);
672 data.volume_is_absolute = !relative_volume;
673 data.save_volume = TRUE;
676 pa_source_output_new_data_set_muted(&data, muted);
677 data.save_muted = TRUE;
680 data.resample_method = PA_RESAMPLER_PEAKS;
683 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
685 pa_source_output_new_data_done(&data);
690 s = pa_msgobject_new(record_stream);
691 s->parent.parent.free = record_stream_free;
692 s->parent.process_msg = record_stream_process_msg;
694 s->source_output = source_output;
695 s->buffer_attr_req = *attr;
696 s->adjust_latency = adjust_latency;
697 s->early_requests = early_requests;
698 pa_atomic_store(&s->on_the_fly, 0);
700 s->source_output->parent.process_msg = source_output_process_msg;
701 s->source_output->push = source_output_push_cb;
702 s->source_output->kill = source_output_kill_cb;
703 s->source_output->get_latency = source_output_get_latency_cb;
704 s->source_output->moving = source_output_moving_cb;
705 s->source_output->suspend = source_output_suspend_cb;
706 s->source_output->send_event = source_output_send_event_cb;
707 s->source_output->userdata = s;
709 fix_record_buffer_attr_pre(s);
711 s->memblockq = pa_memblockq_new(
713 s->buffer_attr.maxlength,
715 pa_frame_size(&source_output->sample_spec),
721 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
722 fix_record_buffer_attr_post(s);
724 *ss = s->source_output->sample_spec;
725 *map = s->source_output->channel_map;
727 pa_idxset_put(c->record_streams, s, &s->index);
729 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
730 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
731 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
732 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
734 pa_source_output_put(s->source_output);
738 /* Called from main context */
739 static void record_stream_send_killed(record_stream *r) {
741 record_stream_assert_ref(r);
743 t = pa_tagstruct_new(NULL, 0);
744 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
745 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
746 pa_tagstruct_putu32(t, r->index);
747 pa_pstream_send_tagstruct(r->connection->pstream, t);
750 /* Called from main context */
751 static void playback_stream_unlink(playback_stream *s) {
758 pa_sink_input_unlink(s->sink_input);
759 pa_sink_input_unref(s->sink_input);
760 s->sink_input = NULL;
763 if (s->drain_request)
764 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
766 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
767 s->connection = NULL;
768 playback_stream_unref(s);
771 /* Called from main context */
772 static void playback_stream_free(pa_object* o) {
773 playback_stream *s = PLAYBACK_STREAM(o);
776 playback_stream_unlink(s);
778 pa_memblockq_free(s->memblockq);
782 /* Called from main context */
783 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
784 playback_stream *s = PLAYBACK_STREAM(o);
785 playback_stream_assert_ref(s);
792 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
797 if ((l = pa_atomic_load(&s->missing)) <= 0)
800 if (pa_atomic_cmpxchg(&s->missing, l, 0))
804 t = pa_tagstruct_new(NULL, 0);
805 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
806 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
807 pa_tagstruct_putu32(t, s->index);
808 pa_tagstruct_putu32(t, (uint32_t) l);
809 pa_pstream_send_tagstruct(s->connection->pstream, t);
811 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
815 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
818 /* pa_log("signalling underflow"); */
820 /* Report that we're empty */
821 t = pa_tagstruct_new(NULL, 0);
822 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
823 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
824 pa_tagstruct_putu32(t, s->index);
825 if (s->connection->version >= 23)
826 pa_tagstruct_puts64(t, offset);
827 pa_pstream_send_tagstruct(s->connection->pstream, t);
831 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
834 /* Notify the user we're overflowed*/
835 t = pa_tagstruct_new(NULL, 0);
836 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
837 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
838 pa_tagstruct_putu32(t, s->index);
839 pa_pstream_send_tagstruct(s->connection->pstream, t);
843 case PLAYBACK_STREAM_MESSAGE_STARTED:
845 if (s->connection->version >= 13) {
848 /* Notify the user we started playback */
849 t = pa_tagstruct_new(NULL, 0);
850 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
851 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
852 pa_tagstruct_putu32(t, s->index);
853 pa_pstream_send_tagstruct(s->connection->pstream, t);
858 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
859 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
862 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
864 s->buffer_attr.tlength = (uint32_t) offset;
866 if (s->connection->version >= 15) {
869 t = pa_tagstruct_new(NULL, 0);
870 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
871 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
872 pa_tagstruct_putu32(t, s->index);
873 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
874 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
875 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
876 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
877 pa_tagstruct_put_usec(t, s->configured_sink_latency);
878 pa_pstream_send_tagstruct(s->connection->pstream, t);
887 /* Called from main context */
888 static void fix_playback_buffer_attr(playback_stream *s) {
889 size_t frame_size, max_prebuf;
890 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
894 /* pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", */
895 /* (long) s->buffer_attr.maxlength, */
896 /* (long) s->buffer_attr.tlength, */
897 /* (long) s->buffer_attr.minreq, */
898 /* (long) s->buffer_attr.prebuf); */
900 /* pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
901 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
902 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
903 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
904 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
906 /* This function will be called from the main thread, before as
907 * well as after the sink input has been activated using
908 * pa_sink_input_put()! That means it may not touch any
909 * ->thread_info data, such as the memblockq! */
911 frame_size = pa_frame_size(&s->sink_input->sample_spec);
912 s->buffer_attr = s->buffer_attr_req;
914 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
915 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
916 if (s->buffer_attr.maxlength <= 0)
917 s->buffer_attr.maxlength = (uint32_t) frame_size;
919 if (s->buffer_attr.tlength == (uint32_t) -1)
920 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
921 if (s->buffer_attr.tlength <= 0)
922 s->buffer_attr.tlength = (uint32_t) frame_size;
924 if (s->buffer_attr.minreq == (uint32_t) -1)
925 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
926 if (s->buffer_attr.minreq <= 0)
927 s->buffer_attr.minreq = (uint32_t) frame_size;
929 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
930 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
932 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
933 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
935 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
936 (double) tlength_usec / PA_USEC_PER_MSEC,
937 (double) minreq_usec / PA_USEC_PER_MSEC);
939 if (s->early_requests) {
941 /* In early request mode we need to emulate the classic
942 * fragment-based playback model. We do this setting the sink
943 * latency to the fragment size. */
945 sink_usec = minreq_usec;
946 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
948 } else if (s->adjust_latency) {
950 /* So, the user asked us to adjust the latency of the stream
951 * buffer according to the what the sink can provide. The
952 * tlength passed in shall be the overall latency. Roughly
953 * half the latency will be spent on the hw buffer, the other
954 * half of it in the async buffer queue we maintain for each
955 * client. In between we'll have a safety space of size
956 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
957 * empty and needs to be filled, then our buffer must have
958 * enough data to fulfill this request immediatly and thus
959 * have at least the same tlength as the size of the hw
960 * buffer. It additionally needs space for 2 times minreq
961 * because if the buffer ran empty and a partial fillup
962 * happens immediately on the next iteration we need to be
963 * able to fulfill it and give the application also minreq
964 * time to fill it up again for the next request Makes 2 times
965 * minreq in plus.. */
967 if (tlength_usec > minreq_usec*2)
968 sink_usec = (tlength_usec - minreq_usec*2)/2;
972 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
976 /* Ok, the user didn't ask us to adjust the latency, but we
977 * still need to make sure that the parameters from the user
980 if (tlength_usec > minreq_usec*2)
981 sink_usec = (tlength_usec - minreq_usec*2);
985 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
988 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
990 if (s->early_requests) {
992 /* Ok, we didn't necessarily get what we were asking for, so
993 * let's tell the user */
995 minreq_usec = s->configured_sink_latency;
997 } else if (s->adjust_latency) {
999 /* Ok, we didn't necessarily get what we were asking for, so
1000 * let's subtract from what we asked for for the remaining
1003 if (tlength_usec >= s->configured_sink_latency)
1004 tlength_usec -= s->configured_sink_latency;
1007 /* FIXME: This is actually larger than necessary, since not all of
1008 * the sink latency is actually rewritable. */
1009 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
1010 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
1012 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
1013 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
1014 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
1016 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
1017 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
1018 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
1020 if (s->buffer_attr.minreq <= 0) {
1021 s->buffer_attr.minreq = (uint32_t) frame_size;
1022 s->buffer_attr.tlength += (uint32_t) frame_size*2;
1025 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
1026 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
1028 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
1030 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
1031 s->buffer_attr.prebuf > max_prebuf)
1032 s->buffer_attr.prebuf = max_prebuf;
1034 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1035 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1036 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1037 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1038 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1041 /* Called from main context */
1042 static playback_stream* playback_stream_new(
1043 pa_native_connection *c,
1046 pa_channel_map *map,
1051 pa_bool_t muted_set,
1052 pa_sink_input_flags_t flags,
1054 pa_bool_t adjust_latency,
1055 pa_bool_t early_requests,
1056 pa_bool_t relative_volume,
1061 /* Note: This function takes ownership of the 'formats' param, so we need
1062 * to take extra care to not leak it */
1064 playback_stream *s, *ssync;
1065 pa_sink_input *sink_input = NULL;
1066 pa_memchunk silence;
1068 int64_t start_index;
1069 pa_sink_input_new_data data;
1077 /* Find syncid group */
1078 PA_IDXSET_FOREACH(ssync, c->output_streams, idx) {
1080 if (!playback_stream_isinstance(ssync))
1083 if (ssync->syncid == syncid)
1087 /* Synced streams must connect to the same sink */
1091 sink = ssync->sink_input->sink;
1092 else if (sink != ssync->sink_input->sink) {
1093 *ret = PA_ERR_INVALID;
1098 pa_sink_input_new_data_init(&data);
1100 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1101 data.driver = __FILE__;
1102 data.module = c->options->module;
1103 data.client = c->client;
1105 pa_sink_input_new_data_set_sink(&data, sink, TRUE);
1106 if (pa_sample_spec_valid(ss))
1107 pa_sink_input_new_data_set_sample_spec(&data, ss);
1108 if (pa_channel_map_valid(map))
1109 pa_sink_input_new_data_set_channel_map(&data, map);
1111 pa_sink_input_new_data_set_formats(&data, formats);
1112 /* Ownership transferred to new_data, so we don't free it ourseleves */
1116 pa_sink_input_new_data_set_volume(&data, volume);
1117 data.volume_is_absolute = !relative_volume;
1118 data.save_volume = TRUE;
1121 pa_sink_input_new_data_set_muted(&data, muted);
1122 data.save_muted = TRUE;
1124 data.sync_base = ssync ? ssync->sink_input : NULL;
1127 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1129 pa_sink_input_new_data_done(&data);
1134 s = pa_msgobject_new(playback_stream);
1135 s->parent.parent.parent.free = playback_stream_free;
1136 s->parent.parent.process_msg = playback_stream_process_msg;
1139 s->sink_input = sink_input;
1140 s->is_underrun = TRUE;
1141 s->drain_request = FALSE;
1142 pa_atomic_store(&s->missing, 0);
1143 s->buffer_attr_req = *a;
1144 s->adjust_latency = adjust_latency;
1145 s->early_requests = early_requests;
1146 pa_atomic_store(&s->seek_or_post_in_queue, 0);
1147 s->seek_windex = -1;
1149 s->sink_input->parent.process_msg = sink_input_process_msg;
1150 s->sink_input->pop = sink_input_pop_cb;
1151 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1152 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1153 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1154 s->sink_input->kill = sink_input_kill_cb;
1155 s->sink_input->moving = sink_input_moving_cb;
1156 s->sink_input->suspend = sink_input_suspend_cb;
1157 s->sink_input->send_event = sink_input_send_event_cb;
1158 s->sink_input->userdata = s;
1160 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1162 fix_playback_buffer_attr(s);
1164 pa_sink_input_get_silence(sink_input, &silence);
1165 s->memblockq = pa_memblockq_new(
1167 s->buffer_attr.maxlength,
1168 s->buffer_attr.tlength,
1169 pa_frame_size(&sink_input->sample_spec),
1170 s->buffer_attr.prebuf,
1171 s->buffer_attr.minreq,
1174 pa_memblock_unref(silence.memblock);
1176 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1178 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1180 /* pa_log("missing original: %li", (long int) *missing); */
1182 *ss = s->sink_input->sample_spec;
1183 *map = s->sink_input->channel_map;
1185 pa_idxset_put(c->output_streams, s, &s->index);
1187 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1188 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1189 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1190 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1191 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1193 pa_sink_input_put(s->sink_input);
1197 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
1202 /* Called from IO context */
1203 static void playback_stream_request_bytes(playback_stream *s) {
1205 int previous_missing;
1207 playback_stream_assert_ref(s);
1209 m = pa_memblockq_pop_missing(s->memblockq);
1211 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1212 /* (unsigned long) m, */
1213 /* pa_memblockq_get_tlength(s->memblockq), */
1214 /* pa_memblockq_get_minreq(s->memblockq), */
1215 /* pa_memblockq_get_length(s->memblockq), */
1216 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1221 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1223 previous_missing = pa_atomic_add(&s->missing, (int) m);
1224 minreq = pa_memblockq_get_minreq(s->memblockq);
1226 if (pa_memblockq_prebuf_active(s->memblockq) ||
1227 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1228 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1231 /* Called from main context */
1232 static void playback_stream_send_killed(playback_stream *p) {
1234 playback_stream_assert_ref(p);
1236 t = pa_tagstruct_new(NULL, 0);
1237 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1238 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1239 pa_tagstruct_putu32(t, p->index);
1240 pa_pstream_send_tagstruct(p->connection->pstream, t);
1243 /* Called from main context */
1244 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1245 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1246 pa_native_connection_assert_ref(c);
1253 case CONNECTION_MESSAGE_REVOKE:
1254 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1257 case CONNECTION_MESSAGE_RELEASE:
1258 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1265 /* Called from main context */
1266 static void native_connection_unlink(pa_native_connection *c) {
1275 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1278 pa_native_options_unref(c->options);
1280 while ((r = pa_idxset_first(c->record_streams, NULL)))
1281 record_stream_unlink(r);
1283 while ((o = pa_idxset_first(c->output_streams, NULL)))
1284 if (playback_stream_isinstance(o))
1285 playback_stream_unlink(PLAYBACK_STREAM(o));
1287 upload_stream_unlink(UPLOAD_STREAM(o));
1289 if (c->subscription)
1290 pa_subscription_free(c->subscription);
1293 pa_pstream_unlink(c->pstream);
1295 if (c->auth_timeout_event) {
1296 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1297 c->auth_timeout_event = NULL;
1300 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1302 pa_native_connection_unref(c);
1305 /* Called from main context */
1306 static void native_connection_free(pa_object *o) {
1307 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1311 native_connection_unlink(c);
1313 pa_idxset_free(c->record_streams, NULL, NULL);
1314 pa_idxset_free(c->output_streams, NULL, NULL);
1316 pa_pdispatch_unref(c->pdispatch);
1317 pa_pstream_unref(c->pstream);
1318 pa_client_free(c->client);
1323 /* Called from main context */
1324 static void native_connection_send_memblock(pa_native_connection *c) {
1328 start = PA_IDXSET_INVALID;
1332 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1335 if (start == PA_IDXSET_INVALID)
1336 start = c->rrobin_index;
1337 else if (start == c->rrobin_index)
1340 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1341 pa_memchunk schunk = chunk;
1343 if (schunk.length > r->buffer_attr.fragsize)
1344 schunk.length = r->buffer_attr.fragsize;
1346 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1348 pa_memblockq_drop(r->memblockq, schunk.length);
1349 pa_memblock_unref(schunk.memblock);
1356 /*** sink input callbacks ***/
1358 /* Called from thread context */
1359 static void handle_seek(playback_stream *s, int64_t indexw) {
1360 playback_stream_assert_ref(s);
1362 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1364 if (s->sink_input->thread_info.underrun_for > 0) {
1366 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1368 if (pa_memblockq_is_readable(s->memblockq)) {
1370 /* We just ended an underrun, let's ask the sink
1371 * for a complete rewind rewrite */
1373 pa_log_debug("Requesting rewind due to end of underrun.");
1374 pa_sink_input_request_rewind(s->sink_input,
1375 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1376 s->sink_input->thread_info.underrun_for),
1377 FALSE, TRUE, FALSE);
1383 indexr = pa_memblockq_get_read_index(s->memblockq);
1385 if (indexw < indexr) {
1386 /* OK, the sink already asked for this data, so
1387 * let's have it usk us again */
1389 pa_log_debug("Requesting rewind due to rewrite.");
1390 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1394 playback_stream_request_bytes(s);
1397 static void flush_write_no_account(pa_memblockq *q) {
1398 pa_memblockq_flush_write(q, FALSE);
1401 /* Called from thread context */
1402 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1403 pa_sink_input *i = PA_SINK_INPUT(o);
1406 pa_sink_input_assert_ref(i);
1407 s = PLAYBACK_STREAM(i->userdata);
1408 playback_stream_assert_ref(s);
1412 case SINK_INPUT_MESSAGE_SEEK:
1413 case SINK_INPUT_MESSAGE_POST_DATA: {
1414 int64_t windex = pa_memblockq_get_write_index(s->memblockq);
1416 if (code == SINK_INPUT_MESSAGE_SEEK) {
1417 /* The client side is incapable of accounting correctly
1418 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1419 * able to deal with that. */
1421 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1422 windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
1425 if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1426 if (pa_log_ratelimit(PA_LOG_WARN))
1427 pa_log_warn("Failed to push data into queue");
1428 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1429 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1432 /* If more data is in queue, we rewind later instead. */
1433 if (s->seek_windex != -1)
1434 windex = PA_MIN(windex, s->seek_windex);
1435 if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
1436 s->seek_windex = windex;
1438 s->seek_windex = -1;
1439 handle_seek(s, windex);
1444 case SINK_INPUT_MESSAGE_DRAIN:
1445 case SINK_INPUT_MESSAGE_FLUSH:
1446 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1447 case SINK_INPUT_MESSAGE_TRIGGER: {
1450 pa_sink_input *isync;
1451 void (*func)(pa_memblockq *bq);
1454 case SINK_INPUT_MESSAGE_FLUSH:
1455 func = flush_write_no_account;
1458 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1459 func = pa_memblockq_prebuf_force;
1462 case SINK_INPUT_MESSAGE_DRAIN:
1463 case SINK_INPUT_MESSAGE_TRIGGER:
1464 func = pa_memblockq_prebuf_disable;
1468 pa_assert_not_reached();
1471 windex = pa_memblockq_get_write_index(s->memblockq);
1473 handle_seek(s, windex);
1475 /* Do the same for all other members in the sync group */
1476 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1477 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1478 windex = pa_memblockq_get_write_index(ssync->memblockq);
1479 func(ssync->memblockq);
1480 handle_seek(ssync, windex);
1483 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1484 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1485 windex = pa_memblockq_get_write_index(ssync->memblockq);
1486 func(ssync->memblockq);
1487 handle_seek(ssync, windex);
1490 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1491 if (!pa_memblockq_is_readable(s->memblockq))
1492 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1494 s->drain_tag = PA_PTR_TO_UINT(userdata);
1495 s->drain_request = TRUE;
1502 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1503 /* Atomically get a snapshot of all timing parameters... */
1504 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1505 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1506 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1507 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1508 s->underrun_for = s->sink_input->thread_info.underrun_for;
1509 s->playing_for = s->sink_input->thread_info.playing_for;
1513 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1516 windex = pa_memblockq_get_write_index(s->memblockq);
1518 pa_memblockq_prebuf_force(s->memblockq);
1520 handle_seek(s, windex);
1522 /* Fall through to the default handler */
1526 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1527 pa_usec_t *r = userdata;
1529 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1531 /* Fall through, the default handler will add in the extra
1532 * latency added by the resampler */
1536 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1537 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1538 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1543 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1546 /* Called from thread context */
1547 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1550 pa_sink_input_assert_ref(i);
1551 s = PLAYBACK_STREAM(i->userdata);
1552 playback_stream_assert_ref(s);
1555 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1557 if (pa_memblockq_is_readable(s->memblockq))
1558 s->is_underrun = FALSE;
1560 if (!s->is_underrun)
1561 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));
1563 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1564 s->drain_request = FALSE;
1565 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);
1566 } else if (!s->is_underrun)
1567 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, pa_memblockq_get_read_index(s->memblockq), NULL, NULL);
1569 s->is_underrun = TRUE;
1571 playback_stream_request_bytes(s);
1574 /* This call will not fail with prebuf=0, hence we check for
1575 underrun explicitly above */
1576 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1579 chunk->length = PA_MIN(nbytes, chunk->length);
1581 if (i->thread_info.underrun_for > 0)
1582 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1584 pa_memblockq_drop(s->memblockq, chunk->length);
1585 playback_stream_request_bytes(s);
1590 /* Called from thread context */
1591 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1594 pa_sink_input_assert_ref(i);
1595 s = PLAYBACK_STREAM(i->userdata);
1596 playback_stream_assert_ref(s);
1598 /* If we are in an underrun, then we don't rewind */
1599 if (i->thread_info.underrun_for > 0)
1602 pa_memblockq_rewind(s->memblockq, nbytes);
1605 /* Called from thread context */
1606 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1609 pa_sink_input_assert_ref(i);
1610 s = PLAYBACK_STREAM(i->userdata);
1611 playback_stream_assert_ref(s);
1613 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1616 /* Called from thread context */
1617 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1619 size_t new_tlength, old_tlength;
1621 pa_sink_input_assert_ref(i);
1622 s = PLAYBACK_STREAM(i->userdata);
1623 playback_stream_assert_ref(s);
1625 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1626 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1628 if (old_tlength < new_tlength) {
1629 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1630 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1631 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1633 if (new_tlength == old_tlength)
1634 pa_log_debug("Failed to increase tlength");
1636 pa_log_debug("Notifying client about increased tlength");
1637 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);
1642 /* Called from main context */
1643 static void sink_input_kill_cb(pa_sink_input *i) {
1646 pa_sink_input_assert_ref(i);
1647 s = PLAYBACK_STREAM(i->userdata);
1648 playback_stream_assert_ref(s);
1650 playback_stream_send_killed(s);
1651 playback_stream_unlink(s);
1654 /* Called from main context */
1655 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1659 pa_sink_input_assert_ref(i);
1660 s = PLAYBACK_STREAM(i->userdata);
1661 playback_stream_assert_ref(s);
1663 if (s->connection->version < 15)
1666 t = pa_tagstruct_new(NULL, 0);
1667 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1668 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1669 pa_tagstruct_putu32(t, s->index);
1670 pa_tagstruct_puts(t, event);
1671 pa_tagstruct_put_proplist(t, pl);
1672 pa_pstream_send_tagstruct(s->connection->pstream, t);
1675 /* Called from main context */
1676 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1680 pa_sink_input_assert_ref(i);
1681 s = PLAYBACK_STREAM(i->userdata);
1682 playback_stream_assert_ref(s);
1684 if (s->connection->version < 12)
1687 t = pa_tagstruct_new(NULL, 0);
1688 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1689 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1690 pa_tagstruct_putu32(t, s->index);
1691 pa_tagstruct_put_boolean(t, suspend);
1692 pa_pstream_send_tagstruct(s->connection->pstream, t);
1695 /* Called from main context */
1696 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1700 pa_sink_input_assert_ref(i);
1701 s = PLAYBACK_STREAM(i->userdata);
1702 playback_stream_assert_ref(s);
1707 fix_playback_buffer_attr(s);
1708 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1709 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1711 if (s->connection->version < 12)
1714 t = pa_tagstruct_new(NULL, 0);
1715 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1716 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1717 pa_tagstruct_putu32(t, s->index);
1718 pa_tagstruct_putu32(t, dest->index);
1719 pa_tagstruct_puts(t, dest->name);
1720 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1722 if (s->connection->version >= 13) {
1723 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1724 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1725 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1726 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1727 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1730 pa_pstream_send_tagstruct(s->connection->pstream, t);
1733 /*** source_output callbacks ***/
1735 /* Called from thread context */
1736 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1737 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1740 pa_source_output_assert_ref(o);
1741 s = RECORD_STREAM(o->userdata);
1742 record_stream_assert_ref(s);
1745 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1746 /* Atomically get a snapshot of all timing parameters... */
1747 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1748 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1749 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1753 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1756 /* Called from thread context */
1757 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1760 pa_source_output_assert_ref(o);
1761 s = RECORD_STREAM(o->userdata);
1762 record_stream_assert_ref(s);
1765 pa_atomic_add(&s->on_the_fly, chunk->length);
1766 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1769 static void source_output_kill_cb(pa_source_output *o) {
1772 pa_source_output_assert_ref(o);
1773 s = RECORD_STREAM(o->userdata);
1774 record_stream_assert_ref(s);
1776 record_stream_send_killed(s);
1777 record_stream_unlink(s);
1780 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1783 pa_source_output_assert_ref(o);
1784 s = RECORD_STREAM(o->userdata);
1785 record_stream_assert_ref(s);
1787 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1789 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1792 /* Called from main context */
1793 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1797 pa_source_output_assert_ref(o);
1798 s = RECORD_STREAM(o->userdata);
1799 record_stream_assert_ref(s);
1801 if (s->connection->version < 15)
1804 t = pa_tagstruct_new(NULL, 0);
1805 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1806 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1807 pa_tagstruct_putu32(t, s->index);
1808 pa_tagstruct_puts(t, event);
1809 pa_tagstruct_put_proplist(t, pl);
1810 pa_pstream_send_tagstruct(s->connection->pstream, t);
1813 /* Called from main context */
1814 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1818 pa_source_output_assert_ref(o);
1819 s = RECORD_STREAM(o->userdata);
1820 record_stream_assert_ref(s);
1822 if (s->connection->version < 12)
1825 t = pa_tagstruct_new(NULL, 0);
1826 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1827 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1828 pa_tagstruct_putu32(t, s->index);
1829 pa_tagstruct_put_boolean(t, suspend);
1830 pa_pstream_send_tagstruct(s->connection->pstream, t);
1833 /* Called from main context */
1834 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1838 pa_source_output_assert_ref(o);
1839 s = RECORD_STREAM(o->userdata);
1840 record_stream_assert_ref(s);
1845 fix_record_buffer_attr_pre(s);
1846 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1847 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1848 fix_record_buffer_attr_post(s);
1850 if (s->connection->version < 12)
1853 t = pa_tagstruct_new(NULL, 0);
1854 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1855 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1856 pa_tagstruct_putu32(t, s->index);
1857 pa_tagstruct_putu32(t, dest->index);
1858 pa_tagstruct_puts(t, dest->name);
1859 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1861 if (s->connection->version >= 13) {
1862 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1863 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1864 pa_tagstruct_put_usec(t, s->configured_source_latency);
1867 pa_pstream_send_tagstruct(s->connection->pstream, t);
1870 /*** pdispatch callbacks ***/
1872 static void protocol_error(pa_native_connection *c) {
1873 pa_log("protocol error, kicking client");
1874 native_connection_unlink(c);
1877 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1878 if (!(expression)) { \
1879 pa_pstream_send_error((pstream), (tag), (error)); \
1884 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
1885 if (!(expression)) { \
1886 pa_pstream_send_error((pstream), (tag), (error)); \
1891 static pa_tagstruct *reply_new(uint32_t tag) {
1892 pa_tagstruct *reply;
1894 reply = pa_tagstruct_new(NULL, 0);
1895 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1896 pa_tagstruct_putu32(reply, tag);
1900 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1901 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1903 uint32_t sink_index, syncid, missing = 0;
1904 pa_buffer_attr attr;
1905 const char *name = NULL, *sink_name;
1908 pa_tagstruct *reply;
1909 pa_sink *sink = NULL;
1917 fix_channels = FALSE,
1919 variable_rate = FALSE,
1921 adjust_latency = FALSE,
1922 early_requests = FALSE,
1923 dont_inhibit_auto_suspend = FALSE,
1926 fail_on_suspend = FALSE,
1927 relative_volume = FALSE,
1928 passthrough = FALSE;
1930 pa_sink_input_flags_t flags = 0;
1931 pa_proplist *p = NULL;
1932 int ret = PA_ERR_INVALID;
1933 uint8_t n_formats = 0;
1934 pa_format_info *format;
1935 pa_idxset *formats = NULL;
1938 pa_native_connection_assert_ref(c);
1940 memset(&attr, 0, sizeof(attr));
1942 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1945 PA_TAG_SAMPLE_SPEC, &ss,
1946 PA_TAG_CHANNEL_MAP, &map,
1947 PA_TAG_U32, &sink_index,
1948 PA_TAG_STRING, &sink_name,
1949 PA_TAG_U32, &attr.maxlength,
1950 PA_TAG_BOOLEAN, &corked,
1951 PA_TAG_U32, &attr.tlength,
1952 PA_TAG_U32, &attr.prebuf,
1953 PA_TAG_U32, &attr.minreq,
1954 PA_TAG_U32, &syncid,
1955 PA_TAG_CVOLUME, &volume,
1956 PA_TAG_INVALID) < 0) {
1962 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
1963 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID, finish);
1964 CHECK_VALIDITY_GOTO(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID, finish);
1965 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
1966 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
1968 p = pa_proplist_new();
1971 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1973 if (c->version >= 12) {
1974 /* Since 0.9.8 the user can ask for a couple of additional flags */
1976 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1977 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1978 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1979 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1980 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1981 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1982 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1989 if (c->version >= 13) {
1991 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1992 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1993 pa_tagstruct_get_proplist(t, p) < 0) {
2000 if (c->version >= 14) {
2002 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2003 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2010 if (c->version >= 15) {
2012 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2013 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2014 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2021 if (c->version >= 17) {
2023 if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
2030 if (c->version >= 18) {
2032 if (pa_tagstruct_get_boolean(t, &passthrough) < 0 ) {
2038 if (c->version >= 21) {
2040 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2046 formats = pa_idxset_new(NULL, NULL);
2048 for (i = 0; i < n_formats; i++) {
2049 format = pa_format_info_new();
2050 if (pa_tagstruct_get_format_info(t, format) < 0) {
2054 pa_idxset_put(formats, format, NULL);
2058 if (n_formats == 0) {
2059 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2060 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2061 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2063 PA_IDXSET_FOREACH(format, formats, i) {
2064 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2068 if (!pa_tagstruct_eof(t)) {
2073 if (sink_index != PA_INVALID_INDEX) {
2075 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
2076 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2080 } else if (sink_name) {
2082 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
2083 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2089 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
2090 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
2091 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
2092 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
2093 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
2094 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
2095 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
2096 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
2097 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2098 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
2099 (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0);
2101 /* Only since protocol version 15 there's a seperate muted_set
2102 * flag. For older versions we synthesize it here */
2103 muted_set = muted_set || muted;
2105 s = playback_stream_new(c, sink, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, p, adjust_latency, early_requests, relative_volume, syncid, &missing, &ret);
2106 /* We no longer own the formats idxset */
2109 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2111 reply = reply_new(tag);
2112 pa_tagstruct_putu32(reply, s->index);
2113 pa_assert(s->sink_input);
2114 pa_tagstruct_putu32(reply, s->sink_input->index);
2115 pa_tagstruct_putu32(reply, missing);
2117 /* pa_log("initial request is %u", missing); */
2119 if (c->version >= 9) {
2120 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2122 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2123 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2124 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2125 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2128 if (c->version >= 12) {
2129 /* Since 0.9.8 we support sending the chosen sample
2130 * spec/channel map/device/suspend status back to the
2133 pa_tagstruct_put_sample_spec(reply, &ss);
2134 pa_tagstruct_put_channel_map(reply, &map);
2136 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2137 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2139 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2142 if (c->version >= 13)
2143 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2145 if (c->version >= 21) {
2146 /* Send back the format we negotiated */
2147 if (s->sink_input->format)
2148 pa_tagstruct_put_format_info(reply, s->sink_input->format);
2150 pa_format_info *f = pa_format_info_new();
2151 pa_tagstruct_put_format_info(reply, f);
2152 pa_format_info_free(f);
2156 pa_pstream_send_tagstruct(c->pstream, reply);
2160 pa_proplist_free(p);
2162 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
2165 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2166 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2169 pa_native_connection_assert_ref(c);
2172 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2173 !pa_tagstruct_eof(t)) {
2178 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2182 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2184 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2185 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2189 playback_stream_unlink(s);
2193 case PA_COMMAND_DELETE_RECORD_STREAM: {
2195 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2196 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2200 record_stream_unlink(s);
2204 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2207 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2208 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2212 upload_stream_unlink(s);
2217 pa_assert_not_reached();
2220 pa_pstream_send_simple_ack(c->pstream, tag);
2223 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2224 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2226 pa_buffer_attr attr;
2227 uint32_t source_index;
2228 const char *name = NULL, *source_name;
2231 pa_tagstruct *reply;
2232 pa_source *source = NULL;
2240 fix_channels = FALSE,
2242 variable_rate = FALSE,
2244 adjust_latency = FALSE,
2245 peak_detect = FALSE,
2246 early_requests = FALSE,
2247 dont_inhibit_auto_suspend = FALSE,
2250 fail_on_suspend = FALSE,
2251 relative_volume = FALSE,
2252 passthrough = FALSE;
2254 pa_source_output_flags_t flags = 0;
2255 pa_proplist *p = NULL;
2256 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2257 pa_sink_input *direct_on_input = NULL;
2258 int ret = PA_ERR_INVALID;
2259 uint8_t n_formats = 0;
2260 pa_format_info *format;
2261 pa_idxset *formats = NULL;
2264 pa_native_connection_assert_ref(c);
2267 memset(&attr, 0, sizeof(attr));
2269 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2270 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2271 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2272 pa_tagstruct_getu32(t, &source_index) < 0 ||
2273 pa_tagstruct_gets(t, &source_name) < 0 ||
2274 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2275 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2276 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2282 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
2283 CHECK_VALIDITY_GOTO(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID, finish);
2284 CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID, finish);
2285 CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
2287 p = pa_proplist_new();
2290 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2292 if (c->version >= 12) {
2293 /* Since 0.9.8 the user can ask for a couple of additional flags */
2295 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2296 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2297 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2298 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2299 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2300 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2301 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2308 if (c->version >= 13) {
2310 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2311 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2312 pa_tagstruct_get_proplist(t, p) < 0 ||
2313 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2320 if (c->version >= 14) {
2322 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2328 if (c->version >= 15) {
2330 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2331 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2338 if (c->version >= 22) {
2339 /* For newer client versions (with per-source-output volumes), we try
2340 * to make the behaviour for playback and record streams the same. */
2343 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2349 formats = pa_idxset_new(NULL, NULL);
2351 for (i = 0; i < n_formats; i++) {
2352 format = pa_format_info_new();
2353 if (pa_tagstruct_get_format_info(t, format) < 0) {
2357 pa_idxset_put(formats, format, NULL);
2360 if (pa_tagstruct_get_cvolume(t, &volume) < 0 ||
2361 pa_tagstruct_get_boolean(t, &muted) < 0 ||
2362 pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2363 pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2364 pa_tagstruct_get_boolean(t, &relative_volume) < 0 ||
2365 pa_tagstruct_get_boolean(t, &passthrough) < 0) {
2371 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
2374 if (n_formats == 0) {
2375 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2376 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2377 CHECK_VALIDITY_GOTO(c->pstream, c->version < 22 || (volume.channels == ss.channels), tag, PA_ERR_INVALID, finish);
2378 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2380 PA_IDXSET_FOREACH(format, formats, i) {
2381 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2386 if (!pa_tagstruct_eof(t)) {
2391 if (source_index != PA_INVALID_INDEX) {
2393 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2394 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2398 } else if (source_name) {
2400 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2401 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2406 if (direct_on_input_idx != PA_INVALID_INDEX) {
2408 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2409 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2415 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2416 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2417 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2418 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2419 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2420 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2421 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2422 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2423 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2424 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0) |
2425 (passthrough ? PA_SOURCE_OUTPUT_PASSTHROUGH : 0);
2427 s = record_stream_new(c, source, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, p, adjust_latency, early_requests, relative_volume, peak_detect, direct_on_input, &ret);
2429 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2431 reply = reply_new(tag);
2432 pa_tagstruct_putu32(reply, s->index);
2433 pa_assert(s->source_output);
2434 pa_tagstruct_putu32(reply, s->source_output->index);
2436 if (c->version >= 9) {
2437 /* Since 0.9 we support sending the buffer metrics back to the client */
2439 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2440 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2443 if (c->version >= 12) {
2444 /* Since 0.9.8 we support sending the chosen sample
2445 * spec/channel map/device/suspend status back to the
2448 pa_tagstruct_put_sample_spec(reply, &ss);
2449 pa_tagstruct_put_channel_map(reply, &map);
2451 pa_tagstruct_putu32(reply, s->source_output->source->index);
2452 pa_tagstruct_puts(reply, s->source_output->source->name);
2454 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2457 if (c->version >= 13)
2458 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2460 if (c->version >= 22) {
2461 /* Send back the format we negotiated */
2462 if (s->source_output->format)
2463 pa_tagstruct_put_format_info(reply, s->source_output->format);
2465 pa_format_info *f = pa_format_info_new();
2466 pa_tagstruct_put_format_info(reply, f);
2467 pa_format_info_free(f);
2471 pa_pstream_send_tagstruct(c->pstream, reply);
2475 pa_proplist_free(p);
2477 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
2480 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2481 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2484 pa_native_connection_assert_ref(c);
2487 if (!pa_tagstruct_eof(t)) {
2492 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2493 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2494 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2496 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2498 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2501 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2502 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2504 pa_tagstruct *reply;
2505 pa_bool_t shm_on_remote = FALSE, do_shm;
2507 pa_native_connection_assert_ref(c);
2510 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2511 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2512 !pa_tagstruct_eof(t)) {
2517 /* Minimum supported version */
2518 if (c->version < 8) {
2519 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2523 /* Starting with protocol version 13 the MSB of the version tag
2524 reflects if shm is available for this pa_native_connection or
2526 if (c->version >= 13) {
2527 shm_on_remote = !!(c->version & 0x80000000U);
2528 c->version &= 0x7FFFFFFFU;
2531 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2533 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2535 if (!c->authorized) {
2536 pa_bool_t success = FALSE;
2539 const pa_creds *creds;
2541 if ((creds = pa_pdispatch_creds(pd))) {
2542 if (creds->uid == getuid())
2544 else if (c->options->auth_group) {
2548 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2549 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2550 else if (gid == creds->gid)
2554 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2555 pa_log_warn("Failed to check group membership.");
2561 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2562 (unsigned long) creds->uid,
2563 (unsigned long) creds->gid,
2568 if (!success && c->options->auth_cookie) {
2571 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2572 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2577 pa_log_warn("Denied access to client with invalid authorization data.");
2578 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2582 c->authorized = TRUE;
2583 if (c->auth_timeout_event) {
2584 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2585 c->auth_timeout_event = NULL;
2589 /* Enable shared memory support if possible */
2591 pa_mempool_is_shared(c->protocol->core->mempool) &&
2594 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2597 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2602 /* Only enable SHM if both sides are owned by the same
2603 * user. This is a security measure because otherwise data
2604 * private to the user might leak. */
2606 const pa_creds *creds;
2607 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2612 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2613 pa_pstream_enable_shm(c->pstream, do_shm);
2615 reply = reply_new(tag);
2616 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2620 /* SHM support is only enabled after both sides made sure they are the same user. */
2624 ucred.uid = getuid();
2625 ucred.gid = getgid();
2627 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2630 pa_pstream_send_tagstruct(c->pstream, reply);
2634 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2635 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2636 const char *name = NULL;
2638 pa_tagstruct *reply;
2640 pa_native_connection_assert_ref(c);
2643 p = pa_proplist_new();
2645 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2646 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2647 !pa_tagstruct_eof(t)) {
2650 pa_proplist_free(p);
2655 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2656 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2657 pa_proplist_free(p);
2661 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2662 pa_proplist_free(p);
2664 reply = reply_new(tag);
2666 if (c->version >= 13)
2667 pa_tagstruct_putu32(reply, c->client->index);
2669 pa_pstream_send_tagstruct(c->pstream, reply);
2672 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2673 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2675 uint32_t idx = PA_IDXSET_INVALID;
2677 pa_native_connection_assert_ref(c);
2680 if (pa_tagstruct_gets(t, &name) < 0 ||
2681 !pa_tagstruct_eof(t)) {
2686 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2687 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);
2689 if (command == PA_COMMAND_LOOKUP_SINK) {
2691 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2695 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2696 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2697 idx = source->index;
2700 if (idx == PA_IDXSET_INVALID)
2701 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2703 pa_tagstruct *reply;
2704 reply = reply_new(tag);
2705 pa_tagstruct_putu32(reply, idx);
2706 pa_pstream_send_tagstruct(c->pstream, reply);
2710 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2711 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2715 pa_native_connection_assert_ref(c);
2718 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2719 !pa_tagstruct_eof(t)) {
2724 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2725 s = pa_idxset_get_by_index(c->output_streams, idx);
2726 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2727 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2729 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);
2732 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2733 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2734 pa_tagstruct *reply;
2735 const pa_mempool_stat *stat;
2737 pa_native_connection_assert_ref(c);
2740 if (!pa_tagstruct_eof(t)) {
2745 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2747 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2749 reply = reply_new(tag);
2750 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2751 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2752 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2753 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2754 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2755 pa_pstream_send_tagstruct(c->pstream, reply);
2758 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2759 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2760 pa_tagstruct *reply;
2762 struct timeval tv, now;
2765 pa_native_connection_assert_ref(c);
2768 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2769 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2770 !pa_tagstruct_eof(t)) {
2775 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2776 s = pa_idxset_get_by_index(c->output_streams, idx);
2777 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2778 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2780 /* Get an atomic snapshot of all timing parameters */
2781 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);
2783 reply = reply_new(tag);
2784 pa_tagstruct_put_usec(reply,
2785 s->current_sink_latency +
2786 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2787 pa_tagstruct_put_usec(reply, 0);
2788 pa_tagstruct_put_boolean(reply,
2789 s->playing_for > 0 &&
2790 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2791 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2792 pa_tagstruct_put_timeval(reply, &tv);
2793 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2794 pa_tagstruct_puts64(reply, s->write_index);
2795 pa_tagstruct_puts64(reply, s->read_index);
2797 if (c->version >= 13) {
2798 pa_tagstruct_putu64(reply, s->underrun_for);
2799 pa_tagstruct_putu64(reply, s->playing_for);
2802 pa_pstream_send_tagstruct(c->pstream, reply);
2805 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2806 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2807 pa_tagstruct *reply;
2809 struct timeval tv, now;
2812 pa_native_connection_assert_ref(c);
2815 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2816 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2817 !pa_tagstruct_eof(t)) {
2822 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2823 s = pa_idxset_get_by_index(c->record_streams, idx);
2824 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2826 /* Get an atomic snapshot of all timing parameters */
2827 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);
2829 reply = reply_new(tag);
2830 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2831 pa_tagstruct_put_usec(reply,
2832 s->current_source_latency +
2833 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec));
2834 pa_tagstruct_put_boolean(reply,
2835 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2836 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2837 pa_tagstruct_put_timeval(reply, &tv);
2838 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2839 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2840 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2841 pa_pstream_send_tagstruct(c->pstream, reply);
2844 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2845 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2848 const char *name = NULL;
2851 pa_tagstruct *reply;
2854 pa_native_connection_assert_ref(c);
2857 if (pa_tagstruct_gets(t, &name) < 0 ||
2858 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2859 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2860 pa_tagstruct_getu32(t, &length) < 0) {
2865 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2866 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2867 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2868 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2869 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2870 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2872 p = pa_proplist_new();
2874 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2875 !pa_tagstruct_eof(t)) {
2878 pa_proplist_free(p);
2882 if (c->version < 13)
2883 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2885 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2886 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2888 if (!name || !pa_namereg_is_valid_name(name)) {
2889 pa_proplist_free(p);
2890 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2893 s = upload_stream_new(c, &ss, &map, name, length, p);
2894 pa_proplist_free(p);
2896 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2898 reply = reply_new(tag);
2899 pa_tagstruct_putu32(reply, s->index);
2900 pa_tagstruct_putu32(reply, length);
2901 pa_pstream_send_tagstruct(c->pstream, reply);
2904 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2905 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2910 pa_native_connection_assert_ref(c);
2913 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2914 !pa_tagstruct_eof(t)) {
2919 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2921 s = pa_idxset_get_by_index(c->output_streams, channel);
2922 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2923 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2925 if (!s->memchunk.memblock)
2926 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2927 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2928 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2930 pa_pstream_send_simple_ack(c->pstream, tag);
2932 upload_stream_unlink(s);
2935 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2936 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2937 uint32_t sink_index;
2940 const char *name, *sink_name;
2943 pa_tagstruct *reply;
2945 pa_native_connection_assert_ref(c);
2948 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2950 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2951 pa_tagstruct_gets(t, &sink_name) < 0 ||
2952 pa_tagstruct_getu32(t, &volume) < 0 ||
2953 pa_tagstruct_gets(t, &name) < 0) {
2958 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2959 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2960 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2961 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2963 if (sink_index != PA_INVALID_INDEX)
2964 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2966 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2968 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2970 p = pa_proplist_new();
2972 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2973 !pa_tagstruct_eof(t)) {
2975 pa_proplist_free(p);
2979 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2981 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2982 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2983 pa_proplist_free(p);
2987 pa_proplist_free(p);
2989 reply = reply_new(tag);
2991 if (c->version >= 13)
2992 pa_tagstruct_putu32(reply, idx);
2994 pa_pstream_send_tagstruct(c->pstream, reply);
2997 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2998 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3001 pa_native_connection_assert_ref(c);
3004 if (pa_tagstruct_gets(t, &name) < 0 ||
3005 !pa_tagstruct_eof(t)) {
3010 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3011 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3013 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
3014 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3018 pa_pstream_send_simple_ack(c->pstream, tag);
3021 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
3024 pa_assert(original);
3028 if (c->version < 12) {
3029 /* Before protocol version 12 we didn't support S32 samples,
3030 * so we need to lie about this to the client */
3032 if (fixed->format == PA_SAMPLE_S32LE)
3033 fixed->format = PA_SAMPLE_FLOAT32LE;
3034 if (fixed->format == PA_SAMPLE_S32BE)
3035 fixed->format = PA_SAMPLE_FLOAT32BE;
3038 if (c->version < 15) {
3039 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
3040 fixed->format = PA_SAMPLE_FLOAT32LE;
3041 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
3042 fixed->format = PA_SAMPLE_FLOAT32BE;
3046 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
3047 pa_sample_spec fixed_ss;
3050 pa_sink_assert_ref(sink);
3052 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
3056 PA_TAG_U32, sink->index,
3057 PA_TAG_STRING, sink->name,
3058 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3059 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3060 PA_TAG_CHANNEL_MAP, &sink->channel_map,
3061 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
3062 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
3063 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
3064 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
3065 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
3066 PA_TAG_USEC, pa_sink_get_latency(sink),
3067 PA_TAG_STRING, sink->driver,
3068 PA_TAG_U32, sink->flags & ~PA_SINK_SHARE_VOLUME_WITH_MASTER,
3071 if (c->version >= 13) {
3072 pa_tagstruct_put_proplist(t, sink->proplist);
3073 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
3076 if (c->version >= 15) {
3077 pa_tagstruct_put_volume(t, sink->base_volume);
3078 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
3079 pa_log_error("Internal sink state is invalid.");
3080 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
3081 pa_tagstruct_putu32(t, sink->n_volume_steps);
3082 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
3085 if (c->version >= 16) {
3086 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
3092 PA_HASHMAP_FOREACH(p, sink->ports, state) {
3093 pa_tagstruct_puts(t, p->name);
3094 pa_tagstruct_puts(t, p->description);
3095 pa_tagstruct_putu32(t, p->priority);
3099 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
3102 if (c->version >= 21) {
3105 pa_idxset *formats = pa_sink_get_formats(sink);
3107 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3108 PA_IDXSET_FOREACH(f, formats, i) {
3109 pa_tagstruct_put_format_info(t, f);
3112 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
3116 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
3117 pa_sample_spec fixed_ss;
3120 pa_source_assert_ref(source);
3122 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
3126 PA_TAG_U32, source->index,
3127 PA_TAG_STRING, source->name,
3128 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3129 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3130 PA_TAG_CHANNEL_MAP, &source->channel_map,
3131 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
3132 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
3133 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
3134 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
3135 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
3136 PA_TAG_USEC, pa_source_get_latency(source),
3137 PA_TAG_STRING, source->driver,
3138 PA_TAG_U32, source->flags,
3141 if (c->version >= 13) {
3142 pa_tagstruct_put_proplist(t, source->proplist);
3143 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
3146 if (c->version >= 15) {
3147 pa_tagstruct_put_volume(t, source->base_volume);
3148 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
3149 pa_log_error("Internal source state is invalid.");
3150 pa_tagstruct_putu32(t, pa_source_get_state(source));
3151 pa_tagstruct_putu32(t, source->n_volume_steps);
3152 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
3155 if (c->version >= 16) {
3157 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
3159 if (source->ports) {
3163 PA_HASHMAP_FOREACH(p, source->ports, state) {
3164 pa_tagstruct_puts(t, p->name);
3165 pa_tagstruct_puts(t, p->description);
3166 pa_tagstruct_putu32(t, p->priority);
3170 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
3173 if (c->version >= 22) {
3176 pa_idxset *formats = pa_source_get_formats(source);
3178 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3179 PA_IDXSET_FOREACH(f, formats, i) {
3180 pa_tagstruct_put_format_info(t, f);
3183 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
3187 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
3191 pa_tagstruct_putu32(t, client->index);
3192 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
3193 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
3194 pa_tagstruct_puts(t, client->driver);
3196 if (c->version >= 13)
3197 pa_tagstruct_put_proplist(t, client->proplist);
3200 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
3207 pa_tagstruct_putu32(t, card->index);
3208 pa_tagstruct_puts(t, card->name);
3209 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
3210 pa_tagstruct_puts(t, card->driver);
3212 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
3214 if (card->profiles) {
3215 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
3216 pa_tagstruct_puts(t, p->name);
3217 pa_tagstruct_puts(t, p->description);
3218 pa_tagstruct_putu32(t, p->n_sinks);
3219 pa_tagstruct_putu32(t, p->n_sources);
3220 pa_tagstruct_putu32(t, p->priority);
3224 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
3225 pa_tagstruct_put_proplist(t, card->proplist);
3228 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3232 pa_tagstruct_putu32(t, module->index);
3233 pa_tagstruct_puts(t, module->name);
3234 pa_tagstruct_puts(t, module->argument);
3235 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3237 if (c->version < 15)
3238 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
3240 if (c->version >= 15)
3241 pa_tagstruct_put_proplist(t, module->proplist);
3244 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3245 pa_sample_spec fixed_ss;
3246 pa_usec_t sink_latency;
3248 pa_bool_t has_volume = FALSE;
3251 pa_sink_input_assert_ref(s);
3253 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3255 has_volume = pa_sink_input_is_volume_readable(s);
3257 pa_sink_input_get_volume(s, &v, TRUE);
3259 pa_cvolume_reset(&v, fixed_ss.channels);
3261 pa_tagstruct_putu32(t, s->index);
3262 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3263 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3264 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3265 pa_tagstruct_putu32(t, s->sink->index);
3266 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3267 pa_tagstruct_put_channel_map(t, &s->channel_map);
3268 pa_tagstruct_put_cvolume(t, &v);
3269 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3270 pa_tagstruct_put_usec(t, sink_latency);
3271 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3272 pa_tagstruct_puts(t, s->driver);
3273 if (c->version >= 11)
3274 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3275 if (c->version >= 13)
3276 pa_tagstruct_put_proplist(t, s->proplist);
3277 if (c->version >= 19)
3278 pa_tagstruct_put_boolean(t, (pa_sink_input_get_state(s) == PA_SINK_INPUT_CORKED));
3279 if (c->version >= 20) {
3280 pa_tagstruct_put_boolean(t, has_volume);
3281 pa_tagstruct_put_boolean(t, s->volume_writable);
3283 if (c->version >= 21)
3284 pa_tagstruct_put_format_info(t, s->format);
3287 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3288 pa_sample_spec fixed_ss;
3289 pa_usec_t source_latency;
3291 pa_bool_t has_volume = FALSE;
3294 pa_source_output_assert_ref(s);
3296 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3298 has_volume = pa_source_output_is_volume_readable(s);
3300 pa_source_output_get_volume(s, &v, TRUE);
3302 pa_cvolume_reset(&v, fixed_ss.channels);
3304 pa_tagstruct_putu32(t, s->index);
3305 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3306 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3307 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3308 pa_tagstruct_putu32(t, s->source->index);
3309 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3310 pa_tagstruct_put_channel_map(t, &s->channel_map);
3311 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3312 pa_tagstruct_put_usec(t, source_latency);
3313 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3314 pa_tagstruct_puts(t, s->driver);
3315 if (c->version >= 13)
3316 pa_tagstruct_put_proplist(t, s->proplist);
3317 if (c->version >= 19)
3318 pa_tagstruct_put_boolean(t, (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_CORKED));
3319 if (c->version >= 22) {
3320 pa_tagstruct_put_cvolume(t, &v);
3321 pa_tagstruct_put_boolean(t, pa_source_output_get_mute(s));
3322 pa_tagstruct_put_boolean(t, has_volume);
3323 pa_tagstruct_put_boolean(t, s->volume_writable);
3324 pa_tagstruct_put_format_info(t, s->format);
3328 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3329 pa_sample_spec fixed_ss;
3335 if (e->memchunk.memblock)
3336 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3338 memset(&fixed_ss, 0, sizeof(fixed_ss));
3340 pa_tagstruct_putu32(t, e->index);
3341 pa_tagstruct_puts(t, e->name);
3343 if (e->volume_is_set)
3346 pa_cvolume_init(&v);
3348 pa_tagstruct_put_cvolume(t, &v);
3349 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3350 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3351 pa_tagstruct_put_channel_map(t, &e->channel_map);
3352 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3353 pa_tagstruct_put_boolean(t, e->lazy);
3354 pa_tagstruct_puts(t, e->filename);
3356 if (c->version >= 13)
3357 pa_tagstruct_put_proplist(t, e->proplist);
3360 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3361 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3363 pa_sink *sink = NULL;
3364 pa_source *source = NULL;
3365 pa_client *client = NULL;
3366 pa_card *card = NULL;
3367 pa_module *module = NULL;
3368 pa_sink_input *si = NULL;
3369 pa_source_output *so = NULL;
3370 pa_scache_entry *sce = NULL;
3371 const char *name = NULL;
3372 pa_tagstruct *reply;
3374 pa_native_connection_assert_ref(c);
3377 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3378 (command != PA_COMMAND_GET_CLIENT_INFO &&
3379 command != PA_COMMAND_GET_MODULE_INFO &&
3380 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3381 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3382 pa_tagstruct_gets(t, &name) < 0) ||
3383 !pa_tagstruct_eof(t)) {
3388 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3389 CHECK_VALIDITY(c->pstream, !name ||
3390 (command == PA_COMMAND_GET_SINK_INFO &&
3391 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3392 (command == PA_COMMAND_GET_SOURCE_INFO &&
3393 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3394 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3395 CHECK_VALIDITY(c->pstream, command == PA_COMMAND_GET_SINK_INFO ||
3396 command == PA_COMMAND_GET_SOURCE_INFO ||
3397 (idx != PA_INVALID_INDEX || name), tag, PA_ERR_INVALID);
3398 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3399 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3401 if (command == PA_COMMAND_GET_SINK_INFO) {
3402 if (idx != PA_INVALID_INDEX)
3403 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3405 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3406 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3407 if (idx != PA_INVALID_INDEX)
3408 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3410 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3411 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3412 if (idx != PA_INVALID_INDEX)
3413 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3415 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3416 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3417 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3418 else if (command == PA_COMMAND_GET_MODULE_INFO)
3419 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3420 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3421 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3422 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3423 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3425 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3426 if (idx != PA_INVALID_INDEX)
3427 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3429 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3432 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3433 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3437 reply = reply_new(tag);
3439 sink_fill_tagstruct(c, reply, sink);
3441 source_fill_tagstruct(c, reply, source);
3443 client_fill_tagstruct(c, reply, client);
3445 card_fill_tagstruct(c, reply, card);
3447 module_fill_tagstruct(c, reply, module);
3449 sink_input_fill_tagstruct(c, reply, si);
3451 source_output_fill_tagstruct(c, reply, so);
3453 scache_fill_tagstruct(c, reply, sce);
3454 pa_pstream_send_tagstruct(c->pstream, reply);
3457 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3458 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3462 pa_tagstruct *reply;
3464 pa_native_connection_assert_ref(c);
3467 if (!pa_tagstruct_eof(t)) {
3472 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3474 reply = reply_new(tag);
3476 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3477 i = c->protocol->core->sinks;
3478 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3479 i = c->protocol->core->sources;
3480 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3481 i = c->protocol->core->clients;
3482 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3483 i = c->protocol->core->cards;
3484 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3485 i = c->protocol->core->modules;
3486 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3487 i = c->protocol->core->sink_inputs;
3488 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3489 i = c->protocol->core->source_outputs;
3491 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3492 i = c->protocol->core->scache;
3496 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3497 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3498 sink_fill_tagstruct(c, reply, p);
3499 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3500 source_fill_tagstruct(c, reply, p);
3501 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3502 client_fill_tagstruct(c, reply, p);
3503 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3504 card_fill_tagstruct(c, reply, p);
3505 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3506 module_fill_tagstruct(c, reply, p);
3507 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3508 sink_input_fill_tagstruct(c, reply, p);
3509 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3510 source_output_fill_tagstruct(c, reply, p);
3512 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3513 scache_fill_tagstruct(c, reply, p);
3518 pa_pstream_send_tagstruct(c->pstream, reply);
3521 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3522 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3523 pa_tagstruct *reply;
3525 pa_source *def_source;
3526 pa_sample_spec fixed_ss;
3529 pa_native_connection_assert_ref(c);
3532 if (!pa_tagstruct_eof(t)) {
3537 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3539 reply = reply_new(tag);
3540 pa_tagstruct_puts(reply, PACKAGE_NAME);
3541 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3543 u = pa_get_user_name_malloc();
3544 pa_tagstruct_puts(reply, u);
3547 h = pa_get_host_name_malloc();
3548 pa_tagstruct_puts(reply, h);
3551 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3552 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3554 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3555 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3556 def_source = pa_namereg_get_default_source(c->protocol->core);
3557 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3559 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3561 if (c->version >= 15)
3562 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3564 pa_pstream_send_tagstruct(c->pstream, reply);
3567 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3569 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3571 pa_native_connection_assert_ref(c);
3573 t = pa_tagstruct_new(NULL, 0);
3574 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3575 pa_tagstruct_putu32(t, (uint32_t) -1);
3576 pa_tagstruct_putu32(t, e);
3577 pa_tagstruct_putu32(t, idx);
3578 pa_pstream_send_tagstruct(c->pstream, t);
3581 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3582 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3583 pa_subscription_mask_t m;
3585 pa_native_connection_assert_ref(c);
3588 if (pa_tagstruct_getu32(t, &m) < 0 ||
3589 !pa_tagstruct_eof(t)) {
3594 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3595 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3597 if (c->subscription)
3598 pa_subscription_free(c->subscription);
3601 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3602 pa_assert(c->subscription);
3604 c->subscription = NULL;
3606 pa_pstream_send_simple_ack(c->pstream, tag);
3609 static void command_set_volume(
3616 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3619 pa_sink *sink = NULL;
3620 pa_source *source = NULL;
3621 pa_sink_input *si = NULL;
3622 pa_source_output *so = NULL;
3623 const char *name = NULL;
3624 const char *client_name;
3626 pa_native_connection_assert_ref(c);
3629 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3630 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3631 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3632 pa_tagstruct_get_cvolume(t, &volume) ||
3633 !pa_tagstruct_eof(t)) {
3638 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3639 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);
3640 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3641 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3642 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3643 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3647 case PA_COMMAND_SET_SINK_VOLUME:
3648 if (idx != PA_INVALID_INDEX)
3649 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3651 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3654 case PA_COMMAND_SET_SOURCE_VOLUME:
3655 if (idx != PA_INVALID_INDEX)
3656 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3658 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3661 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3662 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3665 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME:
3666 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3670 pa_assert_not_reached();
3673 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
3675 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3678 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3680 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3681 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3682 } else if (source) {
3683 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3685 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3686 pa_source_set_volume(source, &volume, TRUE, TRUE);
3688 CHECK_VALIDITY(c->pstream, si->volume_writable, tag, PA_ERR_BADSTATE);
3689 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3691 pa_log_debug("Client %s changes volume of sink input %s.",
3693 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3694 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3696 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &so->sample_spec), tag, PA_ERR_INVALID);
3698 pa_log_debug("Client %s changes volume of source output %s.",
3700 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
3701 pa_source_output_set_volume(so, &volume, TRUE, TRUE);
3704 pa_pstream_send_simple_ack(c->pstream, tag);
3707 static void command_set_mute(
3714 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3717 pa_sink *sink = NULL;
3718 pa_source *source = NULL;
3719 pa_sink_input *si = NULL;
3720 pa_source_output *so = NULL;
3721 const char *name = NULL, *client_name;
3723 pa_native_connection_assert_ref(c);
3726 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3727 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3728 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3729 pa_tagstruct_get_boolean(t, &mute) ||
3730 !pa_tagstruct_eof(t)) {
3735 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3736 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);
3737 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3738 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3739 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3743 case PA_COMMAND_SET_SINK_MUTE:
3744 if (idx != PA_INVALID_INDEX)
3745 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3747 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3751 case PA_COMMAND_SET_SOURCE_MUTE:
3752 if (idx != PA_INVALID_INDEX)
3753 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3755 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3759 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3760 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3763 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE:
3764 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3768 pa_assert_not_reached();
3771 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
3773 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3776 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3777 pa_sink_set_mute(sink, mute, TRUE);
3778 } else if (source) {
3779 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3780 pa_source_set_mute(source, mute, TRUE);
3782 pa_log_debug("Client %s changes mute of sink input %s.",
3784 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3785 pa_sink_input_set_mute(si, mute, TRUE);
3787 pa_log_debug("Client %s changes mute of source output %s.",
3789 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
3790 pa_source_output_set_mute(so, mute, TRUE);
3793 pa_pstream_send_simple_ack(c->pstream, tag);
3796 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3797 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3802 pa_native_connection_assert_ref(c);
3805 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3806 pa_tagstruct_get_boolean(t, &b) < 0 ||
3807 !pa_tagstruct_eof(t)) {
3812 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3813 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3814 s = pa_idxset_get_by_index(c->output_streams, idx);
3815 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3816 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3818 pa_sink_input_cork(s->sink_input, b);
3821 s->is_underrun = TRUE;
3823 pa_pstream_send_simple_ack(c->pstream, tag);
3826 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3827 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3831 pa_native_connection_assert_ref(c);
3834 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3835 !pa_tagstruct_eof(t)) {
3840 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3841 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3842 s = pa_idxset_get_by_index(c->output_streams, idx);
3843 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3844 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3847 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3848 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3851 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3852 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3855 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3856 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3860 pa_assert_not_reached();
3863 pa_pstream_send_simple_ack(c->pstream, tag);
3866 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3867 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3872 pa_native_connection_assert_ref(c);
3875 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3876 pa_tagstruct_get_boolean(t, &b) < 0 ||
3877 !pa_tagstruct_eof(t)) {
3882 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3883 s = pa_idxset_get_by_index(c->record_streams, idx);
3884 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3886 pa_source_output_cork(s->source_output, b);
3887 pa_memblockq_prebuf_force(s->memblockq);
3888 pa_pstream_send_simple_ack(c->pstream, tag);
3891 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3892 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3896 pa_native_connection_assert_ref(c);
3899 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3900 !pa_tagstruct_eof(t)) {
3905 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3906 s = pa_idxset_get_by_index(c->record_streams, idx);
3907 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3909 pa_memblockq_flush_read(s->memblockq);
3910 pa_pstream_send_simple_ack(c->pstream, tag);
3913 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3914 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3917 pa_tagstruct *reply;
3919 pa_native_connection_assert_ref(c);
3922 memset(&a, 0, sizeof(a));
3924 if (pa_tagstruct_getu32(t, &idx) < 0) {
3929 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3931 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3933 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3935 s = pa_idxset_get_by_index(c->output_streams, idx);
3936 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3937 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3939 if (pa_tagstruct_get(
3941 PA_TAG_U32, &a.maxlength,
3942 PA_TAG_U32, &a.tlength,
3943 PA_TAG_U32, &a.prebuf,
3944 PA_TAG_U32, &a.minreq,
3945 PA_TAG_INVALID) < 0 ||
3946 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3947 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3948 !pa_tagstruct_eof(t)) {
3953 s->adjust_latency = adjust_latency;
3954 s->early_requests = early_requests;
3955 s->buffer_attr_req = a;
3957 fix_playback_buffer_attr(s);
3958 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);
3960 reply = reply_new(tag);
3961 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3962 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3963 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3964 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3966 if (c->version >= 13)
3967 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3971 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3972 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3974 s = pa_idxset_get_by_index(c->record_streams, idx);
3975 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3977 if (pa_tagstruct_get(
3979 PA_TAG_U32, &a.maxlength,
3980 PA_TAG_U32, &a.fragsize,
3981 PA_TAG_INVALID) < 0 ||
3982 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3983 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3984 !pa_tagstruct_eof(t)) {
3989 s->adjust_latency = adjust_latency;
3990 s->early_requests = early_requests;
3991 s->buffer_attr_req = a;
3993 fix_record_buffer_attr_pre(s);
3994 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3995 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3996 fix_record_buffer_attr_post(s);
3998 reply = reply_new(tag);
3999 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
4000 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
4002 if (c->version >= 13)
4003 pa_tagstruct_put_usec(reply, s->configured_source_latency);
4006 pa_pstream_send_tagstruct(c->pstream, reply);
4009 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4010 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4014 pa_native_connection_assert_ref(c);
4017 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4018 pa_tagstruct_getu32(t, &rate) < 0 ||
4019 !pa_tagstruct_eof(t)) {
4024 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4025 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
4027 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
4030 s = pa_idxset_get_by_index(c->output_streams, idx);
4031 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4032 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4034 pa_sink_input_set_rate(s->sink_input, rate);
4038 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
4040 s = pa_idxset_get_by_index(c->record_streams, idx);
4041 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4043 pa_source_output_set_rate(s->source_output, rate);
4046 pa_pstream_send_simple_ack(c->pstream, tag);
4049 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4050 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4055 pa_native_connection_assert_ref(c);
4058 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4060 p = pa_proplist_new();
4062 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
4064 if (pa_tagstruct_getu32(t, &mode) < 0 ||
4065 pa_tagstruct_get_proplist(t, p) < 0 ||
4066 !pa_tagstruct_eof(t)) {
4068 pa_proplist_free(p);
4074 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4075 pa_tagstruct_getu32(t, &mode) < 0 ||
4076 pa_tagstruct_get_proplist(t, p) < 0 ||
4077 !pa_tagstruct_eof(t)) {
4079 pa_proplist_free(p);
4084 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
4085 pa_proplist_free(p);
4086 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
4089 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
4092 s = pa_idxset_get_by_index(c->output_streams, idx);
4093 if (!s || !playback_stream_isinstance(s)) {
4094 pa_proplist_free(p);
4095 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
4097 pa_sink_input_update_proplist(s->sink_input, mode, p);
4099 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
4102 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
4103 pa_proplist_free(p);
4104 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
4106 pa_source_output_update_proplist(s->source_output, mode, p);
4109 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
4111 pa_client_update_proplist(c->client, mode, p);
4114 pa_pstream_send_simple_ack(c->pstream, tag);
4115 pa_proplist_free(p);
4118 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4119 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4121 unsigned changed = 0;
4123 pa_strlist *l = NULL;
4125 pa_native_connection_assert_ref(c);
4128 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4130 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
4132 if (pa_tagstruct_getu32(t, &idx) < 0) {
4138 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4141 s = pa_idxset_get_by_index(c->output_streams, idx);
4142 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4143 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4145 p = s->sink_input->proplist;
4147 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4150 s = pa_idxset_get_by_index(c->record_streams, idx);
4151 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4153 p = s->source_output->proplist;
4155 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4157 p = c->client->proplist;
4163 if (pa_tagstruct_gets(t, &k) < 0) {
4172 l = pa_strlist_prepend(l, k);
4175 if (!pa_tagstruct_eof(t)) {
4184 l = pa_strlist_pop(l, &z);
4189 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
4193 pa_pstream_send_simple_ack(c->pstream, tag);
4196 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4199 s = pa_idxset_get_by_index(c->output_streams, idx);
4200 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
4202 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4205 s = pa_idxset_get_by_index(c->record_streams, idx);
4206 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
4209 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4210 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
4215 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4216 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4219 pa_native_connection_assert_ref(c);
4222 if (pa_tagstruct_gets(t, &s) < 0 ||
4223 !pa_tagstruct_eof(t)) {
4228 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4229 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
4231 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
4234 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
4235 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4237 pa_namereg_set_default_source(c->protocol->core, source);
4240 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
4242 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
4243 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4245 pa_namereg_set_default_sink(c->protocol->core, sink);
4248 pa_pstream_send_simple_ack(c->pstream, tag);
4251 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4252 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4256 pa_native_connection_assert_ref(c);
4259 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4260 pa_tagstruct_gets(t, &name) < 0 ||
4261 !pa_tagstruct_eof(t)) {
4266 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4267 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
4269 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
4272 s = pa_idxset_get_by_index(c->output_streams, idx);
4273 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4274 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4276 pa_sink_input_set_name(s->sink_input, name);
4280 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4282 s = pa_idxset_get_by_index(c->record_streams, idx);
4283 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4285 pa_source_output_set_name(s->source_output, name);
4288 pa_pstream_send_simple_ack(c->pstream, tag);
4291 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4292 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4295 pa_native_connection_assert_ref(c);
4298 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4299 !pa_tagstruct_eof(t)) {
4304 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4306 if (command == PA_COMMAND_KILL_CLIENT) {
4309 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4310 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4312 pa_native_connection_ref(c);
4313 pa_client_kill(client);
4315 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4318 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4319 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4321 pa_native_connection_ref(c);
4322 pa_sink_input_kill(s);
4324 pa_source_output *s;
4326 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4328 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4329 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4331 pa_native_connection_ref(c);
4332 pa_source_output_kill(s);
4335 pa_pstream_send_simple_ack(c->pstream, tag);
4336 pa_native_connection_unref(c);
4339 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4340 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4342 const char *name, *argument;
4343 pa_tagstruct *reply;
4345 pa_native_connection_assert_ref(c);
4348 if (pa_tagstruct_gets(t, &name) < 0 ||
4349 pa_tagstruct_gets(t, &argument) < 0 ||
4350 !pa_tagstruct_eof(t)) {
4355 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4356 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4357 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4359 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4360 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4364 reply = reply_new(tag);
4365 pa_tagstruct_putu32(reply, m->index);
4366 pa_pstream_send_tagstruct(c->pstream, reply);
4369 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4370 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4374 pa_native_connection_assert_ref(c);
4377 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4378 !pa_tagstruct_eof(t)) {
4383 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4384 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4385 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4387 pa_module_unload_request(m, FALSE);
4388 pa_pstream_send_simple_ack(c->pstream, tag);
4391 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4392 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4393 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4394 const char *name_device = NULL;
4396 pa_native_connection_assert_ref(c);
4399 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4400 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4401 pa_tagstruct_gets(t, &name_device) < 0 ||
4402 !pa_tagstruct_eof(t)) {
4407 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4408 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4410 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);
4411 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4412 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4413 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4415 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4416 pa_sink_input *si = NULL;
4417 pa_sink *sink = NULL;
4419 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4421 if (idx_device != PA_INVALID_INDEX)
4422 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4424 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4426 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4428 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4429 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4433 pa_source_output *so = NULL;
4436 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4438 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4440 if (idx_device != PA_INVALID_INDEX)
4441 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4443 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4445 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4447 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4448 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4453 pa_pstream_send_simple_ack(c->pstream, tag);
4456 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4457 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4458 uint32_t idx = PA_INVALID_INDEX;
4459 const char *name = NULL;
4462 pa_native_connection_assert_ref(c);
4465 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4466 pa_tagstruct_gets(t, &name) < 0 ||
4467 pa_tagstruct_get_boolean(t, &b) < 0 ||
4468 !pa_tagstruct_eof(t)) {
4473 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4474 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);
4475 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4476 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4477 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4479 if (command == PA_COMMAND_SUSPEND_SINK) {
4481 if (idx == PA_INVALID_INDEX && name && !*name) {
4483 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4485 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4486 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4490 pa_sink *sink = NULL;
4492 if (idx != PA_INVALID_INDEX)
4493 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4495 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4497 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4499 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4500 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4506 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4508 if (idx == PA_INVALID_INDEX && name && !*name) {
4510 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4512 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4513 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4520 if (idx != PA_INVALID_INDEX)
4521 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4523 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4525 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4527 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4528 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4534 pa_pstream_send_simple_ack(c->pstream, tag);
4537 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4538 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4539 uint32_t idx = PA_INVALID_INDEX;
4540 const char *name = NULL;
4542 pa_native_protocol_ext_cb_t cb;
4544 pa_native_connection_assert_ref(c);
4547 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4548 pa_tagstruct_gets(t, &name) < 0) {
4553 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4554 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4555 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4556 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4557 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4559 if (idx != PA_INVALID_INDEX)
4560 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4562 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4563 if (strcmp(name, m->name) == 0)
4567 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4568 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4570 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4571 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4573 if (cb(c->protocol, m, c, tag, t) < 0)
4577 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4578 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4579 uint32_t idx = PA_INVALID_INDEX;
4580 const char *name = NULL, *profile = NULL;
4581 pa_card *card = NULL;
4584 pa_native_connection_assert_ref(c);
4587 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4588 pa_tagstruct_gets(t, &name) < 0 ||
4589 pa_tagstruct_gets(t, &profile) < 0 ||
4590 !pa_tagstruct_eof(t)) {
4595 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4596 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4597 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4598 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4599 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4601 if (idx != PA_INVALID_INDEX)
4602 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4604 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4606 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4608 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4609 pa_pstream_send_error(c->pstream, tag, -ret);
4613 pa_pstream_send_simple_ack(c->pstream, tag);
4616 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4617 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4618 uint32_t idx = PA_INVALID_INDEX;
4619 const char *name = NULL, *port = NULL;
4622 pa_native_connection_assert_ref(c);
4625 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4626 pa_tagstruct_gets(t, &name) < 0 ||
4627 pa_tagstruct_gets(t, &port) < 0 ||
4628 !pa_tagstruct_eof(t)) {
4633 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4634 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);
4635 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4636 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4637 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4639 if (command == PA_COMMAND_SET_SINK_PORT) {
4642 if (idx != PA_INVALID_INDEX)
4643 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4645 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4647 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4649 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4650 pa_pstream_send_error(c->pstream, tag, -ret);
4656 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4658 if (idx != PA_INVALID_INDEX)
4659 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4661 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4663 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4665 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4666 pa_pstream_send_error(c->pstream, tag, -ret);
4671 pa_pstream_send_simple_ack(c->pstream, tag);
4674 /*** pstream callbacks ***/
4676 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4677 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4681 pa_native_connection_assert_ref(c);
4683 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4684 pa_log("invalid packet.");
4685 native_connection_unlink(c);
4689 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) {
4690 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4691 output_stream *stream;
4695 pa_native_connection_assert_ref(c);
4697 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4698 pa_log_debug("Client sent block for invalid stream.");
4703 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4705 if (playback_stream_isinstance(stream)) {
4706 playback_stream *ps = PLAYBACK_STREAM(stream);
4708 pa_atomic_inc(&ps->seek_or_post_in_queue);
4709 if (chunk->memblock) {
4710 if (seek != PA_SEEK_RELATIVE || offset != 0)
4711 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);
4713 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4715 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);
4718 upload_stream *u = UPLOAD_STREAM(stream);
4721 if (!u->memchunk.memblock) {
4722 if (u->length == chunk->length && chunk->memblock) {
4723 u->memchunk = *chunk;
4724 pa_memblock_ref(u->memchunk.memblock);
4727 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4728 u->memchunk.index = u->memchunk.length = 0;
4732 pa_assert(u->memchunk.memblock);
4735 if (l > chunk->length)
4740 dst = pa_memblock_acquire(u->memchunk.memblock);
4742 if (chunk->memblock) {
4744 src = pa_memblock_acquire(chunk->memblock);
4746 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4747 (uint8_t*) src + chunk->index, l);
4749 pa_memblock_release(chunk->memblock);
4751 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4753 pa_memblock_release(u->memchunk.memblock);
4755 u->memchunk.length += l;
4761 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4762 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4765 pa_native_connection_assert_ref(c);
4767 native_connection_unlink(c);
4768 pa_log_info("Connection died.");
4771 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4772 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4775 pa_native_connection_assert_ref(c);
4777 native_connection_send_memblock(c);
4780 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4783 if (!(q = pa_thread_mq_get()))
4784 pa_pstream_send_revoke(p, block_id);
4786 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4789 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4792 if (!(q = pa_thread_mq_get()))
4793 pa_pstream_send_release(p, block_id);
4795 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4798 /*** client callbacks ***/
4800 static void client_kill_cb(pa_client *c) {
4803 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4804 pa_log_info("Connection killed.");
4807 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4809 pa_native_connection *c;
4812 c = PA_NATIVE_CONNECTION(client->userdata);
4813 pa_native_connection_assert_ref(c);
4815 if (c->version < 15)
4818 t = pa_tagstruct_new(NULL, 0);
4819 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4820 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4821 pa_tagstruct_puts(t, event);
4822 pa_tagstruct_put_proplist(t, pl);
4823 pa_pstream_send_tagstruct(c->pstream, t);
4826 /*** module entry points ***/
4828 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4829 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4832 pa_native_connection_assert_ref(c);
4833 pa_assert(c->auth_timeout_event == e);
4835 if (!c->authorized) {
4836 native_connection_unlink(c);
4837 pa_log_info("Connection terminated due to authentication timeout.");
4841 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4842 pa_native_connection *c;
4845 pa_client_new_data data;
4851 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4852 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4853 pa_iochannel_free(io);
4857 pa_client_new_data_init(&data);
4858 data.module = o->module;
4859 data.driver = __FILE__;
4860 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4861 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4862 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4863 client = pa_client_new(p->core, &data);
4864 pa_client_new_data_done(&data);
4869 c = pa_msgobject_new(pa_native_connection);
4870 c->parent.parent.free = native_connection_free;
4871 c->parent.process_msg = native_connection_process_msg;
4873 c->options = pa_native_options_ref(o);
4874 c->authorized = FALSE;
4876 if (o->auth_anonymous) {
4877 pa_log_info("Client authenticated anonymously.");
4878 c->authorized = TRUE;
4881 if (!c->authorized &&
4883 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4885 pa_log_info("Client authenticated by IP ACL.");
4886 c->authorized = TRUE;
4890 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4892 c->auth_timeout_event = NULL;
4894 c->is_local = pa_iochannel_socket_is_local(io);
4898 c->client->kill = client_kill_cb;
4899 c->client->send_event = client_send_event_cb;
4900 c->client->userdata = c;
4902 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4903 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4904 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4905 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4906 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4907 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4908 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4910 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4912 c->record_streams = pa_idxset_new(NULL, NULL);
4913 c->output_streams = pa_idxset_new(NULL, NULL);
4915 c->rrobin_index = PA_IDXSET_INVALID;
4916 c->subscription = NULL;
4918 pa_idxset_put(p->connections, c, NULL);
4921 if (pa_iochannel_creds_supported(io))
4922 pa_iochannel_creds_enable(io);
4925 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4928 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4929 pa_native_connection *c;
4935 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4936 if (c->options->module == m)
4937 native_connection_unlink(c);
4940 static pa_native_protocol* native_protocol_new(pa_core *c) {
4941 pa_native_protocol *p;
4946 p = pa_xnew(pa_native_protocol, 1);
4949 p->connections = pa_idxset_new(NULL, NULL);
4953 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4955 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4956 pa_hook_init(&p->hooks[h], p);
4958 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4963 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4964 pa_native_protocol *p;
4966 if ((p = pa_shared_get(c, "native-protocol")))
4967 return pa_native_protocol_ref(p);
4969 return native_protocol_new(c);
4972 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4974 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4981 void pa_native_protocol_unref(pa_native_protocol *p) {
4982 pa_native_connection *c;
4986 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4988 if (PA_REFCNT_DEC(p) > 0)
4991 while ((c = pa_idxset_first(p->connections, NULL)))
4992 native_connection_unlink(c);
4994 pa_idxset_free(p->connections, NULL, NULL);
4996 pa_strlist_free(p->servers);
4998 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4999 pa_hook_done(&p->hooks[h]);
5001 pa_hashmap_free(p->extensions, NULL, NULL);
5003 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
5008 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
5010 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5013 p->servers = pa_strlist_prepend(p->servers, name);
5015 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5018 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
5020 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5023 p->servers = pa_strlist_remove(p->servers, name);
5025 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5028 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
5030 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5035 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
5037 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5042 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
5044 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5047 pa_assert(!pa_hashmap_get(p->extensions, m));
5049 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
5053 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
5055 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5058 pa_assert_se(pa_hashmap_remove(p->extensions, m));
5061 pa_native_options* pa_native_options_new(void) {
5062 pa_native_options *o;
5064 o = pa_xnew0(pa_native_options, 1);
5070 pa_native_options* pa_native_options_ref(pa_native_options *o) {
5072 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5079 void pa_native_options_unref(pa_native_options *o) {
5081 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5083 if (PA_REFCNT_DEC(o) > 0)
5086 pa_xfree(o->auth_group);
5089 pa_ip_acl_free(o->auth_ip_acl);
5092 pa_auth_cookie_unref(o->auth_cookie);
5097 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
5102 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5105 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
5106 pa_log("auth-anonymous= expects a boolean argument.");
5111 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
5112 pa_log("auth-group-enabled= expects a boolean argument.");
5116 pa_xfree(o->auth_group);
5117 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
5121 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5124 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
5127 if (!(ipa = pa_ip_acl_new(acl))) {
5128 pa_log("Failed to parse IP ACL '%s'", acl);
5133 pa_ip_acl_free(o->auth_ip_acl);
5135 o->auth_ip_acl = ipa;
5139 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
5140 pa_log("auth-cookie-enabled= expects a boolean argument.");
5145 pa_auth_cookie_unref(o->auth_cookie);
5150 /* The new name for this is 'auth-cookie', for compat reasons
5151 * we check the old name too */
5152 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
5153 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
5154 cn = PA_NATIVE_COOKIE_FILE;
5156 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
5160 o->auth_cookie = NULL;
5165 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
5166 pa_native_connection_assert_ref(c);
5171 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
5172 pa_native_connection_assert_ref(c);