2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
32 #include <pulse/rtclock.h>
33 #include <pulse/timeval.h>
34 #include <pulse/version.h>
35 #include <pulse/utf8.h>
36 #include <pulse/util.h>
37 #include <pulse/xmalloc.h>
38 #include <pulse/internal.h>
40 #include <pulsecore/native-common.h>
41 #include <pulsecore/packet.h>
42 #include <pulsecore/client.h>
43 #include <pulsecore/source-output.h>
44 #include <pulsecore/sink-input.h>
45 #include <pulsecore/pstream.h>
46 #include <pulsecore/tagstruct.h>
47 #include <pulsecore/pdispatch.h>
48 #include <pulsecore/pstream-util.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/core-scache.h>
51 #include <pulsecore/core-subscribe.h>
52 #include <pulsecore/log.h>
53 #include <pulsecore/strlist.h>
54 #include <pulsecore/shared.h>
55 #include <pulsecore/sample-util.h>
56 #include <pulsecore/creds.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/ipacl.h>
59 #include <pulsecore/thread-mq.h>
61 #include "protocol-native.h"
64 #include <pulsecore/cynara.h>
65 #include <pulsecore/iochannel.h>
68 /* #define PROTOCOL_NATIVE_DEBUG */
70 /* Kick a client if it doesn't authenticate within this time */
71 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
73 /* Don't accept more connection than this */
74 #define MAX_CONNECTIONS 64
76 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
77 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
78 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
79 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
82 #define DEVICE_BUS_BUILTIN "builtin"
85 struct pa_native_protocol;
87 typedef struct record_stream {
90 pa_native_connection *connection;
93 pa_source_output *source_output;
94 pa_memblockq *memblockq;
96 bool adjust_latency:1;
97 bool early_requests:1;
99 /* Requested buffer attributes */
100 pa_buffer_attr buffer_attr_req;
101 /* Fixed-up and adjusted buffer attributes */
102 pa_buffer_attr buffer_attr;
104 pa_atomic_t on_the_fly;
105 pa_usec_t configured_source_latency;
108 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
109 size_t on_the_fly_snapshot;
110 pa_usec_t current_monitor_latency;
111 pa_usec_t current_source_latency;
114 #define RECORD_STREAM(o) (record_stream_cast(o))
115 PA_DEFINE_PRIVATE_CLASS(record_stream, pa_msgobject);
117 typedef struct output_stream {
121 #define OUTPUT_STREAM(o) (output_stream_cast(o))
122 PA_DEFINE_PRIVATE_CLASS(output_stream, pa_msgobject);
124 typedef struct playback_stream {
125 output_stream parent;
127 pa_native_connection *connection;
130 pa_sink_input *sink_input;
131 pa_memblockq *memblockq;
133 bool adjust_latency:1;
134 bool early_requests:1;
137 bool drain_request:1;
141 /* Optimization to avoid too many rewinds with a lot of small blocks */
142 pa_atomic_t seek_or_post_in_queue;
146 pa_usec_t configured_sink_latency;
147 /* Requested buffer attributes */
148 pa_buffer_attr buffer_attr_req;
149 /* Fixed-up and adjusted buffer attributes */
150 pa_buffer_attr buffer_attr;
152 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
153 int64_t read_index, write_index;
154 size_t render_memblockq_length;
155 pa_usec_t current_sink_latency;
156 uint64_t playing_for, underrun_for;
159 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
160 PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
162 typedef struct upload_stream {
163 output_stream parent;
165 pa_native_connection *connection;
168 pa_memchunk memchunk;
171 pa_sample_spec sample_spec;
172 pa_channel_map channel_map;
173 pa_proplist *proplist;
176 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
177 PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
179 struct pa_native_connection {
181 pa_native_protocol *protocol;
182 pa_native_options *options;
188 pa_pdispatch *pdispatch;
189 pa_idxset *record_streams, *output_streams;
190 uint32_t rrobin_index;
191 pa_subscription *subscription;
192 pa_time_event *auth_timeout_event;
195 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
196 PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
198 struct pa_native_protocol {
202 pa_idxset *connections;
205 pa_hook hooks[PA_NATIVE_HOOK_MAX];
207 pa_hashmap *extensions;
211 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
215 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
216 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
217 SINK_INPUT_MESSAGE_FLUSH,
218 SINK_INPUT_MESSAGE_TRIGGER,
219 SINK_INPUT_MESSAGE_SEEK,
220 SINK_INPUT_MESSAGE_PREBUF_FORCE,
221 SINK_INPUT_MESSAGE_UPDATE_LATENCY,
222 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
226 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
227 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
228 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
229 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
230 PLAYBACK_STREAM_MESSAGE_STARTED,
231 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH,
233 PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT
238 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
242 CONNECTION_MESSAGE_RELEASE,
243 CONNECTION_MESSAGE_REVOKE
246 static bool sink_input_process_underrun_cb(pa_sink_input *i);
247 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
248 static void sink_input_kill_cb(pa_sink_input *i);
249 static void sink_input_suspend_cb(pa_sink_input *i, bool suspend);
250 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
251 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
252 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
253 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
254 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
256 static void native_connection_send_memblock(pa_native_connection *c);
257 static void playback_stream_request_bytes(struct playback_stream*s);
259 static void source_output_kill_cb(pa_source_output *o);
260 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
261 static void source_output_suspend_cb(pa_source_output *o, bool suspend);
262 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
263 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
264 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
266 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
267 static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
269 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
270 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
271 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
272 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
273 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
274 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
275 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
276 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
277 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
278 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
279 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
280 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
281 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
282 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
283 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
284 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
285 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
286 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
287 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
288 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
289 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
290 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
291 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
292 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
293 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
294 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
295 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
296 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
297 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
298 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
299 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
300 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
301 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
302 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
303 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
304 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
305 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
306 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
307 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
308 static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
309 static void command_set_volume_ramp(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
311 static void command_check_privilege(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
314 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
315 [PA_COMMAND_ERROR] = NULL,
316 [PA_COMMAND_TIMEOUT] = NULL,
317 [PA_COMMAND_REPLY] = NULL,
318 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
319 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
320 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
321 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
322 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
323 [PA_COMMAND_AUTH] = command_auth,
324 [PA_COMMAND_REQUEST] = NULL,
325 [PA_COMMAND_EXIT] = command_exit,
326 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
327 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
328 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
329 [PA_COMMAND_STAT] = command_stat,
330 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
331 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
332 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
333 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
334 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
335 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
336 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
337 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
338 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
339 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
340 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
341 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
342 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
343 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
344 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
345 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
346 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
347 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
348 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
349 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
350 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
351 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
352 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
353 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
354 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
356 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
357 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
358 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
359 [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = command_set_volume,
361 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
362 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
363 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
364 [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = command_set_mute,
366 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
367 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
369 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
370 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
371 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
372 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
374 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
375 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
377 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
378 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
379 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
380 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
381 [PA_COMMAND_KILL_CLIENT] = command_kill,
382 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
383 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
384 [PA_COMMAND_LOAD_MODULE] = command_load_module,
385 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
387 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
388 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
389 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
390 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
392 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
393 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
395 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
396 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
398 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
399 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
401 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
402 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
403 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
405 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
406 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
407 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
409 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
411 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
412 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
414 [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = command_set_port_latency_offset,
416 [PA_COMMAND_SET_SINK_VOLUME_RAMP] = command_set_volume_ramp,
417 [PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP] = command_set_volume_ramp,
419 [PA_COMMAND_CHECK_PRIVILEGE] = command_check_privilege,
422 [PA_COMMAND_EXTENSION] = command_extension
425 /* structure management */
428 static int _get_connection_out_fd(pa_native_connection *c) {
429 return pa_iochannel_get_send_fd(pa_pstream_get_iochannel(pa_native_connection_get_pstream(c)));
433 /* Called from main context */
434 static void upload_stream_unlink(upload_stream *s) {
440 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
441 s->connection = NULL;
442 upload_stream_unref(s);
445 /* Called from main context */
446 static void upload_stream_free(pa_object *o) {
447 upload_stream *s = UPLOAD_STREAM(o);
450 upload_stream_unlink(s);
455 pa_proplist_free(s->proplist);
457 if (s->memchunk.memblock)
458 pa_memblock_unref(s->memchunk.memblock);
463 /* Called from main context */
464 static upload_stream* upload_stream_new(
465 pa_native_connection *c,
466 const pa_sample_spec *ss,
467 const pa_channel_map *map,
477 pa_assert(length > 0);
480 s = pa_msgobject_new(upload_stream);
481 s->parent.parent.parent.free = upload_stream_free;
483 s->sample_spec = *ss;
484 s->channel_map = *map;
485 s->name = pa_xstrdup(name);
486 pa_memchunk_reset(&s->memchunk);
488 s->proplist = pa_proplist_copy(p);
489 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
491 pa_idxset_put(c->output_streams, s, &s->index);
496 /* Called from main context */
497 static void record_stream_unlink(record_stream *s) {
503 if (s->source_output) {
504 pa_source_output_unlink(s->source_output);
505 pa_source_output_unref(s->source_output);
506 s->source_output = NULL;
509 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
510 s->connection = NULL;
511 record_stream_unref(s);
514 /* Called from main context */
515 static void record_stream_free(pa_object *o) {
516 record_stream *s = RECORD_STREAM(o);
519 record_stream_unlink(s);
521 pa_memblockq_free(s->memblockq);
525 /* Called from main context */
526 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
527 record_stream *s = RECORD_STREAM(o);
528 record_stream_assert_ref(s);
535 case RECORD_STREAM_MESSAGE_POST_DATA:
537 /* We try to keep up to date with how many bytes are
538 * currently on the fly */
539 pa_atomic_sub(&s->on_the_fly, chunk->length);
541 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
542 /* pa_log_warn("Failed to push data into output queue."); */
546 if (!pa_pstream_is_pending(s->connection->pstream))
547 native_connection_send_memblock(s->connection);
555 /* Called from main context */
556 static void fix_record_buffer_attr_pre(record_stream *s) {
559 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
563 /* This function will be called from the main thread, before as
564 * well as after the source output has been activated using
565 * pa_source_output_put()! That means it may not touch any
566 * ->thread_info data! */
568 frame_size = pa_frame_size(&s->source_output->sample_spec);
569 s->buffer_attr = s->buffer_attr_req;
571 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
572 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
573 if (s->buffer_attr.maxlength <= 0)
574 s->buffer_attr.maxlength = (uint32_t) frame_size;
576 if (s->buffer_attr.fragsize == (uint32_t) -1)
577 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
578 if (s->buffer_attr.fragsize <= 0)
579 s->buffer_attr.fragsize = (uint32_t) frame_size;
581 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
583 if (s->early_requests) {
585 /* In early request mode we need to emulate the classic
586 * fragment-based playback model. We do this setting the source
587 * latency to the fragment size. */
589 source_usec = fragsize_usec;
591 } else if (s->adjust_latency) {
593 /* So, the user asked us to adjust the latency according to
594 * what the source can provide. Half the latency will be
595 * spent on the hw buffer, half of it in the async buffer
596 * queue we maintain for each client. */
598 source_usec = fragsize_usec/2;
602 /* Ok, the user didn't ask us to adjust the latency, hence we
605 source_usec = (pa_usec_t) -1;
608 if (source_usec != (pa_usec_t) -1)
609 s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
611 s->configured_source_latency = 0;
613 if (s->early_requests) {
615 /* Ok, we didn't necessarily get what we were asking for, so
616 * let's tell the user */
618 fragsize_usec = s->configured_source_latency;
620 } else if (s->adjust_latency) {
622 /* Now subtract what we actually got */
624 if (fragsize_usec >= s->configured_source_latency*2)
625 fragsize_usec -= s->configured_source_latency;
627 fragsize_usec = s->configured_source_latency;
630 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
631 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
633 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
635 if (s->buffer_attr.fragsize <= 0)
636 s->buffer_attr.fragsize = (uint32_t) frame_size;
639 /* Called from main context */
640 static void fix_record_buffer_attr_post(record_stream *s) {
645 /* This function will be called from the main thread, before as
646 * well as after the source output has been activated using
647 * pa_source_output_put()! That means it may not touch and
648 * ->thread_info data! */
650 base = pa_frame_size(&s->source_output->sample_spec);
652 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
653 if (s->buffer_attr.fragsize <= 0)
654 s->buffer_attr.fragsize = base;
656 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
657 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
661 static int update_buffer_attr(pa_proplist* proplist, pa_buffer_attr* ret_attr, bool is_playback_stream) {
662 const char* _propStr = NULL;
666 if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_MAXLENGTH)) == NULL) {
667 pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_MAXLENGTH);
670 if (pa_atoi(_propStr, &ret_attr->maxlength)) {
671 pa_log_error("failed to pa_atoi for maxlength");
675 if (is_playback_stream) {
677 if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_TLENGTH)) == NULL) {
678 pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_TLENGTH);
681 if (pa_atoi(_propStr, &ret_attr->tlength)) {
682 pa_log_error("failed to pa_atoi for tlength");
686 if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_PREBUF)) == NULL) {
687 pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_PREBUF);
690 if (pa_atoi(_propStr, &ret_attr->prebuf)) {
691 pa_log_error("failed to pa_atoi for prebuf");
695 if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_MINREQ)) == NULL) {
696 pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_MINREQ);
699 if (pa_atoi(_propStr, &ret_attr->minreq)) {
700 pa_log_error("failed to pa_atoi for minreq");
704 pa_log_info(" - props: maxlength(%d), tlength(%d), prebuf(%d), minreq(%d)",
705 ret_attr->maxlength, ret_attr->tlength, ret_attr->prebuf, ret_attr->minreq);
709 if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_FRAGSIZE)) == NULL) {
710 pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_FRAGSIZE);
713 if (pa_atoi(_propStr, &ret_attr->fragsize)) {
714 pa_log_error("failed to pa_atoi for fragsize");
718 pa_log_info(" - props: maxlength(%d), fragsize(%d)", ret_attr->maxlength, ret_attr->fragsize);
725 /* Called from main context */
726 static record_stream* record_stream_new(
727 pa_native_connection *c,
732 pa_buffer_attr *attr,
736 pa_source_output_flags_t flags,
740 bool relative_volume,
742 pa_sink_input *direct_on_input,
746 pa_source_output *source_output = NULL;
747 pa_source_output_new_data data;
748 char *memblockq_name;
755 pa_source_output_new_data_init(&data);
757 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
758 data.driver = __FILE__;
759 data.module = c->options->module;
760 data.client = c->client;
762 pa_source_output_new_data_set_source(&data, source, false);
763 if (pa_sample_spec_valid(ss))
764 pa_source_output_new_data_set_sample_spec(&data, ss);
765 if (pa_channel_map_valid(map))
766 pa_source_output_new_data_set_channel_map(&data, map);
768 pa_source_output_new_data_set_formats(&data, formats);
769 data.direct_on_input = direct_on_input;
771 pa_source_output_new_data_set_volume(&data, volume, relative_volume);
772 data.save_volume = false;
775 pa_source_output_new_data_set_muted(&data, muted);
776 data.save_muted = false;
779 data.resample_method = PA_RESAMPLER_PEAKS;
782 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
786 pa_buffer_attr buffer_attr;
787 pa_log_info("*** update buffer attributes - record_stream_new()");
788 if (source_output && !update_buffer_attr(source_output->proplist, &buffer_attr, false)) {
789 pa_log_info(" - origins: maxlength(%d), fragsize(%d)", attr->maxlength, attr->fragsize);
790 if ((int)attr->maxlength >= 0)
791 buffer_attr.maxlength = attr->maxlength;
792 if ((int)attr->fragsize >= 0)
793 buffer_attr.fragsize = attr->fragsize;
795 pa_log_info(" - updated: maxlength(%d), fragsize(%d)", attr->maxlength, attr->fragsize);
800 pa_source_output_new_data_done(&data);
805 s = pa_msgobject_new(record_stream);
806 s->parent.parent.free = record_stream_free;
807 s->parent.process_msg = record_stream_process_msg;
809 s->source_output = source_output;
810 s->buffer_attr_req = *attr;
811 s->adjust_latency = adjust_latency;
812 s->early_requests = early_requests;
813 pa_atomic_store(&s->on_the_fly, 0);
815 s->source_output->parent.process_msg = source_output_process_msg;
816 s->source_output->push = source_output_push_cb;
817 s->source_output->kill = source_output_kill_cb;
818 s->source_output->get_latency = source_output_get_latency_cb;
819 s->source_output->moving = source_output_moving_cb;
820 s->source_output->suspend = source_output_suspend_cb;
821 s->source_output->send_event = source_output_send_event_cb;
822 s->source_output->userdata = s;
824 fix_record_buffer_attr_pre(s);
826 memblockq_name = pa_sprintf_malloc("native protocol record stream memblockq [%u]", s->source_output->index);
827 s->memblockq = pa_memblockq_new(
830 s->buffer_attr.maxlength,
832 &source_output->sample_spec,
837 pa_xfree(memblockq_name);
839 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
840 fix_record_buffer_attr_post(s);
842 *ss = s->source_output->sample_spec;
843 *map = s->source_output->channel_map;
845 pa_idxset_put(c->record_streams, s, &s->index);
847 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
848 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
849 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
850 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
852 pa_source_output_put(s->source_output);
856 /* Called from main context */
857 static void record_stream_send_killed(record_stream *r) {
859 record_stream_assert_ref(r);
861 t = pa_tagstruct_new(NULL, 0);
862 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
863 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
864 pa_tagstruct_putu32(t, r->index);
865 pa_pstream_send_tagstruct(r->connection->pstream, t);
868 /* Called from main context */
869 static void playback_stream_unlink(playback_stream *s) {
876 pa_sink_input_unlink(s->sink_input);
877 pa_sink_input_unref(s->sink_input);
878 s->sink_input = NULL;
881 if (s->drain_request)
882 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
884 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
885 s->connection = NULL;
886 playback_stream_unref(s);
889 /* Called from main context */
890 static void playback_stream_free(pa_object* o) {
891 playback_stream *s = PLAYBACK_STREAM(o);
894 playback_stream_unlink(s);
896 pa_memblockq_free(s->memblockq);
900 /* Called from main context */
901 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
902 playback_stream *s = PLAYBACK_STREAM(o);
903 playback_stream_assert_ref(s);
910 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
915 if ((l = pa_atomic_load(&s->missing)) <= 0)
918 if (pa_atomic_cmpxchg(&s->missing, l, 0))
922 t = pa_tagstruct_new(NULL, 0);
923 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
924 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
925 pa_tagstruct_putu32(t, s->index);
926 pa_tagstruct_putu32(t, (uint32_t) l);
927 pa_pstream_send_tagstruct(s->connection->pstream, t);
929 #ifdef PROTOCOL_NATIVE_DEBUG
930 pa_log("Requesting %lu bytes", (unsigned long) l);
935 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
938 #ifdef PROTOCOL_NATIVE_DEBUG
939 pa_log("signalling underflow");
942 /* Report that we're empty */
943 t = pa_tagstruct_new(NULL, 0);
944 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
945 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
946 pa_tagstruct_putu32(t, s->index);
947 if (s->connection->version >= 23)
948 pa_tagstruct_puts64(t, offset);
949 pa_pstream_send_tagstruct(s->connection->pstream, t);
953 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
956 /* Notify the user we're overflowed*/
957 t = pa_tagstruct_new(NULL, 0);
958 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
959 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
960 pa_tagstruct_putu32(t, s->index);
961 pa_pstream_send_tagstruct(s->connection->pstream, t);
965 case PLAYBACK_STREAM_MESSAGE_STARTED:
967 if (s->connection->version >= 13) {
970 /* Notify the user we started playback */
971 t = pa_tagstruct_new(NULL, 0);
972 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
973 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
974 pa_tagstruct_putu32(t, s->index);
975 pa_pstream_send_tagstruct(s->connection->pstream, t);
981 case PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT: {
983 pa_proplist* pl = pa_proplist_new();
985 pa_log_info("received : PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT, send PA_COMMAND_PLAYBACK_STREAM_EVENT(%s)",
986 PA_STREAM_EVENT_POP_TIMEOUT);
988 t = pa_tagstruct_new(NULL, 0);
989 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
990 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
991 pa_tagstruct_putu32(t, s->index);
992 pa_tagstruct_puts(t, PA_STREAM_EVENT_POP_TIMEOUT);
993 pa_tagstruct_put_proplist(t, pl);
994 pa_pstream_send_tagstruct(s->connection->pstream, t);
996 pa_proplist_free(pl);
1001 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
1002 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
1005 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
1007 s->buffer_attr.tlength = (uint32_t) offset;
1009 if (s->connection->version >= 15) {
1012 t = pa_tagstruct_new(NULL, 0);
1013 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
1014 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1015 pa_tagstruct_putu32(t, s->index);
1016 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1017 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1018 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1019 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1020 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1021 pa_pstream_send_tagstruct(s->connection->pstream, t);
1030 /* Called from main context */
1031 static void fix_playback_buffer_attr(playback_stream *s) {
1032 size_t frame_size, max_prebuf;
1033 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
1037 #ifdef PROTOCOL_NATIVE_DEBUG
1038 pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes",
1039 (long) s->buffer_attr_req.maxlength,
1040 (long) s->buffer_attr_req.tlength,
1041 (long) s->buffer_attr_req.minreq,
1042 (long) s->buffer_attr_req.prebuf);
1044 pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms",
1045 (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1046 (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1047 (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1048 (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC));
1051 /* This function will be called from the main thread, before as
1052 * well as after the sink input has been activated using
1053 * pa_sink_input_put()! That means it may not touch any
1054 * ->thread_info data, such as the memblockq! */
1056 frame_size = pa_frame_size(&s->sink_input->sample_spec);
1057 s->buffer_attr = s->buffer_attr_req;
1059 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
1060 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
1061 if (s->buffer_attr.maxlength <= 0)
1062 s->buffer_attr.maxlength = (uint32_t) frame_size;
1064 if (s->buffer_attr.tlength == (uint32_t) -1)
1065 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
1066 if (s->buffer_attr.tlength <= 0)
1067 s->buffer_attr.tlength = (uint32_t) frame_size;
1068 if (s->buffer_attr.tlength > s->buffer_attr.maxlength)
1069 s->buffer_attr.tlength = s->buffer_attr.maxlength;
1071 if (s->buffer_attr.minreq == (uint32_t) -1) {
1072 uint32_t process = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
1073 /* With low-latency, tlength/4 gives a decent default in all of traditional, adjust latency and early request modes. */
1074 uint32_t m = s->buffer_attr.tlength / 4;
1076 m -= m % frame_size;
1077 s->buffer_attr.minreq = PA_MIN(process, m);
1079 if (s->buffer_attr.minreq <= 0)
1080 s->buffer_attr.minreq = (uint32_t) frame_size;
1082 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
1083 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
1085 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
1086 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
1088 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
1089 (double) tlength_usec / PA_USEC_PER_MSEC,
1090 (double) minreq_usec / PA_USEC_PER_MSEC);
1092 if (s->early_requests) {
1094 /* In early request mode we need to emulate the classic
1095 * fragment-based playback model. We do this setting the sink
1096 * latency to the fragment size. */
1098 sink_usec = minreq_usec;
1099 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
1101 } else if (s->adjust_latency) {
1103 /* So, the user asked us to adjust the latency of the stream
1104 * buffer according to the what the sink can provide. The
1105 * tlength passed in shall be the overall latency. Roughly
1106 * half the latency will be spent on the hw buffer, the other
1107 * half of it in the async buffer queue we maintain for each
1108 * client. In between we'll have a safety space of size
1109 * 2*minreq. Why the 2*minreq? When the hw buffer is completely
1110 * empty and needs to be filled, then our buffer must have
1111 * enough data to fulfill this request immediately and thus
1112 * have at least the same tlength as the size of the hw
1113 * buffer. It additionally needs space for 2 times minreq
1114 * because if the buffer ran empty and a partial fillup
1115 * happens immediately on the next iteration we need to be
1116 * able to fulfill it and give the application also minreq
1117 * time to fill it up again for the next request Makes 2 times
1118 * minreq in plus.. */
1120 if (tlength_usec > minreq_usec*2)
1121 sink_usec = (tlength_usec - minreq_usec*2)/2;
1125 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
1129 /* Ok, the user didn't ask us to adjust the latency, but we
1130 * still need to make sure that the parameters from the user
1133 if (tlength_usec > minreq_usec*2)
1134 sink_usec = (tlength_usec - minreq_usec*2);
1138 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
1141 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
1143 if (s->early_requests) {
1145 /* Ok, we didn't necessarily get what we were asking for, so
1146 * let's tell the user */
1148 minreq_usec = s->configured_sink_latency;
1150 } else if (s->adjust_latency) {
1152 /* Ok, we didn't necessarily get what we were asking for, so
1153 * let's subtract from what we asked for for the remaining
1156 if (tlength_usec >= s->configured_sink_latency)
1157 tlength_usec -= s->configured_sink_latency;
1160 pa_log_debug("Requested latency=%0.2f ms, Received latency=%0.2f ms",
1161 (double) sink_usec / PA_USEC_PER_MSEC,
1162 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1164 /* FIXME: This is actually larger than necessary, since not all of
1165 * the sink latency is actually rewritable. */
1166 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
1167 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
1169 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
1170 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
1171 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
1173 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
1174 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
1175 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
1177 if (s->buffer_attr.minreq <= 0) {
1178 s->buffer_attr.minreq = (uint32_t) frame_size;
1179 s->buffer_attr.tlength += (uint32_t) frame_size*2;
1182 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
1183 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
1185 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
1187 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
1188 s->buffer_attr.prebuf > max_prebuf)
1189 s->buffer_attr.prebuf = max_prebuf;
1191 #ifdef PROTOCOL_NATIVE_DEBUG
1192 pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms",
1193 (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1194 (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1195 (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1196 (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC));
1200 /* Called from main context */
1201 static playback_stream* playback_stream_new(
1202 pa_native_connection *c,
1205 pa_channel_map *map,
1211 pa_sink_input_flags_t flags,
1213 bool adjust_latency,
1214 bool early_requests,
1215 bool relative_volume,
1220 /* Note: This function takes ownership of the 'formats' param, so we need
1221 * to take extra care to not leak it */
1223 playback_stream *ssync;
1224 playback_stream *s = NULL;
1225 pa_sink_input *sink_input = NULL;
1226 pa_memchunk silence;
1228 int64_t start_index;
1229 pa_sink_input_new_data data;
1230 char *memblockq_name;
1238 /* Find syncid group */
1239 PA_IDXSET_FOREACH(ssync, c->output_streams, idx) {
1241 if (!playback_stream_isinstance(ssync))
1244 if (ssync->syncid == syncid)
1248 /* Synced streams must connect to the same sink */
1252 sink = ssync->sink_input->sink;
1253 else if (sink != ssync->sink_input->sink) {
1254 *ret = PA_ERR_INVALID;
1259 pa_sink_input_new_data_init(&data);
1261 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1262 data.driver = __FILE__;
1263 data.module = c->options->module;
1264 data.client = c->client;
1266 pa_sink_input_new_data_set_sink(&data, sink, false);
1267 if (pa_sample_spec_valid(ss))
1268 pa_sink_input_new_data_set_sample_spec(&data, ss);
1269 if (pa_channel_map_valid(map))
1270 pa_sink_input_new_data_set_channel_map(&data, map);
1272 pa_sink_input_new_data_set_formats(&data, formats);
1273 /* Ownership transferred to new_data, so we don't free it ourselves */
1277 pa_sink_input_new_data_set_volume(&data, volume, relative_volume);
1278 data.save_volume = false;
1281 pa_sink_input_new_data_set_muted(&data, muted);
1282 data.save_muted = false;
1284 data.sync_base = ssync ? ssync->sink_input : NULL;
1287 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1291 pa_buffer_attr buffer_attr;
1292 pa_log_info("*** update buffer attributes - playback_stream_new()");
1293 if (sink_input && !update_buffer_attr(sink_input->proplist, &buffer_attr, true)) {
1294 pa_log_info(" - origins: maxlength(%d), tlength(%d), prebuf(%d), minreq(%d)",
1295 a->maxlength, a->tlength, a->prebuf, a->minreq);
1296 if ((int)a->maxlength >= 0)
1297 buffer_attr.maxlength = a->maxlength;
1298 /* "tlength" is always set to default value from pa_stream_new_with_proplist_internal() in stream.c.
1299 but here we use tlength from stream-map.json except -1. */
1300 if ((int)buffer_attr.tlength == -1)
1301 buffer_attr.tlength = a->tlength;
1302 if ((int)a->prebuf >= 0)
1303 buffer_attr.prebuf = a->prebuf;
1304 if ((int)a->minreq >= 0)
1305 buffer_attr.minreq = a->minreq;
1307 pa_log_info(" - updated: maxlength(%d), tlength(%d), prebuf(%d), minreq(%d)",
1308 a->maxlength, a->tlength, a->prebuf, a->minreq);
1313 pa_sink_input_new_data_done(&data);
1318 s = pa_msgobject_new(playback_stream);
1319 s->parent.parent.parent.free = playback_stream_free;
1320 s->parent.parent.process_msg = playback_stream_process_msg;
1323 s->sink_input = sink_input;
1324 s->is_underrun = true;
1325 s->drain_request = false;
1326 pa_atomic_store(&s->missing, 0);
1327 s->buffer_attr_req = *a;
1328 s->adjust_latency = adjust_latency;
1329 s->early_requests = early_requests;
1330 pa_atomic_store(&s->seek_or_post_in_queue, 0);
1331 s->seek_windex = -1;
1333 s->sink_input->parent.process_msg = sink_input_process_msg;
1334 s->sink_input->pop = sink_input_pop_cb;
1335 s->sink_input->process_underrun = sink_input_process_underrun_cb;
1336 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1337 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1338 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1339 s->sink_input->kill = sink_input_kill_cb;
1340 s->sink_input->moving = sink_input_moving_cb;
1341 s->sink_input->suspend = sink_input_suspend_cb;
1342 s->sink_input->send_event = sink_input_send_event_cb;
1343 s->sink_input->userdata = s;
1345 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1347 fix_playback_buffer_attr(s);
1349 pa_sink_input_get_silence(sink_input, &silence);
1350 memblockq_name = pa_sprintf_malloc("native protocol playback stream memblockq [%u]", s->sink_input->index);
1351 s->memblockq = pa_memblockq_new(
1354 s->buffer_attr.maxlength,
1355 s->buffer_attr.tlength,
1356 &sink_input->sample_spec,
1357 s->buffer_attr.prebuf,
1358 s->buffer_attr.minreq,
1361 pa_xfree(memblockq_name);
1362 pa_memblock_unref(silence.memblock);
1364 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1366 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1368 #ifdef PROTOCOL_NATIVE_DEBUG
1369 pa_log("missing original: %li", (long int) *missing);
1372 *ss = s->sink_input->sample_spec;
1373 *map = s->sink_input->channel_map;
1375 pa_idxset_put(c->output_streams, s, &s->index);
1377 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1378 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1379 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1380 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1381 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1383 pa_sink_input_put(s->sink_input);
1387 pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
1392 /* Called from IO context */
1393 static void playback_stream_request_bytes(playback_stream *s) {
1395 int previous_missing;
1397 playback_stream_assert_ref(s);
1399 m = pa_memblockq_pop_missing(s->memblockq);
1401 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1402 /* (unsigned long) m, */
1403 /* pa_memblockq_get_tlength(s->memblockq), */
1404 /* pa_memblockq_get_minreq(s->memblockq), */
1405 /* pa_memblockq_get_length(s->memblockq), */
1406 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1411 #ifdef PROTOCOL_NATIVE_DEBUG
1412 pa_log("request_bytes(%lu)", (unsigned long) m);
1415 previous_missing = pa_atomic_add(&s->missing, (int) m);
1416 minreq = pa_memblockq_get_minreq(s->memblockq);
1418 if (pa_memblockq_prebuf_active(s->memblockq) ||
1419 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1420 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1423 /* Called from main context */
1424 static void playback_stream_send_killed(playback_stream *p) {
1426 playback_stream_assert_ref(p);
1428 t = pa_tagstruct_new(NULL, 0);
1429 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1430 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1431 pa_tagstruct_putu32(t, p->index);
1432 pa_pstream_send_tagstruct(p->connection->pstream, t);
1435 /* Called from main context */
1436 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1437 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1438 pa_native_connection_assert_ref(c);
1445 case CONNECTION_MESSAGE_REVOKE:
1446 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1449 case CONNECTION_MESSAGE_RELEASE:
1450 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1457 /* Called from main context */
1458 static void native_connection_unlink(pa_native_connection *c) {
1467 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1470 pa_native_options_unref(c->options);
1472 while ((r = pa_idxset_first(c->record_streams, NULL)))
1473 record_stream_unlink(r);
1475 while ((o = pa_idxset_first(c->output_streams, NULL)))
1476 if (playback_stream_isinstance(o))
1477 playback_stream_unlink(PLAYBACK_STREAM(o));
1479 upload_stream_unlink(UPLOAD_STREAM(o));
1481 if (c->subscription)
1482 pa_subscription_free(c->subscription);
1485 pa_pstream_unlink(c->pstream);
1487 if (c->auth_timeout_event) {
1488 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1489 c->auth_timeout_event = NULL;
1492 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1494 pa_native_connection_unref(c);
1497 /* Called from main context */
1498 static void native_connection_free(pa_object *o) {
1499 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1503 native_connection_unlink(c);
1505 pa_idxset_free(c->record_streams, NULL);
1506 pa_idxset_free(c->output_streams, NULL);
1508 pa_pdispatch_unref(c->pdispatch);
1509 pa_pstream_unref(c->pstream);
1510 pa_client_free(c->client);
1515 /* Called from main context */
1516 static void native_connection_send_memblock(pa_native_connection *c) {
1520 start = PA_IDXSET_INVALID;
1524 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1527 if (start == PA_IDXSET_INVALID)
1528 start = c->rrobin_index;
1529 else if (start == c->rrobin_index)
1532 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1533 pa_memchunk schunk = chunk;
1535 if (schunk.length > r->buffer_attr.fragsize)
1536 schunk.length = r->buffer_attr.fragsize;
1538 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1540 pa_memblockq_drop(r->memblockq, schunk.length);
1541 pa_memblock_unref(schunk.memblock);
1548 /*** sink input callbacks ***/
1550 /* Called from thread context */
1551 static void handle_seek(playback_stream *s, int64_t indexw) {
1552 playback_stream_assert_ref(s);
1554 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1556 if (s->sink_input->thread_info.underrun_for > 0) {
1558 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1560 if (pa_memblockq_is_readable(s->memblockq)) {
1562 /* We just ended an underrun, let's ask the sink
1563 * for a complete rewind rewrite */
1565 pa_log_debug("Requesting rewind due to end of underrun.");
1566 pa_sink_input_request_rewind(s->sink_input,
1567 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1568 s->sink_input->thread_info.underrun_for),
1569 false, true, false);
1575 indexr = pa_memblockq_get_read_index(s->memblockq);
1577 if (indexw < indexr) {
1578 /* OK, the sink already asked for this data, so
1579 * let's have it ask us again */
1581 pa_log_debug("Requesting rewind due to rewrite.");
1582 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), true, false, false);
1586 playback_stream_request_bytes(s);
1589 static void flush_write_no_account(pa_memblockq *q) {
1590 pa_memblockq_flush_write(q, false);
1593 /* Called from thread context */
1594 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1595 pa_sink_input *i = PA_SINK_INPUT(o);
1598 pa_sink_input_assert_ref(i);
1599 s = PLAYBACK_STREAM(i->userdata);
1600 playback_stream_assert_ref(s);
1604 case SINK_INPUT_MESSAGE_SEEK:
1605 case SINK_INPUT_MESSAGE_POST_DATA: {
1606 int64_t windex = pa_memblockq_get_write_index(s->memblockq);
1608 if (code == SINK_INPUT_MESSAGE_SEEK) {
1609 /* The client side is incapable of accounting correctly
1610 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1611 * able to deal with that. */
1613 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1614 windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
1617 if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1618 if (pa_log_ratelimit(PA_LOG_WARN))
1619 pa_log_warn("Failed to push data into queue");
1620 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1621 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, true);
1624 /* If more data is in queue, we rewind later instead. */
1625 if (s->seek_windex != -1)
1626 windex = PA_MIN(windex, s->seek_windex);
1627 if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
1628 s->seek_windex = windex;
1630 s->seek_windex = -1;
1631 handle_seek(s, windex);
1636 case SINK_INPUT_MESSAGE_DRAIN:
1637 case SINK_INPUT_MESSAGE_FLUSH:
1638 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1639 case SINK_INPUT_MESSAGE_TRIGGER: {
1642 pa_sink_input *isync;
1643 void (*func)(pa_memblockq *bq);
1646 case SINK_INPUT_MESSAGE_FLUSH:
1647 func = flush_write_no_account;
1650 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1651 func = pa_memblockq_prebuf_force;
1654 case SINK_INPUT_MESSAGE_DRAIN:
1655 case SINK_INPUT_MESSAGE_TRIGGER:
1656 func = pa_memblockq_prebuf_disable;
1660 pa_assert_not_reached();
1663 windex = pa_memblockq_get_write_index(s->memblockq);
1665 handle_seek(s, windex);
1667 /* Do the same for all other members in the sync group */
1668 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1669 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1670 windex = pa_memblockq_get_write_index(ssync->memblockq);
1671 func(ssync->memblockq);
1672 handle_seek(ssync, windex);
1675 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1676 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1677 windex = pa_memblockq_get_write_index(ssync->memblockq);
1678 func(ssync->memblockq);
1679 handle_seek(ssync, windex);
1683 if (code == SINK_INPUT_MESSAGE_FLUSH) {
1684 pa_log_debug("Requesting rewind due to rewrite. Flush old data in sink");
1685 pa_sink_input_request_rewind(s->sink_input, 0, FALSE, TRUE, FALSE);
1689 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1690 if (!pa_memblockq_is_readable(s->memblockq))
1691 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1693 s->drain_tag = PA_PTR_TO_UINT(userdata);
1694 s->drain_request = true;
1701 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1702 /* Atomically get a snapshot of all timing parameters... */
1703 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1704 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1705 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1706 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1707 s->underrun_for = s->sink_input->thread_info.underrun_for;
1708 s->playing_for = s->sink_input->thread_info.playing_for;
1712 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1715 windex = pa_memblockq_get_write_index(s->memblockq);
1717 /* We enable prebuffering so that after CORKED -> RUNNING
1718 * transitions we don't have trouble with underruns in case the
1719 * buffer has too little data. This must not be done when draining
1720 * has been requested, however, otherwise the buffered audio would
1722 if (!s->drain_request)
1723 pa_memblockq_prebuf_force(s->memblockq);
1725 handle_seek(s, windex);
1727 /* Fall through to the default handler */
1731 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1732 pa_usec_t *r = userdata;
1734 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1736 /* Fall through, the default handler will add in the extra
1737 * latency added by the resampler */
1741 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1742 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1743 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1748 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1751 static bool handle_input_underrun(playback_stream *s, bool force) {
1754 if (pa_memblockq_is_readable(s->memblockq))
1757 if (!s->is_underrun)
1758 pa_log_debug("%s %s of '%s'", force ? "Actual" : "Implicit",
1759 s->drain_request ? "drain" : "underrun", pa_strnull(pa_proplist_gets(s->sink_input->proplist, PA_PROP_MEDIA_NAME)));
1761 send_drain = s->drain_request && (force || pa_sink_input_safe_to_remove(s->sink_input));
1764 s->drain_request = false;
1765 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);
1766 pa_log_debug("Drain acknowledged of '%s'", pa_strnull(pa_proplist_gets(s->sink_input->proplist, PA_PROP_MEDIA_NAME)));
1767 } else if (!s->is_underrun) {
1768 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, pa_memblockq_get_read_index(s->memblockq), NULL, NULL);
1770 s->is_underrun = true;
1771 playback_stream_request_bytes(s);
1775 /* Called from thread context */
1776 static bool sink_input_process_underrun_cb(pa_sink_input *i) {
1779 pa_sink_input_assert_ref(i);
1780 s = PLAYBACK_STREAM(i->userdata);
1781 playback_stream_assert_ref(s);
1783 return handle_input_underrun(s, true);
1787 static void _check_zero_pop_timeout(pa_sink_input *i) {
1788 uint32_t zero_pop_time = 0;
1789 playback_stream *s = PLAYBACK_STREAM(i->userdata);
1791 if (pa_memblockq_get_length(s->memblockq) == 0) {
1792 if (i->zero_pop_start_time) {
1793 /* calculate zero pop time in seconds */
1794 zero_pop_time = (uint32_t)((pa_rtclock_now() - i->zero_pop_start_time) / PA_USEC_PER_SEC);
1796 /* check only once per seconds */
1797 if (zero_pop_time > i->old_zero_pop_time) {
1798 pa_log_debug("zero pop (no sink-input data) for [%u] sec., timeout in [%u] sec.",
1799 zero_pop_time, i->core->zero_pop_threshold);
1801 if (zero_pop_time >= i->core->zero_pop_threshold) {
1802 pa_log_warn("async msgq post : PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT");
1803 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s),
1804 PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT, NULL, 0, NULL, NULL);
1805 i->zero_pop_start_time = 0; /* this will make reset count */
1807 i->old_zero_pop_time = zero_pop_time;
1811 pa_log_debug("zero pop start!!!");
1812 i->zero_pop_start_time = pa_rtclock_now();
1813 i->old_zero_pop_time = 0;
1816 if (i->zero_pop_start_time) {
1817 pa_log_debug("zero pop end...");
1818 i->zero_pop_start_time = 0;
1824 /* Called from thread context */
1825 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1828 pa_sink_input_assert_ref(i);
1829 s = PLAYBACK_STREAM(i->userdata);
1830 playback_stream_assert_ref(s);
1833 #ifdef PROTOCOL_NATIVE_DEBUG
1834 pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq));
1838 /* If zero pops exceeds certain threshold, send message to client to handle this situation */
1839 /* FIXME: maybe we can use s->is_underrun to check.... */
1840 if (!i->is_virtual) /* skip for virtual stream */
1841 _check_zero_pop_timeout(i);
1844 if (!handle_input_underrun(s, false))
1845 s->is_underrun = false;
1847 /* This call will not fail with prebuf=0, hence we check for
1848 underrun explicitly in handle_input_underrun */
1849 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1852 chunk->length = PA_MIN(nbytes, chunk->length);
1854 if (i->thread_info.underrun_for > 0)
1855 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1857 pa_memblockq_drop(s->memblockq, chunk->length);
1858 playback_stream_request_bytes(s);
1863 /* Called from thread context */
1864 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1867 pa_sink_input_assert_ref(i);
1868 s = PLAYBACK_STREAM(i->userdata);
1869 playback_stream_assert_ref(s);
1871 /* If we are in an underrun, then we don't rewind */
1872 if (i->thread_info.underrun_for > 0)
1875 pa_memblockq_rewind(s->memblockq, nbytes);
1878 /* Called from thread context */
1879 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1882 pa_sink_input_assert_ref(i);
1883 s = PLAYBACK_STREAM(i->userdata);
1884 playback_stream_assert_ref(s);
1886 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1889 /* Called from thread context */
1890 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1892 size_t new_tlength, old_tlength;
1894 pa_sink_input_assert_ref(i);
1895 s = PLAYBACK_STREAM(i->userdata);
1896 playback_stream_assert_ref(s);
1898 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1899 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1901 if (old_tlength < new_tlength) {
1902 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1903 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1904 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1906 if (new_tlength == old_tlength)
1907 pa_log_debug("Failed to increase tlength");
1909 pa_log_debug("Notifying client about increased tlength");
1910 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);
1915 /* Called from main context */
1916 static void sink_input_kill_cb(pa_sink_input *i) {
1919 pa_sink_input_assert_ref(i);
1920 s = PLAYBACK_STREAM(i->userdata);
1921 playback_stream_assert_ref(s);
1923 playback_stream_send_killed(s);
1924 playback_stream_unlink(s);
1927 /* Called from main context */
1928 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1932 pa_sink_input_assert_ref(i);
1933 s = PLAYBACK_STREAM(i->userdata);
1934 playback_stream_assert_ref(s);
1936 if (s->connection->version < 15)
1939 t = pa_tagstruct_new(NULL, 0);
1940 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1941 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1942 pa_tagstruct_putu32(t, s->index);
1943 pa_tagstruct_puts(t, event);
1944 pa_tagstruct_put_proplist(t, pl);
1945 pa_pstream_send_tagstruct(s->connection->pstream, t);
1948 /* Called from main context */
1949 static void sink_input_suspend_cb(pa_sink_input *i, bool suspend) {
1953 pa_sink_input_assert_ref(i);
1954 s = PLAYBACK_STREAM(i->userdata);
1955 playback_stream_assert_ref(s);
1957 if (s->connection->version < 12)
1960 t = pa_tagstruct_new(NULL, 0);
1961 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1962 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1963 pa_tagstruct_putu32(t, s->index);
1964 pa_tagstruct_put_boolean(t, suspend);
1965 pa_pstream_send_tagstruct(s->connection->pstream, t);
1968 /* Called from main context */
1969 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1973 pa_sink_input_assert_ref(i);
1974 s = PLAYBACK_STREAM(i->userdata);
1975 playback_stream_assert_ref(s);
1980 fix_playback_buffer_attr(s);
1981 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1982 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1984 if (s->connection->version < 12)
1987 t = pa_tagstruct_new(NULL, 0);
1988 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1989 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1990 pa_tagstruct_putu32(t, s->index);
1991 pa_tagstruct_putu32(t, dest->index);
1992 pa_tagstruct_puts(t, dest->name);
1993 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1995 if (s->connection->version >= 13) {
1996 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1997 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1998 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1999 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
2000 pa_tagstruct_put_usec(t, s->configured_sink_latency);
2003 pa_pstream_send_tagstruct(s->connection->pstream, t);
2006 /*** source_output callbacks ***/
2008 /* Called from thread context */
2009 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
2010 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
2013 pa_source_output_assert_ref(o);
2014 s = RECORD_STREAM(o->userdata);
2015 record_stream_assert_ref(s);
2018 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
2019 /* Atomically get a snapshot of all timing parameters... */
2020 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
2021 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
2022 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
2026 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
2029 /* Called from thread context */
2030 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
2033 pa_source_output_assert_ref(o);
2034 s = RECORD_STREAM(o->userdata);
2035 record_stream_assert_ref(s);
2038 pa_atomic_add(&s->on_the_fly, chunk->length);
2039 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
2042 static void source_output_kill_cb(pa_source_output *o) {
2045 pa_source_output_assert_ref(o);
2046 s = RECORD_STREAM(o->userdata);
2047 record_stream_assert_ref(s);
2049 record_stream_send_killed(s);
2050 record_stream_unlink(s);
2053 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
2056 pa_source_output_assert_ref(o);
2057 s = RECORD_STREAM(o->userdata);
2058 record_stream_assert_ref(s);
2060 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
2062 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
2065 /* Called from main context */
2066 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
2070 pa_source_output_assert_ref(o);
2071 s = RECORD_STREAM(o->userdata);
2072 record_stream_assert_ref(s);
2074 if (s->connection->version < 15)
2077 t = pa_tagstruct_new(NULL, 0);
2078 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
2079 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
2080 pa_tagstruct_putu32(t, s->index);
2081 pa_tagstruct_puts(t, event);
2082 pa_tagstruct_put_proplist(t, pl);
2083 pa_pstream_send_tagstruct(s->connection->pstream, t);
2086 /* Called from main context */
2087 static void source_output_suspend_cb(pa_source_output *o, bool suspend) {
2091 pa_source_output_assert_ref(o);
2092 s = RECORD_STREAM(o->userdata);
2093 record_stream_assert_ref(s);
2095 if (s->connection->version < 12)
2098 t = pa_tagstruct_new(NULL, 0);
2099 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
2100 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
2101 pa_tagstruct_putu32(t, s->index);
2102 pa_tagstruct_put_boolean(t, suspend);
2103 pa_pstream_send_tagstruct(s->connection->pstream, t);
2106 /* Called from main context */
2107 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
2111 pa_source_output_assert_ref(o);
2112 s = RECORD_STREAM(o->userdata);
2113 record_stream_assert_ref(s);
2118 fix_record_buffer_attr_pre(s);
2119 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
2120 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
2121 fix_record_buffer_attr_post(s);
2123 if (s->connection->version < 12)
2126 t = pa_tagstruct_new(NULL, 0);
2127 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
2128 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
2129 pa_tagstruct_putu32(t, s->index);
2130 pa_tagstruct_putu32(t, dest->index);
2131 pa_tagstruct_puts(t, dest->name);
2132 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
2134 if (s->connection->version >= 13) {
2135 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
2136 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
2137 pa_tagstruct_put_usec(t, s->configured_source_latency);
2140 pa_pstream_send_tagstruct(s->connection->pstream, t);
2143 /*** pdispatch callbacks ***/
2145 static void protocol_error(pa_native_connection *c) {
2146 pa_log("protocol error, kicking client");
2147 native_connection_unlink(c);
2150 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
2151 if (!(expression)) { \
2152 pa_pstream_send_error((pstream), (tag), (error)); \
2157 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
2158 if (!(expression)) { \
2159 pa_pstream_send_error((pstream), (tag), (error)); \
2164 static pa_tagstruct *reply_new(uint32_t tag) {
2165 pa_tagstruct *reply;
2167 reply = pa_tagstruct_new(NULL, 0);
2168 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
2169 pa_tagstruct_putu32(reply, tag);
2173 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2174 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2176 uint32_t sink_index, syncid, missing = 0;
2177 pa_buffer_attr attr;
2178 const char *name = NULL, *sink_name;
2181 pa_tagstruct *reply;
2182 pa_sink *sink = NULL;
2190 fix_channels = false,
2192 variable_rate = false,
2194 adjust_latency = false,
2195 early_requests = false,
2196 dont_inhibit_auto_suspend = false,
2199 fail_on_suspend = false,
2200 relative_volume = false,
2201 passthrough = false,
2204 pa_sink_input_flags_t flags = 0;
2205 pa_proplist *p = NULL;
2206 int ret = PA_ERR_INVALID;
2207 uint8_t n_formats = 0;
2208 pa_format_info *format;
2209 pa_idxset *formats = NULL;
2212 pa_native_connection_assert_ref(c);
2214 memset(&attr, 0, sizeof(attr));
2216 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2219 PA_TAG_SAMPLE_SPEC, &ss,
2220 PA_TAG_CHANNEL_MAP, &map,
2221 PA_TAG_U32, &sink_index,
2222 PA_TAG_STRING, &sink_name,
2223 PA_TAG_U32, &attr.maxlength,
2224 PA_TAG_BOOLEAN, &corked,
2225 PA_TAG_U32, &attr.tlength,
2226 PA_TAG_U32, &attr.prebuf,
2227 PA_TAG_U32, &attr.minreq,
2228 PA_TAG_U32, &syncid,
2229 PA_TAG_CVOLUME, &volume,
2230 PA_TAG_INVALID) < 0) {
2236 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
2237 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID, finish);
2238 CHECK_VALIDITY_GOTO(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID, finish);
2239 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
2240 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
2242 p = pa_proplist_new();
2245 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2247 if (c->version >= 12) {
2248 /* Since 0.9.8 the user can ask for a couple of additional flags */
2250 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2251 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2252 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2253 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2254 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2255 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2256 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2263 if (c->version >= 13) {
2265 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
2266 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2267 pa_tagstruct_get_proplist(t, p) < 0) {
2274 if (c->version >= 14) {
2276 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2277 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2284 if (c->version >= 15) {
2286 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2287 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2288 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2295 if (c->version >= 17) {
2297 if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
2304 if (c->version >= 18) {
2306 if (pa_tagstruct_get_boolean(t, &passthrough) < 0 ) {
2312 if (c->version >= 21) {
2314 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2320 formats = pa_idxset_new(NULL, NULL);
2322 for (i = 0; i < n_formats; i++) {
2323 format = pa_format_info_new();
2324 if (pa_tagstruct_get_format_info(t, format) < 0) {
2328 pa_idxset_put(formats, format, NULL);
2333 if (n_formats == 0) {
2334 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2335 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2336 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2338 PA_IDXSET_FOREACH(format, formats, i) {
2339 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2343 if (pa_tagstruct_get_boolean(t, &ramp_muted) < 0 ) {
2348 if (!pa_tagstruct_eof(t)) {
2353 if (sink_index != PA_INVALID_INDEX) {
2355 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
2356 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2360 } else if (sink_name) {
2362 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
2363 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2369 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
2370 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
2371 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
2372 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
2373 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
2374 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
2375 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
2376 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
2377 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2378 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
2379 (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0) |
2380 (ramp_muted ? PA_SINK_INPUT_START_RAMP_MUTED : 0);
2382 /* Only since protocol version 15 there's a separate muted_set
2383 * flag. For older versions we synthesize it here */
2384 muted_set = muted_set || muted;
2386 s = playback_stream_new(c, sink, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, p, adjust_latency, early_requests, relative_volume, syncid, &missing, &ret);
2387 /* We no longer own the formats idxset */
2390 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2392 reply = reply_new(tag);
2393 pa_tagstruct_putu32(reply, s->index);
2394 pa_assert(s->sink_input);
2395 pa_tagstruct_putu32(reply, s->sink_input->index);
2396 pa_tagstruct_putu32(reply, missing);
2398 #ifdef PROTOCOL_NATIVE_DEBUG
2399 pa_log("initial request is %u", missing);
2402 if (c->version >= 9) {
2403 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2405 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2406 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2407 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2408 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2411 if (c->version >= 12) {
2412 /* Since 0.9.8 we support sending the chosen sample
2413 * spec/channel map/device/suspend status back to the
2416 pa_tagstruct_put_sample_spec(reply, &ss);
2417 pa_tagstruct_put_channel_map(reply, &map);
2419 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2420 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2422 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2425 if (c->version >= 13)
2426 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2428 if (c->version >= 21) {
2429 /* Send back the format we negotiated */
2430 if (s->sink_input->format)
2431 pa_tagstruct_put_format_info(reply, s->sink_input->format);
2433 pa_format_info *f = pa_format_info_new();
2434 pa_tagstruct_put_format_info(reply, f);
2435 pa_format_info_free(f);
2439 pa_pstream_send_tagstruct(c->pstream, reply);
2443 pa_proplist_free(p);
2445 pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
2448 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2449 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2452 pa_native_connection_assert_ref(c);
2455 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2456 !pa_tagstruct_eof(t)) {
2461 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2465 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2467 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2468 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2472 playback_stream_unlink(s);
2476 case PA_COMMAND_DELETE_RECORD_STREAM: {
2478 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2479 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2483 record_stream_unlink(s);
2487 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2490 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2491 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2495 upload_stream_unlink(s);
2500 pa_assert_not_reached();
2503 pa_pstream_send_simple_ack(c->pstream, tag);
2507 static void command_check_privilege(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2508 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2509 const char *privilege;
2511 pa_native_connection_assert_ref(c);
2514 if (pa_tagstruct_gets(t, &privilege) < 0) {
2520 CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), privilege), tag, PA_ERR_ACCESS);
2522 pa_log_warn("Cannot check privilege %s", privilege);
2524 pa_pstream_send_simple_ack(c->pstream, tag);
2528 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2529 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2531 pa_buffer_attr attr;
2532 uint32_t source_index;
2533 const char *name = NULL, *source_name;
2536 pa_tagstruct *reply;
2537 pa_source *source = NULL;
2545 fix_channels = false,
2547 variable_rate = false,
2549 adjust_latency = false,
2550 peak_detect = false,
2551 early_requests = false,
2552 dont_inhibit_auto_suspend = false,
2555 fail_on_suspend = false,
2556 relative_volume = false,
2557 passthrough = false;
2559 pa_source_output_flags_t flags = 0;
2560 pa_proplist *p = NULL;
2561 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2562 pa_sink_input *direct_on_input = NULL;
2563 int ret = PA_ERR_INVALID;
2564 uint8_t n_formats = 0;
2565 pa_format_info *format;
2566 pa_idxset *formats = NULL;
2570 bool is_virtual_stream = false;
2573 pa_native_connection_assert_ref(c);
2576 memset(&attr, 0, sizeof(attr));
2578 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2579 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2580 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2581 pa_tagstruct_getu32(t, &source_index) < 0 ||
2582 pa_tagstruct_gets(t, &source_name) < 0 ||
2583 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2584 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2585 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2591 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
2592 CHECK_VALIDITY_GOTO(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID, finish);
2593 CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID, finish);
2594 CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
2597 pa_tagstruct_get_boolean(t, &is_virtual_stream);
2598 pa_log_info("is virtual stream : %s", pa_yes_no(is_virtual_stream));
2599 if (!is_virtual_stream) {
2600 CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), RECORDER_PRIVILEGE),
2601 tag, PA_ERR_ACCESS);
2603 #endif /* USE_SECURITY */
2605 p = pa_proplist_new();
2608 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2610 if (c->version >= 12) {
2611 /* Since 0.9.8 the user can ask for a couple of additional flags */
2613 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2614 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2615 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2616 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2617 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2618 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2619 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2626 if (c->version >= 13) {
2628 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2629 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2630 pa_tagstruct_get_proplist(t, p) < 0 ||
2631 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2638 if (c->version >= 14) {
2640 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2646 if (c->version >= 15) {
2648 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2649 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2656 if (c->version >= 22) {
2657 /* For newer client versions (with per-source-output volumes), we try
2658 * to make the behaviour for playback and record streams the same. */
2661 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2667 formats = pa_idxset_new(NULL, NULL);
2669 for (i = 0; i < n_formats; i++) {
2670 format = pa_format_info_new();
2671 if (pa_tagstruct_get_format_info(t, format) < 0) {
2675 pa_idxset_put(formats, format, NULL);
2678 if (pa_tagstruct_get_cvolume(t, &volume) < 0 ||
2679 pa_tagstruct_get_boolean(t, &muted) < 0 ||
2680 pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2681 pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2682 pa_tagstruct_get_boolean(t, &relative_volume) < 0 ||
2683 pa_tagstruct_get_boolean(t, &passthrough) < 0) {
2689 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
2692 if (n_formats == 0) {
2693 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2694 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2695 CHECK_VALIDITY_GOTO(c->pstream, c->version < 22 || (volume.channels == ss.channels), tag, PA_ERR_INVALID, finish);
2696 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2698 PA_IDXSET_FOREACH(format, formats, i) {
2699 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2703 if (!pa_tagstruct_eof(t)) {
2708 if (source_index != PA_INVALID_INDEX) {
2710 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2711 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2715 } else if (source_name) {
2717 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2718 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2723 if (direct_on_input_idx != PA_INVALID_INDEX) {
2725 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2726 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2732 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2733 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2734 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2735 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2736 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2737 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2738 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2739 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2740 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2741 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0) |
2742 (passthrough ? PA_SOURCE_OUTPUT_PASSTHROUGH : 0);
2744 s = record_stream_new(c, source, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, p, adjust_latency, early_requests, relative_volume, peak_detect, direct_on_input, &ret);
2746 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2748 reply = reply_new(tag);
2749 pa_tagstruct_putu32(reply, s->index);
2750 pa_assert(s->source_output);
2751 pa_tagstruct_putu32(reply, s->source_output->index);
2753 if (c->version >= 9) {
2754 /* Since 0.9 we support sending the buffer metrics back to the client */
2756 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2757 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2760 if (c->version >= 12) {
2761 /* Since 0.9.8 we support sending the chosen sample
2762 * spec/channel map/device/suspend status back to the
2765 pa_tagstruct_put_sample_spec(reply, &ss);
2766 pa_tagstruct_put_channel_map(reply, &map);
2768 pa_tagstruct_putu32(reply, s->source_output->source->index);
2769 pa_tagstruct_puts(reply, s->source_output->source->name);
2771 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2774 if (c->version >= 13)
2775 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2777 if (c->version >= 22) {
2778 /* Send back the format we negotiated */
2779 if (s->source_output->format)
2780 pa_tagstruct_put_format_info(reply, s->source_output->format);
2782 pa_format_info *f = pa_format_info_new();
2783 pa_tagstruct_put_format_info(reply, f);
2784 pa_format_info_free(f);
2788 pa_pstream_send_tagstruct(c->pstream, reply);
2792 pa_proplist_free(p);
2794 pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
2797 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2798 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2801 pa_native_connection_assert_ref(c);
2804 if (!pa_tagstruct_eof(t)) {
2809 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2810 ret = pa_core_exit(c->protocol->core, false, 0);
2811 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2813 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2815 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2818 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2819 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2821 pa_tagstruct *reply;
2822 bool shm_on_remote = false, do_shm;
2824 pa_native_connection_assert_ref(c);
2827 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2828 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2829 !pa_tagstruct_eof(t)) {
2834 /* Minimum supported version */
2835 if (c->version < 8) {
2836 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2840 /* Starting with protocol version 13 the MSB of the version tag
2841 reflects if shm is available for this pa_native_connection or
2843 if (c->version >= 13) {
2844 shm_on_remote = !!(c->version & 0x80000000U);
2845 c->version &= 0x7FFFFFFFU;
2848 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2850 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2852 if (!c->authorized) {
2853 bool success = false;
2856 const pa_creds *creds;
2858 if ((creds = pa_pdispatch_creds(pd))) {
2859 if (creds->uid == getuid())
2861 else if (c->options->auth_group) {
2865 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2866 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2867 else if (gid == creds->gid)
2871 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2872 pa_log_warn("Failed to check group membership.");
2878 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2879 (unsigned long) creds->uid,
2880 (unsigned long) creds->gid,
2885 if (!success && c->options->auth_cookie) {
2888 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2889 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2894 pa_log_warn("Denied access to client with invalid authorization data.");
2895 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2899 c->authorized = true;
2900 if (c->auth_timeout_event) {
2901 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2902 c->auth_timeout_event = NULL;
2906 /* Enable shared memory support if possible */
2908 pa_mempool_is_shared(c->protocol->core->mempool) &&
2911 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2914 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2919 /* Only enable SHM if both sides are owned by the same
2920 * user. This is a security measure because otherwise data
2921 * private to the user might leak. */
2923 const pa_creds *creds;
2924 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2929 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2930 pa_pstream_enable_shm(c->pstream, do_shm);
2932 reply = reply_new(tag);
2933 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2937 /* SHM support is only enabled after both sides made sure they are the same user. */
2941 ucred.uid = getuid();
2942 ucred.gid = getgid();
2944 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2947 pa_pstream_send_tagstruct(c->pstream, reply);
2951 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2952 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2953 const char *name = NULL;
2955 pa_tagstruct *reply;
2957 pa_native_connection_assert_ref(c);
2960 p = pa_proplist_new();
2962 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2963 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2964 !pa_tagstruct_eof(t)) {
2967 pa_proplist_free(p);
2972 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2973 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2974 pa_proplist_free(p);
2978 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2979 pa_proplist_free(p);
2981 reply = reply_new(tag);
2983 if (c->version >= 13)
2984 pa_tagstruct_putu32(reply, c->client->index);
2986 pa_pstream_send_tagstruct(c->pstream, reply);
2989 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2990 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2992 uint32_t idx = PA_IDXSET_INVALID;
2994 pa_native_connection_assert_ref(c);
2997 if (pa_tagstruct_gets(t, &name) < 0 ||
2998 !pa_tagstruct_eof(t)) {
3003 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3004 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_LOOKUP_SINK ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
3006 if (command == PA_COMMAND_LOOKUP_SINK) {
3008 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
3012 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
3013 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
3014 idx = source->index;
3017 if (idx == PA_IDXSET_INVALID)
3018 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3020 pa_tagstruct *reply;
3021 reply = reply_new(tag);
3022 pa_tagstruct_putu32(reply, idx);
3023 pa_pstream_send_tagstruct(c->pstream, reply);
3027 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3028 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3032 pa_native_connection_assert_ref(c);
3035 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3036 !pa_tagstruct_eof(t)) {
3041 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3042 s = pa_idxset_get_by_index(c->output_streams, idx);
3043 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3044 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3046 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);
3049 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3050 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3051 pa_tagstruct *reply;
3052 const pa_mempool_stat *stat;
3054 pa_native_connection_assert_ref(c);
3057 if (!pa_tagstruct_eof(t)) {
3062 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3064 stat = pa_mempool_get_stat(c->protocol->core->mempool);
3066 reply = reply_new(tag);
3067 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
3068 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
3069 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
3070 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
3071 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
3072 pa_pstream_send_tagstruct(c->pstream, reply);
3075 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3076 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3077 pa_tagstruct *reply;
3079 struct timeval tv, now;
3082 pa_native_connection_assert_ref(c);
3085 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3086 pa_tagstruct_get_timeval(t, &tv) < 0 ||
3087 !pa_tagstruct_eof(t)) {
3092 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3093 s = pa_idxset_get_by_index(c->output_streams, idx);
3094 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3095 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3097 /* Get an atomic snapshot of all timing parameters */
3098 pa_assert_se(pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0);
3100 reply = reply_new(tag);
3101 pa_tagstruct_put_usec(reply,
3102 s->current_sink_latency +
3103 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
3104 pa_tagstruct_put_usec(reply, 0);
3105 pa_tagstruct_put_boolean(reply,
3106 s->playing_for > 0 &&
3107 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
3108 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
3109 pa_tagstruct_put_timeval(reply, &tv);
3110 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
3111 pa_tagstruct_puts64(reply, s->write_index);
3112 pa_tagstruct_puts64(reply, s->read_index);
3114 if (c->version >= 13) {
3115 pa_tagstruct_putu64(reply, s->underrun_for);
3116 pa_tagstruct_putu64(reply, s->playing_for);
3119 pa_pstream_send_tagstruct(c->pstream, reply);
3122 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3123 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3124 pa_tagstruct *reply;
3126 struct timeval tv, now;
3129 pa_native_connection_assert_ref(c);
3132 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3133 pa_tagstruct_get_timeval(t, &tv) < 0 ||
3134 !pa_tagstruct_eof(t)) {
3139 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3140 s = pa_idxset_get_by_index(c->record_streams, idx);
3141 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3143 /* Get an atomic snapshot of all timing parameters */
3144 pa_assert_se(pa_asyncmsgq_send(s->source_output->source->asyncmsgq, PA_MSGOBJECT(s->source_output), SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0);
3146 reply = reply_new(tag);
3147 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
3148 pa_tagstruct_put_usec(reply,
3149 s->current_source_latency +
3150 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec));
3151 pa_tagstruct_put_boolean(reply,
3152 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
3153 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
3154 pa_tagstruct_put_timeval(reply, &tv);
3155 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
3156 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
3157 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
3158 pa_pstream_send_tagstruct(c->pstream, reply);
3161 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3162 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3165 const char *name = NULL;
3168 pa_tagstruct *reply;
3171 pa_native_connection_assert_ref(c);
3174 if (pa_tagstruct_gets(t, &name) < 0 ||
3175 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
3176 pa_tagstruct_get_channel_map(t, &map) < 0 ||
3177 pa_tagstruct_getu32(t, &length) < 0) {
3182 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3183 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
3184 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
3185 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
3186 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
3187 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
3189 p = pa_proplist_new();
3191 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
3192 !pa_tagstruct_eof(t)) {
3195 pa_proplist_free(p);
3199 if (c->version < 13)
3200 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
3202 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
3203 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
3205 if (!name || !pa_namereg_is_valid_name(name)) {
3206 pa_proplist_free(p);
3207 CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_INVALID);
3210 s = upload_stream_new(c, &ss, &map, name, length, p);
3211 pa_proplist_free(p);
3213 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
3215 reply = reply_new(tag);
3216 pa_tagstruct_putu32(reply, s->index);
3217 pa_tagstruct_putu32(reply, length);
3218 pa_pstream_send_tagstruct(c->pstream, reply);
3221 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3222 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3227 pa_native_connection_assert_ref(c);
3230 if (pa_tagstruct_getu32(t, &channel) < 0 ||
3231 !pa_tagstruct_eof(t)) {
3236 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3238 s = pa_idxset_get_by_index(c->output_streams, channel);
3239 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3240 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3242 if (!s->memchunk.memblock)
3243 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
3244 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
3245 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
3247 pa_pstream_send_simple_ack(c->pstream, tag);
3249 upload_stream_unlink(s);
3252 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3253 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3254 uint32_t sink_index;
3257 const char *name, *sink_name;
3260 pa_tagstruct *reply;
3262 pa_native_connection_assert_ref(c);
3265 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3267 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
3268 pa_tagstruct_gets(t, &sink_name) < 0 ||
3269 pa_tagstruct_getu32(t, &volume) < 0 ||
3270 pa_tagstruct_gets(t, &name) < 0) {
3275 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
3276 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
3277 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3278 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3280 if (sink_index != PA_INVALID_INDEX)
3281 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
3283 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
3285 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3287 p = pa_proplist_new();
3289 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
3290 !pa_tagstruct_eof(t)) {
3292 pa_proplist_free(p);
3296 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
3298 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
3299 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3300 pa_proplist_free(p);
3304 pa_proplist_free(p);
3306 reply = reply_new(tag);
3308 if (c->version >= 13)
3309 pa_tagstruct_putu32(reply, idx);
3311 pa_pstream_send_tagstruct(c->pstream, reply);
3314 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3315 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3318 pa_native_connection_assert_ref(c);
3321 if (pa_tagstruct_gets(t, &name) < 0 ||
3322 !pa_tagstruct_eof(t)) {
3327 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3328 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3330 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
3331 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3335 pa_pstream_send_simple_ack(c->pstream, tag);
3338 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
3341 pa_assert(original);
3345 if (c->version < 12) {
3346 /* Before protocol version 12 we didn't support S32 samples,
3347 * so we need to lie about this to the client */
3349 if (fixed->format == PA_SAMPLE_S32LE)
3350 fixed->format = PA_SAMPLE_FLOAT32LE;
3351 if (fixed->format == PA_SAMPLE_S32BE)
3352 fixed->format = PA_SAMPLE_FLOAT32BE;
3355 if (c->version < 15) {
3356 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
3357 fixed->format = PA_SAMPLE_FLOAT32LE;
3358 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
3359 fixed->format = PA_SAMPLE_FLOAT32BE;
3363 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
3364 pa_sample_spec fixed_ss;
3367 pa_sink_assert_ref(sink);
3369 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
3373 PA_TAG_U32, sink->index,
3374 PA_TAG_STRING, sink->name,
3375 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3376 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3377 PA_TAG_CHANNEL_MAP, &sink->channel_map,
3378 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
3379 PA_TAG_CVOLUME, pa_sink_get_volume(sink, false),
3380 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, false),
3381 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
3382 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
3383 PA_TAG_USEC, pa_sink_get_latency(sink),
3384 PA_TAG_STRING, sink->driver,
3385 PA_TAG_U32, sink->flags & PA_SINK_CLIENT_FLAGS_MASK,
3388 if (c->version >= 13) {
3389 pa_tagstruct_put_proplist(t, sink->proplist);
3390 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
3393 if (c->version >= 15) {
3394 pa_tagstruct_put_volume(t, sink->base_volume);
3395 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
3396 pa_log_error("Internal sink state is invalid.");
3397 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
3398 pa_tagstruct_putu32(t, sink->n_volume_steps);
3399 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
3402 if (c->version >= 16) {
3406 pa_tagstruct_putu32(t, pa_hashmap_size(sink->ports));
3408 PA_HASHMAP_FOREACH(p, sink->ports, state) {
3409 pa_tagstruct_puts(t, p->name);
3410 pa_tagstruct_puts(t, p->description);
3411 pa_tagstruct_putu32(t, p->priority);
3412 if (c->version >= 24)
3413 pa_tagstruct_putu32(t, p->available);
3416 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
3419 if (c->version >= 21) {
3422 pa_idxset *formats = pa_sink_get_formats(sink);
3424 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3425 PA_IDXSET_FOREACH(f, formats, i) {
3426 pa_tagstruct_put_format_info(t, f);
3429 pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
3433 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
3434 pa_sample_spec fixed_ss;
3437 pa_source_assert_ref(source);
3439 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
3443 PA_TAG_U32, source->index,
3444 PA_TAG_STRING, source->name,
3445 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3446 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3447 PA_TAG_CHANNEL_MAP, &source->channel_map,
3448 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
3449 PA_TAG_CVOLUME, pa_source_get_volume(source, false),
3450 PA_TAG_BOOLEAN, pa_source_get_mute(source, false),
3451 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
3452 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
3453 PA_TAG_USEC, pa_source_get_latency(source),
3454 PA_TAG_STRING, source->driver,
3455 PA_TAG_U32, source->flags & PA_SOURCE_CLIENT_FLAGS_MASK,
3458 if (c->version >= 13) {
3459 pa_tagstruct_put_proplist(t, source->proplist);
3460 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
3463 if (c->version >= 15) {
3464 pa_tagstruct_put_volume(t, source->base_volume);
3465 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
3466 pa_log_error("Internal source state is invalid.");
3467 pa_tagstruct_putu32(t, pa_source_get_state(source));
3468 pa_tagstruct_putu32(t, source->n_volume_steps);
3469 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
3472 if (c->version >= 16) {
3476 pa_tagstruct_putu32(t, pa_hashmap_size(source->ports));
3478 PA_HASHMAP_FOREACH(p, source->ports, state) {
3479 pa_tagstruct_puts(t, p->name);
3480 pa_tagstruct_puts(t, p->description);
3481 pa_tagstruct_putu32(t, p->priority);
3482 if (c->version >= 24)
3483 pa_tagstruct_putu32(t, p->available);
3486 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
3489 if (c->version >= 22) {
3492 pa_idxset *formats = pa_source_get_formats(source);
3494 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3495 PA_IDXSET_FOREACH(f, formats, i) {
3496 pa_tagstruct_put_format_info(t, f);
3499 pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
3503 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
3507 pa_tagstruct_putu32(t, client->index);
3508 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
3509 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
3510 pa_tagstruct_puts(t, client->driver);
3512 if (c->version >= 13)
3513 pa_tagstruct_put_proplist(t, client->proplist);
3516 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
3519 pa_device_port *port;
3524 pa_tagstruct_putu32(t, card->index);
3525 pa_tagstruct_puts(t, card->name);
3526 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
3527 pa_tagstruct_puts(t, card->driver);
3529 pa_tagstruct_putu32(t, pa_hashmap_size(card->profiles));
3531 PA_HASHMAP_FOREACH(p, card->profiles, state) {
3532 pa_tagstruct_puts(t, p->name);
3533 pa_tagstruct_puts(t, p->description);
3534 pa_tagstruct_putu32(t, p->n_sinks);
3535 pa_tagstruct_putu32(t, p->n_sources);
3536 pa_tagstruct_putu32(t, p->priority);
3538 if (c->version >= 29)
3539 pa_tagstruct_putu32(t, (p->available != PA_AVAILABLE_NO));
3542 pa_tagstruct_puts(t, card->active_profile->name);
3543 pa_tagstruct_put_proplist(t, card->proplist);
3545 if (c->version < 26)
3548 pa_tagstruct_putu32(t, pa_hashmap_size(card->ports));
3550 PA_HASHMAP_FOREACH(port, card->ports, state) {
3553 pa_tagstruct_puts(t, port->name);
3554 pa_tagstruct_puts(t, port->description);
3555 pa_tagstruct_putu32(t, port->priority);
3556 pa_tagstruct_putu32(t, port->available);
3557 pa_tagstruct_putu8(t, port->direction);
3558 pa_tagstruct_put_proplist(t, port->proplist);
3560 pa_tagstruct_putu32(t, pa_hashmap_size(port->profiles));
3562 PA_HASHMAP_FOREACH(p, port->profiles, state2)
3563 pa_tagstruct_puts(t, p->name);
3565 if (c->version >= 27)
3566 pa_tagstruct_puts64(t, port->latency_offset);
3570 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3574 pa_tagstruct_putu32(t, module->index);
3575 pa_tagstruct_puts(t, module->name);
3576 pa_tagstruct_puts(t, module->argument);
3577 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3579 if (c->version < 15)
3580 pa_tagstruct_put_boolean(t, false); /* autoload is obsolete */
3582 if (c->version >= 15)
3583 pa_tagstruct_put_proplist(t, module->proplist);
3586 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3587 pa_sample_spec fixed_ss;
3588 pa_usec_t sink_latency;
3590 bool has_volume = false;
3593 pa_sink_input_assert_ref(s);
3595 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3597 has_volume = pa_sink_input_is_volume_readable(s);
3599 pa_sink_input_get_volume(s, &v, true);
3601 pa_cvolume_reset(&v, fixed_ss.channels);
3603 pa_tagstruct_putu32(t, s->index);
3604 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3605 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3606 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3607 pa_tagstruct_putu32(t, s->sink->index);
3608 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3609 pa_tagstruct_put_channel_map(t, &s->channel_map);
3610 pa_tagstruct_put_cvolume(t, &v);
3611 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3612 pa_tagstruct_put_usec(t, sink_latency);
3613 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3614 pa_tagstruct_puts(t, s->driver);
3615 if (c->version >= 11)
3616 pa_tagstruct_put_boolean(t, s->muted);
3617 if (c->version >= 13)
3618 pa_tagstruct_put_proplist(t, s->proplist);
3619 if (c->version >= 19)
3620 pa_tagstruct_put_boolean(t, (pa_sink_input_get_state(s) == PA_SINK_INPUT_CORKED));
3621 if (c->version >= 20) {
3622 pa_tagstruct_put_boolean(t, has_volume);
3623 pa_tagstruct_put_boolean(t, s->volume_writable);
3625 if (c->version >= 21)
3626 pa_tagstruct_put_format_info(t, s->format);
3629 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3630 pa_sample_spec fixed_ss;
3631 pa_usec_t source_latency;
3633 bool has_volume = false;
3636 pa_source_output_assert_ref(s);
3638 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3640 has_volume = pa_source_output_is_volume_readable(s);
3642 pa_source_output_get_volume(s, &v, true);
3644 pa_cvolume_reset(&v, fixed_ss.channels);
3646 pa_tagstruct_putu32(t, s->index);
3647 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3648 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3649 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3650 pa_tagstruct_putu32(t, s->source->index);
3651 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3652 pa_tagstruct_put_channel_map(t, &s->channel_map);
3653 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3654 pa_tagstruct_put_usec(t, source_latency);
3655 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3656 pa_tagstruct_puts(t, s->driver);
3657 if (c->version >= 13)
3658 pa_tagstruct_put_proplist(t, s->proplist);
3659 if (c->version >= 19)
3660 pa_tagstruct_put_boolean(t, (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_CORKED));
3661 if (c->version >= 22) {
3662 pa_tagstruct_put_cvolume(t, &v);
3663 pa_tagstruct_put_boolean(t, s->muted);
3664 pa_tagstruct_put_boolean(t, has_volume);
3665 pa_tagstruct_put_boolean(t, s->volume_writable);
3666 pa_tagstruct_put_format_info(t, s->format);
3670 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3671 pa_sample_spec fixed_ss;
3677 if (e->memchunk.memblock)
3678 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3680 memset(&fixed_ss, 0, sizeof(fixed_ss));
3682 pa_tagstruct_putu32(t, e->index);
3683 pa_tagstruct_puts(t, e->name);
3685 if (e->volume_is_set)
3688 pa_cvolume_init(&v);
3690 pa_tagstruct_put_cvolume(t, &v);
3691 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3692 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3693 pa_tagstruct_put_channel_map(t, &e->channel_map);
3694 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3695 pa_tagstruct_put_boolean(t, e->lazy);
3696 pa_tagstruct_puts(t, e->filename);
3698 if (c->version >= 13)
3699 pa_tagstruct_put_proplist(t, e->proplist);
3702 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3703 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3705 pa_sink *sink = NULL;
3706 pa_source *source = NULL;
3707 pa_client *client = NULL;
3708 pa_card *card = NULL;
3709 pa_module *module = NULL;
3710 pa_sink_input *si = NULL;
3711 pa_source_output *so = NULL;
3712 pa_scache_entry *sce = NULL;
3713 const char *name = NULL;
3714 pa_tagstruct *reply;
3716 pa_native_connection_assert_ref(c);
3719 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3720 (command != PA_COMMAND_GET_CLIENT_INFO &&
3721 command != PA_COMMAND_GET_MODULE_INFO &&
3722 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3723 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3724 pa_tagstruct_gets(t, &name) < 0) ||
3725 !pa_tagstruct_eof(t)) {
3730 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3731 CHECK_VALIDITY(c->pstream, !name ||
3732 (command == PA_COMMAND_GET_SINK_INFO &&
3733 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3734 (command == PA_COMMAND_GET_SOURCE_INFO &&
3735 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3736 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3737 CHECK_VALIDITY(c->pstream, command == PA_COMMAND_GET_SINK_INFO ||
3738 command == PA_COMMAND_GET_SOURCE_INFO ||
3739 (idx != PA_INVALID_INDEX || name), tag, PA_ERR_INVALID);
3740 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3742 if (command == PA_COMMAND_GET_SINK_INFO) {
3743 if (idx != PA_INVALID_INDEX)
3744 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3746 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3747 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3748 if (idx != PA_INVALID_INDEX)
3749 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3751 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3752 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3753 if (idx != PA_INVALID_INDEX)
3754 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3756 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3757 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3758 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3759 else if (command == PA_COMMAND_GET_MODULE_INFO)
3760 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3761 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3762 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3763 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3764 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3766 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3767 if (idx != PA_INVALID_INDEX)
3768 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3770 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3773 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3774 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3778 reply = reply_new(tag);
3780 sink_fill_tagstruct(c, reply, sink);
3782 source_fill_tagstruct(c, reply, source);
3784 client_fill_tagstruct(c, reply, client);
3786 card_fill_tagstruct(c, reply, card);
3788 module_fill_tagstruct(c, reply, module);
3790 sink_input_fill_tagstruct(c, reply, si);
3792 source_output_fill_tagstruct(c, reply, so);
3794 scache_fill_tagstruct(c, reply, sce);
3795 pa_pstream_send_tagstruct(c->pstream, reply);
3798 static void command_get_info_list(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_tagstruct *reply;
3805 pa_native_connection_assert_ref(c);
3808 if (!pa_tagstruct_eof(t)) {
3813 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3815 reply = reply_new(tag);
3817 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3818 i = c->protocol->core->sinks;
3819 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3820 i = c->protocol->core->sources;
3821 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3822 i = c->protocol->core->clients;
3823 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3824 i = c->protocol->core->cards;
3825 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3826 i = c->protocol->core->modules;
3827 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3828 i = c->protocol->core->sink_inputs;
3829 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3830 i = c->protocol->core->source_outputs;
3832 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3833 i = c->protocol->core->scache;
3837 PA_IDXSET_FOREACH(p, i, idx) {
3838 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3839 sink_fill_tagstruct(c, reply, p);
3840 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3841 source_fill_tagstruct(c, reply, p);
3842 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3843 client_fill_tagstruct(c, reply, p);
3844 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3845 card_fill_tagstruct(c, reply, p);
3846 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3847 module_fill_tagstruct(c, reply, p);
3848 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3849 sink_input_fill_tagstruct(c, reply, p);
3850 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3851 source_output_fill_tagstruct(c, reply, p);
3853 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3854 scache_fill_tagstruct(c, reply, p);
3859 pa_pstream_send_tagstruct(c->pstream, reply);
3862 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3863 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3864 pa_tagstruct *reply;
3866 pa_source *def_source;
3867 pa_sample_spec fixed_ss;
3870 pa_native_connection_assert_ref(c);
3873 if (!pa_tagstruct_eof(t)) {
3878 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3880 reply = reply_new(tag);
3881 pa_tagstruct_puts(reply, PACKAGE_NAME);
3882 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3884 u = pa_get_user_name_malloc();
3885 pa_tagstruct_puts(reply, u);
3888 h = pa_get_host_name_malloc();
3889 pa_tagstruct_puts(reply, h);
3892 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3893 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3895 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3896 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3897 def_source = pa_namereg_get_default_source(c->protocol->core);
3898 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3900 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3902 if (c->version >= 15)
3903 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3905 pa_pstream_send_tagstruct(c->pstream, reply);
3908 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3910 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3912 pa_native_connection_assert_ref(c);
3914 t = pa_tagstruct_new(NULL, 0);
3915 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3916 pa_tagstruct_putu32(t, (uint32_t) -1);
3917 pa_tagstruct_putu32(t, e);
3918 pa_tagstruct_putu32(t, idx);
3919 pa_pstream_send_tagstruct(c->pstream, t);
3922 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3923 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3924 pa_subscription_mask_t m;
3926 pa_native_connection_assert_ref(c);
3929 if (pa_tagstruct_getu32(t, &m) < 0 ||
3930 !pa_tagstruct_eof(t)) {
3935 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3936 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3938 if (c->subscription)
3939 pa_subscription_free(c->subscription);
3942 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3943 pa_assert(c->subscription);
3945 c->subscription = NULL;
3947 pa_pstream_send_simple_ack(c->pstream, tag);
3950 static void command_set_volume(
3957 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3960 pa_sink *sink = NULL;
3961 pa_source *source = NULL;
3962 pa_sink_input *si = NULL;
3963 pa_source_output *so = NULL;
3964 const char *name = NULL;
3965 const char *client_name;
3967 pa_native_connection_assert_ref(c);
3970 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3971 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3972 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3973 pa_tagstruct_get_cvolume(t, &volume) ||
3974 !pa_tagstruct_eof(t)) {
3979 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3980 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_VOLUME ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
3981 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
3982 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3985 CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), VOLUME_SET_PRIVILEGE),
3986 tag, PA_ERR_ACCESS);
3987 #endif /* USE_SECURITY */
3991 case PA_COMMAND_SET_SINK_VOLUME:
3992 if (idx != PA_INVALID_INDEX)
3993 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3995 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3998 case PA_COMMAND_SET_SOURCE_VOLUME:
3999 if (idx != PA_INVALID_INDEX)
4000 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4002 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4005 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
4006 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4009 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME:
4010 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4014 pa_assert_not_reached();
4017 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
4019 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
4022 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
4024 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
4025 pa_sink_set_volume(sink, &volume, true, true);
4026 } else if (source) {
4027 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
4029 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
4030 pa_source_set_volume(source, &volume, true, true);
4032 CHECK_VALIDITY(c->pstream, si->volume_writable, tag, PA_ERR_BADSTATE);
4033 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
4035 pa_log_debug("Client %s changes volume of sink input %s.",
4037 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
4038 pa_sink_input_set_volume(si, &volume, true, true);
4040 CHECK_VALIDITY(c->pstream, so->volume_writable, tag, PA_ERR_BADSTATE);
4041 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &so->sample_spec), tag, PA_ERR_INVALID);
4043 pa_log_debug("Client %s changes volume of source output %s.",
4045 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
4046 pa_source_output_set_volume(so, &volume, true, true);
4049 pa_pstream_send_simple_ack(c->pstream, tag);
4052 static void command_set_volume_ramp(
4059 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4061 pa_cvolume_ramp ramp;
4062 pa_sink *sink = NULL;
4063 pa_sink_input *si = NULL;
4064 const char *name = NULL;
4065 const char *client_name;
4067 pa_native_connection_assert_ref(c);
4070 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4071 (command == PA_COMMAND_SET_SINK_VOLUME_RAMP && pa_tagstruct_gets(t, &name) < 0) ||
4072 (command == PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP && pa_tagstruct_gets(t, &name) < 0) ||
4073 pa_tagstruct_get_cvolume_ramp(t, &ramp) ||
4074 !pa_tagstruct_eof(t)) {
4079 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4080 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_VOLUME ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
4081 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4082 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4083 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4085 CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), VOLUME_SET_PRIVILEGE),
4086 tag, PA_ERR_ACCESS);
4087 #endif /* USE_SECURITY */
4091 case PA_COMMAND_SET_SINK_VOLUME_RAMP:
4092 if (idx != PA_INVALID_INDEX)
4093 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4095 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4098 case PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP:
4099 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4103 pa_assert_not_reached();
4106 CHECK_VALIDITY(c->pstream, sink || si, tag, PA_ERR_NOENTITY);
4108 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
4111 pa_log_debug("Client %s changes volume ramp of sink %s.", client_name, sink->name);
4112 pa_sink_set_volume_ramp(sink, &ramp, TRUE, TRUE);
4114 pa_log_debug("Client %s changes volume ramp of sink input %s.", client_name, pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
4115 pa_sink_input_set_volume_ramp(si, &ramp, TRUE, TRUE);
4118 pa_pstream_send_simple_ack(c->pstream, tag);
4121 static void command_set_mute(
4128 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4131 pa_sink *sink = NULL;
4132 pa_source *source = NULL;
4133 pa_sink_input *si = NULL;
4134 pa_source_output *so = NULL;
4135 const char *name = NULL, *client_name;
4137 pa_native_connection_assert_ref(c);
4140 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4141 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
4142 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
4143 pa_tagstruct_get_boolean(t, &mute) ||
4144 !pa_tagstruct_eof(t)) {
4149 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4150 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_MUTE ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
4151 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
4153 CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), VOLUME_SET_PRIVILEGE),
4154 tag, PA_ERR_ACCESS);
4155 #endif /* USE_SECURITY */
4159 case PA_COMMAND_SET_SINK_MUTE:
4160 if (idx != PA_INVALID_INDEX)
4161 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4163 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4167 case PA_COMMAND_SET_SOURCE_MUTE:
4168 if (idx != PA_INVALID_INDEX)
4169 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4171 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4175 case PA_COMMAND_SET_SINK_INPUT_MUTE:
4176 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4179 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE:
4180 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4184 pa_assert_not_reached();
4187 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
4189 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
4192 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
4193 pa_sink_set_mute(sink, mute, true);
4194 } else if (source) {
4195 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
4196 pa_source_set_mute(source, mute, true);
4198 pa_log_debug("Client %s changes mute of sink input %s.",
4200 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
4201 pa_sink_input_set_mute(si, mute, true);
4203 pa_log_debug("Client %s changes mute of source output %s.",
4205 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
4206 pa_source_output_set_mute(so, mute, true);
4209 pa_pstream_send_simple_ack(c->pstream, tag);
4212 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4213 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4218 pa_native_connection_assert_ref(c);
4221 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4222 pa_tagstruct_get_boolean(t, &b) < 0 ||
4223 !pa_tagstruct_eof(t)) {
4228 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4229 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4230 s = pa_idxset_get_by_index(c->output_streams, idx);
4231 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4232 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4234 pa_sink_input_cork(s->sink_input, b);
4237 s->is_underrun = true;
4239 pa_pstream_send_simple_ack(c->pstream, tag);
4242 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4243 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4247 pa_native_connection_assert_ref(c);
4250 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4251 !pa_tagstruct_eof(t)) {
4256 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4257 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4258 s = pa_idxset_get_by_index(c->output_streams, idx);
4259 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4260 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4263 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
4264 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
4267 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
4268 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
4271 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
4272 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
4276 pa_assert_not_reached();
4279 pa_pstream_send_simple_ack(c->pstream, tag);
4282 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4283 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4288 pa_native_connection_assert_ref(c);
4291 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4292 pa_tagstruct_get_boolean(t, &b) < 0 ||
4293 !pa_tagstruct_eof(t)) {
4298 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4299 s = pa_idxset_get_by_index(c->record_streams, idx);
4300 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4302 pa_source_output_cork(s->source_output, b);
4303 pa_memblockq_prebuf_force(s->memblockq);
4304 pa_pstream_send_simple_ack(c->pstream, tag);
4307 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4308 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4312 pa_native_connection_assert_ref(c);
4315 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4316 !pa_tagstruct_eof(t)) {
4321 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4322 s = pa_idxset_get_by_index(c->record_streams, idx);
4323 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4325 pa_memblockq_flush_read(s->memblockq);
4326 pa_pstream_send_simple_ack(c->pstream, tag);
4329 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4330 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4333 pa_tagstruct *reply;
4335 pa_native_connection_assert_ref(c);
4338 memset(&a, 0, sizeof(a));
4340 if (pa_tagstruct_getu32(t, &idx) < 0) {
4345 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4347 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
4349 bool adjust_latency = false, early_requests = false;
4351 s = pa_idxset_get_by_index(c->output_streams, idx);
4352 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4353 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4355 if (pa_tagstruct_get(
4357 PA_TAG_U32, &a.maxlength,
4358 PA_TAG_U32, &a.tlength,
4359 PA_TAG_U32, &a.prebuf,
4360 PA_TAG_U32, &a.minreq,
4361 PA_TAG_INVALID) < 0 ||
4362 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
4363 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
4364 !pa_tagstruct_eof(t)) {
4369 s->adjust_latency = adjust_latency;
4370 s->early_requests = early_requests;
4371 s->buffer_attr_req = a;
4373 fix_playback_buffer_attr(s);
4374 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);
4376 reply = reply_new(tag);
4377 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
4378 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
4379 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
4380 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
4382 if (c->version >= 13)
4383 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
4387 bool adjust_latency = false, early_requests = false;
4388 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
4390 s = pa_idxset_get_by_index(c->record_streams, idx);
4391 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4393 if (pa_tagstruct_get(
4395 PA_TAG_U32, &a.maxlength,
4396 PA_TAG_U32, &a.fragsize,
4397 PA_TAG_INVALID) < 0 ||
4398 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
4399 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
4400 !pa_tagstruct_eof(t)) {
4405 s->adjust_latency = adjust_latency;
4406 s->early_requests = early_requests;
4407 s->buffer_attr_req = a;
4409 fix_record_buffer_attr_pre(s);
4410 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
4411 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
4412 fix_record_buffer_attr_post(s);
4414 reply = reply_new(tag);
4415 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
4416 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
4418 if (c->version >= 13)
4419 pa_tagstruct_put_usec(reply, s->configured_source_latency);
4422 pa_pstream_send_tagstruct(c->pstream, reply);
4425 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4426 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4430 pa_native_connection_assert_ref(c);
4433 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4434 pa_tagstruct_getu32(t, &rate) < 0 ||
4435 !pa_tagstruct_eof(t)) {
4440 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4441 CHECK_VALIDITY(c->pstream, pa_sample_rate_valid(rate), tag, PA_ERR_INVALID);
4443 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
4446 s = pa_idxset_get_by_index(c->output_streams, idx);
4447 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4448 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4450 pa_sink_input_set_rate(s->sink_input, rate);
4454 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
4456 s = pa_idxset_get_by_index(c->record_streams, idx);
4457 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4459 pa_source_output_set_rate(s->source_output, rate);
4462 pa_pstream_send_simple_ack(c->pstream, tag);
4465 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4466 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4471 pa_native_connection_assert_ref(c);
4474 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4476 p = pa_proplist_new();
4478 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
4480 if (pa_tagstruct_getu32(t, &mode) < 0 ||
4481 pa_tagstruct_get_proplist(t, p) < 0 ||
4482 !pa_tagstruct_eof(t)) {
4484 pa_proplist_free(p);
4490 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4491 pa_tagstruct_getu32(t, &mode) < 0 ||
4492 pa_tagstruct_get_proplist(t, p) < 0 ||
4493 !pa_tagstruct_eof(t)) {
4495 pa_proplist_free(p);
4500 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
4501 pa_proplist_free(p);
4502 CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_INVALID);
4505 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
4508 s = pa_idxset_get_by_index(c->output_streams, idx);
4509 if (!s || !playback_stream_isinstance(s)) {
4510 pa_proplist_free(p);
4511 CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_NOENTITY);
4513 pa_sink_input_update_proplist(s->sink_input, mode, p);
4515 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
4518 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
4519 pa_proplist_free(p);
4520 CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_NOENTITY);
4522 pa_source_output_update_proplist(s->source_output, mode, p);
4525 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
4527 pa_client_update_proplist(c->client, mode, p);
4530 pa_pstream_send_simple_ack(c->pstream, tag);
4531 pa_proplist_free(p);
4534 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4535 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4537 unsigned changed = 0;
4539 pa_strlist *l = NULL;
4541 pa_native_connection_assert_ref(c);
4544 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4546 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
4548 if (pa_tagstruct_getu32(t, &idx) < 0) {
4554 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4557 s = pa_idxset_get_by_index(c->output_streams, idx);
4558 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4559 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4561 p = s->sink_input->proplist;
4563 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4566 s = pa_idxset_get_by_index(c->record_streams, idx);
4567 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4569 p = s->source_output->proplist;
4571 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4573 p = c->client->proplist;
4579 if (pa_tagstruct_gets(t, &k) < 0) {
4588 l = pa_strlist_prepend(l, k);
4591 if (!pa_tagstruct_eof(t)) {
4600 l = pa_strlist_pop(l, &z);
4605 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
4609 pa_pstream_send_simple_ack(c->pstream, tag);
4612 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4615 s = pa_idxset_get_by_index(c->output_streams, idx);
4616 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
4618 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4621 s = pa_idxset_get_by_index(c->record_streams, idx);
4622 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
4625 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4626 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
4631 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4632 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4635 pa_native_connection_assert_ref(c);
4638 if (pa_tagstruct_gets(t, &s) < 0 ||
4639 !pa_tagstruct_eof(t)) {
4644 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4645 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
4647 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
4650 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
4651 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4653 pa_namereg_set_default_source(c->protocol->core, source);
4656 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
4658 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
4659 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4661 pa_namereg_set_default_sink(c->protocol->core, sink);
4664 pa_pstream_send_simple_ack(c->pstream, tag);
4668 static void command_set_default_sink_by_api_bus(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4669 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4671 pa_bool_t found = FALSE;
4672 const char *api, *bus;
4673 const char *api_string, *bus_string, *form_factor;
4676 pa_native_connection_assert_ref(c);
4679 if (pa_tagstruct_gets(t, &api) < 0 ||
4680 pa_tagstruct_gets(t, &bus) < 0 ||
4681 !pa_tagstruct_eof(t)) {
4686 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4687 CHECK_VALIDITY(c->pstream, !api || pa_utf8_valid(api), tag, PA_ERR_INVALID);
4688 CHECK_VALIDITY(c->pstream, !bus || pa_utf8_valid(bus), tag, PA_ERR_INVALID);
4690 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK_BY_API_BUS);
4692 PA_IDXSET_FOREACH(sink, c->protocol->core->sinks, idx) {
4693 if (sink && sink->proplist) {
4694 api_string = pa_proplist_gets(sink->proplist, "device.api");
4696 pa_log_debug("Found api = [%s]\n", api_string);
4697 if (!strcmp(api, api_string)) {
4698 bus_string = pa_proplist_gets(sink->proplist, "device.bus");
4700 pa_log_debug("Found bus = [%s]\n", bus_string);
4701 if(!strcmp(bus, bus_string)) {
4702 pa_log_debug(" ** FOUND!!! set default sink to [%s]\n", sink->name);
4706 pa_log_debug("No string [%s] match, match with form_factor = internal\n", bus);
4707 form_factor = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_FORM_FACTOR );
4709 if(!strcmp(form_factor, "internal")) {
4710 pa_log_debug("Found internal device(sink) , set (%s) as default sink", sink->name);
4716 pa_log_debug("This device doesn't have form factor property");
4720 pa_log_debug(" Found no bus ");
4721 if (!strcmp(DEVICE_BUS_BUILTIN, bus)) {
4722 pa_log_debug(" searching bus was builtin, then select this");
4728 pa_log_debug("No string [%s] match!!!!\n", api);
4738 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4740 pa_namereg_set_default_sink(c->protocol->core, sink);
4742 pa_pstream_send_simple_ack(c->pstream, tag);
4745 static void command_set_default_sink_for_usb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4746 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4748 pa_bool_t found = FALSE;
4753 pa_native_connection_assert_ref(c);
4756 if (pa_tagstruct_gets(t, &s) < 0 ||
4757 !pa_tagstruct_eof(t)) {
4762 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4763 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
4765 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK_FOR_USB);
4767 PA_IDXSET_FOREACH(sink, c->protocol->core->sinks, idx) {
4768 if (sink && sink->card && sink->card->proplist) {
4769 if ((serial = pa_proplist_gets(sink->card->proplist, PA_PROP_DEVICE_SERIAL)) == NULL) {
4770 pa_log_warn(" ** No serial for this sink [%s]", sink->name);
4774 if ((found = pa_streq(serial, s))) {
4775 pa_log_info(" ** serial [%s] for sink [%s] is matched, set as default sink\n", serial, sink->name);
4778 pa_log_debug(" ** serial [%s] for sink [%s] is not matched...", serial, sink->name);
4786 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4788 pa_namereg_set_default_sink(c->protocol->core, sink);
4790 pa_pstream_send_simple_ack(c->pstream, tag);
4793 #endif /* __TIZEN__ */
4795 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4796 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4800 pa_native_connection_assert_ref(c);
4803 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4804 pa_tagstruct_gets(t, &name) < 0 ||
4805 !pa_tagstruct_eof(t)) {
4810 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4811 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
4813 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
4816 s = pa_idxset_get_by_index(c->output_streams, idx);
4817 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4818 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4820 pa_sink_input_set_name(s->sink_input, name);
4824 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4826 s = pa_idxset_get_by_index(c->record_streams, idx);
4827 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4829 pa_source_output_set_name(s->source_output, name);
4832 pa_pstream_send_simple_ack(c->pstream, tag);
4835 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4836 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4839 pa_native_connection_assert_ref(c);
4842 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4843 !pa_tagstruct_eof(t)) {
4848 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4850 if (command == PA_COMMAND_KILL_CLIENT) {
4853 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4854 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4856 pa_native_connection_ref(c);
4857 pa_client_kill(client);
4859 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4862 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4863 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4865 pa_native_connection_ref(c);
4866 pa_sink_input_kill(s);
4868 pa_source_output *s;
4870 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4872 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4873 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4875 pa_native_connection_ref(c);
4876 pa_source_output_kill(s);
4879 pa_pstream_send_simple_ack(c->pstream, tag);
4880 pa_native_connection_unref(c);
4883 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4884 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4886 const char *name, *argument;
4887 pa_tagstruct *reply;
4889 pa_native_connection_assert_ref(c);
4892 if (pa_tagstruct_gets(t, &name) < 0 ||
4893 pa_tagstruct_gets(t, &argument) < 0 ||
4894 !pa_tagstruct_eof(t)) {
4899 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4900 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4901 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4903 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4904 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4908 reply = reply_new(tag);
4909 pa_tagstruct_putu32(reply, m->index);
4910 pa_pstream_send_tagstruct(c->pstream, reply);
4913 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4914 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4918 pa_native_connection_assert_ref(c);
4921 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4922 !pa_tagstruct_eof(t)) {
4927 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4928 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4929 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4931 pa_module_unload_request(m, false);
4932 pa_pstream_send_simple_ack(c->pstream, tag);
4935 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4936 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4937 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4938 const char *name_device = NULL;
4940 pa_native_connection_assert_ref(c);
4943 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4944 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4945 pa_tagstruct_gets(t, &name_device) < 0 ||
4946 !pa_tagstruct_eof(t)) {
4951 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4952 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4954 CHECK_VALIDITY(c->pstream, !name_device || pa_namereg_is_valid_name_or_wildcard(name_device, command == PA_COMMAND_MOVE_SINK_INPUT ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
4955 CHECK_VALIDITY(c->pstream, (idx_device != PA_INVALID_INDEX) ^ (name_device != NULL), tag, PA_ERR_INVALID);
4957 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4958 pa_sink_input *si = NULL;
4959 pa_sink *sink = NULL;
4961 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4963 if (idx_device != PA_INVALID_INDEX)
4964 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4966 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4968 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4970 if (pa_sink_input_move_to(si, sink, true) < 0) {
4971 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4975 pa_source_output *so = NULL;
4978 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4980 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4982 if (idx_device != PA_INVALID_INDEX)
4983 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4985 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4987 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4989 if (pa_source_output_move_to(so, source, true) < 0) {
4990 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4995 pa_pstream_send_simple_ack(c->pstream, tag);
4998 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4999 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5000 uint32_t idx = PA_INVALID_INDEX;
5001 const char *name = NULL;
5004 pa_native_connection_assert_ref(c);
5007 if (pa_tagstruct_getu32(t, &idx) < 0 ||
5008 pa_tagstruct_gets(t, &name) < 0 ||
5009 pa_tagstruct_get_boolean(t, &b) < 0 ||
5010 !pa_tagstruct_eof(t)) {
5015 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5016 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SUSPEND_SINK ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) || *name == 0, tag, PA_ERR_INVALID);
5017 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
5019 if (command == PA_COMMAND_SUSPEND_SINK) {
5021 if (idx == PA_INVALID_INDEX && name && !*name) {
5023 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
5025 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
5026 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
5030 pa_sink *sink = NULL;
5032 if (idx != PA_INVALID_INDEX)
5033 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
5035 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
5037 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
5039 pa_log_debug("%s of sink %s requested by client %" PRIu32 ".",
5040 b ? "Suspending" : "Resuming", sink->name, c->client->index);
5042 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
5043 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
5049 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
5051 if (idx == PA_INVALID_INDEX && name && !*name) {
5053 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
5055 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
5056 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
5063 if (idx != PA_INVALID_INDEX)
5064 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
5066 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
5068 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
5070 pa_log_debug("%s of source %s requested by client %" PRIu32 ".",
5071 b ? "Suspending" : "Resuming", source->name, c->client->index);
5073 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
5074 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
5080 pa_pstream_send_simple_ack(c->pstream, tag);
5083 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5084 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5085 uint32_t idx = PA_INVALID_INDEX;
5086 const char *name = NULL;
5088 pa_native_protocol_ext_cb_t cb;
5090 pa_native_connection_assert_ref(c);
5093 if (pa_tagstruct_getu32(t, &idx) < 0 ||
5094 pa_tagstruct_gets(t, &name) < 0) {
5099 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5100 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
5101 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
5103 if (idx != PA_INVALID_INDEX)
5104 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
5106 PA_IDXSET_FOREACH(m, c->protocol->core->modules, idx)
5107 if (pa_streq(name, m->name))
5110 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
5111 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
5113 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
5114 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
5116 if (cb(c->protocol, m, c, tag, t) < 0)
5120 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5121 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5122 uint32_t idx = PA_INVALID_INDEX;
5123 const char *name = NULL, *profile_name = NULL;
5124 pa_card *card = NULL;
5125 pa_card_profile *profile;
5128 pa_native_connection_assert_ref(c);
5131 if (pa_tagstruct_getu32(t, &idx) < 0 ||
5132 pa_tagstruct_gets(t, &name) < 0 ||
5133 pa_tagstruct_gets(t, &profile_name) < 0 ||
5134 !pa_tagstruct_eof(t)) {
5139 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5140 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
5141 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
5142 CHECK_VALIDITY(c->pstream, profile_name, tag, PA_ERR_INVALID);
5144 if (idx != PA_INVALID_INDEX)
5145 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
5147 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
5149 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
5151 profile = pa_hashmap_get(card->profiles, profile_name);
5153 CHECK_VALIDITY(c->pstream, profile, tag, PA_ERR_NOENTITY);
5155 if ((ret = pa_card_set_profile(card, profile, true)) < 0) {
5156 pa_pstream_send_error(c->pstream, tag, -ret);
5160 pa_pstream_send_simple_ack(c->pstream, tag);
5163 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5164 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5165 uint32_t idx = PA_INVALID_INDEX;
5166 const char *name = NULL, *port = NULL;
5169 pa_native_connection_assert_ref(c);
5172 if (pa_tagstruct_getu32(t, &idx) < 0 ||
5173 pa_tagstruct_gets(t, &name) < 0 ||
5174 pa_tagstruct_gets(t, &port) < 0 ||
5175 !pa_tagstruct_eof(t)) {
5180 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5181 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_PORT ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
5182 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
5183 CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_INVALID);
5185 if (command == PA_COMMAND_SET_SINK_PORT) {
5188 if (idx != PA_INVALID_INDEX)
5189 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
5191 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
5193 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
5195 if ((ret = pa_sink_set_port(sink, port, true)) < 0) {
5196 pa_pstream_send_error(c->pstream, tag, -ret);
5202 pa_assert(command == PA_COMMAND_SET_SOURCE_PORT);
5204 if (idx != PA_INVALID_INDEX)
5205 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
5207 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
5209 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
5211 if ((ret = pa_source_set_port(source, port, true)) < 0) {
5212 pa_pstream_send_error(c->pstream, tag, -ret);
5217 pa_pstream_send_simple_ack(c->pstream, tag);
5220 static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5221 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5222 const char *port_name, *card_name;
5223 uint32_t idx = PA_INVALID_INDEX;
5225 pa_card *card = NULL;
5226 pa_device_port *port = NULL;
5228 pa_native_connection_assert_ref(c);
5231 if (pa_tagstruct_getu32(t, &idx) < 0 ||
5232 pa_tagstruct_gets(t, &card_name) < 0 ||
5233 pa_tagstruct_gets(t, &port_name) < 0 ||
5234 pa_tagstruct_gets64(t, &offset) < 0 ||
5235 !pa_tagstruct_eof(t)) {
5240 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5241 CHECK_VALIDITY(c->pstream, !card_name || pa_namereg_is_valid_name(card_name), tag, PA_ERR_INVALID);
5242 CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (card_name != NULL), tag, PA_ERR_INVALID);
5243 CHECK_VALIDITY(c->pstream, port_name, tag, PA_ERR_INVALID);
5245 if (idx != PA_INVALID_INDEX)
5246 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
5248 card = pa_namereg_get(c->protocol->core, card_name, PA_NAMEREG_CARD);
5250 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
5252 port = pa_hashmap_get(card->ports, port_name);
5253 CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_NOENTITY);
5255 pa_device_port_set_latency_offset(port, offset);
5257 pa_pstream_send_simple_ack(c->pstream, tag);
5260 /*** pstream callbacks ***/
5262 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
5263 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5267 pa_native_connection_assert_ref(c);
5269 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
5270 pa_log("invalid packet.");
5271 native_connection_unlink(c);
5275 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) {
5276 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5277 output_stream *stream;
5281 pa_native_connection_assert_ref(c);
5283 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
5284 pa_log_debug("Client sent block for invalid stream.");
5289 #ifdef PROTOCOL_NATIVE_DEBUG
5290 pa_log("got %lu bytes from client", (unsigned long) chunk->length);
5293 if (playback_stream_isinstance(stream)) {
5294 playback_stream *ps = PLAYBACK_STREAM(stream);
5296 pa_atomic_inc(&ps->seek_or_post_in_queue);
5297 if (chunk->memblock) {
5298 if (seek != PA_SEEK_RELATIVE || offset != 0)
5299 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, chunk, NULL);
5301 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
5303 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);
5306 upload_stream *u = UPLOAD_STREAM(stream);
5309 if (!u->memchunk.memblock) {
5310 if (u->length == chunk->length && chunk->memblock) {
5311 u->memchunk = *chunk;
5312 pa_memblock_ref(u->memchunk.memblock);
5315 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
5316 u->memchunk.index = u->memchunk.length = 0;
5320 pa_assert(u->memchunk.memblock);
5323 if (l > chunk->length)
5328 dst = pa_memblock_acquire(u->memchunk.memblock);
5330 if (chunk->memblock) {
5332 src = pa_memblock_acquire(chunk->memblock);
5334 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
5335 (uint8_t*) src + chunk->index, l);
5337 pa_memblock_release(chunk->memblock);
5339 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
5341 pa_memblock_release(u->memchunk.memblock);
5343 u->memchunk.length += l;
5349 static void pstream_die_callback(pa_pstream *p, void *userdata) {
5350 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5353 pa_native_connection_assert_ref(c);
5355 native_connection_unlink(c);
5356 pa_log_info("Connection died.");
5359 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
5360 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5363 pa_native_connection_assert_ref(c);
5365 native_connection_send_memblock(c);
5368 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
5371 if (!(q = pa_thread_mq_get()))
5372 pa_pstream_send_revoke(p, block_id);
5374 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
5377 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
5380 if (!(q = pa_thread_mq_get()))
5381 pa_pstream_send_release(p, block_id);
5383 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
5386 /*** client callbacks ***/
5388 static void client_kill_cb(pa_client *c) {
5391 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
5392 pa_log_info("Connection killed.");
5395 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
5397 pa_native_connection *c;
5400 c = PA_NATIVE_CONNECTION(client->userdata);
5401 pa_native_connection_assert_ref(c);
5403 if (c->version < 15)
5406 t = pa_tagstruct_new(NULL, 0);
5407 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
5408 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
5409 pa_tagstruct_puts(t, event);
5410 pa_tagstruct_put_proplist(t, pl);
5411 pa_pstream_send_tagstruct(c->pstream, t);
5414 /*** module entry points ***/
5416 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
5417 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5420 pa_native_connection_assert_ref(c);
5421 pa_assert(c->auth_timeout_event == e);
5423 if (!c->authorized) {
5424 native_connection_unlink(c);
5425 pa_log_info("Connection terminated due to authentication timeout.");
5429 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
5430 pa_native_connection *c;
5433 pa_client_new_data data;
5439 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
5440 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
5441 pa_iochannel_free(io);
5445 pa_client_new_data_init(&data);
5446 data.module = o->module;
5447 data.driver = __FILE__;
5448 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
5449 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
5450 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
5451 client = pa_client_new(p->core, &data);
5452 pa_client_new_data_done(&data);
5457 c = pa_msgobject_new(pa_native_connection);
5458 c->parent.parent.free = native_connection_free;
5459 c->parent.process_msg = native_connection_process_msg;
5461 c->options = pa_native_options_ref(o);
5462 c->authorized = false;
5464 if (o->auth_anonymous) {
5465 pa_log_info("Client authenticated anonymously.");
5466 c->authorized = true;
5469 if (!c->authorized &&
5471 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
5473 pa_log_info("Client authenticated by IP ACL.");
5474 c->authorized = true;
5478 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
5480 c->auth_timeout_event = NULL;
5482 c->is_local = pa_iochannel_socket_is_local(io);
5486 c->client->kill = client_kill_cb;
5487 c->client->send_event = client_send_event_cb;
5488 c->client->userdata = c;
5490 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
5491 pa_pstream_set_receive_packet_callback(c->pstream, pstream_packet_callback, c);
5492 pa_pstream_set_receive_memblock_callback(c->pstream, pstream_memblock_callback, c);
5493 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
5494 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
5495 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
5496 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
5498 c->pdispatch = pa_pdispatch_new(p->core->mainloop, true, command_table, PA_COMMAND_MAX);
5500 c->record_streams = pa_idxset_new(NULL, NULL);
5501 c->output_streams = pa_idxset_new(NULL, NULL);
5503 c->rrobin_index = PA_IDXSET_INVALID;
5504 c->subscription = NULL;
5506 pa_idxset_put(p->connections, c, NULL);
5509 if (pa_iochannel_creds_supported(io))
5510 pa_iochannel_creds_enable(io);
5513 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
5516 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
5517 pa_native_connection *c;
5523 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
5524 if (c->options->module == m)
5525 native_connection_unlink(c);
5528 static pa_native_protocol* native_protocol_new(pa_core *c) {
5529 pa_native_protocol *p;
5534 p = pa_xnew(pa_native_protocol, 1);
5537 p->connections = pa_idxset_new(NULL, NULL);
5541 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
5543 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
5544 pa_hook_init(&p->hooks[h], p);
5546 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
5551 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
5552 pa_native_protocol *p;
5554 if ((p = pa_shared_get(c, "native-protocol")))
5555 return pa_native_protocol_ref(p);
5557 return native_protocol_new(c);
5560 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
5562 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5569 void pa_native_protocol_unref(pa_native_protocol *p) {
5570 pa_native_connection *c;
5574 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5576 if (PA_REFCNT_DEC(p) > 0)
5579 while ((c = pa_idxset_first(p->connections, NULL)))
5580 native_connection_unlink(c);
5582 pa_idxset_free(p->connections, NULL);
5584 pa_strlist_free(p->servers);
5586 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
5587 pa_hook_done(&p->hooks[h]);
5589 pa_hashmap_free(p->extensions);
5591 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
5596 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
5598 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5601 p->servers = pa_strlist_prepend(p->servers, name);
5603 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5606 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
5608 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5611 p->servers = pa_strlist_remove(p->servers, name);
5613 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5616 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
5618 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5623 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
5625 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5630 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
5632 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5635 pa_assert(!pa_hashmap_get(p->extensions, m));
5637 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
5641 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
5643 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5646 pa_assert_se(pa_hashmap_remove(p->extensions, m));
5649 pa_native_options* pa_native_options_new(void) {
5650 pa_native_options *o;
5652 o = pa_xnew0(pa_native_options, 1);
5658 pa_native_options* pa_native_options_ref(pa_native_options *o) {
5660 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5667 void pa_native_options_unref(pa_native_options *o) {
5669 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5671 if (PA_REFCNT_DEC(o) > 0)
5674 pa_xfree(o->auth_group);
5677 pa_ip_acl_free(o->auth_ip_acl);
5680 pa_auth_cookie_unref(o->auth_cookie);
5685 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
5690 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5693 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
5694 pa_log("auth-anonymous= expects a boolean argument.");
5699 if (pa_modargs_get_value_boolean(ma, "auth-group-enable", &enabled) < 0) {
5700 pa_log("auth-group-enable= expects a boolean argument.");
5704 pa_xfree(o->auth_group);
5705 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
5709 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5712 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
5715 if (!(ipa = pa_ip_acl_new(acl))) {
5716 pa_log("Failed to parse IP ACL '%s'", acl);
5721 pa_ip_acl_free(o->auth_ip_acl);
5723 o->auth_ip_acl = ipa;
5727 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
5728 pa_log("auth-cookie-enabled= expects a boolean argument.");
5733 pa_auth_cookie_unref(o->auth_cookie);
5738 /* The new name for this is 'auth-cookie', for compat reasons
5739 * we check the old name too */
5740 cn = pa_modargs_get_value(ma, "auth-cookie", NULL);
5742 cn = pa_modargs_get_value(ma, "cookie", NULL);
5745 o->auth_cookie = pa_auth_cookie_get(c, cn, true, PA_NATIVE_COOKIE_LENGTH);
5747 o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE, false, PA_NATIVE_COOKIE_LENGTH);
5748 if (!o->auth_cookie) {
5749 o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE_FALLBACK, false, PA_NATIVE_COOKIE_LENGTH);
5751 if (!o->auth_cookie)
5752 o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE, true, PA_NATIVE_COOKIE_LENGTH);
5756 if (!o->auth_cookie)
5760 o->auth_cookie = NULL;
5765 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
5766 pa_native_connection_assert_ref(c);
5771 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
5772 pa_native_connection_assert_ref(c);