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