2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
32 #include <pulse/timeval.h>
33 #include <pulse/version.h>
34 #include <pulse/utf8.h>
35 #include <pulse/util.h>
36 #include <pulse/xmalloc.h>
38 #include <pulsecore/native-common.h>
39 #include <pulsecore/packet.h>
40 #include <pulsecore/client.h>
41 #include <pulsecore/source-output.h>
42 #include <pulsecore/sink-input.h>
43 #include <pulsecore/pstream.h>
44 #include <pulsecore/tagstruct.h>
45 #include <pulsecore/pdispatch.h>
46 #include <pulsecore/pstream-util.h>
47 #include <pulsecore/authkey.h>
48 #include <pulsecore/namereg.h>
49 #include <pulsecore/core-scache.h>
50 #include <pulsecore/core-subscribe.h>
51 #include <pulsecore/log.h>
52 #include <pulsecore/strlist.h>
53 #include <pulsecore/shared.h>
54 #include <pulsecore/sample-util.h>
55 #include <pulsecore/llist.h>
56 #include <pulsecore/creds.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/ipacl.h>
59 #include <pulsecore/thread-mq.h>
61 #include "protocol-native.h"
63 /* Kick a client if it doesn't authenticate within this time */
64 #define AUTH_TIMEOUT 60
66 /* Don't accept more connection than this */
67 #define MAX_CONNECTIONS 64
69 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
70 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
71 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
72 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
74 struct pa_native_protocol;
76 typedef struct record_stream {
79 pa_native_connection *connection;
82 pa_source_output *source_output;
83 pa_memblockq *memblockq;
85 pa_bool_t adjust_latency:1;
86 pa_bool_t early_requests:1;
88 pa_buffer_attr buffer_attr;
89 pa_usec_t source_latency;
92 PA_DECLARE_CLASS(record_stream);
93 #define RECORD_STREAM(o) (record_stream_cast(o))
94 static PA_DEFINE_CHECK_TYPE(record_stream, pa_msgobject);
96 typedef struct output_stream {
100 PA_DECLARE_CLASS(output_stream);
101 #define OUTPUT_STREAM(o) (output_stream_cast(o))
102 static PA_DEFINE_CHECK_TYPE(output_stream, pa_msgobject);
104 typedef struct playback_stream {
105 output_stream parent;
107 pa_native_connection *connection;
110 pa_sink_input *sink_input;
111 pa_memblockq *memblockq;
113 pa_bool_t adjust_latency:1;
114 pa_bool_t early_requests:1;
116 pa_bool_t is_underrun:1;
117 pa_bool_t drain_request:1;
122 pa_usec_t sink_latency;
123 pa_buffer_attr buffer_attr;
125 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
126 int64_t read_index, write_index;
127 size_t render_memblockq_length;
130 PA_DECLARE_CLASS(playback_stream);
131 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
132 static PA_DEFINE_CHECK_TYPE(playback_stream, output_stream);
134 typedef struct upload_stream {
135 output_stream parent;
137 pa_native_connection *connection;
140 pa_memchunk memchunk;
143 pa_sample_spec sample_spec;
144 pa_channel_map channel_map;
145 pa_proplist *proplist;
148 PA_DECLARE_CLASS(upload_stream);
149 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
150 static PA_DEFINE_CHECK_TYPE(upload_stream, output_stream);
152 struct pa_native_connection {
154 pa_native_protocol *protocol;
155 pa_native_options *options;
156 pa_bool_t authorized:1;
157 pa_bool_t is_local:1;
161 pa_pdispatch *pdispatch;
162 pa_idxset *record_streams, *output_streams;
163 uint32_t rrobin_index;
164 pa_subscription *subscription;
165 pa_time_event *auth_timeout_event;
168 PA_DECLARE_CLASS(pa_native_connection);
169 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
170 static PA_DEFINE_CHECK_TYPE(pa_native_connection, pa_msgobject);
172 struct pa_native_protocol {
176 pa_idxset *connections;
179 pa_hook hooks[PA_NATIVE_HOOK_MAX];
181 pa_hashmap *extensions;
185 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
186 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
187 SINK_INPUT_MESSAGE_FLUSH,
188 SINK_INPUT_MESSAGE_TRIGGER,
189 SINK_INPUT_MESSAGE_SEEK,
190 SINK_INPUT_MESSAGE_PREBUF_FORCE,
191 SINK_INPUT_MESSAGE_UPDATE_LATENCY,
192 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
196 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
197 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
198 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
199 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
200 PLAYBACK_STREAM_MESSAGE_STARTED,
201 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
205 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
209 CONNECTION_MESSAGE_RELEASE,
210 CONNECTION_MESSAGE_REVOKE
213 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
214 static void sink_input_kill_cb(pa_sink_input *i);
215 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
216 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
217 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
218 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
219 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
220 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
222 static void native_connection_send_memblock(pa_native_connection *c);
223 static void playback_stream_request_bytes(struct playback_stream*s);
225 static void source_output_kill_cb(pa_source_output *o);
226 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
227 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend);
228 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
229 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
230 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
232 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
234 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
235 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
236 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
237 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
238 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
239 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
240 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
241 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
242 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
243 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
244 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
245 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
246 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
247 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
248 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
249 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
250 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
251 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
252 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
253 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
254 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
255 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
256 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
257 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
258 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
259 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
260 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
261 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
262 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
263 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
264 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
265 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
266 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
267 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
268 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
269 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
270 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
271 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
273 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
274 [PA_COMMAND_ERROR] = NULL,
275 [PA_COMMAND_TIMEOUT] = NULL,
276 [PA_COMMAND_REPLY] = NULL,
277 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
278 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
279 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
280 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
281 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
282 [PA_COMMAND_AUTH] = command_auth,
283 [PA_COMMAND_REQUEST] = NULL,
284 [PA_COMMAND_EXIT] = command_exit,
285 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
286 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
287 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
288 [PA_COMMAND_STAT] = command_stat,
289 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
290 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
291 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
292 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
293 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
294 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
295 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
296 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
297 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
298 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
299 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
300 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
301 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
302 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
303 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
304 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
305 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
306 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
307 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
308 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
309 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
310 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
311 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
312 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
313 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
315 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
316 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
317 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
319 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
320 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
321 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
323 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
324 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
326 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
327 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
328 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
329 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
331 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
332 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
334 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
335 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
336 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
337 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
338 [PA_COMMAND_KILL_CLIENT] = command_kill,
339 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
340 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
341 [PA_COMMAND_LOAD_MODULE] = command_load_module,
342 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
344 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
345 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
346 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
347 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
349 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
350 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
352 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
353 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
355 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
356 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
358 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
359 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
360 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
362 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
363 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
364 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
366 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
368 [PA_COMMAND_EXTENSION] = command_extension
371 /* structure management */
373 /* Called from main context */
374 static void upload_stream_unlink(upload_stream *s) {
380 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
381 s->connection = NULL;
382 upload_stream_unref(s);
385 /* Called from main context */
386 static void upload_stream_free(pa_object *o) {
387 upload_stream *s = UPLOAD_STREAM(o);
390 upload_stream_unlink(s);
395 pa_proplist_free(s->proplist);
397 if (s->memchunk.memblock)
398 pa_memblock_unref(s->memchunk.memblock);
403 /* Called from main context */
404 static upload_stream* upload_stream_new(
405 pa_native_connection *c,
406 const pa_sample_spec *ss,
407 const pa_channel_map *map,
417 pa_assert(length > 0);
420 s = pa_msgobject_new(upload_stream);
421 s->parent.parent.parent.free = upload_stream_free;
423 s->sample_spec = *ss;
424 s->channel_map = *map;
425 s->name = pa_xstrdup(name);
426 pa_memchunk_reset(&s->memchunk);
428 s->proplist = pa_proplist_copy(p);
429 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
431 pa_idxset_put(c->output_streams, s, &s->index);
436 /* Called from main context */
437 static void record_stream_unlink(record_stream *s) {
443 if (s->source_output) {
444 pa_source_output_unlink(s->source_output);
445 pa_source_output_unref(s->source_output);
446 s->source_output = NULL;
449 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
450 s->connection = NULL;
451 record_stream_unref(s);
454 /* Called from main context */
455 static void record_stream_free(pa_object *o) {
456 record_stream *s = RECORD_STREAM(o);
459 record_stream_unlink(s);
461 pa_memblockq_free(s->memblockq);
465 /* Called from main context */
466 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
467 record_stream *s = RECORD_STREAM(o);
468 record_stream_assert_ref(s);
475 case RECORD_STREAM_MESSAGE_POST_DATA:
477 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
478 /* pa_log_warn("Failed to push data into output queue."); */
482 if (!pa_pstream_is_pending(s->connection->pstream))
483 native_connection_send_memblock(s->connection);
491 /* Called from main context */
492 static void fix_record_buffer_attr_pre(record_stream *s) {
495 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
499 /* This function will be called from the main thread, before as
500 * well as after the source output has been activated using
501 * pa_source_output_put()! That means it may not touch any
502 * ->thread_info data! */
504 frame_size = pa_frame_size(&s->source_output->sample_spec);
506 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
507 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
508 if (s->buffer_attr.maxlength <= 0)
509 s->buffer_attr.maxlength = (uint32_t) frame_size;
511 if (s->buffer_attr.fragsize == (uint32_t) -1)
512 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
513 if (s->buffer_attr.fragsize <= 0)
514 s->buffer_attr.fragsize = (uint32_t) frame_size;
516 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
518 if (s->early_requests) {
520 /* In early request mode we need to emulate the classic
521 * fragment-based playback model. We do this setting the source
522 * latency to the fragment size. */
524 source_usec = fragsize_usec;
526 } else if (s->adjust_latency) {
528 /* So, the user asked us to adjust the latency according to
529 * what the source can provide. Half the latency will be
530 * spent on the hw buffer, half of it in the async buffer
531 * queue we maintain for each client. */
533 source_usec = fragsize_usec/2;
537 /* Ok, the user didn't ask us to adjust the latency, hence we
544 s->source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
546 s->source_latency = 0;
548 if (s->early_requests) {
550 /* Ok, we didn't necessarily get what we were asking for, so
551 * let's tell the user */
553 fragsize_usec = s->source_latency;
555 } else if (s->adjust_latency) {
557 /* Now subtract what we actually got */
559 if (fragsize_usec >= s->source_latency*2)
560 fragsize_usec -= s->source_latency;
562 fragsize_usec = s->source_latency;
565 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
566 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
568 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
570 if (s->buffer_attr.fragsize <= 0)
571 s->buffer_attr.fragsize = (uint32_t) frame_size;
574 /* Called from main context */
575 static void fix_record_buffer_attr_post(record_stream *s) {
580 /* This function will be called from the main thread, before as
581 * well as after the source output has been activated using
582 * pa_source_output_put()! That means it may not touch and
583 * ->thread_info data! */
585 base = pa_frame_size(&s->source_output->sample_spec);
587 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
588 if (s->buffer_attr.fragsize <= 0)
589 s->buffer_attr.fragsize = base;
591 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
592 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
595 /* Called from main context */
596 static record_stream* record_stream_new(
597 pa_native_connection *c,
601 pa_bool_t peak_detect,
602 pa_buffer_attr *attr,
603 pa_source_output_flags_t flags,
605 pa_bool_t adjust_latency,
606 pa_sink_input *direct_on_input,
607 pa_bool_t early_requests,
611 pa_source_output *source_output = NULL;
613 pa_source_output_new_data data;
620 pa_source_output_new_data_init(&data);
622 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
623 data.driver = __FILE__;
624 data.module = c->options->module;
625 data.client = c->client;
626 data.source = source;
627 data.direct_on_input = direct_on_input;
628 pa_source_output_new_data_set_sample_spec(&data, ss);
629 pa_source_output_new_data_set_channel_map(&data, map);
631 data.resample_method = PA_RESAMPLER_PEAKS;
633 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data, flags);
635 pa_source_output_new_data_done(&data);
640 s = pa_msgobject_new(record_stream);
641 s->parent.parent.free = record_stream_free;
642 s->parent.process_msg = record_stream_process_msg;
644 s->source_output = source_output;
645 s->buffer_attr = *attr;
646 s->adjust_latency = adjust_latency;
647 s->early_requests = early_requests;
649 s->source_output->push = source_output_push_cb;
650 s->source_output->kill = source_output_kill_cb;
651 s->source_output->get_latency = source_output_get_latency_cb;
652 s->source_output->moving = source_output_moving_cb;
653 s->source_output->suspend = source_output_suspend_cb;
654 s->source_output->send_event = source_output_send_event_cb;
655 s->source_output->userdata = s;
657 fix_record_buffer_attr_pre(s);
659 s->memblockq = pa_memblockq_new(
661 s->buffer_attr.maxlength,
663 base = pa_frame_size(&source_output->sample_spec),
669 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
670 fix_record_buffer_attr_post(s);
672 *ss = s->source_output->sample_spec;
673 *map = s->source_output->channel_map;
675 pa_idxset_put(c->record_streams, s, &s->index);
677 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
678 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->source_latency) / PA_USEC_PER_MSEC,
679 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
680 (double) s->source_latency / PA_USEC_PER_MSEC);
682 pa_source_output_put(s->source_output);
686 /* Called from main context */
687 static void record_stream_send_killed(record_stream *r) {
689 record_stream_assert_ref(r);
691 t = pa_tagstruct_new(NULL, 0);
692 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
693 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
694 pa_tagstruct_putu32(t, r->index);
695 pa_pstream_send_tagstruct(r->connection->pstream, t);
698 /* Called from main context */
699 static void playback_stream_unlink(playback_stream *s) {
706 pa_sink_input_unlink(s->sink_input);
707 pa_sink_input_unref(s->sink_input);
708 s->sink_input = NULL;
711 if (s->drain_request)
712 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
714 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
715 s->connection = NULL;
716 playback_stream_unref(s);
719 /* Called from main context */
720 static void playback_stream_free(pa_object* o) {
721 playback_stream *s = PLAYBACK_STREAM(o);
724 playback_stream_unlink(s);
726 pa_memblockq_free(s->memblockq);
730 /* Called from main context */
731 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
732 playback_stream *s = PLAYBACK_STREAM(o);
733 playback_stream_assert_ref(s);
739 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
744 if ((l = (uint32_t) pa_atomic_load(&s->missing)) <= 0)
747 if (pa_atomic_cmpxchg(&s->missing, (int) l, 0))
754 t = pa_tagstruct_new(NULL, 0);
755 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
756 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
757 pa_tagstruct_putu32(t, s->index);
758 pa_tagstruct_putu32(t, l);
759 pa_pstream_send_tagstruct(s->connection->pstream, t);
761 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
765 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
768 /* pa_log("signalling underflow"); */
770 /* Report that we're empty */
771 t = pa_tagstruct_new(NULL, 0);
772 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
773 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
774 pa_tagstruct_putu32(t, s->index);
775 pa_pstream_send_tagstruct(s->connection->pstream, t);
779 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
782 /* Notify the user we're overflowed*/
783 t = pa_tagstruct_new(NULL, 0);
784 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
785 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
786 pa_tagstruct_putu32(t, s->index);
787 pa_pstream_send_tagstruct(s->connection->pstream, t);
791 case PLAYBACK_STREAM_MESSAGE_STARTED:
793 if (s->connection->version >= 13) {
796 /* Notify the user we started playback */
797 t = pa_tagstruct_new(NULL, 0);
798 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
799 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
800 pa_tagstruct_putu32(t, s->index);
801 pa_pstream_send_tagstruct(s->connection->pstream, t);
806 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
807 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
810 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH: {
813 s->buffer_attr.tlength = (uint32_t) offset;
815 t = pa_tagstruct_new(NULL, 0);
816 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
817 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
818 pa_tagstruct_putu32(t, s->index);
819 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
820 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
821 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
822 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
823 pa_tagstruct_put_usec(t, s->sink_latency);
824 pa_pstream_send_tagstruct(s->connection->pstream, t);
833 /* Called from main context */
834 static void fix_playback_buffer_attr(playback_stream *s) {
836 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
840 /* This function will be called from the main thread, before as
841 * well as after the sink input has been activated using
842 * pa_sink_input_put()! That means it may not touch any
843 * ->thread_info data, such as the memblockq! */
845 frame_size = pa_frame_size(&s->sink_input->sample_spec);
847 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
848 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
849 if (s->buffer_attr.maxlength <= 0)
850 s->buffer_attr.maxlength = (uint32_t) frame_size;
852 if (s->buffer_attr.tlength == (uint32_t) -1)
853 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
854 if (s->buffer_attr.tlength <= 0)
855 s->buffer_attr.tlength = (uint32_t) frame_size;
857 if (s->buffer_attr.minreq == (uint32_t) -1)
858 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
859 if (s->buffer_attr.minreq <= 0)
860 s->buffer_attr.minreq = (uint32_t) frame_size;
862 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
863 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
865 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
866 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
868 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
869 (double) tlength_usec / PA_USEC_PER_MSEC,
870 (double) minreq_usec / PA_USEC_PER_MSEC);
872 if (s->early_requests) {
874 /* In early request mode we need to emulate the classic
875 * fragment-based playback model. We do this setting the sink
876 * latency to the fragment size. */
878 sink_usec = minreq_usec;
879 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
881 } else if (s->adjust_latency) {
883 /* So, the user asked us to adjust the latency of the stream
884 * buffer according to the what the sink can provide. The
885 * tlength passed in shall be the overall latency. Roughly
886 * half the latency will be spent on the hw buffer, the other
887 * half of it in the async buffer queue we maintain for each
888 * client. In between we'll have a safety space of size
889 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
890 * empty and needs to be filled, then our buffer must have
891 * enough data to fulfill this request immediatly and thus
892 * have at least the same tlength as the size of the hw
893 * buffer. It additionally needs space for 2 times minreq
894 * because if the buffer ran empty and a partial fillup
895 * happens immediately on the next iteration we need to be
896 * able to fulfill it and give the application also minreq
897 * time to fill it up again for the next request Makes 2 times
898 * minreq in plus.. */
900 if (tlength_usec > minreq_usec*2)
901 sink_usec = (tlength_usec - minreq_usec*2)/2;
905 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
909 /* Ok, the user didn't ask us to adjust the latency, but we
910 * still need to make sure that the parameters from the user
913 if (tlength_usec > minreq_usec*2)
914 sink_usec = (tlength_usec - minreq_usec*2);
918 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
921 s->sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
923 if (s->early_requests) {
925 /* Ok, we didn't necessarily get what we were asking for, so
926 * let's tell the user */
928 minreq_usec = s->sink_latency;
930 } else if (s->adjust_latency) {
932 /* Ok, we didn't necessarily get what we were asking for, so
933 * let's subtract from what we asked for for the remaining
936 if (tlength_usec >= s->sink_latency)
937 tlength_usec -= s->sink_latency;
940 /* FIXME: This is actually larger than necessary, since not all of
941 * the sink latency is actually rewritable. */
942 if (tlength_usec < s->sink_latency + 2*minreq_usec)
943 tlength_usec = s->sink_latency + 2*minreq_usec;
945 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
946 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
947 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
949 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
950 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
951 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
953 if (s->buffer_attr.minreq <= 0) {
954 s->buffer_attr.minreq = (uint32_t) frame_size;
955 s->buffer_attr.tlength += (uint32_t) frame_size*2;
958 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
959 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
961 if (s->buffer_attr.prebuf == (uint32_t) -1 || s->buffer_attr.prebuf > s->buffer_attr.tlength)
962 s->buffer_attr.prebuf = s->buffer_attr.tlength;
965 /* Called from main context */
966 static playback_stream* playback_stream_new(
967 pa_native_connection *c,
977 pa_sink_input_flags_t flags,
979 pa_bool_t adjust_latency,
980 pa_bool_t early_requests,
983 playback_stream *s, *ssync;
984 pa_sink_input *sink_input = NULL;
988 pa_sink_input_new_data data;
996 /* Find syncid group */
997 for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) {
999 if (!playback_stream_isinstance(ssync))
1002 if (ssync->syncid == syncid)
1006 /* Synced streams must connect to the same sink */
1010 sink = ssync->sink_input->sink;
1011 else if (sink != ssync->sink_input->sink) {
1012 *ret = PA_ERR_INVALID;
1017 pa_sink_input_new_data_init(&data);
1019 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1020 data.driver = __FILE__;
1021 data.module = c->options->module;
1022 data.client = c->client;
1024 pa_sink_input_new_data_set_sample_spec(&data, ss);
1025 pa_sink_input_new_data_set_channel_map(&data, map);
1027 pa_sink_input_new_data_set_volume(&data, volume);
1029 pa_sink_input_new_data_set_muted(&data, muted);
1030 data.sync_base = ssync ? ssync->sink_input : NULL;
1032 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data, flags);
1034 pa_sink_input_new_data_done(&data);
1039 s = pa_msgobject_new(playback_stream);
1040 s->parent.parent.parent.free = playback_stream_free;
1041 s->parent.parent.process_msg = playback_stream_process_msg;
1044 s->sink_input = sink_input;
1045 s->is_underrun = TRUE;
1046 s->drain_request = FALSE;
1047 pa_atomic_store(&s->missing, 0);
1048 s->buffer_attr = *a;
1049 s->adjust_latency = adjust_latency;
1050 s->early_requests = early_requests;
1052 s->sink_input->parent.process_msg = sink_input_process_msg;
1053 s->sink_input->pop = sink_input_pop_cb;
1054 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1055 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1056 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1057 s->sink_input->kill = sink_input_kill_cb;
1058 s->sink_input->moving = sink_input_moving_cb;
1059 s->sink_input->suspend = sink_input_suspend_cb;
1060 s->sink_input->send_event = sink_input_send_event_cb;
1061 s->sink_input->userdata = s;
1063 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1065 fix_playback_buffer_attr(s);
1067 pa_sink_input_get_silence(sink_input, &silence);
1068 s->memblockq = pa_memblockq_new(
1070 s->buffer_attr.maxlength,
1071 s->buffer_attr.tlength,
1072 pa_frame_size(&sink_input->sample_spec),
1073 s->buffer_attr.prebuf,
1074 s->buffer_attr.minreq,
1077 pa_memblock_unref(silence.memblock);
1079 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1081 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1083 *ss = s->sink_input->sample_spec;
1084 *map = s->sink_input->channel_map;
1086 pa_idxset_put(c->output_streams, s, &s->index);
1088 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1089 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->sink_latency) / PA_USEC_PER_MSEC,
1090 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1091 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1092 (double) s->sink_latency / PA_USEC_PER_MSEC);
1094 pa_sink_input_put(s->sink_input);
1098 /* Called from IO context */
1099 static void playback_stream_request_bytes(playback_stream *s) {
1100 size_t m, previous_missing, minreq;
1102 playback_stream_assert_ref(s);
1104 m = pa_memblockq_pop_missing(s->memblockq);
1109 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1111 previous_missing = (size_t) pa_atomic_add(&s->missing, (int) m);
1112 minreq = pa_memblockq_get_minreq(s->memblockq);
1114 if (pa_memblockq_prebuf_active(s->memblockq) ||
1115 (previous_missing < minreq && previous_missing+m >= minreq))
1116 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1120 /* Called from main context */
1121 static void playback_stream_send_killed(playback_stream *p) {
1123 playback_stream_assert_ref(p);
1125 t = pa_tagstruct_new(NULL, 0);
1126 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1127 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1128 pa_tagstruct_putu32(t, p->index);
1129 pa_pstream_send_tagstruct(p->connection->pstream, t);
1132 /* Called from main context */
1133 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1134 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1135 pa_native_connection_assert_ref(c);
1142 case CONNECTION_MESSAGE_REVOKE:
1143 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1146 case CONNECTION_MESSAGE_RELEASE:
1147 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1154 /* Called from main context */
1155 static void native_connection_unlink(pa_native_connection *c) {
1164 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1167 pa_native_options_unref(c->options);
1169 while ((r = pa_idxset_first(c->record_streams, NULL)))
1170 record_stream_unlink(r);
1172 while ((o = pa_idxset_first(c->output_streams, NULL)))
1173 if (playback_stream_isinstance(o))
1174 playback_stream_unlink(PLAYBACK_STREAM(o));
1176 upload_stream_unlink(UPLOAD_STREAM(o));
1178 if (c->subscription)
1179 pa_subscription_free(c->subscription);
1182 pa_pstream_unlink(c->pstream);
1184 if (c->auth_timeout_event) {
1185 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1186 c->auth_timeout_event = NULL;
1189 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1191 pa_native_connection_unref(c);
1194 /* Called from main context */
1195 static void native_connection_free(pa_object *o) {
1196 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1200 native_connection_unlink(c);
1202 pa_idxset_free(c->record_streams, NULL, NULL);
1203 pa_idxset_free(c->output_streams, NULL, NULL);
1205 pa_pdispatch_unref(c->pdispatch);
1206 pa_pstream_unref(c->pstream);
1207 pa_client_free(c->client);
1212 /* Called from main context */
1213 static void native_connection_send_memblock(pa_native_connection *c) {
1217 start = PA_IDXSET_INVALID;
1221 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1224 if (start == PA_IDXSET_INVALID)
1225 start = c->rrobin_index;
1226 else if (start == c->rrobin_index)
1229 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1230 pa_memchunk schunk = chunk;
1232 if (schunk.length > r->buffer_attr.fragsize)
1233 schunk.length = r->buffer_attr.fragsize;
1235 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1237 pa_memblockq_drop(r->memblockq, schunk.length);
1238 pa_memblock_unref(schunk.memblock);
1245 /*** sink input callbacks ***/
1247 /* Called from thread context */
1248 static void handle_seek(playback_stream *s, int64_t indexw) {
1249 playback_stream_assert_ref(s);
1251 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1253 if (s->sink_input->thread_info.underrun_for > 0) {
1255 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1257 if (pa_memblockq_is_readable(s->memblockq)) {
1259 /* We just ended an underrun, let's ask the sink
1260 * for a complete rewind rewrite */
1262 pa_log_debug("Requesting rewind due to end of underrun.");
1263 pa_sink_input_request_rewind(s->sink_input,
1264 (size_t) (s->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : s->sink_input->thread_info.underrun_for),
1265 FALSE, TRUE, FALSE);
1271 indexr = pa_memblockq_get_read_index(s->memblockq);
1273 if (indexw < indexr) {
1274 /* OK, the sink already asked for this data, so
1275 * let's have it usk us again */
1277 pa_log_debug("Requesting rewind due to rewrite.");
1278 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1282 playback_stream_request_bytes(s);
1285 /* Called from thread context */
1286 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1287 pa_sink_input *i = PA_SINK_INPUT(o);
1290 pa_sink_input_assert_ref(i);
1291 s = PLAYBACK_STREAM(i->userdata);
1292 playback_stream_assert_ref(s);
1296 case SINK_INPUT_MESSAGE_SEEK: {
1299 windex = pa_memblockq_get_write_index(s->memblockq);
1300 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata));
1302 handle_seek(s, windex);
1306 case SINK_INPUT_MESSAGE_POST_DATA: {
1311 windex = pa_memblockq_get_write_index(s->memblockq);
1313 /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
1315 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1316 pa_log_warn("Failed to push data into queue");
1317 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1318 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE);
1321 handle_seek(s, windex);
1323 /* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1328 case SINK_INPUT_MESSAGE_DRAIN:
1329 case SINK_INPUT_MESSAGE_FLUSH:
1330 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1331 case SINK_INPUT_MESSAGE_TRIGGER: {
1334 pa_sink_input *isync;
1335 void (*func)(pa_memblockq *bq);
1338 case SINK_INPUT_MESSAGE_FLUSH:
1339 func = pa_memblockq_flush_write;
1342 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1343 func = pa_memblockq_prebuf_force;
1346 case SINK_INPUT_MESSAGE_DRAIN:
1347 case SINK_INPUT_MESSAGE_TRIGGER:
1348 func = pa_memblockq_prebuf_disable;
1352 pa_assert_not_reached();
1355 windex = pa_memblockq_get_write_index(s->memblockq);
1357 handle_seek(s, windex);
1359 /* Do the same for all other members in the sync group */
1360 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1361 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1362 windex = pa_memblockq_get_write_index(ssync->memblockq);
1363 func(ssync->memblockq);
1364 handle_seek(ssync, windex);
1367 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1368 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1369 windex = pa_memblockq_get_write_index(ssync->memblockq);
1370 func(ssync->memblockq);
1371 handle_seek(ssync, windex);
1374 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1375 if (!pa_memblockq_is_readable(s->memblockq))
1376 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1378 s->drain_tag = PA_PTR_TO_UINT(userdata);
1379 s->drain_request = TRUE;
1386 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1388 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1389 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1390 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1393 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1396 windex = pa_memblockq_get_write_index(s->memblockq);
1398 pa_memblockq_prebuf_force(s->memblockq);
1400 handle_seek(s, windex);
1402 /* Fall through to the default handler */
1406 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1407 pa_usec_t *r = userdata;
1409 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1411 /* Fall through, the default handler will add in the extra
1412 * latency added by the resampler */
1416 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1417 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1418 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1423 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1426 /* Called from thread context */
1427 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1430 pa_sink_input_assert_ref(i);
1431 s = PLAYBACK_STREAM(i->userdata);
1432 playback_stream_assert_ref(s);
1435 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1437 if (pa_memblockq_is_readable(s->memblockq))
1438 s->is_underrun = FALSE;
1440 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));
1442 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1443 s->drain_request = FALSE;
1444 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);
1445 } else if (!s->is_underrun)
1446 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1448 s->is_underrun = TRUE;
1450 playback_stream_request_bytes(s);
1453 /* This call will not fail with prebuf=0, hence we check for
1454 underrun explicitly above */
1455 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1458 chunk->length = PA_MIN(nbytes, chunk->length);
1460 if (i->thread_info.underrun_for > 0)
1461 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1463 pa_memblockq_drop(s->memblockq, chunk->length);
1464 playback_stream_request_bytes(s);
1469 /* Called from thread context */
1470 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1473 pa_sink_input_assert_ref(i);
1474 s = PLAYBACK_STREAM(i->userdata);
1475 playback_stream_assert_ref(s);
1477 /* If we are in an underrun, then we don't rewind */
1478 if (i->thread_info.underrun_for > 0)
1481 pa_memblockq_rewind(s->memblockq, nbytes);
1484 /* Called from thread context */
1485 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1488 pa_sink_input_assert_ref(i);
1489 s = PLAYBACK_STREAM(i->userdata);
1490 playback_stream_assert_ref(s);
1492 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1495 /* Called from thread context */
1496 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1498 size_t new_tlength, old_tlength;
1500 pa_sink_input_assert_ref(i);
1501 s = PLAYBACK_STREAM(i->userdata);
1502 playback_stream_assert_ref(s);
1504 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1505 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1507 if (old_tlength < new_tlength) {
1508 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1509 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1510 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1512 if (new_tlength == old_tlength)
1513 pa_log_debug("Failed to increase tlength");
1515 pa_log_debug("Notifying client about increased tlength");
1516 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);
1521 /* Called from main context */
1522 static void sink_input_kill_cb(pa_sink_input *i) {
1525 pa_sink_input_assert_ref(i);
1526 s = PLAYBACK_STREAM(i->userdata);
1527 playback_stream_assert_ref(s);
1529 playback_stream_send_killed(s);
1530 playback_stream_unlink(s);
1533 /* Called from main context */
1534 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1538 pa_sink_input_assert_ref(i);
1539 s = PLAYBACK_STREAM(i->userdata);
1540 playback_stream_assert_ref(s);
1542 if (s->connection->version < 15)
1545 t = pa_tagstruct_new(NULL, 0);
1546 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1547 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1548 pa_tagstruct_putu32(t, s->index);
1549 pa_tagstruct_puts(t, event);
1550 pa_tagstruct_put_proplist(t, pl);
1551 pa_pstream_send_tagstruct(s->connection->pstream, t);
1554 /* Called from main context */
1555 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1559 pa_sink_input_assert_ref(i);
1560 s = PLAYBACK_STREAM(i->userdata);
1561 playback_stream_assert_ref(s);
1563 if (s->connection->version < 12)
1566 t = pa_tagstruct_new(NULL, 0);
1567 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1568 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1569 pa_tagstruct_putu32(t, s->index);
1570 pa_tagstruct_put_boolean(t, suspend);
1571 pa_pstream_send_tagstruct(s->connection->pstream, t);
1574 /* Called from main context */
1575 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1579 pa_sink_input_assert_ref(i);
1580 s = PLAYBACK_STREAM(i->userdata);
1581 playback_stream_assert_ref(s);
1583 fix_playback_buffer_attr(s);
1584 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1585 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1587 if (s->connection->version < 12)
1590 t = pa_tagstruct_new(NULL, 0);
1591 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1592 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1593 pa_tagstruct_putu32(t, s->index);
1594 pa_tagstruct_putu32(t, dest->index);
1595 pa_tagstruct_puts(t, dest->name);
1596 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1598 if (s->connection->version >= 13) {
1599 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1600 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1601 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1602 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1603 pa_tagstruct_put_usec(t, s->sink_latency);
1606 pa_pstream_send_tagstruct(s->connection->pstream, t);
1609 /*** source_output callbacks ***/
1611 /* Called from thread context */
1612 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1615 pa_source_output_assert_ref(o);
1616 s = RECORD_STREAM(o->userdata);
1617 record_stream_assert_ref(s);
1620 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1623 static void source_output_kill_cb(pa_source_output *o) {
1626 pa_source_output_assert_ref(o);
1627 s = RECORD_STREAM(o->userdata);
1628 record_stream_assert_ref(s);
1630 record_stream_send_killed(s);
1631 record_stream_unlink(s);
1634 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1637 pa_source_output_assert_ref(o);
1638 s = RECORD_STREAM(o->userdata);
1639 record_stream_assert_ref(s);
1641 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1643 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1646 /* Called from main context */
1647 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1651 pa_source_output_assert_ref(o);
1652 s = RECORD_STREAM(o->userdata);
1653 record_stream_assert_ref(s);
1655 if (s->connection->version < 15)
1658 t = pa_tagstruct_new(NULL, 0);
1659 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1660 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1661 pa_tagstruct_putu32(t, s->index);
1662 pa_tagstruct_puts(t, event);
1663 pa_tagstruct_put_proplist(t, pl);
1664 pa_pstream_send_tagstruct(s->connection->pstream, t);
1667 /* Called from main context */
1668 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1672 pa_source_output_assert_ref(o);
1673 s = RECORD_STREAM(o->userdata);
1674 record_stream_assert_ref(s);
1676 if (s->connection->version < 12)
1679 t = pa_tagstruct_new(NULL, 0);
1680 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1681 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1682 pa_tagstruct_putu32(t, s->index);
1683 pa_tagstruct_put_boolean(t, suspend);
1684 pa_pstream_send_tagstruct(s->connection->pstream, t);
1687 /* Called from main context */
1688 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1692 pa_source_output_assert_ref(o);
1693 s = RECORD_STREAM(o->userdata);
1694 record_stream_assert_ref(s);
1696 fix_record_buffer_attr_pre(s);
1697 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1698 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1699 fix_record_buffer_attr_post(s);
1701 if (s->connection->version < 12)
1704 t = pa_tagstruct_new(NULL, 0);
1705 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1706 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1707 pa_tagstruct_putu32(t, s->index);
1708 pa_tagstruct_putu32(t, dest->index);
1709 pa_tagstruct_puts(t, dest->name);
1710 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1712 if (s->connection->version >= 13) {
1713 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1714 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1715 pa_tagstruct_put_usec(t, s->source_latency);
1718 pa_pstream_send_tagstruct(s->connection->pstream, t);
1721 /*** pdispatch callbacks ***/
1723 static void protocol_error(pa_native_connection *c) {
1724 pa_log("protocol error, kicking client");
1725 native_connection_unlink(c);
1728 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1729 if (!(expression)) { \
1730 pa_pstream_send_error((pstream), (tag), (error)); \
1735 static pa_tagstruct *reply_new(uint32_t tag) {
1736 pa_tagstruct *reply;
1738 reply = pa_tagstruct_new(NULL, 0);
1739 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1740 pa_tagstruct_putu32(reply, tag);
1744 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1745 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1747 uint32_t sink_index, syncid, missing;
1748 pa_buffer_attr attr;
1749 const char *name = NULL, *sink_name;
1752 pa_tagstruct *reply;
1753 pa_sink *sink = NULL;
1761 fix_channels = FALSE,
1763 variable_rate = FALSE,
1765 adjust_latency = FALSE,
1766 early_requests = FALSE,
1767 dont_inhibit_auto_suspend = FALSE,
1769 fail_on_suspend = FALSE;
1770 pa_sink_input_flags_t flags = 0;
1772 pa_bool_t volume_set = TRUE;
1773 int ret = PA_ERR_INVALID;
1775 pa_native_connection_assert_ref(c);
1777 memset(&attr, 0, sizeof(attr));
1779 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1782 PA_TAG_SAMPLE_SPEC, &ss,
1783 PA_TAG_CHANNEL_MAP, &map,
1784 PA_TAG_U32, &sink_index,
1785 PA_TAG_STRING, &sink_name,
1786 PA_TAG_U32, &attr.maxlength,
1787 PA_TAG_BOOLEAN, &corked,
1788 PA_TAG_U32, &attr.tlength,
1789 PA_TAG_U32, &attr.prebuf,
1790 PA_TAG_U32, &attr.minreq,
1791 PA_TAG_U32, &syncid,
1792 PA_TAG_CVOLUME, &volume,
1793 PA_TAG_INVALID) < 0) {
1799 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1800 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name(sink_name), tag, PA_ERR_INVALID);
1801 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
1802 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
1803 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
1804 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
1805 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
1806 CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID);
1808 p = pa_proplist_new();
1811 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1813 if (c->version >= 12) {
1814 /* Since 0.9.8 the user can ask for a couple of additional flags */
1816 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1817 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1818 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1819 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1820 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1821 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1822 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1825 pa_proplist_free(p);
1830 if (c->version >= 13) {
1832 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1833 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1834 pa_tagstruct_get_proplist(t, p) < 0) {
1836 pa_proplist_free(p);
1841 if (c->version >= 14) {
1843 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
1844 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
1846 pa_proplist_free(p);
1851 if (c->version >= 15) {
1853 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
1854 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
1855 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
1857 pa_proplist_free(p);
1862 if (!pa_tagstruct_eof(t)) {
1864 pa_proplist_free(p);
1868 if (sink_index != PA_INVALID_INDEX) {
1870 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
1871 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1872 pa_proplist_free(p);
1876 } else if (sink_name) {
1878 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
1879 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1880 pa_proplist_free(p);
1886 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
1887 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
1888 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
1889 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
1890 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
1891 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
1892 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
1893 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
1894 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
1895 (fail_on_suspend ? PA_SINK_INPUT_FAIL_ON_SUSPEND : 0);
1897 /* Only since protocol version 15 there's a seperate muted_set
1898 * flag. For older versions we synthesize it here */
1899 muted_set = muted_set || muted;
1901 s = playback_stream_new(c, sink, &ss, &map, &attr, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, &ret);
1902 pa_proplist_free(p);
1904 CHECK_VALIDITY(c->pstream, s, tag, ret);
1906 reply = reply_new(tag);
1907 pa_tagstruct_putu32(reply, s->index);
1908 pa_assert(s->sink_input);
1909 pa_tagstruct_putu32(reply, s->sink_input->index);
1910 pa_tagstruct_putu32(reply, missing);
1912 /* pa_log("initial request is %u", missing); */
1914 if (c->version >= 9) {
1915 /* Since 0.9.0 we support sending the buffer metrics back to the client */
1917 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
1918 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
1919 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
1920 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
1923 if (c->version >= 12) {
1924 /* Since 0.9.8 we support sending the chosen sample
1925 * spec/channel map/device/suspend status back to the
1928 pa_tagstruct_put_sample_spec(reply, &ss);
1929 pa_tagstruct_put_channel_map(reply, &map);
1931 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
1932 pa_tagstruct_puts(reply, s->sink_input->sink->name);
1934 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
1937 if (c->version >= 13)
1938 pa_tagstruct_put_usec(reply, s->sink_latency);
1940 pa_pstream_send_tagstruct(c->pstream, reply);
1943 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1944 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1947 pa_native_connection_assert_ref(c);
1950 if (pa_tagstruct_getu32(t, &channel) < 0 ||
1951 !pa_tagstruct_eof(t)) {
1956 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1960 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
1962 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
1963 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
1967 playback_stream_unlink(s);
1971 case PA_COMMAND_DELETE_RECORD_STREAM: {
1973 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
1974 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
1978 record_stream_unlink(s);
1982 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
1985 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
1986 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
1990 upload_stream_unlink(s);
1995 pa_assert_not_reached();
1998 pa_pstream_send_simple_ack(c->pstream, tag);
2001 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2002 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2004 pa_buffer_attr attr;
2005 uint32_t source_index;
2006 const char *name = NULL, *source_name;
2009 pa_tagstruct *reply;
2010 pa_source *source = NULL;
2017 fix_channels = FALSE,
2019 variable_rate = FALSE,
2020 adjust_latency = FALSE,
2021 peak_detect = FALSE,
2022 early_requests = FALSE,
2023 dont_inhibit_auto_suspend = FALSE,
2024 fail_on_suspend = FALSE;
2025 pa_source_output_flags_t flags = 0;
2027 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2028 pa_sink_input *direct_on_input = NULL;
2029 int ret = PA_ERR_INVALID;
2031 pa_native_connection_assert_ref(c);
2034 memset(&attr, 0, sizeof(attr));
2036 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2037 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2038 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2039 pa_tagstruct_getu32(t, &source_index) < 0 ||
2040 pa_tagstruct_gets(t, &source_name) < 0 ||
2041 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2042 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2043 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2048 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2049 CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name(source_name), tag, PA_ERR_INVALID);
2050 CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID);
2051 CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2052 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2053 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2054 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2056 p = pa_proplist_new();
2059 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2061 if (c->version >= 12) {
2062 /* Since 0.9.8 the user can ask for a couple of additional flags */
2064 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2065 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2066 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2067 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2068 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2069 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2070 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2073 pa_proplist_free(p);
2078 if (c->version >= 13) {
2080 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2081 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2082 pa_tagstruct_get_proplist(t, p) < 0 ||
2083 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2085 pa_proplist_free(p);
2090 if (c->version >= 14) {
2092 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2094 pa_proplist_free(p);
2099 if (c->version >= 15) {
2101 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2102 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2104 pa_proplist_free(p);
2109 if (!pa_tagstruct_eof(t)) {
2111 pa_proplist_free(p);
2115 if (source_index != PA_INVALID_INDEX) {
2117 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2118 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2119 pa_proplist_free(p);
2123 } else if (source_name) {
2125 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2126 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2127 pa_proplist_free(p);
2132 if (direct_on_input_idx != PA_INVALID_INDEX) {
2134 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2135 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2136 pa_proplist_free(p);
2142 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2143 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2144 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2145 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2146 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2147 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2148 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2149 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2150 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2151 (fail_on_suspend ? PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND : 0);
2153 s = record_stream_new(c, source, &ss, &map, peak_detect, &attr, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
2154 pa_proplist_free(p);
2156 CHECK_VALIDITY(c->pstream, s, tag, ret);
2158 reply = reply_new(tag);
2159 pa_tagstruct_putu32(reply, s->index);
2160 pa_assert(s->source_output);
2161 pa_tagstruct_putu32(reply, s->source_output->index);
2163 if (c->version >= 9) {
2164 /* Since 0.9 we support sending the buffer metrics back to the client */
2166 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2167 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2170 if (c->version >= 12) {
2171 /* Since 0.9.8 we support sending the chosen sample
2172 * spec/channel map/device/suspend status back to the
2175 pa_tagstruct_put_sample_spec(reply, &ss);
2176 pa_tagstruct_put_channel_map(reply, &map);
2178 pa_tagstruct_putu32(reply, s->source_output->source->index);
2179 pa_tagstruct_puts(reply, s->source_output->source->name);
2181 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2184 if (c->version >= 13)
2185 pa_tagstruct_put_usec(reply, s->source_latency);
2187 pa_pstream_send_tagstruct(c->pstream, reply);
2190 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2191 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2194 pa_native_connection_assert_ref(c);
2197 if (!pa_tagstruct_eof(t)) {
2202 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2203 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2204 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2206 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2209 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2210 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2212 pa_tagstruct *reply;
2213 pa_bool_t shm_on_remote = FALSE, do_shm;
2215 pa_native_connection_assert_ref(c);
2218 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2219 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2220 !pa_tagstruct_eof(t)) {
2225 /* Minimum supported version */
2226 if (c->version < 8) {
2227 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2231 /* Starting with protocol version 13 the MSB of the version tag
2232 reflects if shm is available for this pa_native_connection or
2234 if (c->version >= 13) {
2235 shm_on_remote = !!(c->version & 0x80000000U);
2236 c->version &= 0x7FFFFFFFU;
2239 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2241 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2243 if (!c->authorized) {
2244 pa_bool_t success = FALSE;
2247 const pa_creds *creds;
2249 if ((creds = pa_pdispatch_creds(pd))) {
2250 if (creds->uid == getuid())
2252 else if (c->options->auth_group) {
2256 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2257 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2258 else if (gid == creds->gid)
2262 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2263 pa_log_warn("Failed to check group membership.");
2269 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2270 (unsigned long) creds->uid,
2271 (unsigned long) creds->gid,
2276 if (!success && c->options->auth_cookie) {
2279 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2280 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2285 pa_log_warn("Denied access to client with invalid authorization data.");
2286 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2290 c->authorized = TRUE;
2291 if (c->auth_timeout_event) {
2292 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2293 c->auth_timeout_event = NULL;
2297 /* Enable shared memory support if possible */
2299 pa_mempool_is_shared(c->protocol->core->mempool) &&
2302 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2305 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2310 /* Only enable SHM if both sides are owned by the same
2311 * user. This is a security measure because otherwise data
2312 * private to the user might leak. */
2314 const pa_creds *creds;
2315 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2320 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2321 pa_pstream_enable_shm(c->pstream, do_shm);
2323 reply = reply_new(tag);
2324 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2328 /* SHM support is only enabled after both sides made sure they are the same user. */
2332 ucred.uid = getuid();
2333 ucred.gid = getgid();
2335 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2338 pa_pstream_send_tagstruct(c->pstream, reply);
2342 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2343 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2344 const char *name = NULL;
2346 pa_tagstruct *reply;
2348 pa_native_connection_assert_ref(c);
2351 p = pa_proplist_new();
2353 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2354 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2355 !pa_tagstruct_eof(t)) {
2358 pa_proplist_free(p);
2363 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2364 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2365 pa_proplist_free(p);
2369 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2370 pa_proplist_free(p);
2372 reply = reply_new(tag);
2374 if (c->version >= 13)
2375 pa_tagstruct_putu32(reply, c->client->index);
2377 pa_pstream_send_tagstruct(c->pstream, reply);
2380 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2381 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2383 uint32_t idx = PA_IDXSET_INVALID;
2385 pa_native_connection_assert_ref(c);
2388 if (pa_tagstruct_gets(t, &name) < 0 ||
2389 !pa_tagstruct_eof(t)) {
2394 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2395 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2397 if (command == PA_COMMAND_LOOKUP_SINK) {
2399 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2403 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2404 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2405 idx = source->index;
2408 if (idx == PA_IDXSET_INVALID)
2409 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2411 pa_tagstruct *reply;
2412 reply = reply_new(tag);
2413 pa_tagstruct_putu32(reply, idx);
2414 pa_pstream_send_tagstruct(c->pstream, reply);
2418 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2419 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2423 pa_native_connection_assert_ref(c);
2426 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2427 !pa_tagstruct_eof(t)) {
2432 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2433 s = pa_idxset_get_by_index(c->output_streams, idx);
2434 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2435 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2437 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);
2440 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2441 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2442 pa_tagstruct *reply;
2443 const pa_mempool_stat *stat;
2445 pa_native_connection_assert_ref(c);
2448 if (!pa_tagstruct_eof(t)) {
2453 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2455 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2457 reply = reply_new(tag);
2458 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2459 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2460 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2461 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2462 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2463 pa_pstream_send_tagstruct(c->pstream, reply);
2466 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2467 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2468 pa_tagstruct *reply;
2470 struct timeval tv, now;
2474 pa_native_connection_assert_ref(c);
2477 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2478 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2479 !pa_tagstruct_eof(t)) {
2484 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2485 s = pa_idxset_get_by_index(c->output_streams, idx);
2486 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2487 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2488 CHECK_VALIDITY(c->pstream, pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0, tag, PA_ERR_NOENTITY)
2490 reply = reply_new(tag);
2492 latency = pa_sink_get_latency(s->sink_input->sink);
2493 latency += pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sample_spec);
2495 pa_tagstruct_put_usec(reply, latency);
2497 pa_tagstruct_put_usec(reply, 0);
2498 pa_tagstruct_put_boolean(reply, s->sink_input->thread_info.playing_for > 0);
2499 pa_tagstruct_put_timeval(reply, &tv);
2500 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2501 pa_tagstruct_puts64(reply, s->write_index);
2502 pa_tagstruct_puts64(reply, s->read_index);
2504 if (c->version >= 13) {
2505 pa_tagstruct_putu64(reply, s->sink_input->thread_info.underrun_for);
2506 pa_tagstruct_putu64(reply, s->sink_input->thread_info.playing_for);
2509 pa_pstream_send_tagstruct(c->pstream, reply);
2512 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2513 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2514 pa_tagstruct *reply;
2516 struct timeval tv, now;
2519 pa_native_connection_assert_ref(c);
2522 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2523 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2524 !pa_tagstruct_eof(t)) {
2529 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2530 s = pa_idxset_get_by_index(c->record_streams, idx);
2531 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2533 reply = reply_new(tag);
2534 pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0);
2535 pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source));
2536 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING);
2537 pa_tagstruct_put_timeval(reply, &tv);
2538 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2539 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2540 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2541 pa_pstream_send_tagstruct(c->pstream, reply);
2544 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2545 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2548 const char *name = NULL;
2551 pa_tagstruct *reply;
2554 pa_native_connection_assert_ref(c);
2557 if (pa_tagstruct_gets(t, &name) < 0 ||
2558 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2559 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2560 pa_tagstruct_getu32(t, &length) < 0) {
2565 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2566 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2567 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2568 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2569 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2570 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2572 p = pa_proplist_new();
2574 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2575 !pa_tagstruct_eof(t)) {
2578 pa_proplist_free(p);
2582 if (c->version < 13)
2583 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2585 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2586 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2588 if (!name || !pa_namereg_is_valid_name(name)) {
2589 pa_proplist_free(p);
2590 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2593 s = upload_stream_new(c, &ss, &map, name, length, p);
2594 pa_proplist_free(p);
2596 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2598 reply = reply_new(tag);
2599 pa_tagstruct_putu32(reply, s->index);
2600 pa_tagstruct_putu32(reply, length);
2601 pa_pstream_send_tagstruct(c->pstream, reply);
2604 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2605 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2610 pa_native_connection_assert_ref(c);
2613 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2614 !pa_tagstruct_eof(t)) {
2619 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2621 s = pa_idxset_get_by_index(c->output_streams, channel);
2622 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2623 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2625 if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2626 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2628 pa_pstream_send_simple_ack(c->pstream, tag);
2630 upload_stream_unlink(s);
2633 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2634 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2635 uint32_t sink_index;
2638 const char *name, *sink_name;
2641 pa_tagstruct *reply;
2643 pa_native_connection_assert_ref(c);
2646 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2648 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2649 pa_tagstruct_gets(t, &sink_name) < 0 ||
2650 pa_tagstruct_getu32(t, &volume) < 0 ||
2651 pa_tagstruct_gets(t, &name) < 0) {
2656 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name(sink_name), tag, PA_ERR_INVALID);
2657 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2658 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2659 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2661 if (sink_index != PA_INVALID_INDEX)
2662 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2664 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2666 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2668 p = pa_proplist_new();
2670 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2671 !pa_tagstruct_eof(t)) {
2673 pa_proplist_free(p);
2677 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2679 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2680 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2681 pa_proplist_free(p);
2685 pa_proplist_free(p);
2687 reply = reply_new(tag);
2689 if (c->version >= 13)
2690 pa_tagstruct_putu32(reply, idx);
2692 pa_pstream_send_tagstruct(c->pstream, reply);
2695 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2696 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2699 pa_native_connection_assert_ref(c);
2702 if (pa_tagstruct_gets(t, &name) < 0 ||
2703 !pa_tagstruct_eof(t)) {
2708 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2709 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2711 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
2712 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2716 pa_pstream_send_simple_ack(c->pstream, tag);
2719 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
2722 pa_assert(original);
2726 if (c->version < 12) {
2727 /* Before protocol version 12 we didn't support S32 samples,
2728 * so we need to lie about this to the client */
2730 if (fixed->format == PA_SAMPLE_S32LE)
2731 fixed->format = PA_SAMPLE_FLOAT32LE;
2732 if (fixed->format == PA_SAMPLE_S32BE)
2733 fixed->format = PA_SAMPLE_FLOAT32BE;
2736 if (c->version < 15) {
2737 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
2738 fixed->format = PA_SAMPLE_FLOAT32LE;
2739 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
2740 fixed->format = PA_SAMPLE_FLOAT32BE;
2744 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
2745 pa_sample_spec fixed_ss;
2748 pa_sink_assert_ref(sink);
2750 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
2754 PA_TAG_U32, sink->index,
2755 PA_TAG_STRING, sink->name,
2756 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2757 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2758 PA_TAG_CHANNEL_MAP, &sink->channel_map,
2759 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
2760 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
2761 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
2762 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
2763 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
2764 PA_TAG_USEC, pa_sink_get_latency(sink),
2765 PA_TAG_STRING, sink->driver,
2766 PA_TAG_U32, sink->flags,
2769 if (c->version >= 13) {
2770 pa_tagstruct_put_proplist(t, sink->proplist);
2771 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
2774 if (c->version >= 15) {
2775 pa_tagstruct_put_volume(t, sink->base_volume);
2776 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
2777 pa_log_error("Internal sink state is invalid.");
2778 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
2779 pa_tagstruct_putu32(t, sink->n_volume_steps);
2780 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
2784 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
2785 pa_sample_spec fixed_ss;
2788 pa_source_assert_ref(source);
2790 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
2794 PA_TAG_U32, source->index,
2795 PA_TAG_STRING, source->name,
2796 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2797 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2798 PA_TAG_CHANNEL_MAP, &source->channel_map,
2799 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
2800 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
2801 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
2802 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
2803 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
2804 PA_TAG_USEC, pa_source_get_latency(source),
2805 PA_TAG_STRING, source->driver,
2806 PA_TAG_U32, source->flags,
2809 if (c->version >= 13) {
2810 pa_tagstruct_put_proplist(t, source->proplist);
2811 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
2814 if (c->version >= 15) {
2815 pa_tagstruct_put_volume(t, source->base_volume);
2816 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
2817 pa_log_error("Internal source state is invalid.");
2818 pa_tagstruct_putu32(t, pa_source_get_state(source));
2819 pa_tagstruct_putu32(t, source->n_volume_steps);
2820 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
2824 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
2828 pa_tagstruct_putu32(t, client->index);
2829 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
2830 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
2831 pa_tagstruct_puts(t, client->driver);
2833 if (c->version >= 13)
2834 pa_tagstruct_put_proplist(t, client->proplist);
2837 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
2844 pa_tagstruct_putu32(t, card->index);
2845 pa_tagstruct_puts(t, card->name);
2846 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
2847 pa_tagstruct_puts(t, card->driver);
2849 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
2851 if (card->profiles) {
2852 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
2853 pa_tagstruct_puts(t, p->name);
2854 pa_tagstruct_puts(t, p->description);
2855 pa_tagstruct_putu32(t, p->n_sinks);
2856 pa_tagstruct_putu32(t, p->n_sources);
2857 pa_tagstruct_putu32(t, p->priority);
2861 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
2862 pa_tagstruct_put_proplist(t, card->proplist);
2865 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
2869 pa_tagstruct_putu32(t, module->index);
2870 pa_tagstruct_puts(t, module->name);
2871 pa_tagstruct_puts(t, module->argument);
2872 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
2874 if (c->version < 15)
2875 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
2877 if (c->version >= 15)
2878 pa_tagstruct_put_proplist(t, module->proplist);
2881 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
2882 pa_sample_spec fixed_ss;
2883 pa_usec_t sink_latency;
2886 pa_sink_input_assert_ref(s);
2888 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
2890 pa_tagstruct_putu32(t, s->index);
2891 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
2892 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
2893 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
2894 pa_tagstruct_putu32(t, s->sink->index);
2895 pa_tagstruct_put_sample_spec(t, &fixed_ss);
2896 pa_tagstruct_put_channel_map(t, &s->channel_map);
2897 pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s));
2898 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
2899 pa_tagstruct_put_usec(t, sink_latency);
2900 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
2901 pa_tagstruct_puts(t, s->driver);
2902 if (c->version >= 11)
2903 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
2904 if (c->version >= 13)
2905 pa_tagstruct_put_proplist(t, s->proplist);
2908 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
2909 pa_sample_spec fixed_ss;
2910 pa_usec_t source_latency;
2913 pa_source_output_assert_ref(s);
2915 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
2917 pa_tagstruct_putu32(t, s->index);
2918 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
2919 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
2920 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
2921 pa_tagstruct_putu32(t, s->source->index);
2922 pa_tagstruct_put_sample_spec(t, &fixed_ss);
2923 pa_tagstruct_put_channel_map(t, &s->channel_map);
2924 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
2925 pa_tagstruct_put_usec(t, source_latency);
2926 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
2927 pa_tagstruct_puts(t, s->driver);
2929 if (c->version >= 13)
2930 pa_tagstruct_put_proplist(t, s->proplist);
2933 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
2934 pa_sample_spec fixed_ss;
2940 if (e->memchunk.memblock)
2941 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
2943 memset(&fixed_ss, 0, sizeof(fixed_ss));
2945 pa_tagstruct_putu32(t, e->index);
2946 pa_tagstruct_puts(t, e->name);
2948 if (e->volume_is_set)
2951 pa_cvolume_init(&v);
2953 pa_tagstruct_put_cvolume(t, &v);
2954 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
2955 pa_tagstruct_put_sample_spec(t, &fixed_ss);
2956 pa_tagstruct_put_channel_map(t, &e->channel_map);
2957 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
2958 pa_tagstruct_put_boolean(t, e->lazy);
2959 pa_tagstruct_puts(t, e->filename);
2961 if (c->version >= 13)
2962 pa_tagstruct_put_proplist(t, e->proplist);
2965 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2966 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2968 pa_sink *sink = NULL;
2969 pa_source *source = NULL;
2970 pa_client *client = NULL;
2971 pa_card *card = NULL;
2972 pa_module *module = NULL;
2973 pa_sink_input *si = NULL;
2974 pa_source_output *so = NULL;
2975 pa_scache_entry *sce = NULL;
2976 const char *name = NULL;
2977 pa_tagstruct *reply;
2979 pa_native_connection_assert_ref(c);
2982 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2983 (command != PA_COMMAND_GET_CLIENT_INFO &&
2984 command != PA_COMMAND_GET_MODULE_INFO &&
2985 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
2986 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
2987 pa_tagstruct_gets(t, &name) < 0) ||
2988 !pa_tagstruct_eof(t)) {
2993 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2994 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2995 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
2996 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
2997 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2999 if (command == PA_COMMAND_GET_SINK_INFO) {
3000 if (idx != PA_INVALID_INDEX)
3001 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3003 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3004 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3005 if (idx != PA_INVALID_INDEX)
3006 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3008 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3009 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3010 if (idx != PA_INVALID_INDEX)
3011 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3013 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3014 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3015 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3016 else if (command == PA_COMMAND_GET_MODULE_INFO)
3017 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3018 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3019 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3020 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3021 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3023 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3024 if (idx != PA_INVALID_INDEX)
3025 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3027 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3030 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3031 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3035 reply = reply_new(tag);
3037 sink_fill_tagstruct(c, reply, sink);
3039 source_fill_tagstruct(c, reply, source);
3041 client_fill_tagstruct(c, reply, client);
3043 card_fill_tagstruct(c, reply, card);
3045 module_fill_tagstruct(c, reply, module);
3047 sink_input_fill_tagstruct(c, reply, si);
3049 source_output_fill_tagstruct(c, reply, so);
3051 scache_fill_tagstruct(c, reply, sce);
3052 pa_pstream_send_tagstruct(c->pstream, reply);
3055 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3056 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3060 pa_tagstruct *reply;
3062 pa_native_connection_assert_ref(c);
3065 if (!pa_tagstruct_eof(t)) {
3070 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3072 reply = reply_new(tag);
3074 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3075 i = c->protocol->core->sinks;
3076 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3077 i = c->protocol->core->sources;
3078 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3079 i = c->protocol->core->clients;
3080 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3081 i = c->protocol->core->cards;
3082 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3083 i = c->protocol->core->modules;
3084 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3085 i = c->protocol->core->sink_inputs;
3086 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3087 i = c->protocol->core->source_outputs;
3089 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3090 i = c->protocol->core->scache;
3094 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3095 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3096 sink_fill_tagstruct(c, reply, p);
3097 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3098 source_fill_tagstruct(c, reply, p);
3099 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3100 client_fill_tagstruct(c, reply, p);
3101 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3102 card_fill_tagstruct(c, reply, p);
3103 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3104 module_fill_tagstruct(c, reply, p);
3105 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3106 sink_input_fill_tagstruct(c, reply, p);
3107 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3108 source_output_fill_tagstruct(c, reply, p);
3110 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3111 scache_fill_tagstruct(c, reply, p);
3116 pa_pstream_send_tagstruct(c->pstream, reply);
3119 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3120 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3121 pa_tagstruct *reply;
3124 pa_source *def_source;
3125 pa_sample_spec fixed_ss;
3127 pa_native_connection_assert_ref(c);
3130 if (!pa_tagstruct_eof(t)) {
3135 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3137 reply = reply_new(tag);
3138 pa_tagstruct_puts(reply, PACKAGE_NAME);
3139 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3140 pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt)));
3141 pa_tagstruct_puts(reply, pa_get_host_name(txt, sizeof(txt)));
3143 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3144 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3146 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3147 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3148 def_source = pa_namereg_get_default_source(c->protocol->core);
3149 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3151 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3153 if (c->version >= 15)
3154 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3156 pa_pstream_send_tagstruct(c->pstream, reply);
3159 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3161 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3163 pa_native_connection_assert_ref(c);
3165 t = pa_tagstruct_new(NULL, 0);
3166 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3167 pa_tagstruct_putu32(t, (uint32_t) -1);
3168 pa_tagstruct_putu32(t, e);
3169 pa_tagstruct_putu32(t, idx);
3170 pa_pstream_send_tagstruct(c->pstream, t);
3173 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3174 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3175 pa_subscription_mask_t m;
3177 pa_native_connection_assert_ref(c);
3180 if (pa_tagstruct_getu32(t, &m) < 0 ||
3181 !pa_tagstruct_eof(t)) {
3186 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3187 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3189 if (c->subscription)
3190 pa_subscription_free(c->subscription);
3193 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3194 pa_assert(c->subscription);
3196 c->subscription = NULL;
3198 pa_pstream_send_simple_ack(c->pstream, tag);
3201 static void command_set_volume(
3208 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3211 pa_sink *sink = NULL;
3212 pa_source *source = NULL;
3213 pa_sink_input *si = NULL;
3214 const char *name = NULL;
3216 pa_native_connection_assert_ref(c);
3219 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3220 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3221 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3222 pa_tagstruct_get_cvolume(t, &volume) ||
3223 !pa_tagstruct_eof(t)) {
3228 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3229 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3230 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3231 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3232 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3233 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3237 case PA_COMMAND_SET_SINK_VOLUME:
3238 if (idx != PA_INVALID_INDEX)
3239 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3241 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3244 case PA_COMMAND_SET_SOURCE_VOLUME:
3245 if (idx != PA_INVALID_INDEX)
3246 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3248 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3251 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3252 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3256 pa_assert_not_reached();
3259 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3262 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3264 pa_source_set_volume(source, &volume);
3266 pa_sink_input_set_volume(si, &volume, TRUE);
3268 pa_pstream_send_simple_ack(c->pstream, tag);
3271 static void command_set_mute(
3278 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3281 pa_sink *sink = NULL;
3282 pa_source *source = NULL;
3283 pa_sink_input *si = NULL;
3284 const char *name = NULL;
3286 pa_native_connection_assert_ref(c);
3289 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3290 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3291 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3292 pa_tagstruct_get_boolean(t, &mute) ||
3293 !pa_tagstruct_eof(t)) {
3298 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3299 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3300 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3301 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3302 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3306 case PA_COMMAND_SET_SINK_MUTE:
3308 if (idx != PA_INVALID_INDEX)
3309 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3311 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3315 case PA_COMMAND_SET_SOURCE_MUTE:
3316 if (idx != PA_INVALID_INDEX)
3317 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3319 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3323 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3324 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3328 pa_assert_not_reached();
3331 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3334 pa_sink_set_mute(sink, mute);
3336 pa_source_set_mute(source, mute);
3338 pa_sink_input_set_mute(si, mute, TRUE);
3340 pa_pstream_send_simple_ack(c->pstream, tag);
3343 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3344 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3349 pa_native_connection_assert_ref(c);
3352 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3353 pa_tagstruct_get_boolean(t, &b) < 0 ||
3354 !pa_tagstruct_eof(t)) {
3359 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3360 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3361 s = pa_idxset_get_by_index(c->output_streams, idx);
3362 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3363 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3365 pa_sink_input_cork(s->sink_input, b);
3368 s->is_underrun = TRUE;
3370 pa_pstream_send_simple_ack(c->pstream, tag);
3373 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3374 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3378 pa_native_connection_assert_ref(c);
3381 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3382 !pa_tagstruct_eof(t)) {
3387 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3388 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3389 s = pa_idxset_get_by_index(c->output_streams, idx);
3390 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3391 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3394 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3395 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3398 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3399 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3402 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3403 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3407 pa_assert_not_reached();
3410 pa_pstream_send_simple_ack(c->pstream, tag);
3413 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3414 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3419 pa_native_connection_assert_ref(c);
3422 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3423 pa_tagstruct_get_boolean(t, &b) < 0 ||
3424 !pa_tagstruct_eof(t)) {
3429 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3430 s = pa_idxset_get_by_index(c->record_streams, idx);
3431 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3433 pa_source_output_cork(s->source_output, b);
3434 pa_memblockq_prebuf_force(s->memblockq);
3435 pa_pstream_send_simple_ack(c->pstream, tag);
3438 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3439 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3443 pa_native_connection_assert_ref(c);
3446 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3447 !pa_tagstruct_eof(t)) {
3452 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3453 s = pa_idxset_get_by_index(c->record_streams, idx);
3454 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3456 pa_memblockq_flush_read(s->memblockq);
3457 pa_pstream_send_simple_ack(c->pstream, tag);
3460 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3461 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3464 pa_tagstruct *reply;
3466 pa_native_connection_assert_ref(c);
3469 memset(&a, 0, sizeof(a));
3471 if (pa_tagstruct_getu32(t, &idx) < 0) {
3476 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3478 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3480 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3482 s = pa_idxset_get_by_index(c->output_streams, idx);
3483 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3484 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3486 if (pa_tagstruct_get(
3488 PA_TAG_U32, &a.maxlength,
3489 PA_TAG_U32, &a.tlength,
3490 PA_TAG_U32, &a.prebuf,
3491 PA_TAG_U32, &a.minreq,
3492 PA_TAG_INVALID) < 0 ||
3493 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3494 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3495 !pa_tagstruct_eof(t)) {
3500 s->adjust_latency = adjust_latency;
3501 s->early_requests = early_requests;
3504 fix_playback_buffer_attr(s);
3505 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);
3507 reply = reply_new(tag);
3508 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3509 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3510 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3511 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3513 if (c->version >= 13)
3514 pa_tagstruct_put_usec(reply, s->sink_latency);
3518 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3519 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3521 s = pa_idxset_get_by_index(c->record_streams, idx);
3522 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3524 if (pa_tagstruct_get(
3526 PA_TAG_U32, &a.maxlength,
3527 PA_TAG_U32, &a.fragsize,
3528 PA_TAG_INVALID) < 0 ||
3529 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3530 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3531 !pa_tagstruct_eof(t)) {
3536 s->adjust_latency = adjust_latency;
3537 s->early_requests = early_requests;
3540 fix_record_buffer_attr_pre(s);
3541 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3542 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3543 fix_record_buffer_attr_post(s);
3545 reply = reply_new(tag);
3546 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3547 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3549 if (c->version >= 13)
3550 pa_tagstruct_put_usec(reply, s->source_latency);
3553 pa_pstream_send_tagstruct(c->pstream, reply);
3556 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3557 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3561 pa_native_connection_assert_ref(c);
3564 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3565 pa_tagstruct_getu32(t, &rate) < 0 ||
3566 !pa_tagstruct_eof(t)) {
3571 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3572 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
3574 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
3577 s = pa_idxset_get_by_index(c->output_streams, idx);
3578 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3579 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3581 pa_sink_input_set_rate(s->sink_input, rate);
3585 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
3587 s = pa_idxset_get_by_index(c->record_streams, idx);
3588 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3590 pa_source_output_set_rate(s->source_output, rate);
3593 pa_pstream_send_simple_ack(c->pstream, tag);
3596 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3597 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3602 pa_native_connection_assert_ref(c);
3605 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3607 p = pa_proplist_new();
3609 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
3611 if (pa_tagstruct_getu32(t, &mode) < 0 ||
3612 pa_tagstruct_get_proplist(t, p) < 0 ||
3613 !pa_tagstruct_eof(t)) {
3615 pa_proplist_free(p);
3621 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3622 pa_tagstruct_getu32(t, &mode) < 0 ||
3623 pa_tagstruct_get_proplist(t, p) < 0 ||
3624 !pa_tagstruct_eof(t)) {
3626 pa_proplist_free(p);
3631 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
3632 pa_proplist_free(p);
3633 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
3636 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
3639 s = pa_idxset_get_by_index(c->output_streams, idx);
3640 if (!s || !playback_stream_isinstance(s)) {
3641 pa_proplist_free(p);
3642 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3644 pa_sink_input_update_proplist(s->sink_input, mode, p);
3646 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
3649 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
3650 pa_proplist_free(p);
3651 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3653 pa_source_output_update_proplist(s->source_output, mode, p);
3656 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
3658 pa_client_update_proplist(c->client, mode, p);
3661 pa_pstream_send_simple_ack(c->pstream, tag);
3662 pa_proplist_free(p);
3665 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3666 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3668 unsigned changed = 0;
3670 pa_strlist *l = NULL;
3672 pa_native_connection_assert_ref(c);
3675 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3677 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
3679 if (pa_tagstruct_getu32(t, &idx) < 0) {
3685 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3688 s = pa_idxset_get_by_index(c->output_streams, idx);
3689 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3690 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3692 p = s->sink_input->proplist;
3694 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3697 s = pa_idxset_get_by_index(c->record_streams, idx);
3698 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3700 p = s->source_output->proplist;
3702 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3704 p = c->client->proplist;
3710 if (pa_tagstruct_gets(t, &k) < 0) {
3719 l = pa_strlist_prepend(l, k);
3722 if (!pa_tagstruct_eof(t)) {
3731 l = pa_strlist_pop(l, &z);
3736 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
3740 pa_pstream_send_simple_ack(c->pstream, tag);
3743 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3746 s = pa_idxset_get_by_index(c->output_streams, idx);
3747 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
3749 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3752 s = pa_idxset_get_by_index(c->record_streams, idx);
3753 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
3756 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3757 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
3762 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3763 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3766 pa_native_connection_assert_ref(c);
3769 if (pa_tagstruct_gets(t, &s) < 0 ||
3770 !pa_tagstruct_eof(t)) {
3775 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3776 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
3778 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
3781 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
3782 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
3784 pa_namereg_set_default_source(c->protocol->core, source);
3787 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
3789 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
3790 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3792 pa_namereg_set_default_sink(c->protocol->core, sink);
3795 pa_pstream_send_simple_ack(c->pstream, tag);
3798 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3799 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3803 pa_native_connection_assert_ref(c);
3806 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3807 pa_tagstruct_gets(t, &name) < 0 ||
3808 !pa_tagstruct_eof(t)) {
3813 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3814 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
3816 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
3819 s = pa_idxset_get_by_index(c->output_streams, idx);
3820 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3821 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3823 pa_sink_input_set_name(s->sink_input, name);
3827 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
3829 s = pa_idxset_get_by_index(c->record_streams, idx);
3830 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3832 pa_source_output_set_name(s->source_output, name);
3835 pa_pstream_send_simple_ack(c->pstream, tag);
3838 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3839 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3842 pa_native_connection_assert_ref(c);
3845 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3846 !pa_tagstruct_eof(t)) {
3851 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3853 if (command == PA_COMMAND_KILL_CLIENT) {
3856 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3857 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
3859 pa_native_connection_ref(c);
3860 pa_client_kill(client);
3862 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
3865 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3866 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3868 pa_native_connection_ref(c);
3869 pa_sink_input_kill(s);
3871 pa_source_output *s;
3873 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
3875 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3876 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3878 pa_native_connection_ref(c);
3879 pa_source_output_kill(s);
3882 pa_pstream_send_simple_ack(c->pstream, tag);
3883 pa_native_connection_unref(c);
3886 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3887 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3889 const char *name, *argument;
3890 pa_tagstruct *reply;
3892 pa_native_connection_assert_ref(c);
3895 if (pa_tagstruct_gets(t, &name) < 0 ||
3896 pa_tagstruct_gets(t, &argument) < 0 ||
3897 !pa_tagstruct_eof(t)) {
3902 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3903 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
3904 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
3906 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
3907 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
3911 reply = reply_new(tag);
3912 pa_tagstruct_putu32(reply, m->index);
3913 pa_pstream_send_tagstruct(c->pstream, reply);
3916 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3917 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3921 pa_native_connection_assert_ref(c);
3924 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3925 !pa_tagstruct_eof(t)) {
3930 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3931 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3932 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
3934 pa_module_unload_request(m, FALSE);
3935 pa_pstream_send_simple_ack(c->pstream, tag);
3938 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3939 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3940 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
3941 const char *name_device = NULL;
3943 pa_native_connection_assert_ref(c);
3946 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3947 pa_tagstruct_getu32(t, &idx_device) < 0 ||
3948 pa_tagstruct_gets(t, &name_device) < 0 ||
3949 !pa_tagstruct_eof(t)) {
3954 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3955 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3957 CHECK_VALIDITY(c->pstream, !name_device || pa_namereg_is_valid_name(name_device), tag, PA_ERR_INVALID);
3958 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
3959 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
3960 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3962 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
3963 pa_sink_input *si = NULL;
3964 pa_sink *sink = NULL;
3966 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3968 if (idx_device != PA_INVALID_INDEX)
3969 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
3971 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
3973 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
3975 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
3976 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
3980 pa_source_output *so = NULL;
3983 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
3985 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3987 if (idx_device != PA_INVALID_INDEX)
3988 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
3990 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
3992 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
3994 if (pa_source_output_move_to(so, source, TRUE) < 0) {
3995 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4000 pa_pstream_send_simple_ack(c->pstream, tag);
4003 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4004 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4005 uint32_t idx = PA_INVALID_INDEX;
4006 const char *name = NULL;
4009 pa_native_connection_assert_ref(c);
4012 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4013 pa_tagstruct_gets(t, &name) < 0 ||
4014 pa_tagstruct_get_boolean(t, &b) < 0 ||
4015 !pa_tagstruct_eof(t)) {
4020 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4021 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name) || *name == 0, tag, PA_ERR_INVALID);
4022 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4023 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4024 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4026 if (command == PA_COMMAND_SUSPEND_SINK) {
4028 if (idx == PA_INVALID_INDEX && name && !*name) {
4030 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4032 if (pa_sink_suspend_all(c->protocol->core, b) < 0) {
4033 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4037 pa_sink *sink = NULL;
4039 if (idx != PA_INVALID_INDEX)
4040 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4042 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4044 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4046 if (pa_sink_suspend(sink, b) < 0) {
4047 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4053 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4055 if (idx == PA_INVALID_INDEX && name && !*name) {
4057 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4059 if (pa_source_suspend_all(c->protocol->core, b) < 0) {
4060 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4067 if (idx != PA_INVALID_INDEX)
4068 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4070 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4072 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4074 if (pa_source_suspend(source, b) < 0) {
4075 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4081 pa_pstream_send_simple_ack(c->pstream, tag);
4084 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4085 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4086 uint32_t idx = PA_INVALID_INDEX;
4087 const char *name = NULL;
4089 pa_native_protocol_ext_cb_t cb;
4091 pa_native_connection_assert_ref(c);
4094 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4095 pa_tagstruct_gets(t, &name) < 0) {
4100 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4101 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4102 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4103 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4104 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4106 if (idx != PA_INVALID_INDEX)
4107 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4109 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4110 if (strcmp(name, m->name) == 0)
4114 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4115 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4117 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4118 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4120 if (cb(c->protocol, m, c, tag, t) < 0)
4124 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4125 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4126 uint32_t idx = PA_INVALID_INDEX;
4127 const char *name = NULL, *profile = NULL;
4128 pa_card *card = NULL;
4130 pa_native_connection_assert_ref(c);
4133 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4134 pa_tagstruct_gets(t, &name) < 0 ||
4135 pa_tagstruct_gets(t, &profile) < 0 ||
4136 !pa_tagstruct_eof(t)) {
4141 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4142 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4143 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4144 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4145 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4147 if (idx != PA_INVALID_INDEX)
4148 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4150 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4152 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4154 if (pa_card_set_profile(card, profile, TRUE) < 0) {
4155 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4159 pa_pstream_send_simple_ack(c->pstream, tag);
4162 /*** pstream callbacks ***/
4164 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4165 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4169 pa_native_connection_assert_ref(c);
4171 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4172 pa_log("invalid packet.");
4173 native_connection_unlink(c);
4177 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) {
4178 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4179 output_stream *stream;
4183 pa_native_connection_assert_ref(c);
4185 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4186 pa_log("client sent block for invalid stream.");
4191 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4193 if (playback_stream_isinstance(stream)) {
4194 playback_stream *ps = PLAYBACK_STREAM(stream);
4196 if (chunk->memblock) {
4197 if (seek != PA_SEEK_RELATIVE || offset != 0)
4198 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, NULL, NULL);
4200 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4202 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);
4205 upload_stream *u = UPLOAD_STREAM(stream);
4208 if (!u->memchunk.memblock) {
4209 if (u->length == chunk->length && chunk->memblock) {
4210 u->memchunk = *chunk;
4211 pa_memblock_ref(u->memchunk.memblock);
4214 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4215 u->memchunk.index = u->memchunk.length = 0;
4219 pa_assert(u->memchunk.memblock);
4222 if (l > chunk->length)
4227 dst = pa_memblock_acquire(u->memchunk.memblock);
4229 if (chunk->memblock) {
4231 src = pa_memblock_acquire(chunk->memblock);
4233 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4234 (uint8_t*) src + chunk->index, l);
4236 pa_memblock_release(chunk->memblock);
4238 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4240 pa_memblock_release(u->memchunk.memblock);
4242 u->memchunk.length += l;
4248 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4249 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4252 pa_native_connection_assert_ref(c);
4254 native_connection_unlink(c);
4255 pa_log_info("Connection died.");
4258 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4259 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4262 pa_native_connection_assert_ref(c);
4264 native_connection_send_memblock(c);
4267 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4270 if (!(q = pa_thread_mq_get()))
4271 pa_pstream_send_revoke(p, block_id);
4273 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4276 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4279 if (!(q = pa_thread_mq_get()))
4280 pa_pstream_send_release(p, block_id);
4282 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4285 /*** client callbacks ***/
4287 static void client_kill_cb(pa_client *c) {
4290 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4291 pa_log_info("Connection killed.");
4294 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4296 pa_native_connection *c;
4299 c = PA_NATIVE_CONNECTION(client->userdata);
4300 pa_native_connection_assert_ref(c);
4302 if (c->version < 15)
4305 t = pa_tagstruct_new(NULL, 0);
4306 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4307 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4308 pa_tagstruct_puts(t, event);
4309 pa_tagstruct_put_proplist(t, pl);
4310 pa_pstream_send_tagstruct(c->pstream, t);
4313 /*** module entry points ***/
4315 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
4316 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4320 pa_native_connection_assert_ref(c);
4321 pa_assert(c->auth_timeout_event == e);
4323 if (!c->authorized) {
4324 native_connection_unlink(c);
4325 pa_log_info("Connection terminated due to authentication timeout.");
4329 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4330 pa_native_connection *c;
4333 pa_client_new_data data;
4339 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4340 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4341 pa_iochannel_free(io);
4345 pa_client_new_data_init(&data);
4346 data.module = o->module;
4347 data.driver = __FILE__;
4348 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4349 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4350 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4351 client = pa_client_new(p->core, &data);
4352 pa_client_new_data_done(&data);
4357 c = pa_msgobject_new(pa_native_connection);
4358 c->parent.parent.free = native_connection_free;
4359 c->parent.process_msg = native_connection_process_msg;
4361 c->options = pa_native_options_ref(o);
4362 c->authorized = FALSE;
4364 if (o->auth_anonymous) {
4365 pa_log_info("Client authenticated anonymously.");
4366 c->authorized = TRUE;
4369 if (!c->authorized &&
4371 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4373 pa_log_info("Client authenticated by IP ACL.");
4374 c->authorized = TRUE;
4377 if (!c->authorized) {
4379 pa_gettimeofday(&tv);
4380 tv.tv_sec += AUTH_TIMEOUT;
4381 c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c);
4383 c->auth_timeout_event = NULL;
4385 c->is_local = pa_iochannel_socket_is_local(io);
4389 c->client->kill = client_kill_cb;
4390 c->client->send_event = client_send_event_cb;
4391 c->client->userdata = c;
4393 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4394 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4395 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4396 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4397 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4398 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4399 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4401 c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX);
4403 c->record_streams = pa_idxset_new(NULL, NULL);
4404 c->output_streams = pa_idxset_new(NULL, NULL);
4406 c->rrobin_index = PA_IDXSET_INVALID;
4407 c->subscription = NULL;
4409 pa_idxset_put(p->connections, c, NULL);
4412 if (pa_iochannel_creds_supported(io))
4413 pa_iochannel_creds_enable(io);
4416 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4419 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4420 pa_native_connection *c;
4426 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4427 if (c->options->module == m)
4428 native_connection_unlink(c);
4431 static pa_native_protocol* native_protocol_new(pa_core *c) {
4432 pa_native_protocol *p;
4437 p = pa_xnew(pa_native_protocol, 1);
4440 p->connections = pa_idxset_new(NULL, NULL);
4444 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4446 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4447 pa_hook_init(&p->hooks[h], p);
4449 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4454 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4455 pa_native_protocol *p;
4457 if ((p = pa_shared_get(c, "native-protocol")))
4458 return pa_native_protocol_ref(p);
4460 return native_protocol_new(c);
4463 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4465 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4472 void pa_native_protocol_unref(pa_native_protocol *p) {
4473 pa_native_connection *c;
4477 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4479 if (PA_REFCNT_DEC(p) > 0)
4482 while ((c = pa_idxset_first(p->connections, NULL)))
4483 native_connection_unlink(c);
4485 pa_idxset_free(p->connections, NULL, NULL);
4487 pa_strlist_free(p->servers);
4489 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4490 pa_hook_done(&p->hooks[h]);
4492 pa_hashmap_free(p->extensions, NULL, NULL);
4494 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4499 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
4501 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4504 p->servers = pa_strlist_prepend(p->servers, name);
4506 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4509 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
4511 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4514 p->servers = pa_strlist_remove(p->servers, name);
4516 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4519 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
4521 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4526 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
4528 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4533 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
4535 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4538 pa_assert(!pa_hashmap_get(p->extensions, m));
4540 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
4544 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
4546 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4549 pa_assert_se(pa_hashmap_remove(p->extensions, m));
4552 pa_native_options* pa_native_options_new(void) {
4553 pa_native_options *o;
4555 o = pa_xnew0(pa_native_options, 1);
4561 pa_native_options* pa_native_options_ref(pa_native_options *o) {
4563 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4570 void pa_native_options_unref(pa_native_options *o) {
4572 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4574 if (PA_REFCNT_DEC(o) > 0)
4577 pa_xfree(o->auth_group);
4580 pa_ip_acl_free(o->auth_ip_acl);
4583 pa_auth_cookie_unref(o->auth_cookie);
4588 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
4593 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4596 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
4597 pa_log("auth-anonymous= expects a boolean argument.");
4602 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
4603 pa_log("auth-group-enabled= expects a boolean argument.");
4607 pa_xfree(o->auth_group);
4608 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
4612 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4615 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
4618 if (!(ipa = pa_ip_acl_new(acl))) {
4619 pa_log("Failed to parse IP ACL '%s'", acl);
4624 pa_ip_acl_free(o->auth_ip_acl);
4626 o->auth_ip_acl = ipa;
4630 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
4631 pa_log("auth-cookie-enabled= expects a boolean argument.");
4636 pa_auth_cookie_unref(o->auth_cookie);
4641 /* The new name for this is 'auth-cookie', for compat reasons
4642 * we check the old name too */
4643 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
4644 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
4645 cn = PA_NATIVE_COOKIE_FILE;
4647 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
4651 o->auth_cookie = NULL;
4656 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
4657 pa_native_connection_assert_ref(c);