remap: fix counters for mmx and sse remap
[pulseaudio-mirror.git] / src / pulsecore / protocol-native.c
blobd961dba2dd5c758a29a974832774bc4cd3d23fb1
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 pa_atomic_t missing;
129 pa_usec_t configured_sink_latency;
130 pa_buffer_attr buffer_attr;
132 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
133 int64_t read_index, write_index;
134 size_t render_memblockq_length;
135 pa_usec_t current_sink_latency;
136 uint64_t playing_for, underrun_for;
137 } playback_stream;
139 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
140 PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
142 typedef struct upload_stream {
143 output_stream parent;
145 pa_native_connection *connection;
146 uint32_t index;
148 pa_memchunk memchunk;
149 size_t length;
150 char *name;
151 pa_sample_spec sample_spec;
152 pa_channel_map channel_map;
153 pa_proplist *proplist;
154 } upload_stream;
156 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
157 PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
159 struct pa_native_connection {
160 pa_msgobject parent;
161 pa_native_protocol *protocol;
162 pa_native_options *options;
163 pa_bool_t authorized:1;
164 pa_bool_t is_local:1;
165 uint32_t version;
166 pa_client *client;
167 pa_pstream *pstream;
168 pa_pdispatch *pdispatch;
169 pa_idxset *record_streams, *output_streams;
170 uint32_t rrobin_index;
171 pa_subscription *subscription;
172 pa_time_event *auth_timeout_event;
175 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
176 PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
178 struct pa_native_protocol {
179 PA_REFCNT_DECLARE;
181 pa_core *core;
182 pa_idxset *connections;
184 pa_strlist *servers;
185 pa_hook hooks[PA_NATIVE_HOOK_MAX];
187 pa_hashmap *extensions;
190 enum {
191 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
194 enum {
195 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
196 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
197 SINK_INPUT_MESSAGE_FLUSH,
198 SINK_INPUT_MESSAGE_TRIGGER,
199 SINK_INPUT_MESSAGE_SEEK,
200 SINK_INPUT_MESSAGE_PREBUF_FORCE,
201 SINK_INPUT_MESSAGE_UPDATE_LATENCY,
202 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
205 enum {
206 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
207 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
208 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
209 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
210 PLAYBACK_STREAM_MESSAGE_STARTED,
211 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
214 enum {
215 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
218 enum {
219 CONNECTION_MESSAGE_RELEASE,
220 CONNECTION_MESSAGE_REVOKE
223 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
224 static void sink_input_kill_cb(pa_sink_input *i);
225 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
226 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
227 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
228 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
229 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
230 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
232 static void native_connection_send_memblock(pa_native_connection *c);
233 static void playback_stream_request_bytes(struct playback_stream*s);
235 static void source_output_kill_cb(pa_source_output *o);
236 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
237 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend);
238 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
239 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
240 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
242 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
243 static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
245 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
246 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
247 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
248 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
249 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
250 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
251 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
252 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
253 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
254 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
255 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
256 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
257 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
258 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
259 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
260 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
261 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
262 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
263 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
264 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
265 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
266 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
267 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
268 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
269 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
270 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
271 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
272 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
273 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
274 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
275 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
276 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
277 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
278 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
279 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
280 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
281 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
282 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
283 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
285 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
286 [PA_COMMAND_ERROR] = NULL,
287 [PA_COMMAND_TIMEOUT] = NULL,
288 [PA_COMMAND_REPLY] = NULL,
289 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
290 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
291 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
292 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
293 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
294 [PA_COMMAND_AUTH] = command_auth,
295 [PA_COMMAND_REQUEST] = NULL,
296 [PA_COMMAND_EXIT] = command_exit,
297 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
298 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
299 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
300 [PA_COMMAND_STAT] = command_stat,
301 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
302 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
303 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
304 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
305 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
306 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
307 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
308 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
309 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
310 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
311 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
312 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
313 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
314 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
315 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
316 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
317 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
318 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
319 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
320 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
321 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
322 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
323 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
324 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
325 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
327 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
328 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
329 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
331 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
332 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
333 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
335 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
336 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
338 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
339 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
340 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
341 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
343 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
344 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
346 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
347 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
348 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
349 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
350 [PA_COMMAND_KILL_CLIENT] = command_kill,
351 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
352 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
353 [PA_COMMAND_LOAD_MODULE] = command_load_module,
354 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
356 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
357 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
358 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
359 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
361 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
362 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
364 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
365 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
367 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
368 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
370 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
371 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
372 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
374 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
375 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
376 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
378 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
380 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
381 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
383 [PA_COMMAND_EXTENSION] = command_extension
386 /* structure management */
388 /* Called from main context */
389 static void upload_stream_unlink(upload_stream *s) {
390 pa_assert(s);
392 if (!s->connection)
393 return;
395 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
396 s->connection = NULL;
397 upload_stream_unref(s);
400 /* Called from main context */
401 static void upload_stream_free(pa_object *o) {
402 upload_stream *s = UPLOAD_STREAM(o);
403 pa_assert(s);
405 upload_stream_unlink(s);
407 pa_xfree(s->name);
409 if (s->proplist)
410 pa_proplist_free(s->proplist);
412 if (s->memchunk.memblock)
413 pa_memblock_unref(s->memchunk.memblock);
415 pa_xfree(s);
418 /* Called from main context */
419 static upload_stream* upload_stream_new(
420 pa_native_connection *c,
421 const pa_sample_spec *ss,
422 const pa_channel_map *map,
423 const char *name,
424 size_t length,
425 pa_proplist *p) {
427 upload_stream *s;
429 pa_assert(c);
430 pa_assert(ss);
431 pa_assert(name);
432 pa_assert(length > 0);
433 pa_assert(p);
435 s = pa_msgobject_new(upload_stream);
436 s->parent.parent.parent.free = upload_stream_free;
437 s->connection = c;
438 s->sample_spec = *ss;
439 s->channel_map = *map;
440 s->name = pa_xstrdup(name);
441 pa_memchunk_reset(&s->memchunk);
442 s->length = length;
443 s->proplist = pa_proplist_copy(p);
444 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
446 pa_idxset_put(c->output_streams, s, &s->index);
448 return s;
451 /* Called from main context */
452 static void record_stream_unlink(record_stream *s) {
453 pa_assert(s);
455 if (!s->connection)
456 return;
458 if (s->source_output) {
459 pa_source_output_unlink(s->source_output);
460 pa_source_output_unref(s->source_output);
461 s->source_output = NULL;
464 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
465 s->connection = NULL;
466 record_stream_unref(s);
469 /* Called from main context */
470 static void record_stream_free(pa_object *o) {
471 record_stream *s = RECORD_STREAM(o);
472 pa_assert(s);
474 record_stream_unlink(s);
476 pa_memblockq_free(s->memblockq);
477 pa_xfree(s);
480 /* Called from main context */
481 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
482 record_stream *s = RECORD_STREAM(o);
483 record_stream_assert_ref(s);
485 if (!s->connection)
486 return -1;
488 switch (code) {
490 case RECORD_STREAM_MESSAGE_POST_DATA:
492 /* We try to keep up to date with how many bytes are
493 * currently on the fly */
494 pa_atomic_sub(&s->on_the_fly, chunk->length);
496 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
497 /* pa_log_warn("Failed to push data into output queue."); */
498 return -1;
501 if (!pa_pstream_is_pending(s->connection->pstream))
502 native_connection_send_memblock(s->connection);
504 break;
507 return 0;
510 /* Called from main context */
511 static void fix_record_buffer_attr_pre(record_stream *s) {
513 size_t frame_size;
514 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
516 pa_assert(s);
518 /* This function will be called from the main thread, before as
519 * well as after the source output has been activated using
520 * pa_source_output_put()! That means it may not touch any
521 * ->thread_info data! */
523 frame_size = pa_frame_size(&s->source_output->sample_spec);
525 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
526 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
527 if (s->buffer_attr.maxlength <= 0)
528 s->buffer_attr.maxlength = (uint32_t) frame_size;
530 if (s->buffer_attr.fragsize == (uint32_t) -1)
531 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
532 if (s->buffer_attr.fragsize <= 0)
533 s->buffer_attr.fragsize = (uint32_t) frame_size;
535 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
537 if (s->early_requests) {
539 /* In early request mode we need to emulate the classic
540 * fragment-based playback model. We do this setting the source
541 * latency to the fragment size. */
543 source_usec = fragsize_usec;
545 } else if (s->adjust_latency) {
547 /* So, the user asked us to adjust the latency according to
548 * what the source can provide. Half the latency will be
549 * spent on the hw buffer, half of it in the async buffer
550 * queue we maintain for each client. */
552 source_usec = fragsize_usec/2;
554 } else {
556 /* Ok, the user didn't ask us to adjust the latency, hence we
557 * don't */
559 source_usec = (pa_usec_t) -1;
562 if (source_usec != (pa_usec_t) -1)
563 s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
564 else
565 s->configured_source_latency = 0;
567 if (s->early_requests) {
569 /* Ok, we didn't necessarily get what we were asking for, so
570 * let's tell the user */
572 fragsize_usec = s->configured_source_latency;
574 } else if (s->adjust_latency) {
576 /* Now subtract what we actually got */
578 if (fragsize_usec >= s->configured_source_latency*2)
579 fragsize_usec -= s->configured_source_latency;
580 else
581 fragsize_usec = s->configured_source_latency;
584 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
585 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
587 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
589 if (s->buffer_attr.fragsize <= 0)
590 s->buffer_attr.fragsize = (uint32_t) frame_size;
593 /* Called from main context */
594 static void fix_record_buffer_attr_post(record_stream *s) {
595 size_t base;
597 pa_assert(s);
599 /* This function will be called from the main thread, before as
600 * well as after the source output has been activated using
601 * pa_source_output_put()! That means it may not touch and
602 * ->thread_info data! */
604 base = pa_frame_size(&s->source_output->sample_spec);
606 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
607 if (s->buffer_attr.fragsize <= 0)
608 s->buffer_attr.fragsize = base;
610 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
611 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
614 /* Called from main context */
615 static record_stream* record_stream_new(
616 pa_native_connection *c,
617 pa_source *source,
618 pa_sample_spec *ss,
619 pa_channel_map *map,
620 pa_bool_t peak_detect,
621 pa_buffer_attr *attr,
622 pa_source_output_flags_t flags,
623 pa_proplist *p,
624 pa_bool_t adjust_latency,
625 pa_sink_input *direct_on_input,
626 pa_bool_t early_requests,
627 int *ret) {
629 record_stream *s;
630 pa_source_output *source_output = NULL;
631 size_t base;
632 pa_source_output_new_data data;
634 pa_assert(c);
635 pa_assert(ss);
636 pa_assert(p);
637 pa_assert(ret);
639 pa_source_output_new_data_init(&data);
641 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
642 data.driver = __FILE__;
643 data.module = c->options->module;
644 data.client = c->client;
645 data.source = source;
646 data.direct_on_input = direct_on_input;
647 pa_source_output_new_data_set_sample_spec(&data, ss);
648 pa_source_output_new_data_set_channel_map(&data, map);
649 if (peak_detect)
650 data.resample_method = PA_RESAMPLER_PEAKS;
651 data.flags = flags;
653 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
655 pa_source_output_new_data_done(&data);
657 if (!source_output)
658 return NULL;
660 s = pa_msgobject_new(record_stream);
661 s->parent.parent.free = record_stream_free;
662 s->parent.process_msg = record_stream_process_msg;
663 s->connection = c;
664 s->source_output = source_output;
665 s->buffer_attr = *attr;
666 s->adjust_latency = adjust_latency;
667 s->early_requests = early_requests;
668 pa_atomic_store(&s->on_the_fly, 0);
670 s->source_output->parent.process_msg = source_output_process_msg;
671 s->source_output->push = source_output_push_cb;
672 s->source_output->kill = source_output_kill_cb;
673 s->source_output->get_latency = source_output_get_latency_cb;
674 s->source_output->moving = source_output_moving_cb;
675 s->source_output->suspend = source_output_suspend_cb;
676 s->source_output->send_event = source_output_send_event_cb;
677 s->source_output->userdata = s;
679 fix_record_buffer_attr_pre(s);
681 s->memblockq = pa_memblockq_new(
683 s->buffer_attr.maxlength,
685 base = pa_frame_size(&source_output->sample_spec),
689 NULL);
691 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
692 fix_record_buffer_attr_post(s);
694 *ss = s->source_output->sample_spec;
695 *map = s->source_output->channel_map;
697 pa_idxset_put(c->record_streams, s, &s->index);
699 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
700 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
701 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
702 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
704 pa_source_output_put(s->source_output);
705 return s;
708 /* Called from main context */
709 static void record_stream_send_killed(record_stream *r) {
710 pa_tagstruct *t;
711 record_stream_assert_ref(r);
713 t = pa_tagstruct_new(NULL, 0);
714 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
715 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
716 pa_tagstruct_putu32(t, r->index);
717 pa_pstream_send_tagstruct(r->connection->pstream, t);
720 /* Called from main context */
721 static void playback_stream_unlink(playback_stream *s) {
722 pa_assert(s);
724 if (!s->connection)
725 return;
727 if (s->sink_input) {
728 pa_sink_input_unlink(s->sink_input);
729 pa_sink_input_unref(s->sink_input);
730 s->sink_input = NULL;
733 if (s->drain_request)
734 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
736 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
737 s->connection = NULL;
738 playback_stream_unref(s);
741 /* Called from main context */
742 static void playback_stream_free(pa_object* o) {
743 playback_stream *s = PLAYBACK_STREAM(o);
744 pa_assert(s);
746 playback_stream_unlink(s);
748 pa_memblockq_free(s->memblockq);
749 pa_xfree(s);
752 /* Called from main context */
753 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
754 playback_stream *s = PLAYBACK_STREAM(o);
755 playback_stream_assert_ref(s);
757 if (!s->connection)
758 return -1;
760 switch (code) {
762 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
763 pa_tagstruct *t;
764 int l = 0;
766 for (;;) {
767 if ((l = pa_atomic_load(&s->missing)) <= 0)
768 return 0;
770 if (pa_atomic_cmpxchg(&s->missing, l, 0))
771 break;
774 t = pa_tagstruct_new(NULL, 0);
775 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
776 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
777 pa_tagstruct_putu32(t, s->index);
778 pa_tagstruct_putu32(t, (uint32_t) l);
779 pa_pstream_send_tagstruct(s->connection->pstream, t);
781 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
782 break;
785 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
786 pa_tagstruct *t;
788 /* pa_log("signalling underflow"); */
790 /* Report that we're empty */
791 t = pa_tagstruct_new(NULL, 0);
792 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
793 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
794 pa_tagstruct_putu32(t, s->index);
795 pa_pstream_send_tagstruct(s->connection->pstream, t);
796 break;
799 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
800 pa_tagstruct *t;
802 /* Notify the user we're overflowed*/
803 t = pa_tagstruct_new(NULL, 0);
804 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
805 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
806 pa_tagstruct_putu32(t, s->index);
807 pa_pstream_send_tagstruct(s->connection->pstream, t);
808 break;
811 case PLAYBACK_STREAM_MESSAGE_STARTED:
813 if (s->connection->version >= 13) {
814 pa_tagstruct *t;
816 /* Notify the user we started playback */
817 t = pa_tagstruct_new(NULL, 0);
818 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
819 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
820 pa_tagstruct_putu32(t, s->index);
821 pa_pstream_send_tagstruct(s->connection->pstream, t);
824 break;
826 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
827 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
828 break;
830 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH: {
831 pa_tagstruct *t;
833 s->buffer_attr.tlength = (uint32_t) offset;
835 t = pa_tagstruct_new(NULL, 0);
836 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
837 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
838 pa_tagstruct_putu32(t, s->index);
839 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
840 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
841 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
842 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
843 pa_tagstruct_put_usec(t, s->configured_sink_latency);
844 pa_pstream_send_tagstruct(s->connection->pstream, t);
846 break;
850 return 0;
853 /* Called from main context */
854 static void fix_playback_buffer_attr(playback_stream *s) {
855 size_t frame_size, max_prebuf;
856 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
858 pa_assert(s);
860 /* This function will be called from the main thread, before as
861 * well as after the sink input has been activated using
862 * pa_sink_input_put()! That means it may not touch any
863 * ->thread_info data, such as the memblockq! */
865 frame_size = pa_frame_size(&s->sink_input->sample_spec);
867 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
868 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
869 if (s->buffer_attr.maxlength <= 0)
870 s->buffer_attr.maxlength = (uint32_t) frame_size;
872 if (s->buffer_attr.tlength == (uint32_t) -1)
873 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
874 if (s->buffer_attr.tlength <= 0)
875 s->buffer_attr.tlength = (uint32_t) frame_size;
877 if (s->buffer_attr.minreq == (uint32_t) -1)
878 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
879 if (s->buffer_attr.minreq <= 0)
880 s->buffer_attr.minreq = (uint32_t) frame_size;
882 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
883 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
885 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
886 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
888 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
889 (double) tlength_usec / PA_USEC_PER_MSEC,
890 (double) minreq_usec / PA_USEC_PER_MSEC);
892 if (s->early_requests) {
894 /* In early request mode we need to emulate the classic
895 * fragment-based playback model. We do this setting the sink
896 * latency to the fragment size. */
898 sink_usec = minreq_usec;
899 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
901 } else if (s->adjust_latency) {
903 /* So, the user asked us to adjust the latency of the stream
904 * buffer according to the what the sink can provide. The
905 * tlength passed in shall be the overall latency. Roughly
906 * half the latency will be spent on the hw buffer, the other
907 * half of it in the async buffer queue we maintain for each
908 * client. In between we'll have a safety space of size
909 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
910 * empty and needs to be filled, then our buffer must have
911 * enough data to fulfill this request immediatly and thus
912 * have at least the same tlength as the size of the hw
913 * buffer. It additionally needs space for 2 times minreq
914 * because if the buffer ran empty and a partial fillup
915 * happens immediately on the next iteration we need to be
916 * able to fulfill it and give the application also minreq
917 * time to fill it up again for the next request Makes 2 times
918 * minreq in plus.. */
920 if (tlength_usec > minreq_usec*2)
921 sink_usec = (tlength_usec - minreq_usec*2)/2;
922 else
923 sink_usec = 0;
925 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
927 } else {
929 /* Ok, the user didn't ask us to adjust the latency, but we
930 * still need to make sure that the parameters from the user
931 * do make sense. */
933 if (tlength_usec > minreq_usec*2)
934 sink_usec = (tlength_usec - minreq_usec*2);
935 else
936 sink_usec = 0;
938 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
941 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
943 if (s->early_requests) {
945 /* Ok, we didn't necessarily get what we were asking for, so
946 * let's tell the user */
948 minreq_usec = s->configured_sink_latency;
950 } else if (s->adjust_latency) {
952 /* Ok, we didn't necessarily get what we were asking for, so
953 * let's subtract from what we asked for for the remaining
954 * buffer space */
956 if (tlength_usec >= s->configured_sink_latency)
957 tlength_usec -= s->configured_sink_latency;
960 /* FIXME: This is actually larger than necessary, since not all of
961 * the sink latency is actually rewritable. */
962 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
963 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
965 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
966 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
967 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
969 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
970 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
971 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
973 if (s->buffer_attr.minreq <= 0) {
974 s->buffer_attr.minreq = (uint32_t) frame_size;
975 s->buffer_attr.tlength += (uint32_t) frame_size*2;
978 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
979 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
981 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
983 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
984 s->buffer_attr.prebuf > max_prebuf)
985 s->buffer_attr.prebuf = max_prebuf;
988 /* Called from main context */
989 static playback_stream* playback_stream_new(
990 pa_native_connection *c,
991 pa_sink *sink,
992 pa_sample_spec *ss,
993 pa_channel_map *map,
994 pa_buffer_attr *a,
995 pa_cvolume *volume,
996 pa_bool_t muted,
997 pa_bool_t muted_set,
998 uint32_t syncid,
999 uint32_t *missing,
1000 pa_sink_input_flags_t flags,
1001 pa_proplist *p,
1002 pa_bool_t adjust_latency,
1003 pa_bool_t early_requests,
1004 int *ret) {
1006 playback_stream *s, *ssync;
1007 pa_sink_input *sink_input = NULL;
1008 pa_memchunk silence;
1009 uint32_t idx;
1010 int64_t start_index;
1011 pa_sink_input_new_data data;
1013 pa_assert(c);
1014 pa_assert(ss);
1015 pa_assert(missing);
1016 pa_assert(p);
1017 pa_assert(ret);
1019 /* Find syncid group */
1020 for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) {
1022 if (!playback_stream_isinstance(ssync))
1023 continue;
1025 if (ssync->syncid == syncid)
1026 break;
1029 /* Synced streams must connect to the same sink */
1030 if (ssync) {
1032 if (!sink)
1033 sink = ssync->sink_input->sink;
1034 else if (sink != ssync->sink_input->sink) {
1035 *ret = PA_ERR_INVALID;
1036 return NULL;
1040 pa_sink_input_new_data_init(&data);
1042 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1043 data.driver = __FILE__;
1044 data.module = c->options->module;
1045 data.client = c->client;
1046 data.sink = sink;
1047 pa_sink_input_new_data_set_sample_spec(&data, ss);
1048 pa_sink_input_new_data_set_channel_map(&data, map);
1049 if (volume)
1050 pa_sink_input_new_data_set_volume(&data, volume);
1051 if (muted_set)
1052 pa_sink_input_new_data_set_muted(&data, muted);
1053 data.sync_base = ssync ? ssync->sink_input : NULL;
1054 data.flags = flags;
1056 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1058 pa_sink_input_new_data_done(&data);
1060 if (!sink_input)
1061 return NULL;
1063 s = pa_msgobject_new(playback_stream);
1064 s->parent.parent.parent.free = playback_stream_free;
1065 s->parent.parent.process_msg = playback_stream_process_msg;
1066 s->connection = c;
1067 s->syncid = syncid;
1068 s->sink_input = sink_input;
1069 s->is_underrun = TRUE;
1070 s->drain_request = FALSE;
1071 pa_atomic_store(&s->missing, 0);
1072 s->buffer_attr = *a;
1073 s->adjust_latency = adjust_latency;
1074 s->early_requests = early_requests;
1076 s->sink_input->parent.process_msg = sink_input_process_msg;
1077 s->sink_input->pop = sink_input_pop_cb;
1078 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1079 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1080 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1081 s->sink_input->kill = sink_input_kill_cb;
1082 s->sink_input->moving = sink_input_moving_cb;
1083 s->sink_input->suspend = sink_input_suspend_cb;
1084 s->sink_input->send_event = sink_input_send_event_cb;
1085 s->sink_input->userdata = s;
1087 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1089 fix_playback_buffer_attr(s);
1091 pa_sink_input_get_silence(sink_input, &silence);
1092 s->memblockq = pa_memblockq_new(
1093 start_index,
1094 s->buffer_attr.maxlength,
1095 s->buffer_attr.tlength,
1096 pa_frame_size(&sink_input->sample_spec),
1097 s->buffer_attr.prebuf,
1098 s->buffer_attr.minreq,
1100 &silence);
1101 pa_memblock_unref(silence.memblock);
1103 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1105 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1107 *ss = s->sink_input->sample_spec;
1108 *map = s->sink_input->channel_map;
1110 pa_idxset_put(c->output_streams, s, &s->index);
1112 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1113 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1114 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1115 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1116 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1118 pa_sink_input_put(s->sink_input);
1119 return s;
1122 /* Called from IO context */
1123 static void playback_stream_request_bytes(playback_stream *s) {
1124 size_t m, minreq;
1125 int previous_missing;
1127 playback_stream_assert_ref(s);
1129 m = pa_memblockq_pop_missing(s->memblockq);
1131 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu)", */
1132 /* (unsigned long) m, */
1133 /* pa_memblockq_get_tlength(s->memblockq), */
1134 /* pa_memblockq_get_minreq(s->memblockq), */
1135 /* pa_memblockq_get_length(s->memblockq)); */
1137 if (m <= 0)
1138 return;
1140 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1142 previous_missing = pa_atomic_add(&s->missing, (int) m);
1143 minreq = pa_memblockq_get_minreq(s->memblockq);
1145 if (pa_memblockq_prebuf_active(s->memblockq) ||
1146 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1147 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1150 /* Called from main context */
1151 static void playback_stream_send_killed(playback_stream *p) {
1152 pa_tagstruct *t;
1153 playback_stream_assert_ref(p);
1155 t = pa_tagstruct_new(NULL, 0);
1156 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1157 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1158 pa_tagstruct_putu32(t, p->index);
1159 pa_pstream_send_tagstruct(p->connection->pstream, t);
1162 /* Called from main context */
1163 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1164 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1165 pa_native_connection_assert_ref(c);
1167 if (!c->protocol)
1168 return -1;
1170 switch (code) {
1172 case CONNECTION_MESSAGE_REVOKE:
1173 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1174 break;
1176 case CONNECTION_MESSAGE_RELEASE:
1177 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1178 break;
1181 return 0;
1184 /* Called from main context */
1185 static void native_connection_unlink(pa_native_connection *c) {
1186 record_stream *r;
1187 output_stream *o;
1189 pa_assert(c);
1191 if (!c->protocol)
1192 return;
1194 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1196 if (c->options)
1197 pa_native_options_unref(c->options);
1199 while ((r = pa_idxset_first(c->record_streams, NULL)))
1200 record_stream_unlink(r);
1202 while ((o = pa_idxset_first(c->output_streams, NULL)))
1203 if (playback_stream_isinstance(o))
1204 playback_stream_unlink(PLAYBACK_STREAM(o));
1205 else
1206 upload_stream_unlink(UPLOAD_STREAM(o));
1208 if (c->subscription)
1209 pa_subscription_free(c->subscription);
1211 if (c->pstream)
1212 pa_pstream_unlink(c->pstream);
1214 if (c->auth_timeout_event) {
1215 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1216 c->auth_timeout_event = NULL;
1219 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1220 c->protocol = NULL;
1221 pa_native_connection_unref(c);
1224 /* Called from main context */
1225 static void native_connection_free(pa_object *o) {
1226 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1228 pa_assert(c);
1230 native_connection_unlink(c);
1232 pa_idxset_free(c->record_streams, NULL, NULL);
1233 pa_idxset_free(c->output_streams, NULL, NULL);
1235 pa_pdispatch_unref(c->pdispatch);
1236 pa_pstream_unref(c->pstream);
1237 pa_client_free(c->client);
1239 pa_xfree(c);
1242 /* Called from main context */
1243 static void native_connection_send_memblock(pa_native_connection *c) {
1244 uint32_t start;
1245 record_stream *r;
1247 start = PA_IDXSET_INVALID;
1248 for (;;) {
1249 pa_memchunk chunk;
1251 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1252 return;
1254 if (start == PA_IDXSET_INVALID)
1255 start = c->rrobin_index;
1256 else if (start == c->rrobin_index)
1257 return;
1259 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1260 pa_memchunk schunk = chunk;
1262 if (schunk.length > r->buffer_attr.fragsize)
1263 schunk.length = r->buffer_attr.fragsize;
1265 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1267 pa_memblockq_drop(r->memblockq, schunk.length);
1268 pa_memblock_unref(schunk.memblock);
1270 return;
1275 /*** sink input callbacks ***/
1277 /* Called from thread context */
1278 static void handle_seek(playback_stream *s, int64_t indexw) {
1279 playback_stream_assert_ref(s);
1281 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1283 if (s->sink_input->thread_info.underrun_for > 0) {
1285 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1287 if (pa_memblockq_is_readable(s->memblockq)) {
1289 /* We just ended an underrun, let's ask the sink
1290 * for a complete rewind rewrite */
1292 pa_log_debug("Requesting rewind due to end of underrun.");
1293 pa_sink_input_request_rewind(s->sink_input,
1294 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1295 s->sink_input->thread_info.underrun_for),
1296 FALSE, TRUE, FALSE);
1299 } else {
1300 int64_t indexr;
1302 indexr = pa_memblockq_get_read_index(s->memblockq);
1304 if (indexw < indexr) {
1305 /* OK, the sink already asked for this data, so
1306 * let's have it usk us again */
1308 pa_log_debug("Requesting rewind due to rewrite.");
1309 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1313 playback_stream_request_bytes(s);
1316 /* Called from thread context */
1317 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1318 pa_sink_input *i = PA_SINK_INPUT(o);
1319 playback_stream *s;
1321 pa_sink_input_assert_ref(i);
1322 s = PLAYBACK_STREAM(i->userdata);
1323 playback_stream_assert_ref(s);
1325 switch (code) {
1327 case SINK_INPUT_MESSAGE_SEEK: {
1328 int64_t windex;
1330 windex = pa_memblockq_get_write_index(s->memblockq);
1332 /* The client side is incapable of accounting correctly
1333 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1334 * able to deal with that. */
1336 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1338 handle_seek(s, windex);
1339 return 0;
1342 case SINK_INPUT_MESSAGE_POST_DATA: {
1343 int64_t windex;
1345 pa_assert(chunk);
1347 windex = pa_memblockq_get_write_index(s->memblockq);
1349 /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
1351 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1353 if (pa_log_ratelimit())
1354 pa_log_warn("Failed to push data into queue");
1355 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1356 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1359 handle_seek(s, windex);
1361 /* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1363 return 0;
1366 case SINK_INPUT_MESSAGE_DRAIN:
1367 case SINK_INPUT_MESSAGE_FLUSH:
1368 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1369 case SINK_INPUT_MESSAGE_TRIGGER: {
1371 int64_t windex;
1372 pa_sink_input *isync;
1373 void (*func)(pa_memblockq *bq);
1375 switch (code) {
1376 case SINK_INPUT_MESSAGE_FLUSH:
1377 func = pa_memblockq_flush_write;
1378 break;
1380 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1381 func = pa_memblockq_prebuf_force;
1382 break;
1384 case SINK_INPUT_MESSAGE_DRAIN:
1385 case SINK_INPUT_MESSAGE_TRIGGER:
1386 func = pa_memblockq_prebuf_disable;
1387 break;
1389 default:
1390 pa_assert_not_reached();
1393 windex = pa_memblockq_get_write_index(s->memblockq);
1394 func(s->memblockq);
1395 handle_seek(s, windex);
1397 /* Do the same for all other members in the sync group */
1398 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1399 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1400 windex = pa_memblockq_get_write_index(ssync->memblockq);
1401 func(ssync->memblockq);
1402 handle_seek(ssync, windex);
1405 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1406 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1407 windex = pa_memblockq_get_write_index(ssync->memblockq);
1408 func(ssync->memblockq);
1409 handle_seek(ssync, windex);
1412 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1413 if (!pa_memblockq_is_readable(s->memblockq))
1414 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1415 else {
1416 s->drain_tag = PA_PTR_TO_UINT(userdata);
1417 s->drain_request = TRUE;
1421 return 0;
1424 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1425 /* Atomically get a snapshot of all timing parameters... */
1426 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1427 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1428 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1429 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1430 s->underrun_for = s->sink_input->thread_info.underrun_for;
1431 s->playing_for = s->sink_input->thread_info.playing_for;
1433 return 0;
1435 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1436 int64_t windex;
1438 windex = pa_memblockq_get_write_index(s->memblockq);
1440 pa_memblockq_prebuf_force(s->memblockq);
1442 handle_seek(s, windex);
1444 /* Fall through to the default handler */
1445 break;
1448 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1449 pa_usec_t *r = userdata;
1451 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1453 /* Fall through, the default handler will add in the extra
1454 * latency added by the resampler */
1455 break;
1458 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1459 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1460 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1461 return 0;
1465 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1468 /* Called from thread context */
1469 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1470 playback_stream *s;
1472 pa_sink_input_assert_ref(i);
1473 s = PLAYBACK_STREAM(i->userdata);
1474 playback_stream_assert_ref(s);
1475 pa_assert(chunk);
1477 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1479 if (pa_memblockq_is_readable(s->memblockq))
1480 s->is_underrun = FALSE;
1481 else {
1482 if (!s->is_underrun)
1483 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));
1485 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1486 s->drain_request = FALSE;
1487 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);
1488 } else if (!s->is_underrun)
1489 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1491 s->is_underrun = TRUE;
1493 playback_stream_request_bytes(s);
1496 /* This call will not fail with prebuf=0, hence we check for
1497 underrun explicitly above */
1498 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1499 return -1;
1501 chunk->length = PA_MIN(nbytes, chunk->length);
1503 if (i->thread_info.underrun_for > 0)
1504 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1506 pa_memblockq_drop(s->memblockq, chunk->length);
1507 playback_stream_request_bytes(s);
1509 return 0;
1512 /* Called from thread context */
1513 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1514 playback_stream *s;
1516 pa_sink_input_assert_ref(i);
1517 s = PLAYBACK_STREAM(i->userdata);
1518 playback_stream_assert_ref(s);
1520 /* If we are in an underrun, then we don't rewind */
1521 if (i->thread_info.underrun_for > 0)
1522 return;
1524 pa_memblockq_rewind(s->memblockq, nbytes);
1527 /* Called from thread context */
1528 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1529 playback_stream *s;
1531 pa_sink_input_assert_ref(i);
1532 s = PLAYBACK_STREAM(i->userdata);
1533 playback_stream_assert_ref(s);
1535 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1538 /* Called from thread context */
1539 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1540 playback_stream *s;
1541 size_t new_tlength, old_tlength;
1543 pa_sink_input_assert_ref(i);
1544 s = PLAYBACK_STREAM(i->userdata);
1545 playback_stream_assert_ref(s);
1547 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1548 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1550 if (old_tlength < new_tlength) {
1551 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1552 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1553 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1555 if (new_tlength == old_tlength)
1556 pa_log_debug("Failed to increase tlength");
1557 else {
1558 pa_log_debug("Notifying client about increased tlength");
1559 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);
1564 /* Called from main context */
1565 static void sink_input_kill_cb(pa_sink_input *i) {
1566 playback_stream *s;
1568 pa_sink_input_assert_ref(i);
1569 s = PLAYBACK_STREAM(i->userdata);
1570 playback_stream_assert_ref(s);
1572 playback_stream_send_killed(s);
1573 playback_stream_unlink(s);
1576 /* Called from main context */
1577 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1578 playback_stream *s;
1579 pa_tagstruct *t;
1581 pa_sink_input_assert_ref(i);
1582 s = PLAYBACK_STREAM(i->userdata);
1583 playback_stream_assert_ref(s);
1585 if (s->connection->version < 15)
1586 return;
1588 t = pa_tagstruct_new(NULL, 0);
1589 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1590 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1591 pa_tagstruct_putu32(t, s->index);
1592 pa_tagstruct_puts(t, event);
1593 pa_tagstruct_put_proplist(t, pl);
1594 pa_pstream_send_tagstruct(s->connection->pstream, t);
1597 /* Called from main context */
1598 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1599 playback_stream *s;
1600 pa_tagstruct *t;
1602 pa_sink_input_assert_ref(i);
1603 s = PLAYBACK_STREAM(i->userdata);
1604 playback_stream_assert_ref(s);
1606 if (s->connection->version < 12)
1607 return;
1609 t = pa_tagstruct_new(NULL, 0);
1610 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1611 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1612 pa_tagstruct_putu32(t, s->index);
1613 pa_tagstruct_put_boolean(t, suspend);
1614 pa_pstream_send_tagstruct(s->connection->pstream, t);
1617 /* Called from main context */
1618 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1619 playback_stream *s;
1620 pa_tagstruct *t;
1622 pa_sink_input_assert_ref(i);
1623 s = PLAYBACK_STREAM(i->userdata);
1624 playback_stream_assert_ref(s);
1626 if (!dest)
1627 return;
1629 fix_playback_buffer_attr(s);
1630 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1631 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1633 if (s->connection->version < 12)
1634 return;
1636 t = pa_tagstruct_new(NULL, 0);
1637 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1638 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1639 pa_tagstruct_putu32(t, s->index);
1640 pa_tagstruct_putu32(t, dest->index);
1641 pa_tagstruct_puts(t, dest->name);
1642 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1644 if (s->connection->version >= 13) {
1645 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1646 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1647 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1648 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1649 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1652 pa_pstream_send_tagstruct(s->connection->pstream, t);
1655 /*** source_output callbacks ***/
1657 /* Called from thread context */
1658 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1659 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1660 record_stream *s;
1662 pa_source_output_assert_ref(o);
1663 s = RECORD_STREAM(o->userdata);
1664 record_stream_assert_ref(s);
1666 switch (code) {
1667 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1668 /* Atomically get a snapshot of all timing parameters... */
1669 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1670 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1671 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1672 return 0;
1675 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1678 /* Called from thread context */
1679 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1680 record_stream *s;
1682 pa_source_output_assert_ref(o);
1683 s = RECORD_STREAM(o->userdata);
1684 record_stream_assert_ref(s);
1685 pa_assert(chunk);
1687 pa_atomic_add(&s->on_the_fly, chunk->length);
1688 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1691 static void source_output_kill_cb(pa_source_output *o) {
1692 record_stream *s;
1694 pa_source_output_assert_ref(o);
1695 s = RECORD_STREAM(o->userdata);
1696 record_stream_assert_ref(s);
1698 record_stream_send_killed(s);
1699 record_stream_unlink(s);
1702 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1703 record_stream *s;
1705 pa_source_output_assert_ref(o);
1706 s = RECORD_STREAM(o->userdata);
1707 record_stream_assert_ref(s);
1709 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1711 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1714 /* Called from main context */
1715 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1716 record_stream *s;
1717 pa_tagstruct *t;
1719 pa_source_output_assert_ref(o);
1720 s = RECORD_STREAM(o->userdata);
1721 record_stream_assert_ref(s);
1723 if (s->connection->version < 15)
1724 return;
1726 t = pa_tagstruct_new(NULL, 0);
1727 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1728 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1729 pa_tagstruct_putu32(t, s->index);
1730 pa_tagstruct_puts(t, event);
1731 pa_tagstruct_put_proplist(t, pl);
1732 pa_pstream_send_tagstruct(s->connection->pstream, t);
1735 /* Called from main context */
1736 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1737 record_stream *s;
1738 pa_tagstruct *t;
1740 pa_source_output_assert_ref(o);
1741 s = RECORD_STREAM(o->userdata);
1742 record_stream_assert_ref(s);
1744 if (s->connection->version < 12)
1745 return;
1747 t = pa_tagstruct_new(NULL, 0);
1748 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1749 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1750 pa_tagstruct_putu32(t, s->index);
1751 pa_tagstruct_put_boolean(t, suspend);
1752 pa_pstream_send_tagstruct(s->connection->pstream, t);
1755 /* Called from main context */
1756 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1757 record_stream *s;
1758 pa_tagstruct *t;
1760 pa_source_output_assert_ref(o);
1761 s = RECORD_STREAM(o->userdata);
1762 record_stream_assert_ref(s);
1764 if (!dest)
1765 return;
1767 fix_record_buffer_attr_pre(s);
1768 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1769 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1770 fix_record_buffer_attr_post(s);
1772 if (s->connection->version < 12)
1773 return;
1775 t = pa_tagstruct_new(NULL, 0);
1776 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1777 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1778 pa_tagstruct_putu32(t, s->index);
1779 pa_tagstruct_putu32(t, dest->index);
1780 pa_tagstruct_puts(t, dest->name);
1781 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1783 if (s->connection->version >= 13) {
1784 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1785 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1786 pa_tagstruct_put_usec(t, s->configured_source_latency);
1789 pa_pstream_send_tagstruct(s->connection->pstream, t);
1792 /*** pdispatch callbacks ***/
1794 static void protocol_error(pa_native_connection *c) {
1795 pa_log("protocol error, kicking client");
1796 native_connection_unlink(c);
1799 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1800 if (!(expression)) { \
1801 pa_pstream_send_error((pstream), (tag), (error)); \
1802 return; \
1804 } while(0);
1806 static pa_tagstruct *reply_new(uint32_t tag) {
1807 pa_tagstruct *reply;
1809 reply = pa_tagstruct_new(NULL, 0);
1810 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1811 pa_tagstruct_putu32(reply, tag);
1812 return reply;
1815 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1816 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1817 playback_stream *s;
1818 uint32_t sink_index, syncid, missing;
1819 pa_buffer_attr attr;
1820 const char *name = NULL, *sink_name;
1821 pa_sample_spec ss;
1822 pa_channel_map map;
1823 pa_tagstruct *reply;
1824 pa_sink *sink = NULL;
1825 pa_cvolume volume;
1826 pa_bool_t
1827 corked = FALSE,
1828 no_remap = FALSE,
1829 no_remix = FALSE,
1830 fix_format = FALSE,
1831 fix_rate = FALSE,
1832 fix_channels = FALSE,
1833 no_move = FALSE,
1834 variable_rate = FALSE,
1835 muted = FALSE,
1836 adjust_latency = FALSE,
1837 early_requests = FALSE,
1838 dont_inhibit_auto_suspend = FALSE,
1839 muted_set = FALSE,
1840 fail_on_suspend = FALSE;
1841 pa_sink_input_flags_t flags = 0;
1842 pa_proplist *p;
1843 pa_bool_t volume_set = TRUE;
1844 int ret = PA_ERR_INVALID;
1846 pa_native_connection_assert_ref(c);
1847 pa_assert(t);
1848 memset(&attr, 0, sizeof(attr));
1850 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1851 pa_tagstruct_get(
1853 PA_TAG_SAMPLE_SPEC, &ss,
1854 PA_TAG_CHANNEL_MAP, &map,
1855 PA_TAG_U32, &sink_index,
1856 PA_TAG_STRING, &sink_name,
1857 PA_TAG_U32, &attr.maxlength,
1858 PA_TAG_BOOLEAN, &corked,
1859 PA_TAG_U32, &attr.tlength,
1860 PA_TAG_U32, &attr.prebuf,
1861 PA_TAG_U32, &attr.minreq,
1862 PA_TAG_U32, &syncid,
1863 PA_TAG_CVOLUME, &volume,
1864 PA_TAG_INVALID) < 0) {
1866 protocol_error(c);
1867 return;
1870 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1871 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
1872 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
1873 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
1874 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
1875 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
1876 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
1877 CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID);
1879 p = pa_proplist_new();
1881 if (name)
1882 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1884 if (c->version >= 12) {
1885 /* Since 0.9.8 the user can ask for a couple of additional flags */
1887 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1888 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1889 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1890 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1891 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1892 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1893 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1895 protocol_error(c);
1896 pa_proplist_free(p);
1897 return;
1901 if (c->version >= 13) {
1903 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1904 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1905 pa_tagstruct_get_proplist(t, p) < 0) {
1906 protocol_error(c);
1907 pa_proplist_free(p);
1908 return;
1912 if (c->version >= 14) {
1914 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
1915 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
1916 protocol_error(c);
1917 pa_proplist_free(p);
1918 return;
1922 if (c->version >= 15) {
1924 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
1925 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
1926 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
1927 protocol_error(c);
1928 pa_proplist_free(p);
1929 return;
1933 if (!pa_tagstruct_eof(t)) {
1934 protocol_error(c);
1935 pa_proplist_free(p);
1936 return;
1939 if (sink_index != PA_INVALID_INDEX) {
1941 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
1942 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1943 pa_proplist_free(p);
1944 return;
1947 } else if (sink_name) {
1949 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
1950 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1951 pa_proplist_free(p);
1952 return;
1956 flags =
1957 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
1958 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
1959 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
1960 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
1961 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
1962 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
1963 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
1964 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
1965 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
1966 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0);
1968 /* Only since protocol version 15 there's a seperate muted_set
1969 * flag. For older versions we synthesize it here */
1970 muted_set = muted_set || muted;
1972 s = playback_stream_new(c, sink, &ss, &map, &attr, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, &ret);
1973 pa_proplist_free(p);
1975 CHECK_VALIDITY(c->pstream, s, tag, ret);
1977 reply = reply_new(tag);
1978 pa_tagstruct_putu32(reply, s->index);
1979 pa_assert(s->sink_input);
1980 pa_tagstruct_putu32(reply, s->sink_input->index);
1981 pa_tagstruct_putu32(reply, missing);
1983 /* pa_log("initial request is %u", missing); */
1985 if (c->version >= 9) {
1986 /* Since 0.9.0 we support sending the buffer metrics back to the client */
1988 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
1989 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
1990 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
1991 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
1994 if (c->version >= 12) {
1995 /* Since 0.9.8 we support sending the chosen sample
1996 * spec/channel map/device/suspend status back to the
1997 * client */
1999 pa_tagstruct_put_sample_spec(reply, &ss);
2000 pa_tagstruct_put_channel_map(reply, &map);
2002 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2003 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2005 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2008 if (c->version >= 13)
2009 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2011 pa_pstream_send_tagstruct(c->pstream, reply);
2014 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2015 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2016 uint32_t channel;
2018 pa_native_connection_assert_ref(c);
2019 pa_assert(t);
2021 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2022 !pa_tagstruct_eof(t)) {
2023 protocol_error(c);
2024 return;
2027 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2029 switch (command) {
2031 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2032 playback_stream *s;
2033 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2034 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2035 return;
2038 playback_stream_unlink(s);
2039 break;
2042 case PA_COMMAND_DELETE_RECORD_STREAM: {
2043 record_stream *s;
2044 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2045 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2046 return;
2049 record_stream_unlink(s);
2050 break;
2053 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2054 upload_stream *s;
2056 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2057 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2058 return;
2061 upload_stream_unlink(s);
2062 break;
2065 default:
2066 pa_assert_not_reached();
2069 pa_pstream_send_simple_ack(c->pstream, tag);
2072 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2073 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2074 record_stream *s;
2075 pa_buffer_attr attr;
2076 uint32_t source_index;
2077 const char *name = NULL, *source_name;
2078 pa_sample_spec ss;
2079 pa_channel_map map;
2080 pa_tagstruct *reply;
2081 pa_source *source = NULL;
2082 pa_bool_t
2083 corked = FALSE,
2084 no_remap = FALSE,
2085 no_remix = FALSE,
2086 fix_format = FALSE,
2087 fix_rate = FALSE,
2088 fix_channels = FALSE,
2089 no_move = FALSE,
2090 variable_rate = FALSE,
2091 adjust_latency = FALSE,
2092 peak_detect = FALSE,
2093 early_requests = FALSE,
2094 dont_inhibit_auto_suspend = FALSE,
2095 fail_on_suspend = FALSE;
2096 pa_source_output_flags_t flags = 0;
2097 pa_proplist *p;
2098 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2099 pa_sink_input *direct_on_input = NULL;
2100 int ret = PA_ERR_INVALID;
2102 pa_native_connection_assert_ref(c);
2103 pa_assert(t);
2105 memset(&attr, 0, sizeof(attr));
2107 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2108 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2109 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2110 pa_tagstruct_getu32(t, &source_index) < 0 ||
2111 pa_tagstruct_gets(t, &source_name) < 0 ||
2112 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2113 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2114 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2115 protocol_error(c);
2116 return;
2119 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2120 CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
2121 CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID);
2122 CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2123 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2124 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2125 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2127 p = pa_proplist_new();
2129 if (name)
2130 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2132 if (c->version >= 12) {
2133 /* Since 0.9.8 the user can ask for a couple of additional flags */
2135 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2136 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2137 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2138 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2139 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2140 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2141 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2143 protocol_error(c);
2144 pa_proplist_free(p);
2145 return;
2149 if (c->version >= 13) {
2151 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2152 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2153 pa_tagstruct_get_proplist(t, p) < 0 ||
2154 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2155 protocol_error(c);
2156 pa_proplist_free(p);
2157 return;
2161 if (c->version >= 14) {
2163 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2164 protocol_error(c);
2165 pa_proplist_free(p);
2166 return;
2170 if (c->version >= 15) {
2172 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2173 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2174 protocol_error(c);
2175 pa_proplist_free(p);
2176 return;
2180 if (!pa_tagstruct_eof(t)) {
2181 protocol_error(c);
2182 pa_proplist_free(p);
2183 return;
2186 if (source_index != PA_INVALID_INDEX) {
2188 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2189 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2190 pa_proplist_free(p);
2191 return;
2194 } else if (source_name) {
2196 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2197 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2198 pa_proplist_free(p);
2199 return;
2203 if (direct_on_input_idx != PA_INVALID_INDEX) {
2205 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2206 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2207 pa_proplist_free(p);
2208 return;
2212 flags =
2213 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2214 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2215 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2216 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2217 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2218 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2219 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2220 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2221 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2222 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0);
2224 s = record_stream_new(c, source, &ss, &map, peak_detect, &attr, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
2225 pa_proplist_free(p);
2227 CHECK_VALIDITY(c->pstream, s, tag, ret);
2229 reply = reply_new(tag);
2230 pa_tagstruct_putu32(reply, s->index);
2231 pa_assert(s->source_output);
2232 pa_tagstruct_putu32(reply, s->source_output->index);
2234 if (c->version >= 9) {
2235 /* Since 0.9 we support sending the buffer metrics back to the client */
2237 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2238 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2241 if (c->version >= 12) {
2242 /* Since 0.9.8 we support sending the chosen sample
2243 * spec/channel map/device/suspend status back to the
2244 * client */
2246 pa_tagstruct_put_sample_spec(reply, &ss);
2247 pa_tagstruct_put_channel_map(reply, &map);
2249 pa_tagstruct_putu32(reply, s->source_output->source->index);
2250 pa_tagstruct_puts(reply, s->source_output->source->name);
2252 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2255 if (c->version >= 13)
2256 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2258 pa_pstream_send_tagstruct(c->pstream, reply);
2261 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2262 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2263 int ret;
2265 pa_native_connection_assert_ref(c);
2266 pa_assert(t);
2268 if (!pa_tagstruct_eof(t)) {
2269 protocol_error(c);
2270 return;
2273 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2274 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2275 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2277 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2280 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2281 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2282 const void*cookie;
2283 pa_tagstruct *reply;
2284 pa_bool_t shm_on_remote = FALSE, do_shm;
2286 pa_native_connection_assert_ref(c);
2287 pa_assert(t);
2289 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2290 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2291 !pa_tagstruct_eof(t)) {
2292 protocol_error(c);
2293 return;
2296 /* Minimum supported version */
2297 if (c->version < 8) {
2298 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2299 return;
2302 /* Starting with protocol version 13 the MSB of the version tag
2303 reflects if shm is available for this pa_native_connection or
2304 not. */
2305 if (c->version >= 13) {
2306 shm_on_remote = !!(c->version & 0x80000000U);
2307 c->version &= 0x7FFFFFFFU;
2310 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2312 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2314 if (!c->authorized) {
2315 pa_bool_t success = FALSE;
2317 #ifdef HAVE_CREDS
2318 const pa_creds *creds;
2320 if ((creds = pa_pdispatch_creds(pd))) {
2321 if (creds->uid == getuid())
2322 success = TRUE;
2323 else if (c->options->auth_group) {
2324 int r;
2325 gid_t gid;
2327 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2328 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2329 else if (gid == creds->gid)
2330 success = TRUE;
2332 if (!success) {
2333 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2334 pa_log_warn("Failed to check group membership.");
2335 else if (r > 0)
2336 success = TRUE;
2340 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2341 (unsigned long) creds->uid,
2342 (unsigned long) creds->gid,
2343 (int) success);
2345 #endif
2347 if (!success && c->options->auth_cookie) {
2348 const uint8_t *ac;
2350 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2351 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2352 success = TRUE;
2355 if (!success) {
2356 pa_log_warn("Denied access to client with invalid authorization data.");
2357 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2358 return;
2361 c->authorized = TRUE;
2362 if (c->auth_timeout_event) {
2363 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2364 c->auth_timeout_event = NULL;
2368 /* Enable shared memory support if possible */
2369 do_shm =
2370 pa_mempool_is_shared(c->protocol->core->mempool) &&
2371 c->is_local;
2373 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2375 if (do_shm)
2376 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2377 do_shm = FALSE;
2379 #ifdef HAVE_CREDS
2380 if (do_shm) {
2381 /* Only enable SHM if both sides are owned by the same
2382 * user. This is a security measure because otherwise data
2383 * private to the user might leak. */
2385 const pa_creds *creds;
2386 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2387 do_shm = FALSE;
2389 #endif
2391 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2392 pa_pstream_enable_shm(c->pstream, do_shm);
2394 reply = reply_new(tag);
2395 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2397 #ifdef HAVE_CREDS
2399 /* SHM support is only enabled after both sides made sure they are the same user. */
2401 pa_creds ucred;
2403 ucred.uid = getuid();
2404 ucred.gid = getgid();
2406 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2408 #else
2409 pa_pstream_send_tagstruct(c->pstream, reply);
2410 #endif
2413 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2414 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2415 const char *name = NULL;
2416 pa_proplist *p;
2417 pa_tagstruct *reply;
2419 pa_native_connection_assert_ref(c);
2420 pa_assert(t);
2422 p = pa_proplist_new();
2424 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2425 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2426 !pa_tagstruct_eof(t)) {
2428 protocol_error(c);
2429 pa_proplist_free(p);
2430 return;
2433 if (name)
2434 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2435 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2436 pa_proplist_free(p);
2437 return;
2440 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2441 pa_proplist_free(p);
2443 reply = reply_new(tag);
2445 if (c->version >= 13)
2446 pa_tagstruct_putu32(reply, c->client->index);
2448 pa_pstream_send_tagstruct(c->pstream, reply);
2451 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2452 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2453 const char *name;
2454 uint32_t idx = PA_IDXSET_INVALID;
2456 pa_native_connection_assert_ref(c);
2457 pa_assert(t);
2459 if (pa_tagstruct_gets(t, &name) < 0 ||
2460 !pa_tagstruct_eof(t)) {
2461 protocol_error(c);
2462 return;
2465 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2466 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);
2468 if (command == PA_COMMAND_LOOKUP_SINK) {
2469 pa_sink *sink;
2470 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2471 idx = sink->index;
2472 } else {
2473 pa_source *source;
2474 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2475 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2476 idx = source->index;
2479 if (idx == PA_IDXSET_INVALID)
2480 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2481 else {
2482 pa_tagstruct *reply;
2483 reply = reply_new(tag);
2484 pa_tagstruct_putu32(reply, idx);
2485 pa_pstream_send_tagstruct(c->pstream, reply);
2489 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2490 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2491 uint32_t idx;
2492 playback_stream *s;
2494 pa_native_connection_assert_ref(c);
2495 pa_assert(t);
2497 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2498 !pa_tagstruct_eof(t)) {
2499 protocol_error(c);
2500 return;
2503 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2504 s = pa_idxset_get_by_index(c->output_streams, idx);
2505 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2506 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2508 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);
2511 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2512 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2513 pa_tagstruct *reply;
2514 const pa_mempool_stat *stat;
2516 pa_native_connection_assert_ref(c);
2517 pa_assert(t);
2519 if (!pa_tagstruct_eof(t)) {
2520 protocol_error(c);
2521 return;
2524 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2526 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2528 reply = reply_new(tag);
2529 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2530 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2531 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2532 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2533 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2534 pa_pstream_send_tagstruct(c->pstream, reply);
2537 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2538 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2539 pa_tagstruct *reply;
2540 playback_stream *s;
2541 struct timeval tv, now;
2542 uint32_t idx;
2544 pa_native_connection_assert_ref(c);
2545 pa_assert(t);
2547 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2548 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2549 !pa_tagstruct_eof(t)) {
2550 protocol_error(c);
2551 return;
2554 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2555 s = pa_idxset_get_by_index(c->output_streams, idx);
2556 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2557 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2559 /* Get an atomic snapshot of all timing parameters */
2560 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);
2562 reply = reply_new(tag);
2563 pa_tagstruct_put_usec(reply,
2564 s->current_sink_latency +
2565 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2566 pa_tagstruct_put_usec(reply, 0);
2567 pa_tagstruct_put_boolean(reply,
2568 s->playing_for > 0 &&
2569 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2570 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2571 pa_tagstruct_put_timeval(reply, &tv);
2572 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2573 pa_tagstruct_puts64(reply, s->write_index);
2574 pa_tagstruct_puts64(reply, s->read_index);
2576 if (c->version >= 13) {
2577 pa_tagstruct_putu64(reply, s->underrun_for);
2578 pa_tagstruct_putu64(reply, s->playing_for);
2581 pa_pstream_send_tagstruct(c->pstream, reply);
2584 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2585 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2586 pa_tagstruct *reply;
2587 record_stream *s;
2588 struct timeval tv, now;
2589 uint32_t idx;
2591 pa_native_connection_assert_ref(c);
2592 pa_assert(t);
2594 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2595 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2596 !pa_tagstruct_eof(t)) {
2597 protocol_error(c);
2598 return;
2601 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2602 s = pa_idxset_get_by_index(c->record_streams, idx);
2603 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2605 /* Get an atomic snapshot of all timing parameters */
2606 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);
2608 reply = reply_new(tag);
2609 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2610 pa_tagstruct_put_usec(reply,
2611 s->current_source_latency +
2612 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->sample_spec));
2613 pa_tagstruct_put_boolean(reply,
2614 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2615 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2616 pa_tagstruct_put_timeval(reply, &tv);
2617 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2618 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2619 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2620 pa_pstream_send_tagstruct(c->pstream, reply);
2623 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2624 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2625 upload_stream *s;
2626 uint32_t length;
2627 const char *name = NULL;
2628 pa_sample_spec ss;
2629 pa_channel_map map;
2630 pa_tagstruct *reply;
2631 pa_proplist *p;
2633 pa_native_connection_assert_ref(c);
2634 pa_assert(t);
2636 if (pa_tagstruct_gets(t, &name) < 0 ||
2637 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2638 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2639 pa_tagstruct_getu32(t, &length) < 0) {
2640 protocol_error(c);
2641 return;
2644 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2645 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2646 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2647 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2648 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2649 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2651 p = pa_proplist_new();
2653 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2654 !pa_tagstruct_eof(t)) {
2656 protocol_error(c);
2657 pa_proplist_free(p);
2658 return;
2661 if (c->version < 13)
2662 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2663 else if (!name)
2664 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2665 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2667 if (!name || !pa_namereg_is_valid_name(name)) {
2668 pa_proplist_free(p);
2669 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2672 s = upload_stream_new(c, &ss, &map, name, length, p);
2673 pa_proplist_free(p);
2675 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2677 reply = reply_new(tag);
2678 pa_tagstruct_putu32(reply, s->index);
2679 pa_tagstruct_putu32(reply, length);
2680 pa_pstream_send_tagstruct(c->pstream, reply);
2683 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2684 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2685 uint32_t channel;
2686 upload_stream *s;
2687 uint32_t idx;
2689 pa_native_connection_assert_ref(c);
2690 pa_assert(t);
2692 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2693 !pa_tagstruct_eof(t)) {
2694 protocol_error(c);
2695 return;
2698 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2700 s = pa_idxset_get_by_index(c->output_streams, channel);
2701 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2702 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2704 if (!s->memchunk.memblock)
2705 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2706 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2707 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2708 else
2709 pa_pstream_send_simple_ack(c->pstream, tag);
2711 upload_stream_unlink(s);
2714 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2715 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2716 uint32_t sink_index;
2717 pa_volume_t volume;
2718 pa_sink *sink;
2719 const char *name, *sink_name;
2720 uint32_t idx;
2721 pa_proplist *p;
2722 pa_tagstruct *reply;
2724 pa_native_connection_assert_ref(c);
2725 pa_assert(t);
2727 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2729 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2730 pa_tagstruct_gets(t, &sink_name) < 0 ||
2731 pa_tagstruct_getu32(t, &volume) < 0 ||
2732 pa_tagstruct_gets(t, &name) < 0) {
2733 protocol_error(c);
2734 return;
2737 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2738 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2739 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2740 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2742 if (sink_index != PA_INVALID_INDEX)
2743 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2744 else
2745 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2747 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2749 p = pa_proplist_new();
2751 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2752 !pa_tagstruct_eof(t)) {
2753 protocol_error(c);
2754 pa_proplist_free(p);
2755 return;
2758 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2760 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2761 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2762 pa_proplist_free(p);
2763 return;
2766 pa_proplist_free(p);
2768 reply = reply_new(tag);
2770 if (c->version >= 13)
2771 pa_tagstruct_putu32(reply, idx);
2773 pa_pstream_send_tagstruct(c->pstream, reply);
2776 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2777 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2778 const char *name;
2780 pa_native_connection_assert_ref(c);
2781 pa_assert(t);
2783 if (pa_tagstruct_gets(t, &name) < 0 ||
2784 !pa_tagstruct_eof(t)) {
2785 protocol_error(c);
2786 return;
2789 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2790 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2792 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
2793 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2794 return;
2797 pa_pstream_send_simple_ack(c->pstream, tag);
2800 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
2801 pa_assert(c);
2802 pa_assert(fixed);
2803 pa_assert(original);
2805 *fixed = *original;
2807 if (c->version < 12) {
2808 /* Before protocol version 12 we didn't support S32 samples,
2809 * so we need to lie about this to the client */
2811 if (fixed->format == PA_SAMPLE_S32LE)
2812 fixed->format = PA_SAMPLE_FLOAT32LE;
2813 if (fixed->format == PA_SAMPLE_S32BE)
2814 fixed->format = PA_SAMPLE_FLOAT32BE;
2817 if (c->version < 15) {
2818 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
2819 fixed->format = PA_SAMPLE_FLOAT32LE;
2820 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
2821 fixed->format = PA_SAMPLE_FLOAT32BE;
2825 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
2826 pa_sample_spec fixed_ss;
2828 pa_assert(t);
2829 pa_sink_assert_ref(sink);
2831 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
2833 pa_tagstruct_put(
2835 PA_TAG_U32, sink->index,
2836 PA_TAG_STRING, sink->name,
2837 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2838 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2839 PA_TAG_CHANNEL_MAP, &sink->channel_map,
2840 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
2841 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
2842 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
2843 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
2844 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
2845 PA_TAG_USEC, pa_sink_get_latency(sink),
2846 PA_TAG_STRING, sink->driver,
2847 PA_TAG_U32, sink->flags,
2848 PA_TAG_INVALID);
2850 if (c->version >= 13) {
2851 pa_tagstruct_put_proplist(t, sink->proplist);
2852 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
2855 if (c->version >= 15) {
2856 pa_tagstruct_put_volume(t, sink->base_volume);
2857 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
2858 pa_log_error("Internal sink state is invalid.");
2859 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
2860 pa_tagstruct_putu32(t, sink->n_volume_steps);
2861 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
2864 if (c->version >= 16) {
2865 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
2867 if (sink->ports) {
2868 void *state;
2869 pa_device_port *p;
2871 PA_HASHMAP_FOREACH(p, sink->ports, state) {
2872 pa_tagstruct_puts(t, p->name);
2873 pa_tagstruct_puts(t, p->description);
2874 pa_tagstruct_putu32(t, p->priority);
2878 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
2882 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
2883 pa_sample_spec fixed_ss;
2885 pa_assert(t);
2886 pa_source_assert_ref(source);
2888 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
2890 pa_tagstruct_put(
2892 PA_TAG_U32, source->index,
2893 PA_TAG_STRING, source->name,
2894 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2895 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2896 PA_TAG_CHANNEL_MAP, &source->channel_map,
2897 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
2898 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
2899 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
2900 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
2901 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
2902 PA_TAG_USEC, pa_source_get_latency(source),
2903 PA_TAG_STRING, source->driver,
2904 PA_TAG_U32, source->flags,
2905 PA_TAG_INVALID);
2907 if (c->version >= 13) {
2908 pa_tagstruct_put_proplist(t, source->proplist);
2909 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
2912 if (c->version >= 15) {
2913 pa_tagstruct_put_volume(t, source->base_volume);
2914 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
2915 pa_log_error("Internal source state is invalid.");
2916 pa_tagstruct_putu32(t, pa_source_get_state(source));
2917 pa_tagstruct_putu32(t, source->n_volume_steps);
2918 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
2921 if (c->version >= 16) {
2923 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
2925 if (source->ports) {
2926 void *state;
2927 pa_device_port *p;
2929 PA_HASHMAP_FOREACH(p, source->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, source->active_port ? source->active_port->name : NULL);
2940 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
2941 pa_assert(t);
2942 pa_assert(client);
2944 pa_tagstruct_putu32(t, client->index);
2945 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
2946 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
2947 pa_tagstruct_puts(t, client->driver);
2949 if (c->version >= 13)
2950 pa_tagstruct_put_proplist(t, client->proplist);
2953 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
2954 void *state = NULL;
2955 pa_card_profile *p;
2957 pa_assert(t);
2958 pa_assert(card);
2960 pa_tagstruct_putu32(t, card->index);
2961 pa_tagstruct_puts(t, card->name);
2962 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
2963 pa_tagstruct_puts(t, card->driver);
2965 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
2967 if (card->profiles) {
2968 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
2969 pa_tagstruct_puts(t, p->name);
2970 pa_tagstruct_puts(t, p->description);
2971 pa_tagstruct_putu32(t, p->n_sinks);
2972 pa_tagstruct_putu32(t, p->n_sources);
2973 pa_tagstruct_putu32(t, p->priority);
2977 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
2978 pa_tagstruct_put_proplist(t, card->proplist);
2981 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
2982 pa_assert(t);
2983 pa_assert(module);
2985 pa_tagstruct_putu32(t, module->index);
2986 pa_tagstruct_puts(t, module->name);
2987 pa_tagstruct_puts(t, module->argument);
2988 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
2990 if (c->version < 15)
2991 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
2993 if (c->version >= 15)
2994 pa_tagstruct_put_proplist(t, module->proplist);
2997 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
2998 pa_sample_spec fixed_ss;
2999 pa_usec_t sink_latency;
3000 pa_cvolume v;
3002 pa_assert(t);
3003 pa_sink_input_assert_ref(s);
3005 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3007 pa_tagstruct_putu32(t, s->index);
3008 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3009 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3010 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3011 pa_tagstruct_putu32(t, s->sink->index);
3012 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3013 pa_tagstruct_put_channel_map(t, &s->channel_map);
3014 pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s, &v, TRUE));
3015 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3016 pa_tagstruct_put_usec(t, sink_latency);
3017 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3018 pa_tagstruct_puts(t, s->driver);
3019 if (c->version >= 11)
3020 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3021 if (c->version >= 13)
3022 pa_tagstruct_put_proplist(t, s->proplist);
3025 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3026 pa_sample_spec fixed_ss;
3027 pa_usec_t source_latency;
3029 pa_assert(t);
3030 pa_source_output_assert_ref(s);
3032 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3034 pa_tagstruct_putu32(t, s->index);
3035 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3036 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3037 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3038 pa_tagstruct_putu32(t, s->source->index);
3039 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3040 pa_tagstruct_put_channel_map(t, &s->channel_map);
3041 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3042 pa_tagstruct_put_usec(t, source_latency);
3043 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3044 pa_tagstruct_puts(t, s->driver);
3046 if (c->version >= 13)
3047 pa_tagstruct_put_proplist(t, s->proplist);
3050 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3051 pa_sample_spec fixed_ss;
3052 pa_cvolume v;
3054 pa_assert(t);
3055 pa_assert(e);
3057 if (e->memchunk.memblock)
3058 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3059 else
3060 memset(&fixed_ss, 0, sizeof(fixed_ss));
3062 pa_tagstruct_putu32(t, e->index);
3063 pa_tagstruct_puts(t, e->name);
3065 if (e->volume_is_set)
3066 v = e->volume;
3067 else
3068 pa_cvolume_init(&v);
3070 pa_tagstruct_put_cvolume(t, &v);
3071 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3072 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3073 pa_tagstruct_put_channel_map(t, &e->channel_map);
3074 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3075 pa_tagstruct_put_boolean(t, e->lazy);
3076 pa_tagstruct_puts(t, e->filename);
3078 if (c->version >= 13)
3079 pa_tagstruct_put_proplist(t, e->proplist);
3082 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3083 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3084 uint32_t idx;
3085 pa_sink *sink = NULL;
3086 pa_source *source = NULL;
3087 pa_client *client = NULL;
3088 pa_card *card = NULL;
3089 pa_module *module = NULL;
3090 pa_sink_input *si = NULL;
3091 pa_source_output *so = NULL;
3092 pa_scache_entry *sce = NULL;
3093 const char *name = NULL;
3094 pa_tagstruct *reply;
3096 pa_native_connection_assert_ref(c);
3097 pa_assert(t);
3099 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3100 (command != PA_COMMAND_GET_CLIENT_INFO &&
3101 command != PA_COMMAND_GET_MODULE_INFO &&
3102 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3103 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3104 pa_tagstruct_gets(t, &name) < 0) ||
3105 !pa_tagstruct_eof(t)) {
3106 protocol_error(c);
3107 return;
3110 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3111 CHECK_VALIDITY(c->pstream, !name ||
3112 (command == PA_COMMAND_GET_SINK_INFO &&
3113 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3114 (command == PA_COMMAND_GET_SOURCE_INFO &&
3115 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3116 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3117 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3118 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3119 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3121 if (command == PA_COMMAND_GET_SINK_INFO) {
3122 if (idx != PA_INVALID_INDEX)
3123 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3124 else
3125 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3126 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3127 if (idx != PA_INVALID_INDEX)
3128 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3129 else
3130 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3131 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3132 if (idx != PA_INVALID_INDEX)
3133 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3134 else
3135 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3136 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3137 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3138 else if (command == PA_COMMAND_GET_MODULE_INFO)
3139 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3140 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3141 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3142 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3143 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3144 else {
3145 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3146 if (idx != PA_INVALID_INDEX)
3147 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3148 else
3149 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3152 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3153 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3154 return;
3157 reply = reply_new(tag);
3158 if (sink)
3159 sink_fill_tagstruct(c, reply, sink);
3160 else if (source)
3161 source_fill_tagstruct(c, reply, source);
3162 else if (client)
3163 client_fill_tagstruct(c, reply, client);
3164 else if (card)
3165 card_fill_tagstruct(c, reply, card);
3166 else if (module)
3167 module_fill_tagstruct(c, reply, module);
3168 else if (si)
3169 sink_input_fill_tagstruct(c, reply, si);
3170 else if (so)
3171 source_output_fill_tagstruct(c, reply, so);
3172 else
3173 scache_fill_tagstruct(c, reply, sce);
3174 pa_pstream_send_tagstruct(c->pstream, reply);
3177 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3178 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3179 pa_idxset *i;
3180 uint32_t idx;
3181 void *p;
3182 pa_tagstruct *reply;
3184 pa_native_connection_assert_ref(c);
3185 pa_assert(t);
3187 if (!pa_tagstruct_eof(t)) {
3188 protocol_error(c);
3189 return;
3192 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3194 reply = reply_new(tag);
3196 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3197 i = c->protocol->core->sinks;
3198 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3199 i = c->protocol->core->sources;
3200 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3201 i = c->protocol->core->clients;
3202 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3203 i = c->protocol->core->cards;
3204 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3205 i = c->protocol->core->modules;
3206 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3207 i = c->protocol->core->sink_inputs;
3208 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3209 i = c->protocol->core->source_outputs;
3210 else {
3211 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3212 i = c->protocol->core->scache;
3215 if (i) {
3216 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3217 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3218 sink_fill_tagstruct(c, reply, p);
3219 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3220 source_fill_tagstruct(c, reply, p);
3221 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3222 client_fill_tagstruct(c, reply, p);
3223 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3224 card_fill_tagstruct(c, reply, p);
3225 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3226 module_fill_tagstruct(c, reply, p);
3227 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3228 sink_input_fill_tagstruct(c, reply, p);
3229 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3230 source_output_fill_tagstruct(c, reply, p);
3231 else {
3232 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3233 scache_fill_tagstruct(c, reply, p);
3238 pa_pstream_send_tagstruct(c->pstream, reply);
3241 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3242 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3243 pa_tagstruct *reply;
3244 pa_sink *def_sink;
3245 pa_source *def_source;
3246 pa_sample_spec fixed_ss;
3247 char *h, *u;
3249 pa_native_connection_assert_ref(c);
3250 pa_assert(t);
3252 if (!pa_tagstruct_eof(t)) {
3253 protocol_error(c);
3254 return;
3257 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3259 reply = reply_new(tag);
3260 pa_tagstruct_puts(reply, PACKAGE_NAME);
3261 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3263 u = pa_get_user_name_malloc();
3264 pa_tagstruct_puts(reply, u);
3265 pa_xfree(u);
3267 h = pa_get_host_name_malloc();
3268 pa_tagstruct_puts(reply, h);
3269 pa_xfree(h);
3271 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3272 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3274 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3275 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3276 def_source = pa_namereg_get_default_source(c->protocol->core);
3277 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3279 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3281 if (c->version >= 15)
3282 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3284 pa_pstream_send_tagstruct(c->pstream, reply);
3287 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3288 pa_tagstruct *t;
3289 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3291 pa_native_connection_assert_ref(c);
3293 t = pa_tagstruct_new(NULL, 0);
3294 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3295 pa_tagstruct_putu32(t, (uint32_t) -1);
3296 pa_tagstruct_putu32(t, e);
3297 pa_tagstruct_putu32(t, idx);
3298 pa_pstream_send_tagstruct(c->pstream, t);
3301 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3302 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3303 pa_subscription_mask_t m;
3305 pa_native_connection_assert_ref(c);
3306 pa_assert(t);
3308 if (pa_tagstruct_getu32(t, &m) < 0 ||
3309 !pa_tagstruct_eof(t)) {
3310 protocol_error(c);
3311 return;
3314 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3315 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3317 if (c->subscription)
3318 pa_subscription_free(c->subscription);
3320 if (m != 0) {
3321 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3322 pa_assert(c->subscription);
3323 } else
3324 c->subscription = NULL;
3326 pa_pstream_send_simple_ack(c->pstream, tag);
3329 static void command_set_volume(
3330 pa_pdispatch *pd,
3331 uint32_t command,
3332 uint32_t tag,
3333 pa_tagstruct *t,
3334 void *userdata) {
3336 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3337 uint32_t idx;
3338 pa_cvolume volume;
3339 pa_sink *sink = NULL;
3340 pa_source *source = NULL;
3341 pa_sink_input *si = NULL;
3342 const char *name = NULL;
3343 const char *client_name;
3345 pa_native_connection_assert_ref(c);
3346 pa_assert(t);
3348 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3349 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3350 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3351 pa_tagstruct_get_cvolume(t, &volume) ||
3352 !pa_tagstruct_eof(t)) {
3353 protocol_error(c);
3354 return;
3357 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3358 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);
3359 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3360 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3361 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3362 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3364 switch (command) {
3366 case PA_COMMAND_SET_SINK_VOLUME:
3367 if (idx != PA_INVALID_INDEX)
3368 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3369 else
3370 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3371 break;
3373 case PA_COMMAND_SET_SOURCE_VOLUME:
3374 if (idx != PA_INVALID_INDEX)
3375 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3376 else
3377 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3378 break;
3380 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3381 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3382 break;
3384 default:
3385 pa_assert_not_reached();
3388 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3390 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3392 if (sink) {
3393 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3395 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3396 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3397 } else if (source) {
3398 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3400 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3401 pa_source_set_volume(source, &volume, TRUE);
3402 } else if (si) {
3403 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3405 pa_log_debug("Client %s changes volume of sink input %s.",
3406 client_name,
3407 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3408 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3411 pa_pstream_send_simple_ack(c->pstream, tag);
3414 static void command_set_mute(
3415 pa_pdispatch *pd,
3416 uint32_t command,
3417 uint32_t tag,
3418 pa_tagstruct *t,
3419 void *userdata) {
3421 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3422 uint32_t idx;
3423 pa_bool_t mute;
3424 pa_sink *sink = NULL;
3425 pa_source *source = NULL;
3426 pa_sink_input *si = NULL;
3427 const char *name = NULL, *client_name;
3429 pa_native_connection_assert_ref(c);
3430 pa_assert(t);
3432 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3433 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3434 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3435 pa_tagstruct_get_boolean(t, &mute) ||
3436 !pa_tagstruct_eof(t)) {
3437 protocol_error(c);
3438 return;
3441 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3442 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);
3443 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3444 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3445 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3447 switch (command) {
3449 case PA_COMMAND_SET_SINK_MUTE:
3450 if (idx != PA_INVALID_INDEX)
3451 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3452 else
3453 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3455 break;
3457 case PA_COMMAND_SET_SOURCE_MUTE:
3458 if (idx != PA_INVALID_INDEX)
3459 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3460 else
3461 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3463 break;
3465 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3466 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3467 break;
3469 default:
3470 pa_assert_not_reached();
3473 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3475 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3477 if (sink) {
3478 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3479 pa_sink_set_mute(sink, mute, TRUE);
3480 } else if (source) {
3481 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3482 pa_source_set_mute(source, mute, TRUE);
3483 } else if (si) {
3484 pa_log_debug("Client %s changes mute of sink input %s.",
3485 client_name,
3486 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3487 pa_sink_input_set_mute(si, mute, TRUE);
3490 pa_pstream_send_simple_ack(c->pstream, tag);
3493 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3494 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3495 uint32_t idx;
3496 pa_bool_t b;
3497 playback_stream *s;
3499 pa_native_connection_assert_ref(c);
3500 pa_assert(t);
3502 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3503 pa_tagstruct_get_boolean(t, &b) < 0 ||
3504 !pa_tagstruct_eof(t)) {
3505 protocol_error(c);
3506 return;
3509 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3510 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3511 s = pa_idxset_get_by_index(c->output_streams, idx);
3512 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3513 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3515 pa_sink_input_cork(s->sink_input, b);
3517 if (b)
3518 s->is_underrun = TRUE;
3520 pa_pstream_send_simple_ack(c->pstream, tag);
3523 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3524 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3525 uint32_t idx;
3526 playback_stream *s;
3528 pa_native_connection_assert_ref(c);
3529 pa_assert(t);
3531 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3532 !pa_tagstruct_eof(t)) {
3533 protocol_error(c);
3534 return;
3537 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3538 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3539 s = pa_idxset_get_by_index(c->output_streams, idx);
3540 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3541 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3543 switch (command) {
3544 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3545 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3546 break;
3548 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3549 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3550 break;
3552 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3553 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3554 break;
3556 default:
3557 pa_assert_not_reached();
3560 pa_pstream_send_simple_ack(c->pstream, tag);
3563 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3564 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3565 uint32_t idx;
3566 record_stream *s;
3567 pa_bool_t b;
3569 pa_native_connection_assert_ref(c);
3570 pa_assert(t);
3572 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3573 pa_tagstruct_get_boolean(t, &b) < 0 ||
3574 !pa_tagstruct_eof(t)) {
3575 protocol_error(c);
3576 return;
3579 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3580 s = pa_idxset_get_by_index(c->record_streams, idx);
3581 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3583 pa_source_output_cork(s->source_output, b);
3584 pa_memblockq_prebuf_force(s->memblockq);
3585 pa_pstream_send_simple_ack(c->pstream, tag);
3588 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3589 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3590 uint32_t idx;
3591 record_stream *s;
3593 pa_native_connection_assert_ref(c);
3594 pa_assert(t);
3596 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3597 !pa_tagstruct_eof(t)) {
3598 protocol_error(c);
3599 return;
3602 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3603 s = pa_idxset_get_by_index(c->record_streams, idx);
3604 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3606 pa_memblockq_flush_read(s->memblockq);
3607 pa_pstream_send_simple_ack(c->pstream, tag);
3610 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3611 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3612 uint32_t idx;
3613 pa_buffer_attr a;
3614 pa_tagstruct *reply;
3616 pa_native_connection_assert_ref(c);
3617 pa_assert(t);
3619 memset(&a, 0, sizeof(a));
3621 if (pa_tagstruct_getu32(t, &idx) < 0) {
3622 protocol_error(c);
3623 return;
3626 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3628 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3629 playback_stream *s;
3630 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3632 s = pa_idxset_get_by_index(c->output_streams, idx);
3633 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3634 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3636 if (pa_tagstruct_get(
3638 PA_TAG_U32, &a.maxlength,
3639 PA_TAG_U32, &a.tlength,
3640 PA_TAG_U32, &a.prebuf,
3641 PA_TAG_U32, &a.minreq,
3642 PA_TAG_INVALID) < 0 ||
3643 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3644 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3645 !pa_tagstruct_eof(t)) {
3646 protocol_error(c);
3647 return;
3650 s->adjust_latency = adjust_latency;
3651 s->early_requests = early_requests;
3652 s->buffer_attr = a;
3654 fix_playback_buffer_attr(s);
3655 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);
3657 reply = reply_new(tag);
3658 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3659 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3660 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3661 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3663 if (c->version >= 13)
3664 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3666 } else {
3667 record_stream *s;
3668 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3669 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3671 s = pa_idxset_get_by_index(c->record_streams, idx);
3672 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3674 if (pa_tagstruct_get(
3676 PA_TAG_U32, &a.maxlength,
3677 PA_TAG_U32, &a.fragsize,
3678 PA_TAG_INVALID) < 0 ||
3679 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3680 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3681 !pa_tagstruct_eof(t)) {
3682 protocol_error(c);
3683 return;
3686 s->adjust_latency = adjust_latency;
3687 s->early_requests = early_requests;
3688 s->buffer_attr = a;
3690 fix_record_buffer_attr_pre(s);
3691 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3692 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3693 fix_record_buffer_attr_post(s);
3695 reply = reply_new(tag);
3696 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3697 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3699 if (c->version >= 13)
3700 pa_tagstruct_put_usec(reply, s->configured_source_latency);
3703 pa_pstream_send_tagstruct(c->pstream, reply);
3706 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3707 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3708 uint32_t idx;
3709 uint32_t rate;
3711 pa_native_connection_assert_ref(c);
3712 pa_assert(t);
3714 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3715 pa_tagstruct_getu32(t, &rate) < 0 ||
3716 !pa_tagstruct_eof(t)) {
3717 protocol_error(c);
3718 return;
3721 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3722 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
3724 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
3725 playback_stream *s;
3727 s = pa_idxset_get_by_index(c->output_streams, idx);
3728 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3729 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3731 pa_sink_input_set_rate(s->sink_input, rate);
3733 } else {
3734 record_stream *s;
3735 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
3737 s = pa_idxset_get_by_index(c->record_streams, idx);
3738 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3740 pa_source_output_set_rate(s->source_output, rate);
3743 pa_pstream_send_simple_ack(c->pstream, tag);
3746 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3747 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3748 uint32_t idx;
3749 uint32_t mode;
3750 pa_proplist *p;
3752 pa_native_connection_assert_ref(c);
3753 pa_assert(t);
3755 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3757 p = pa_proplist_new();
3759 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
3761 if (pa_tagstruct_getu32(t, &mode) < 0 ||
3762 pa_tagstruct_get_proplist(t, p) < 0 ||
3763 !pa_tagstruct_eof(t)) {
3764 protocol_error(c);
3765 pa_proplist_free(p);
3766 return;
3769 } else {
3771 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3772 pa_tagstruct_getu32(t, &mode) < 0 ||
3773 pa_tagstruct_get_proplist(t, p) < 0 ||
3774 !pa_tagstruct_eof(t)) {
3775 protocol_error(c);
3776 pa_proplist_free(p);
3777 return;
3781 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
3782 pa_proplist_free(p);
3783 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
3786 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
3787 playback_stream *s;
3789 s = pa_idxset_get_by_index(c->output_streams, idx);
3790 if (!s || !playback_stream_isinstance(s)) {
3791 pa_proplist_free(p);
3792 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3794 pa_sink_input_update_proplist(s->sink_input, mode, p);
3796 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
3797 record_stream *s;
3799 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
3800 pa_proplist_free(p);
3801 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3803 pa_source_output_update_proplist(s->source_output, mode, p);
3805 } else {
3806 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
3808 pa_client_update_proplist(c->client, mode, p);
3811 pa_pstream_send_simple_ack(c->pstream, tag);
3812 pa_proplist_free(p);
3815 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3816 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3817 uint32_t idx;
3818 unsigned changed = 0;
3819 pa_proplist *p;
3820 pa_strlist *l = NULL;
3822 pa_native_connection_assert_ref(c);
3823 pa_assert(t);
3825 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3827 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
3829 if (pa_tagstruct_getu32(t, &idx) < 0) {
3830 protocol_error(c);
3831 return;
3835 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3836 playback_stream *s;
3838 s = pa_idxset_get_by_index(c->output_streams, idx);
3839 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3840 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3842 p = s->sink_input->proplist;
3844 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3845 record_stream *s;
3847 s = pa_idxset_get_by_index(c->record_streams, idx);
3848 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3850 p = s->source_output->proplist;
3851 } else {
3852 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3854 p = c->client->proplist;
3857 for (;;) {
3858 const char *k;
3860 if (pa_tagstruct_gets(t, &k) < 0) {
3861 protocol_error(c);
3862 pa_strlist_free(l);
3863 return;
3866 if (!k)
3867 break;
3869 l = pa_strlist_prepend(l, k);
3872 if (!pa_tagstruct_eof(t)) {
3873 protocol_error(c);
3874 pa_strlist_free(l);
3875 return;
3878 for (;;) {
3879 char *z;
3881 l = pa_strlist_pop(l, &z);
3883 if (!z)
3884 break;
3886 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
3887 pa_xfree(z);
3890 pa_pstream_send_simple_ack(c->pstream, tag);
3892 if (changed) {
3893 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3894 playback_stream *s;
3896 s = pa_idxset_get_by_index(c->output_streams, idx);
3897 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
3899 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3900 record_stream *s;
3902 s = pa_idxset_get_by_index(c->record_streams, idx);
3903 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
3905 } else {
3906 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3907 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
3912 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3913 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3914 const char *s;
3916 pa_native_connection_assert_ref(c);
3917 pa_assert(t);
3919 if (pa_tagstruct_gets(t, &s) < 0 ||
3920 !pa_tagstruct_eof(t)) {
3921 protocol_error(c);
3922 return;
3925 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3926 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
3928 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
3929 pa_source *source;
3931 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
3932 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
3934 pa_namereg_set_default_source(c->protocol->core, source);
3935 } else {
3936 pa_sink *sink;
3937 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
3939 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
3940 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3942 pa_namereg_set_default_sink(c->protocol->core, sink);
3945 pa_pstream_send_simple_ack(c->pstream, tag);
3948 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3949 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3950 uint32_t idx;
3951 const char *name;
3953 pa_native_connection_assert_ref(c);
3954 pa_assert(t);
3956 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3957 pa_tagstruct_gets(t, &name) < 0 ||
3958 !pa_tagstruct_eof(t)) {
3959 protocol_error(c);
3960 return;
3963 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3964 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
3966 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
3967 playback_stream *s;
3969 s = pa_idxset_get_by_index(c->output_streams, idx);
3970 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3971 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3973 pa_sink_input_set_name(s->sink_input, name);
3975 } else {
3976 record_stream *s;
3977 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
3979 s = pa_idxset_get_by_index(c->record_streams, idx);
3980 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3982 pa_source_output_set_name(s->source_output, name);
3985 pa_pstream_send_simple_ack(c->pstream, tag);
3988 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3989 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3990 uint32_t idx;
3992 pa_native_connection_assert_ref(c);
3993 pa_assert(t);
3995 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3996 !pa_tagstruct_eof(t)) {
3997 protocol_error(c);
3998 return;
4001 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4003 if (command == PA_COMMAND_KILL_CLIENT) {
4004 pa_client *client;
4006 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4007 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4009 pa_native_connection_ref(c);
4010 pa_client_kill(client);
4012 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4013 pa_sink_input *s;
4015 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4016 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4018 pa_native_connection_ref(c);
4019 pa_sink_input_kill(s);
4020 } else {
4021 pa_source_output *s;
4023 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4025 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4026 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4028 pa_native_connection_ref(c);
4029 pa_source_output_kill(s);
4032 pa_pstream_send_simple_ack(c->pstream, tag);
4033 pa_native_connection_unref(c);
4036 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4037 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4038 pa_module *m;
4039 const char *name, *argument;
4040 pa_tagstruct *reply;
4042 pa_native_connection_assert_ref(c);
4043 pa_assert(t);
4045 if (pa_tagstruct_gets(t, &name) < 0 ||
4046 pa_tagstruct_gets(t, &argument) < 0 ||
4047 !pa_tagstruct_eof(t)) {
4048 protocol_error(c);
4049 return;
4052 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4053 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4054 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4056 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4057 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4058 return;
4061 reply = reply_new(tag);
4062 pa_tagstruct_putu32(reply, m->index);
4063 pa_pstream_send_tagstruct(c->pstream, reply);
4066 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4067 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4068 uint32_t idx;
4069 pa_module *m;
4071 pa_native_connection_assert_ref(c);
4072 pa_assert(t);
4074 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4075 !pa_tagstruct_eof(t)) {
4076 protocol_error(c);
4077 return;
4080 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4081 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4082 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4084 pa_module_unload_request(m, FALSE);
4085 pa_pstream_send_simple_ack(c->pstream, tag);
4088 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4089 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4090 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4091 const char *name_device = NULL;
4093 pa_native_connection_assert_ref(c);
4094 pa_assert(t);
4096 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4097 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4098 pa_tagstruct_gets(t, &name_device) < 0 ||
4099 !pa_tagstruct_eof(t)) {
4100 protocol_error(c);
4101 return;
4104 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4105 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4107 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);
4108 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4109 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4110 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4112 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4113 pa_sink_input *si = NULL;
4114 pa_sink *sink = NULL;
4116 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4118 if (idx_device != PA_INVALID_INDEX)
4119 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4120 else
4121 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4123 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4125 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4126 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4127 return;
4129 } else {
4130 pa_source_output *so = NULL;
4131 pa_source *source;
4133 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4135 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4137 if (idx_device != PA_INVALID_INDEX)
4138 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4139 else
4140 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4142 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4144 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4145 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4146 return;
4150 pa_pstream_send_simple_ack(c->pstream, tag);
4153 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4154 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4155 uint32_t idx = PA_INVALID_INDEX;
4156 const char *name = NULL;
4157 pa_bool_t b;
4159 pa_native_connection_assert_ref(c);
4160 pa_assert(t);
4162 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4163 pa_tagstruct_gets(t, &name) < 0 ||
4164 pa_tagstruct_get_boolean(t, &b) < 0 ||
4165 !pa_tagstruct_eof(t)) {
4166 protocol_error(c);
4167 return;
4170 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4171 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);
4172 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4173 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4174 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4176 if (command == PA_COMMAND_SUSPEND_SINK) {
4178 if (idx == PA_INVALID_INDEX && name && !*name) {
4180 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4182 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4183 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4184 return;
4186 } else {
4187 pa_sink *sink = NULL;
4189 if (idx != PA_INVALID_INDEX)
4190 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4191 else
4192 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4194 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4196 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4197 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4198 return;
4201 } else {
4203 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4205 if (idx == PA_INVALID_INDEX && name && !*name) {
4207 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4209 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4210 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4211 return;
4214 } else {
4215 pa_source *source;
4217 if (idx != PA_INVALID_INDEX)
4218 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4219 else
4220 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4222 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4224 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4225 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4226 return;
4231 pa_pstream_send_simple_ack(c->pstream, tag);
4234 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4235 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4236 uint32_t idx = PA_INVALID_INDEX;
4237 const char *name = NULL;
4238 pa_module *m;
4239 pa_native_protocol_ext_cb_t cb;
4241 pa_native_connection_assert_ref(c);
4242 pa_assert(t);
4244 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4245 pa_tagstruct_gets(t, &name) < 0) {
4246 protocol_error(c);
4247 return;
4250 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4251 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4252 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4253 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4254 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4256 if (idx != PA_INVALID_INDEX)
4257 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4258 else {
4259 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4260 if (strcmp(name, m->name) == 0)
4261 break;
4264 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4265 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4267 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4268 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4270 if (cb(c->protocol, m, c, tag, t) < 0)
4271 protocol_error(c);
4274 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4275 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4276 uint32_t idx = PA_INVALID_INDEX;
4277 const char *name = NULL, *profile = NULL;
4278 pa_card *card = NULL;
4279 int ret;
4281 pa_native_connection_assert_ref(c);
4282 pa_assert(t);
4284 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4285 pa_tagstruct_gets(t, &name) < 0 ||
4286 pa_tagstruct_gets(t, &profile) < 0 ||
4287 !pa_tagstruct_eof(t)) {
4288 protocol_error(c);
4289 return;
4292 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4293 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4294 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4295 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4296 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4298 if (idx != PA_INVALID_INDEX)
4299 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4300 else
4301 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4303 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4305 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4306 pa_pstream_send_error(c->pstream, tag, -ret);
4307 return;
4310 pa_pstream_send_simple_ack(c->pstream, tag);
4313 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4314 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4315 uint32_t idx = PA_INVALID_INDEX;
4316 const char *name = NULL, *port = NULL;
4317 int ret;
4319 pa_native_connection_assert_ref(c);
4320 pa_assert(t);
4322 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4323 pa_tagstruct_gets(t, &name) < 0 ||
4324 pa_tagstruct_gets(t, &port) < 0 ||
4325 !pa_tagstruct_eof(t)) {
4326 protocol_error(c);
4327 return;
4330 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4331 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);
4332 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4333 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4334 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4336 if (command == PA_COMMAND_SET_SINK_PORT) {
4337 pa_sink *sink;
4339 if (idx != PA_INVALID_INDEX)
4340 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4341 else
4342 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4344 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4346 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4347 pa_pstream_send_error(c->pstream, tag, -ret);
4348 return;
4350 } else {
4351 pa_source *source;
4353 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4355 if (idx != PA_INVALID_INDEX)
4356 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4357 else
4358 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4360 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4362 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4363 pa_pstream_send_error(c->pstream, tag, -ret);
4364 return;
4368 pa_pstream_send_simple_ack(c->pstream, tag);
4371 /*** pstream callbacks ***/
4373 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4374 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4376 pa_assert(p);
4377 pa_assert(packet);
4378 pa_native_connection_assert_ref(c);
4380 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4381 pa_log("invalid packet.");
4382 native_connection_unlink(c);
4386 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) {
4387 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4388 output_stream *stream;
4390 pa_assert(p);
4391 pa_assert(chunk);
4392 pa_native_connection_assert_ref(c);
4394 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4395 pa_log_debug("Client sent block for invalid stream.");
4396 /* Ignoring */
4397 return;
4400 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4402 if (playback_stream_isinstance(stream)) {
4403 playback_stream *ps = PLAYBACK_STREAM(stream);
4405 if (chunk->memblock) {
4406 if (seek != PA_SEEK_RELATIVE || offset != 0)
4407 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, NULL, NULL);
4409 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4410 } else
4411 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);
4413 } else {
4414 upload_stream *u = UPLOAD_STREAM(stream);
4415 size_t l;
4417 if (!u->memchunk.memblock) {
4418 if (u->length == chunk->length && chunk->memblock) {
4419 u->memchunk = *chunk;
4420 pa_memblock_ref(u->memchunk.memblock);
4421 u->length = 0;
4422 } else {
4423 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4424 u->memchunk.index = u->memchunk.length = 0;
4428 pa_assert(u->memchunk.memblock);
4430 l = u->length;
4431 if (l > chunk->length)
4432 l = chunk->length;
4434 if (l > 0) {
4435 void *dst;
4436 dst = pa_memblock_acquire(u->memchunk.memblock);
4438 if (chunk->memblock) {
4439 void *src;
4440 src = pa_memblock_acquire(chunk->memblock);
4442 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4443 (uint8_t*) src + chunk->index, l);
4445 pa_memblock_release(chunk->memblock);
4446 } else
4447 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4449 pa_memblock_release(u->memchunk.memblock);
4451 u->memchunk.length += l;
4452 u->length -= l;
4457 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4458 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4460 pa_assert(p);
4461 pa_native_connection_assert_ref(c);
4463 native_connection_unlink(c);
4464 pa_log_info("Connection died.");
4467 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4468 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4470 pa_assert(p);
4471 pa_native_connection_assert_ref(c);
4473 native_connection_send_memblock(c);
4476 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4477 pa_thread_mq *q;
4479 if (!(q = pa_thread_mq_get()))
4480 pa_pstream_send_revoke(p, block_id);
4481 else
4482 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4485 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4486 pa_thread_mq *q;
4488 if (!(q = pa_thread_mq_get()))
4489 pa_pstream_send_release(p, block_id);
4490 else
4491 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4494 /*** client callbacks ***/
4496 static void client_kill_cb(pa_client *c) {
4497 pa_assert(c);
4499 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4500 pa_log_info("Connection killed.");
4503 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4504 pa_tagstruct *t;
4505 pa_native_connection *c;
4507 pa_assert(client);
4508 c = PA_NATIVE_CONNECTION(client->userdata);
4509 pa_native_connection_assert_ref(c);
4511 if (c->version < 15)
4512 return;
4514 t = pa_tagstruct_new(NULL, 0);
4515 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4516 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4517 pa_tagstruct_puts(t, event);
4518 pa_tagstruct_put_proplist(t, pl);
4519 pa_pstream_send_tagstruct(c->pstream, t);
4522 /*** module entry points ***/
4524 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4525 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4527 pa_assert(m);
4528 pa_native_connection_assert_ref(c);
4529 pa_assert(c->auth_timeout_event == e);
4531 if (!c->authorized) {
4532 native_connection_unlink(c);
4533 pa_log_info("Connection terminated due to authentication timeout.");
4537 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4538 pa_native_connection *c;
4539 char pname[128];
4540 pa_client *client;
4541 pa_client_new_data data;
4543 pa_assert(p);
4544 pa_assert(io);
4545 pa_assert(o);
4547 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4548 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4549 pa_iochannel_free(io);
4550 return;
4553 pa_client_new_data_init(&data);
4554 data.module = o->module;
4555 data.driver = __FILE__;
4556 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4557 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4558 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4559 client = pa_client_new(p->core, &data);
4560 pa_client_new_data_done(&data);
4562 if (!client)
4563 return;
4565 c = pa_msgobject_new(pa_native_connection);
4566 c->parent.parent.free = native_connection_free;
4567 c->parent.process_msg = native_connection_process_msg;
4568 c->protocol = p;
4569 c->options = pa_native_options_ref(o);
4570 c->authorized = FALSE;
4572 if (o->auth_anonymous) {
4573 pa_log_info("Client authenticated anonymously.");
4574 c->authorized = TRUE;
4577 if (!c->authorized &&
4578 o->auth_ip_acl &&
4579 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4581 pa_log_info("Client authenticated by IP ACL.");
4582 c->authorized = TRUE;
4585 if (!c->authorized)
4586 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4587 else
4588 c->auth_timeout_event = NULL;
4590 c->is_local = pa_iochannel_socket_is_local(io);
4591 c->version = 8;
4593 c->client = client;
4594 c->client->kill = client_kill_cb;
4595 c->client->send_event = client_send_event_cb;
4596 c->client->userdata = c;
4598 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4599 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4600 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4601 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4602 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4603 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4604 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4606 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4608 c->record_streams = pa_idxset_new(NULL, NULL);
4609 c->output_streams = pa_idxset_new(NULL, NULL);
4611 c->rrobin_index = PA_IDXSET_INVALID;
4612 c->subscription = NULL;
4614 pa_idxset_put(p->connections, c, NULL);
4616 #ifdef HAVE_CREDS
4617 if (pa_iochannel_creds_supported(io))
4618 pa_iochannel_creds_enable(io);
4619 #endif
4621 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4624 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4625 pa_native_connection *c;
4626 void *state = NULL;
4628 pa_assert(p);
4629 pa_assert(m);
4631 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4632 if (c->options->module == m)
4633 native_connection_unlink(c);
4636 static pa_native_protocol* native_protocol_new(pa_core *c) {
4637 pa_native_protocol *p;
4638 pa_native_hook_t h;
4640 pa_assert(c);
4642 p = pa_xnew(pa_native_protocol, 1);
4643 PA_REFCNT_INIT(p);
4644 p->core = c;
4645 p->connections = pa_idxset_new(NULL, NULL);
4647 p->servers = NULL;
4649 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4651 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4652 pa_hook_init(&p->hooks[h], p);
4654 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4656 return p;
4659 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4660 pa_native_protocol *p;
4662 if ((p = pa_shared_get(c, "native-protocol")))
4663 return pa_native_protocol_ref(p);
4665 return native_protocol_new(c);
4668 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4669 pa_assert(p);
4670 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4672 PA_REFCNT_INC(p);
4674 return p;
4677 void pa_native_protocol_unref(pa_native_protocol *p) {
4678 pa_native_connection *c;
4679 pa_native_hook_t h;
4681 pa_assert(p);
4682 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4684 if (PA_REFCNT_DEC(p) > 0)
4685 return;
4687 while ((c = pa_idxset_first(p->connections, NULL)))
4688 native_connection_unlink(c);
4690 pa_idxset_free(p->connections, NULL, NULL);
4692 pa_strlist_free(p->servers);
4694 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4695 pa_hook_done(&p->hooks[h]);
4697 pa_hashmap_free(p->extensions, NULL, NULL);
4699 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4701 pa_xfree(p);
4704 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
4705 pa_assert(p);
4706 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4707 pa_assert(name);
4709 p->servers = pa_strlist_prepend(p->servers, name);
4711 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4714 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
4715 pa_assert(p);
4716 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4717 pa_assert(name);
4719 p->servers = pa_strlist_remove(p->servers, name);
4721 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4724 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
4725 pa_assert(p);
4726 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4728 return p->hooks;
4731 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
4732 pa_assert(p);
4733 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4735 return p->servers;
4738 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
4739 pa_assert(p);
4740 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4741 pa_assert(m);
4742 pa_assert(cb);
4743 pa_assert(!pa_hashmap_get(p->extensions, m));
4745 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
4746 return 0;
4749 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
4750 pa_assert(p);
4751 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4752 pa_assert(m);
4754 pa_assert_se(pa_hashmap_remove(p->extensions, m));
4757 pa_native_options* pa_native_options_new(void) {
4758 pa_native_options *o;
4760 o = pa_xnew0(pa_native_options, 1);
4761 PA_REFCNT_INIT(o);
4763 return o;
4766 pa_native_options* pa_native_options_ref(pa_native_options *o) {
4767 pa_assert(o);
4768 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4770 PA_REFCNT_INC(o);
4772 return o;
4775 void pa_native_options_unref(pa_native_options *o) {
4776 pa_assert(o);
4777 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4779 if (PA_REFCNT_DEC(o) > 0)
4780 return;
4782 pa_xfree(o->auth_group);
4784 if (o->auth_ip_acl)
4785 pa_ip_acl_free(o->auth_ip_acl);
4787 if (o->auth_cookie)
4788 pa_auth_cookie_unref(o->auth_cookie);
4790 pa_xfree(o);
4793 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
4794 pa_bool_t enabled;
4795 const char *acl;
4797 pa_assert(o);
4798 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4799 pa_assert(ma);
4801 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
4802 pa_log("auth-anonymous= expects a boolean argument.");
4803 return -1;
4806 enabled = TRUE;
4807 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
4808 pa_log("auth-group-enabled= expects a boolean argument.");
4809 return -1;
4812 pa_xfree(o->auth_group);
4813 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
4815 #ifndef HAVE_CREDS
4816 if (o->auth_group)
4817 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4818 #endif
4820 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
4821 pa_ip_acl *ipa;
4823 if (!(ipa = pa_ip_acl_new(acl))) {
4824 pa_log("Failed to parse IP ACL '%s'", acl);
4825 return -1;
4828 if (o->auth_ip_acl)
4829 pa_ip_acl_free(o->auth_ip_acl);
4831 o->auth_ip_acl = ipa;
4834 enabled = TRUE;
4835 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
4836 pa_log("auth-cookie-enabled= expects a boolean argument.");
4837 return -1;
4840 if (o->auth_cookie)
4841 pa_auth_cookie_unref(o->auth_cookie);
4843 if (enabled) {
4844 const char *cn;
4846 /* The new name for this is 'auth-cookie', for compat reasons
4847 * we check the old name too */
4848 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
4849 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
4850 cn = PA_NATIVE_COOKIE_FILE;
4852 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
4853 return -1;
4855 } else
4856 o->auth_cookie = NULL;
4858 return 0;
4861 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
4862 pa_native_connection_assert_ref(c);
4864 return c->pstream;
4867 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
4868 pa_native_connection_assert_ref(c);
4870 return c->client;