def: Hide server-side sink/source flags
[pulseaudio-raopUDP/pulseaudio-raop-alac.git] / src / pulsecore / protocol-native.c
blobe8714784afc2b39acaeefe647b19119ff727d31f
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>
38 #include <pulse/internal.h>
40 #include <pulsecore/native-common.h>
41 #include <pulsecore/packet.h>
42 #include <pulsecore/client.h>
43 #include <pulsecore/source-output.h>
44 #include <pulsecore/sink-input.h>
45 #include <pulsecore/pstream.h>
46 #include <pulsecore/tagstruct.h>
47 #include <pulsecore/pdispatch.h>
48 #include <pulsecore/pstream-util.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/core-scache.h>
51 #include <pulsecore/core-subscribe.h>
52 #include <pulsecore/log.h>
53 #include <pulsecore/strlist.h>
54 #include <pulsecore/shared.h>
55 #include <pulsecore/sample-util.h>
56 #include <pulsecore/creds.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/ipacl.h>
59 #include <pulsecore/thread-mq.h>
61 #include "protocol-native.h"
63 /* Kick a client if it doesn't authenticate within this time */
64 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
66 /* Don't accept more connection than this */
67 #define MAX_CONNECTIONS 64
69 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
70 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
71 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
72 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
74 struct pa_native_protocol;
76 typedef struct record_stream {
77 pa_msgobject parent;
79 pa_native_connection *connection;
80 uint32_t index;
82 pa_source_output *source_output;
83 pa_memblockq *memblockq;
85 pa_bool_t adjust_latency:1;
86 pa_bool_t early_requests:1;
88 /* Requested buffer attributes */
89 pa_buffer_attr buffer_attr_req;
90 /* Fixed-up and adjusted buffer attributes */
91 pa_buffer_attr buffer_attr;
93 pa_atomic_t on_the_fly;
94 pa_usec_t configured_source_latency;
95 size_t drop_initial;
97 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
98 size_t on_the_fly_snapshot;
99 pa_usec_t current_monitor_latency;
100 pa_usec_t current_source_latency;
101 } record_stream;
103 #define RECORD_STREAM(o) (record_stream_cast(o))
104 PA_DEFINE_PRIVATE_CLASS(record_stream, pa_msgobject);
106 typedef struct output_stream {
107 pa_msgobject parent;
108 } output_stream;
110 #define OUTPUT_STREAM(o) (output_stream_cast(o))
111 PA_DEFINE_PRIVATE_CLASS(output_stream, pa_msgobject);
113 typedef struct playback_stream {
114 output_stream parent;
116 pa_native_connection *connection;
117 uint32_t index;
119 pa_sink_input *sink_input;
120 pa_memblockq *memblockq;
122 pa_bool_t adjust_latency:1;
123 pa_bool_t early_requests:1;
125 pa_bool_t is_underrun:1;
126 pa_bool_t drain_request:1;
127 uint32_t drain_tag;
128 uint32_t syncid;
130 /* Optimization to avoid too many rewinds with a lot of small blocks */
131 pa_atomic_t seek_or_post_in_queue;
132 int64_t seek_windex;
134 pa_atomic_t missing;
135 pa_usec_t configured_sink_latency;
136 /* Requested buffer attributes */
137 pa_buffer_attr buffer_attr_req;
138 /* Fixed-up and adjusted buffer attributes */
139 pa_buffer_attr buffer_attr;
141 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
142 int64_t read_index, write_index;
143 size_t render_memblockq_length;
144 pa_usec_t current_sink_latency;
145 uint64_t playing_for, underrun_for;
146 } playback_stream;
148 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
149 PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
151 typedef struct upload_stream {
152 output_stream parent;
154 pa_native_connection *connection;
155 uint32_t index;
157 pa_memchunk memchunk;
158 size_t length;
159 char *name;
160 pa_sample_spec sample_spec;
161 pa_channel_map channel_map;
162 pa_proplist *proplist;
163 } upload_stream;
165 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
166 PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
168 struct pa_native_connection {
169 pa_msgobject parent;
170 pa_native_protocol *protocol;
171 pa_native_options *options;
172 pa_bool_t authorized:1;
173 pa_bool_t is_local:1;
174 uint32_t version;
175 pa_client *client;
176 pa_pstream *pstream;
177 pa_pdispatch *pdispatch;
178 pa_idxset *record_streams, *output_streams;
179 uint32_t rrobin_index;
180 pa_subscription *subscription;
181 pa_time_event *auth_timeout_event;
184 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
185 PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
187 struct pa_native_protocol {
188 PA_REFCNT_DECLARE;
190 pa_core *core;
191 pa_idxset *connections;
193 pa_strlist *servers;
194 pa_hook hooks[PA_NATIVE_HOOK_MAX];
196 pa_hashmap *extensions;
199 enum {
200 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
203 enum {
204 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
205 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
206 SINK_INPUT_MESSAGE_FLUSH,
207 SINK_INPUT_MESSAGE_TRIGGER,
208 SINK_INPUT_MESSAGE_SEEK,
209 SINK_INPUT_MESSAGE_PREBUF_FORCE,
210 SINK_INPUT_MESSAGE_UPDATE_LATENCY,
211 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
214 enum {
215 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
216 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
217 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
218 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
219 PLAYBACK_STREAM_MESSAGE_STARTED,
220 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
223 enum {
224 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
227 enum {
228 CONNECTION_MESSAGE_RELEASE,
229 CONNECTION_MESSAGE_REVOKE
232 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
233 static void sink_input_kill_cb(pa_sink_input *i);
234 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
235 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
236 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
237 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
238 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
239 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
241 static void native_connection_send_memblock(pa_native_connection *c);
242 static void playback_stream_request_bytes(struct playback_stream*s);
244 static void source_output_kill_cb(pa_source_output *o);
245 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
246 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend);
247 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
248 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
249 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
251 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
252 static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
254 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
255 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
256 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
257 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
258 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
259 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
260 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
261 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
262 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
263 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
264 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
265 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
266 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
267 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
268 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
269 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
270 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
271 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
272 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
273 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
274 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
275 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
276 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
277 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
278 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
279 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
280 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
281 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
282 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
283 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
284 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
285 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
286 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
287 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
288 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
289 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
290 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
291 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
292 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
294 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
295 [PA_COMMAND_ERROR] = NULL,
296 [PA_COMMAND_TIMEOUT] = NULL,
297 [PA_COMMAND_REPLY] = NULL,
298 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
299 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
300 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
301 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
302 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
303 [PA_COMMAND_AUTH] = command_auth,
304 [PA_COMMAND_REQUEST] = NULL,
305 [PA_COMMAND_EXIT] = command_exit,
306 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
307 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
308 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
309 [PA_COMMAND_STAT] = command_stat,
310 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
311 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
312 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
313 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
314 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
315 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
316 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
317 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
318 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
319 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
320 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
321 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
322 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
323 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
324 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
325 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
326 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
327 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
328 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
329 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
330 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
331 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
332 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
333 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
334 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
336 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
337 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
338 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
339 [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = command_set_volume,
341 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
342 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
343 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
344 [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = command_set_mute,
346 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
347 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
349 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
350 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
351 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
352 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
354 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
355 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
357 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
358 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
359 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
360 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
361 [PA_COMMAND_KILL_CLIENT] = command_kill,
362 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
363 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
364 [PA_COMMAND_LOAD_MODULE] = command_load_module,
365 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
367 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
368 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
369 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
370 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
372 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
373 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
375 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
376 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
378 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
379 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
381 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
382 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
383 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
385 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
386 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
387 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
389 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
391 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
392 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
394 [PA_COMMAND_EXTENSION] = command_extension
397 /* structure management */
399 /* Called from main context */
400 static void upload_stream_unlink(upload_stream *s) {
401 pa_assert(s);
403 if (!s->connection)
404 return;
406 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
407 s->connection = NULL;
408 upload_stream_unref(s);
411 /* Called from main context */
412 static void upload_stream_free(pa_object *o) {
413 upload_stream *s = UPLOAD_STREAM(o);
414 pa_assert(s);
416 upload_stream_unlink(s);
418 pa_xfree(s->name);
420 if (s->proplist)
421 pa_proplist_free(s->proplist);
423 if (s->memchunk.memblock)
424 pa_memblock_unref(s->memchunk.memblock);
426 pa_xfree(s);
429 /* Called from main context */
430 static upload_stream* upload_stream_new(
431 pa_native_connection *c,
432 const pa_sample_spec *ss,
433 const pa_channel_map *map,
434 const char *name,
435 size_t length,
436 pa_proplist *p) {
438 upload_stream *s;
440 pa_assert(c);
441 pa_assert(ss);
442 pa_assert(name);
443 pa_assert(length > 0);
444 pa_assert(p);
446 s = pa_msgobject_new(upload_stream);
447 s->parent.parent.parent.free = upload_stream_free;
448 s->connection = c;
449 s->sample_spec = *ss;
450 s->channel_map = *map;
451 s->name = pa_xstrdup(name);
452 pa_memchunk_reset(&s->memchunk);
453 s->length = length;
454 s->proplist = pa_proplist_copy(p);
455 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
457 pa_idxset_put(c->output_streams, s, &s->index);
459 return s;
462 /* Called from main context */
463 static void record_stream_unlink(record_stream *s) {
464 pa_assert(s);
466 if (!s->connection)
467 return;
469 if (s->source_output) {
470 pa_source_output_unlink(s->source_output);
471 pa_source_output_unref(s->source_output);
472 s->source_output = NULL;
475 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
476 s->connection = NULL;
477 record_stream_unref(s);
480 /* Called from main context */
481 static void record_stream_free(pa_object *o) {
482 record_stream *s = RECORD_STREAM(o);
483 pa_assert(s);
485 record_stream_unlink(s);
487 pa_memblockq_free(s->memblockq);
488 pa_xfree(s);
491 /* Called from main context */
492 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
493 record_stream *s = RECORD_STREAM(o);
494 record_stream_assert_ref(s);
496 if (!s->connection)
497 return -1;
499 switch (code) {
501 case RECORD_STREAM_MESSAGE_POST_DATA:
503 /* We try to keep up to date with how many bytes are
504 * currently on the fly */
505 pa_atomic_sub(&s->on_the_fly, chunk->length);
507 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
508 /* pa_log_warn("Failed to push data into output queue."); */
509 return -1;
512 if (!pa_pstream_is_pending(s->connection->pstream))
513 native_connection_send_memblock(s->connection);
515 break;
518 return 0;
521 /* Called from main context */
522 static void fix_record_buffer_attr_pre(record_stream *s) {
524 size_t frame_size;
525 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
527 pa_assert(s);
529 /* This function will be called from the main thread, before as
530 * well as after the source output has been activated using
531 * pa_source_output_put()! That means it may not touch any
532 * ->thread_info data! */
534 frame_size = pa_frame_size(&s->source_output->sample_spec);
535 s->buffer_attr = s->buffer_attr_req;
537 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
538 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
539 if (s->buffer_attr.maxlength <= 0)
540 s->buffer_attr.maxlength = (uint32_t) frame_size;
542 if (s->buffer_attr.fragsize == (uint32_t) -1)
543 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
544 if (s->buffer_attr.fragsize <= 0)
545 s->buffer_attr.fragsize = (uint32_t) frame_size;
547 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
549 if (s->early_requests) {
551 /* In early request mode we need to emulate the classic
552 * fragment-based playback model. We do this setting the source
553 * latency to the fragment size. */
555 source_usec = fragsize_usec;
557 } else if (s->adjust_latency) {
559 /* So, the user asked us to adjust the latency according to
560 * what the source can provide. Half the latency will be
561 * spent on the hw buffer, half of it in the async buffer
562 * queue we maintain for each client. */
564 source_usec = fragsize_usec/2;
566 } else {
568 /* Ok, the user didn't ask us to adjust the latency, hence we
569 * don't */
571 source_usec = (pa_usec_t) -1;
574 if (source_usec != (pa_usec_t) -1)
575 s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
576 else
577 s->configured_source_latency = 0;
579 if (s->early_requests) {
581 /* Ok, we didn't necessarily get what we were asking for, so
582 * let's tell the user */
584 fragsize_usec = s->configured_source_latency;
586 } else if (s->adjust_latency) {
588 /* Now subtract what we actually got */
590 if (fragsize_usec >= s->configured_source_latency*2)
591 fragsize_usec -= s->configured_source_latency;
592 else
593 fragsize_usec = s->configured_source_latency;
596 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
597 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
599 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
601 if (s->buffer_attr.fragsize <= 0)
602 s->buffer_attr.fragsize = (uint32_t) frame_size;
605 /* Called from main context */
606 static void fix_record_buffer_attr_post(record_stream *s) {
607 size_t base;
609 pa_assert(s);
611 /* This function will be called from the main thread, before as
612 * well as after the source output has been activated using
613 * pa_source_output_put()! That means it may not touch and
614 * ->thread_info data! */
616 base = pa_frame_size(&s->source_output->sample_spec);
618 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
619 if (s->buffer_attr.fragsize <= 0)
620 s->buffer_attr.fragsize = base;
622 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
623 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
626 /* Called from main context */
627 static record_stream* record_stream_new(
628 pa_native_connection *c,
629 pa_source *source,
630 pa_sample_spec *ss,
631 pa_channel_map *map,
632 pa_idxset *formats,
633 pa_buffer_attr *attr,
634 pa_cvolume *volume,
635 pa_bool_t muted,
636 pa_bool_t muted_set,
637 pa_source_output_flags_t flags,
638 pa_proplist *p,
639 pa_bool_t adjust_latency,
640 pa_bool_t early_requests,
641 pa_bool_t relative_volume,
642 pa_bool_t peak_detect,
643 pa_sink_input *direct_on_input,
644 int *ret) {
646 record_stream *s;
647 pa_source_output *source_output = NULL;
648 pa_source_output_new_data data;
650 pa_assert(c);
651 pa_assert(ss);
652 pa_assert(p);
653 pa_assert(ret);
655 pa_source_output_new_data_init(&data);
657 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
658 data.driver = __FILE__;
659 data.module = c->options->module;
660 data.client = c->client;
661 if (source)
662 pa_source_output_new_data_set_source(&data, source, TRUE);
663 if (pa_sample_spec_valid(ss))
664 pa_source_output_new_data_set_sample_spec(&data, ss);
665 if (pa_channel_map_valid(map))
666 pa_source_output_new_data_set_channel_map(&data, map);
667 if (formats)
668 pa_source_output_new_data_set_formats(&data, formats);
669 data.direct_on_input = direct_on_input;
670 if (volume) {
671 pa_source_output_new_data_set_volume(&data, volume);
672 data.volume_is_absolute = !relative_volume;
673 data.save_volume = TRUE;
675 if (muted_set) {
676 pa_source_output_new_data_set_muted(&data, muted);
677 data.save_muted = TRUE;
679 if (peak_detect)
680 data.resample_method = PA_RESAMPLER_PEAKS;
681 data.flags = flags;
683 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
685 pa_source_output_new_data_done(&data);
687 if (!source_output)
688 return NULL;
690 s = pa_msgobject_new(record_stream);
691 s->parent.parent.free = record_stream_free;
692 s->parent.process_msg = record_stream_process_msg;
693 s->connection = c;
694 s->source_output = source_output;
695 s->buffer_attr_req = *attr;
696 s->adjust_latency = adjust_latency;
697 s->early_requests = early_requests;
698 pa_atomic_store(&s->on_the_fly, 0);
700 s->source_output->parent.process_msg = source_output_process_msg;
701 s->source_output->push = source_output_push_cb;
702 s->source_output->kill = source_output_kill_cb;
703 s->source_output->get_latency = source_output_get_latency_cb;
704 s->source_output->moving = source_output_moving_cb;
705 s->source_output->suspend = source_output_suspend_cb;
706 s->source_output->send_event = source_output_send_event_cb;
707 s->source_output->userdata = s;
709 fix_record_buffer_attr_pre(s);
711 s->memblockq = pa_memblockq_new(
713 s->buffer_attr.maxlength,
715 pa_frame_size(&source_output->sample_spec),
719 NULL);
721 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
722 fix_record_buffer_attr_post(s);
724 *ss = s->source_output->sample_spec;
725 *map = s->source_output->channel_map;
727 pa_idxset_put(c->record_streams, s, &s->index);
729 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
730 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
731 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
732 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
734 pa_source_output_put(s->source_output);
735 return s;
738 /* Called from main context */
739 static void record_stream_send_killed(record_stream *r) {
740 pa_tagstruct *t;
741 record_stream_assert_ref(r);
743 t = pa_tagstruct_new(NULL, 0);
744 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
745 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
746 pa_tagstruct_putu32(t, r->index);
747 pa_pstream_send_tagstruct(r->connection->pstream, t);
750 /* Called from main context */
751 static void playback_stream_unlink(playback_stream *s) {
752 pa_assert(s);
754 if (!s->connection)
755 return;
757 if (s->sink_input) {
758 pa_sink_input_unlink(s->sink_input);
759 pa_sink_input_unref(s->sink_input);
760 s->sink_input = NULL;
763 if (s->drain_request)
764 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
766 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
767 s->connection = NULL;
768 playback_stream_unref(s);
771 /* Called from main context */
772 static void playback_stream_free(pa_object* o) {
773 playback_stream *s = PLAYBACK_STREAM(o);
774 pa_assert(s);
776 playback_stream_unlink(s);
778 pa_memblockq_free(s->memblockq);
779 pa_xfree(s);
782 /* Called from main context */
783 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
784 playback_stream *s = PLAYBACK_STREAM(o);
785 playback_stream_assert_ref(s);
787 if (!s->connection)
788 return -1;
790 switch (code) {
792 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
793 pa_tagstruct *t;
794 int l = 0;
796 for (;;) {
797 if ((l = pa_atomic_load(&s->missing)) <= 0)
798 return 0;
800 if (pa_atomic_cmpxchg(&s->missing, l, 0))
801 break;
804 t = pa_tagstruct_new(NULL, 0);
805 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
806 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
807 pa_tagstruct_putu32(t, s->index);
808 pa_tagstruct_putu32(t, (uint32_t) l);
809 pa_pstream_send_tagstruct(s->connection->pstream, t);
811 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
812 break;
815 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
816 pa_tagstruct *t;
818 /* pa_log("signalling underflow"); */
820 /* Report that we're empty */
821 t = pa_tagstruct_new(NULL, 0);
822 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
823 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
824 pa_tagstruct_putu32(t, s->index);
825 if (s->connection->version >= 23)
826 pa_tagstruct_puts64(t, offset);
827 pa_pstream_send_tagstruct(s->connection->pstream, t);
828 break;
831 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
832 pa_tagstruct *t;
834 /* Notify the user we're overflowed*/
835 t = pa_tagstruct_new(NULL, 0);
836 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
837 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
838 pa_tagstruct_putu32(t, s->index);
839 pa_pstream_send_tagstruct(s->connection->pstream, t);
840 break;
843 case PLAYBACK_STREAM_MESSAGE_STARTED:
845 if (s->connection->version >= 13) {
846 pa_tagstruct *t;
848 /* Notify the user we started playback */
849 t = pa_tagstruct_new(NULL, 0);
850 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
851 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
852 pa_tagstruct_putu32(t, s->index);
853 pa_pstream_send_tagstruct(s->connection->pstream, t);
856 break;
858 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
859 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
860 break;
862 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
864 s->buffer_attr.tlength = (uint32_t) offset;
866 if (s->connection->version >= 15) {
867 pa_tagstruct *t;
869 t = pa_tagstruct_new(NULL, 0);
870 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
871 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
872 pa_tagstruct_putu32(t, s->index);
873 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
874 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
875 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
876 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
877 pa_tagstruct_put_usec(t, s->configured_sink_latency);
878 pa_pstream_send_tagstruct(s->connection->pstream, t);
881 break;
884 return 0;
887 /* Called from main context */
888 static void fix_playback_buffer_attr(playback_stream *s) {
889 size_t frame_size, max_prebuf;
890 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
892 pa_assert(s);
894 /* pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", */
895 /* (long) s->buffer_attr.maxlength, */
896 /* (long) s->buffer_attr.tlength, */
897 /* (long) s->buffer_attr.minreq, */
898 /* (long) s->buffer_attr.prebuf); */
900 /* pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
901 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
902 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
903 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
904 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
906 /* This function will be called from the main thread, before as
907 * well as after the sink input has been activated using
908 * pa_sink_input_put()! That means it may not touch any
909 * ->thread_info data, such as the memblockq! */
911 frame_size = pa_frame_size(&s->sink_input->sample_spec);
912 s->buffer_attr = s->buffer_attr_req;
914 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
915 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
916 if (s->buffer_attr.maxlength <= 0)
917 s->buffer_attr.maxlength = (uint32_t) frame_size;
919 if (s->buffer_attr.tlength == (uint32_t) -1)
920 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
921 if (s->buffer_attr.tlength <= 0)
922 s->buffer_attr.tlength = (uint32_t) frame_size;
924 if (s->buffer_attr.minreq == (uint32_t) -1)
925 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
926 if (s->buffer_attr.minreq <= 0)
927 s->buffer_attr.minreq = (uint32_t) frame_size;
929 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
930 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
932 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
933 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
935 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
936 (double) tlength_usec / PA_USEC_PER_MSEC,
937 (double) minreq_usec / PA_USEC_PER_MSEC);
939 if (s->early_requests) {
941 /* In early request mode we need to emulate the classic
942 * fragment-based playback model. We do this setting the sink
943 * latency to the fragment size. */
945 sink_usec = minreq_usec;
946 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
948 } else if (s->adjust_latency) {
950 /* So, the user asked us to adjust the latency of the stream
951 * buffer according to the what the sink can provide. The
952 * tlength passed in shall be the overall latency. Roughly
953 * half the latency will be spent on the hw buffer, the other
954 * half of it in the async buffer queue we maintain for each
955 * client. In between we'll have a safety space of size
956 * 2*minreq. Why the 2*minreq? When the hw buffer is completely
957 * empty and needs to be filled, then our buffer must have
958 * enough data to fulfill this request immediately and thus
959 * have at least the same tlength as the size of the hw
960 * buffer. It additionally needs space for 2 times minreq
961 * because if the buffer ran empty and a partial fillup
962 * happens immediately on the next iteration we need to be
963 * able to fulfill it and give the application also minreq
964 * time to fill it up again for the next request Makes 2 times
965 * minreq in plus.. */
967 if (tlength_usec > minreq_usec*2)
968 sink_usec = (tlength_usec - minreq_usec*2)/2;
969 else
970 sink_usec = 0;
972 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
974 } else {
976 /* Ok, the user didn't ask us to adjust the latency, but we
977 * still need to make sure that the parameters from the user
978 * do make sense. */
980 if (tlength_usec > minreq_usec*2)
981 sink_usec = (tlength_usec - minreq_usec*2);
982 else
983 sink_usec = 0;
985 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
988 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
990 if (s->early_requests) {
992 /* Ok, we didn't necessarily get what we were asking for, so
993 * let's tell the user */
995 minreq_usec = s->configured_sink_latency;
997 } else if (s->adjust_latency) {
999 /* Ok, we didn't necessarily get what we were asking for, so
1000 * let's subtract from what we asked for for the remaining
1001 * buffer space */
1003 if (tlength_usec >= s->configured_sink_latency)
1004 tlength_usec -= s->configured_sink_latency;
1007 /* FIXME: This is actually larger than necessary, since not all of
1008 * the sink latency is actually rewritable. */
1009 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
1010 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
1012 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
1013 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
1014 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
1016 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
1017 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
1018 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
1020 if (s->buffer_attr.minreq <= 0) {
1021 s->buffer_attr.minreq = (uint32_t) frame_size;
1022 s->buffer_attr.tlength += (uint32_t) frame_size*2;
1025 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
1026 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
1028 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
1030 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
1031 s->buffer_attr.prebuf > max_prebuf)
1032 s->buffer_attr.prebuf = max_prebuf;
1034 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1035 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1036 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1037 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1038 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1041 /* Called from main context */
1042 static playback_stream* playback_stream_new(
1043 pa_native_connection *c,
1044 pa_sink *sink,
1045 pa_sample_spec *ss,
1046 pa_channel_map *map,
1047 pa_idxset *formats,
1048 pa_buffer_attr *a,
1049 pa_cvolume *volume,
1050 pa_bool_t muted,
1051 pa_bool_t muted_set,
1052 pa_sink_input_flags_t flags,
1053 pa_proplist *p,
1054 pa_bool_t adjust_latency,
1055 pa_bool_t early_requests,
1056 pa_bool_t relative_volume,
1057 uint32_t syncid,
1058 uint32_t *missing,
1059 int *ret) {
1061 /* Note: This function takes ownership of the 'formats' param, so we need
1062 * to take extra care to not leak it */
1064 playback_stream *ssync;
1065 playback_stream *s = NULL;
1066 pa_sink_input *sink_input = NULL;
1067 pa_memchunk silence;
1068 uint32_t idx;
1069 int64_t start_index;
1070 pa_sink_input_new_data data;
1072 pa_assert(c);
1073 pa_assert(ss);
1074 pa_assert(missing);
1075 pa_assert(p);
1076 pa_assert(ret);
1078 /* Find syncid group */
1079 PA_IDXSET_FOREACH(ssync, c->output_streams, idx) {
1081 if (!playback_stream_isinstance(ssync))
1082 continue;
1084 if (ssync->syncid == syncid)
1085 break;
1088 /* Synced streams must connect to the same sink */
1089 if (ssync) {
1091 if (!sink)
1092 sink = ssync->sink_input->sink;
1093 else if (sink != ssync->sink_input->sink) {
1094 *ret = PA_ERR_INVALID;
1095 goto out;
1099 pa_sink_input_new_data_init(&data);
1101 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1102 data.driver = __FILE__;
1103 data.module = c->options->module;
1104 data.client = c->client;
1105 if (sink)
1106 pa_sink_input_new_data_set_sink(&data, sink, TRUE);
1107 if (pa_sample_spec_valid(ss))
1108 pa_sink_input_new_data_set_sample_spec(&data, ss);
1109 if (pa_channel_map_valid(map))
1110 pa_sink_input_new_data_set_channel_map(&data, map);
1111 if (formats) {
1112 pa_sink_input_new_data_set_formats(&data, formats);
1113 /* Ownership transferred to new_data, so we don't free it ourselves */
1114 formats = NULL;
1116 if (volume) {
1117 pa_sink_input_new_data_set_volume(&data, volume);
1118 data.volume_is_absolute = !relative_volume;
1119 data.save_volume = TRUE;
1121 if (muted_set) {
1122 pa_sink_input_new_data_set_muted(&data, muted);
1123 data.save_muted = TRUE;
1125 data.sync_base = ssync ? ssync->sink_input : NULL;
1126 data.flags = flags;
1128 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1130 pa_sink_input_new_data_done(&data);
1132 if (!sink_input)
1133 goto out;
1135 s = pa_msgobject_new(playback_stream);
1136 s->parent.parent.parent.free = playback_stream_free;
1137 s->parent.parent.process_msg = playback_stream_process_msg;
1138 s->connection = c;
1139 s->syncid = syncid;
1140 s->sink_input = sink_input;
1141 s->is_underrun = TRUE;
1142 s->drain_request = FALSE;
1143 pa_atomic_store(&s->missing, 0);
1144 s->buffer_attr_req = *a;
1145 s->adjust_latency = adjust_latency;
1146 s->early_requests = early_requests;
1147 pa_atomic_store(&s->seek_or_post_in_queue, 0);
1148 s->seek_windex = -1;
1150 s->sink_input->parent.process_msg = sink_input_process_msg;
1151 s->sink_input->pop = sink_input_pop_cb;
1152 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1153 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1154 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1155 s->sink_input->kill = sink_input_kill_cb;
1156 s->sink_input->moving = sink_input_moving_cb;
1157 s->sink_input->suspend = sink_input_suspend_cb;
1158 s->sink_input->send_event = sink_input_send_event_cb;
1159 s->sink_input->userdata = s;
1161 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1163 fix_playback_buffer_attr(s);
1165 pa_sink_input_get_silence(sink_input, &silence);
1166 s->memblockq = pa_memblockq_new(
1167 start_index,
1168 s->buffer_attr.maxlength,
1169 s->buffer_attr.tlength,
1170 pa_frame_size(&sink_input->sample_spec),
1171 s->buffer_attr.prebuf,
1172 s->buffer_attr.minreq,
1174 &silence);
1175 pa_memblock_unref(silence.memblock);
1177 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1179 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1181 /* pa_log("missing original: %li", (long int) *missing); */
1183 *ss = s->sink_input->sample_spec;
1184 *map = s->sink_input->channel_map;
1186 pa_idxset_put(c->output_streams, s, &s->index);
1188 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1189 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1190 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1191 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1192 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1194 pa_sink_input_put(s->sink_input);
1196 out:
1197 if (formats)
1198 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
1200 return s;
1203 /* Called from IO context */
1204 static void playback_stream_request_bytes(playback_stream *s) {
1205 size_t m, minreq;
1206 int previous_missing;
1208 playback_stream_assert_ref(s);
1210 m = pa_memblockq_pop_missing(s->memblockq);
1212 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1213 /* (unsigned long) m, */
1214 /* pa_memblockq_get_tlength(s->memblockq), */
1215 /* pa_memblockq_get_minreq(s->memblockq), */
1216 /* pa_memblockq_get_length(s->memblockq), */
1217 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1219 if (m <= 0)
1220 return;
1222 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1224 previous_missing = pa_atomic_add(&s->missing, (int) m);
1225 minreq = pa_memblockq_get_minreq(s->memblockq);
1227 if (pa_memblockq_prebuf_active(s->memblockq) ||
1228 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1229 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1232 /* Called from main context */
1233 static void playback_stream_send_killed(playback_stream *p) {
1234 pa_tagstruct *t;
1235 playback_stream_assert_ref(p);
1237 t = pa_tagstruct_new(NULL, 0);
1238 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1239 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1240 pa_tagstruct_putu32(t, p->index);
1241 pa_pstream_send_tagstruct(p->connection->pstream, t);
1244 /* Called from main context */
1245 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1246 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1247 pa_native_connection_assert_ref(c);
1249 if (!c->protocol)
1250 return -1;
1252 switch (code) {
1254 case CONNECTION_MESSAGE_REVOKE:
1255 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1256 break;
1258 case CONNECTION_MESSAGE_RELEASE:
1259 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1260 break;
1263 return 0;
1266 /* Called from main context */
1267 static void native_connection_unlink(pa_native_connection *c) {
1268 record_stream *r;
1269 output_stream *o;
1271 pa_assert(c);
1273 if (!c->protocol)
1274 return;
1276 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1278 if (c->options)
1279 pa_native_options_unref(c->options);
1281 while ((r = pa_idxset_first(c->record_streams, NULL)))
1282 record_stream_unlink(r);
1284 while ((o = pa_idxset_first(c->output_streams, NULL)))
1285 if (playback_stream_isinstance(o))
1286 playback_stream_unlink(PLAYBACK_STREAM(o));
1287 else
1288 upload_stream_unlink(UPLOAD_STREAM(o));
1290 if (c->subscription)
1291 pa_subscription_free(c->subscription);
1293 if (c->pstream)
1294 pa_pstream_unlink(c->pstream);
1296 if (c->auth_timeout_event) {
1297 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1298 c->auth_timeout_event = NULL;
1301 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1302 c->protocol = NULL;
1303 pa_native_connection_unref(c);
1306 /* Called from main context */
1307 static void native_connection_free(pa_object *o) {
1308 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1310 pa_assert(c);
1312 native_connection_unlink(c);
1314 pa_idxset_free(c->record_streams, NULL, NULL);
1315 pa_idxset_free(c->output_streams, NULL, NULL);
1317 pa_pdispatch_unref(c->pdispatch);
1318 pa_pstream_unref(c->pstream);
1319 pa_client_free(c->client);
1321 pa_xfree(c);
1324 /* Called from main context */
1325 static void native_connection_send_memblock(pa_native_connection *c) {
1326 uint32_t start;
1327 record_stream *r;
1329 start = PA_IDXSET_INVALID;
1330 for (;;) {
1331 pa_memchunk chunk;
1333 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1334 return;
1336 if (start == PA_IDXSET_INVALID)
1337 start = c->rrobin_index;
1338 else if (start == c->rrobin_index)
1339 return;
1341 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1342 pa_memchunk schunk = chunk;
1344 if (schunk.length > r->buffer_attr.fragsize)
1345 schunk.length = r->buffer_attr.fragsize;
1347 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1349 pa_memblockq_drop(r->memblockq, schunk.length);
1350 pa_memblock_unref(schunk.memblock);
1352 return;
1357 /*** sink input callbacks ***/
1359 /* Called from thread context */
1360 static void handle_seek(playback_stream *s, int64_t indexw) {
1361 playback_stream_assert_ref(s);
1363 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1365 if (s->sink_input->thread_info.underrun_for > 0) {
1367 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1369 if (pa_memblockq_is_readable(s->memblockq)) {
1371 /* We just ended an underrun, let's ask the sink
1372 * for a complete rewind rewrite */
1374 pa_log_debug("Requesting rewind due to end of underrun.");
1375 pa_sink_input_request_rewind(s->sink_input,
1376 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1377 s->sink_input->thread_info.underrun_for),
1378 FALSE, TRUE, FALSE);
1381 } else {
1382 int64_t indexr;
1384 indexr = pa_memblockq_get_read_index(s->memblockq);
1386 if (indexw < indexr) {
1387 /* OK, the sink already asked for this data, so
1388 * let's have it ask us again */
1390 pa_log_debug("Requesting rewind due to rewrite.");
1391 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1395 playback_stream_request_bytes(s);
1398 static void flush_write_no_account(pa_memblockq *q) {
1399 pa_memblockq_flush_write(q, FALSE);
1402 /* Called from thread context */
1403 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1404 pa_sink_input *i = PA_SINK_INPUT(o);
1405 playback_stream *s;
1407 pa_sink_input_assert_ref(i);
1408 s = PLAYBACK_STREAM(i->userdata);
1409 playback_stream_assert_ref(s);
1411 switch (code) {
1413 case SINK_INPUT_MESSAGE_SEEK:
1414 case SINK_INPUT_MESSAGE_POST_DATA: {
1415 int64_t windex = pa_memblockq_get_write_index(s->memblockq);
1417 if (code == SINK_INPUT_MESSAGE_SEEK) {
1418 /* The client side is incapable of accounting correctly
1419 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1420 * able to deal with that. */
1422 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1423 windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
1426 if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1427 if (pa_log_ratelimit(PA_LOG_WARN))
1428 pa_log_warn("Failed to push data into queue");
1429 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1430 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1433 /* If more data is in queue, we rewind later instead. */
1434 if (s->seek_windex != -1)
1435 windex = PA_MIN(windex, s->seek_windex);
1436 if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
1437 s->seek_windex = windex;
1438 else {
1439 s->seek_windex = -1;
1440 handle_seek(s, windex);
1442 return 0;
1445 case SINK_INPUT_MESSAGE_DRAIN:
1446 case SINK_INPUT_MESSAGE_FLUSH:
1447 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1448 case SINK_INPUT_MESSAGE_TRIGGER: {
1450 int64_t windex;
1451 pa_sink_input *isync;
1452 void (*func)(pa_memblockq *bq);
1454 switch (code) {
1455 case SINK_INPUT_MESSAGE_FLUSH:
1456 func = flush_write_no_account;
1457 break;
1459 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1460 func = pa_memblockq_prebuf_force;
1461 break;
1463 case SINK_INPUT_MESSAGE_DRAIN:
1464 case SINK_INPUT_MESSAGE_TRIGGER:
1465 func = pa_memblockq_prebuf_disable;
1466 break;
1468 default:
1469 pa_assert_not_reached();
1472 windex = pa_memblockq_get_write_index(s->memblockq);
1473 func(s->memblockq);
1474 handle_seek(s, windex);
1476 /* Do the same for all other members in the sync group */
1477 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1478 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1479 windex = pa_memblockq_get_write_index(ssync->memblockq);
1480 func(ssync->memblockq);
1481 handle_seek(ssync, windex);
1484 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1485 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1486 windex = pa_memblockq_get_write_index(ssync->memblockq);
1487 func(ssync->memblockq);
1488 handle_seek(ssync, windex);
1491 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1492 if (!pa_memblockq_is_readable(s->memblockq))
1493 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1494 else {
1495 s->drain_tag = PA_PTR_TO_UINT(userdata);
1496 s->drain_request = TRUE;
1500 return 0;
1503 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1504 /* Atomically get a snapshot of all timing parameters... */
1505 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1506 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1507 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1508 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1509 s->underrun_for = s->sink_input->thread_info.underrun_for;
1510 s->playing_for = s->sink_input->thread_info.playing_for;
1512 return 0;
1514 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1515 int64_t windex;
1517 windex = pa_memblockq_get_write_index(s->memblockq);
1519 pa_memblockq_prebuf_force(s->memblockq);
1521 handle_seek(s, windex);
1523 /* Fall through to the default handler */
1524 break;
1527 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1528 pa_usec_t *r = userdata;
1530 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1532 /* Fall through, the default handler will add in the extra
1533 * latency added by the resampler */
1534 break;
1537 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1538 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1539 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1540 return 0;
1544 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1547 /* Called from thread context */
1548 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1549 playback_stream *s;
1551 pa_sink_input_assert_ref(i);
1552 s = PLAYBACK_STREAM(i->userdata);
1553 playback_stream_assert_ref(s);
1554 pa_assert(chunk);
1556 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1558 if (pa_memblockq_is_readable(s->memblockq))
1559 s->is_underrun = FALSE;
1560 else {
1561 if (!s->is_underrun)
1562 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));
1564 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1565 s->drain_request = FALSE;
1566 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);
1567 } else if (!s->is_underrun)
1568 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, pa_memblockq_get_read_index(s->memblockq), NULL, NULL);
1570 s->is_underrun = TRUE;
1572 playback_stream_request_bytes(s);
1575 /* This call will not fail with prebuf=0, hence we check for
1576 underrun explicitly above */
1577 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1578 return -1;
1580 chunk->length = PA_MIN(nbytes, chunk->length);
1582 if (i->thread_info.underrun_for > 0)
1583 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1585 pa_memblockq_drop(s->memblockq, chunk->length);
1586 playback_stream_request_bytes(s);
1588 return 0;
1591 /* Called from thread context */
1592 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1593 playback_stream *s;
1595 pa_sink_input_assert_ref(i);
1596 s = PLAYBACK_STREAM(i->userdata);
1597 playback_stream_assert_ref(s);
1599 /* If we are in an underrun, then we don't rewind */
1600 if (i->thread_info.underrun_for > 0)
1601 return;
1603 pa_memblockq_rewind(s->memblockq, nbytes);
1606 /* Called from thread context */
1607 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1608 playback_stream *s;
1610 pa_sink_input_assert_ref(i);
1611 s = PLAYBACK_STREAM(i->userdata);
1612 playback_stream_assert_ref(s);
1614 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1617 /* Called from thread context */
1618 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1619 playback_stream *s;
1620 size_t new_tlength, old_tlength;
1622 pa_sink_input_assert_ref(i);
1623 s = PLAYBACK_STREAM(i->userdata);
1624 playback_stream_assert_ref(s);
1626 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1627 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1629 if (old_tlength < new_tlength) {
1630 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1631 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1632 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1634 if (new_tlength == old_tlength)
1635 pa_log_debug("Failed to increase tlength");
1636 else {
1637 pa_log_debug("Notifying client about increased tlength");
1638 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);
1643 /* Called from main context */
1644 static void sink_input_kill_cb(pa_sink_input *i) {
1645 playback_stream *s;
1647 pa_sink_input_assert_ref(i);
1648 s = PLAYBACK_STREAM(i->userdata);
1649 playback_stream_assert_ref(s);
1651 playback_stream_send_killed(s);
1652 playback_stream_unlink(s);
1655 /* Called from main context */
1656 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1657 playback_stream *s;
1658 pa_tagstruct *t;
1660 pa_sink_input_assert_ref(i);
1661 s = PLAYBACK_STREAM(i->userdata);
1662 playback_stream_assert_ref(s);
1664 if (s->connection->version < 15)
1665 return;
1667 t = pa_tagstruct_new(NULL, 0);
1668 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1669 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1670 pa_tagstruct_putu32(t, s->index);
1671 pa_tagstruct_puts(t, event);
1672 pa_tagstruct_put_proplist(t, pl);
1673 pa_pstream_send_tagstruct(s->connection->pstream, t);
1676 /* Called from main context */
1677 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1678 playback_stream *s;
1679 pa_tagstruct *t;
1681 pa_sink_input_assert_ref(i);
1682 s = PLAYBACK_STREAM(i->userdata);
1683 playback_stream_assert_ref(s);
1685 if (s->connection->version < 12)
1686 return;
1688 t = pa_tagstruct_new(NULL, 0);
1689 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1690 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1691 pa_tagstruct_putu32(t, s->index);
1692 pa_tagstruct_put_boolean(t, suspend);
1693 pa_pstream_send_tagstruct(s->connection->pstream, t);
1696 /* Called from main context */
1697 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1698 playback_stream *s;
1699 pa_tagstruct *t;
1701 pa_sink_input_assert_ref(i);
1702 s = PLAYBACK_STREAM(i->userdata);
1703 playback_stream_assert_ref(s);
1705 if (!dest)
1706 return;
1708 fix_playback_buffer_attr(s);
1709 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1710 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1712 if (s->connection->version < 12)
1713 return;
1715 t = pa_tagstruct_new(NULL, 0);
1716 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1717 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1718 pa_tagstruct_putu32(t, s->index);
1719 pa_tagstruct_putu32(t, dest->index);
1720 pa_tagstruct_puts(t, dest->name);
1721 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1723 if (s->connection->version >= 13) {
1724 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1725 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1726 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1727 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1728 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1731 pa_pstream_send_tagstruct(s->connection->pstream, t);
1734 /*** source_output callbacks ***/
1736 /* Called from thread context */
1737 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1738 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1739 record_stream *s;
1741 pa_source_output_assert_ref(o);
1742 s = RECORD_STREAM(o->userdata);
1743 record_stream_assert_ref(s);
1745 switch (code) {
1746 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1747 /* Atomically get a snapshot of all timing parameters... */
1748 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1749 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1750 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1751 return 0;
1754 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1757 /* Called from thread context */
1758 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1759 record_stream *s;
1761 pa_source_output_assert_ref(o);
1762 s = RECORD_STREAM(o->userdata);
1763 record_stream_assert_ref(s);
1764 pa_assert(chunk);
1766 pa_atomic_add(&s->on_the_fly, chunk->length);
1767 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1770 static void source_output_kill_cb(pa_source_output *o) {
1771 record_stream *s;
1773 pa_source_output_assert_ref(o);
1774 s = RECORD_STREAM(o->userdata);
1775 record_stream_assert_ref(s);
1777 record_stream_send_killed(s);
1778 record_stream_unlink(s);
1781 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1782 record_stream *s;
1784 pa_source_output_assert_ref(o);
1785 s = RECORD_STREAM(o->userdata);
1786 record_stream_assert_ref(s);
1788 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1790 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1793 /* Called from main context */
1794 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1795 record_stream *s;
1796 pa_tagstruct *t;
1798 pa_source_output_assert_ref(o);
1799 s = RECORD_STREAM(o->userdata);
1800 record_stream_assert_ref(s);
1802 if (s->connection->version < 15)
1803 return;
1805 t = pa_tagstruct_new(NULL, 0);
1806 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1807 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1808 pa_tagstruct_putu32(t, s->index);
1809 pa_tagstruct_puts(t, event);
1810 pa_tagstruct_put_proplist(t, pl);
1811 pa_pstream_send_tagstruct(s->connection->pstream, t);
1814 /* Called from main context */
1815 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1816 record_stream *s;
1817 pa_tagstruct *t;
1819 pa_source_output_assert_ref(o);
1820 s = RECORD_STREAM(o->userdata);
1821 record_stream_assert_ref(s);
1823 if (s->connection->version < 12)
1824 return;
1826 t = pa_tagstruct_new(NULL, 0);
1827 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1828 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1829 pa_tagstruct_putu32(t, s->index);
1830 pa_tagstruct_put_boolean(t, suspend);
1831 pa_pstream_send_tagstruct(s->connection->pstream, t);
1834 /* Called from main context */
1835 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1836 record_stream *s;
1837 pa_tagstruct *t;
1839 pa_source_output_assert_ref(o);
1840 s = RECORD_STREAM(o->userdata);
1841 record_stream_assert_ref(s);
1843 if (!dest)
1844 return;
1846 fix_record_buffer_attr_pre(s);
1847 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1848 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1849 fix_record_buffer_attr_post(s);
1851 if (s->connection->version < 12)
1852 return;
1854 t = pa_tagstruct_new(NULL, 0);
1855 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1856 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1857 pa_tagstruct_putu32(t, s->index);
1858 pa_tagstruct_putu32(t, dest->index);
1859 pa_tagstruct_puts(t, dest->name);
1860 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1862 if (s->connection->version >= 13) {
1863 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1864 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1865 pa_tagstruct_put_usec(t, s->configured_source_latency);
1868 pa_pstream_send_tagstruct(s->connection->pstream, t);
1871 /*** pdispatch callbacks ***/
1873 static void protocol_error(pa_native_connection *c) {
1874 pa_log("protocol error, kicking client");
1875 native_connection_unlink(c);
1878 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1879 if (!(expression)) { \
1880 pa_pstream_send_error((pstream), (tag), (error)); \
1881 return; \
1883 } while(0);
1885 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
1886 if (!(expression)) { \
1887 pa_pstream_send_error((pstream), (tag), (error)); \
1888 goto label; \
1890 } while(0);
1892 static pa_tagstruct *reply_new(uint32_t tag) {
1893 pa_tagstruct *reply;
1895 reply = pa_tagstruct_new(NULL, 0);
1896 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1897 pa_tagstruct_putu32(reply, tag);
1898 return reply;
1901 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1902 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1903 playback_stream *s;
1904 uint32_t sink_index, syncid, missing = 0;
1905 pa_buffer_attr attr;
1906 const char *name = NULL, *sink_name;
1907 pa_sample_spec ss;
1908 pa_channel_map map;
1909 pa_tagstruct *reply;
1910 pa_sink *sink = NULL;
1911 pa_cvolume volume;
1912 pa_bool_t
1913 corked = FALSE,
1914 no_remap = FALSE,
1915 no_remix = FALSE,
1916 fix_format = FALSE,
1917 fix_rate = FALSE,
1918 fix_channels = FALSE,
1919 no_move = FALSE,
1920 variable_rate = FALSE,
1921 muted = FALSE,
1922 adjust_latency = FALSE,
1923 early_requests = FALSE,
1924 dont_inhibit_auto_suspend = FALSE,
1925 volume_set = TRUE,
1926 muted_set = FALSE,
1927 fail_on_suspend = FALSE,
1928 relative_volume = FALSE,
1929 passthrough = FALSE;
1931 pa_sink_input_flags_t flags = 0;
1932 pa_proplist *p = NULL;
1933 int ret = PA_ERR_INVALID;
1934 uint8_t n_formats = 0;
1935 pa_format_info *format;
1936 pa_idxset *formats = NULL;
1937 uint32_t i;
1939 pa_native_connection_assert_ref(c);
1940 pa_assert(t);
1941 memset(&attr, 0, sizeof(attr));
1943 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1944 pa_tagstruct_get(
1946 PA_TAG_SAMPLE_SPEC, &ss,
1947 PA_TAG_CHANNEL_MAP, &map,
1948 PA_TAG_U32, &sink_index,
1949 PA_TAG_STRING, &sink_name,
1950 PA_TAG_U32, &attr.maxlength,
1951 PA_TAG_BOOLEAN, &corked,
1952 PA_TAG_U32, &attr.tlength,
1953 PA_TAG_U32, &attr.prebuf,
1954 PA_TAG_U32, &attr.minreq,
1955 PA_TAG_U32, &syncid,
1956 PA_TAG_CVOLUME, &volume,
1957 PA_TAG_INVALID) < 0) {
1959 protocol_error(c);
1960 goto finish;
1963 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
1964 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID, finish);
1965 CHECK_VALIDITY_GOTO(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID, finish);
1966 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
1967 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
1969 p = pa_proplist_new();
1971 if (name)
1972 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1974 if (c->version >= 12) {
1975 /* Since 0.9.8 the user can ask for a couple of additional flags */
1977 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1978 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1979 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1980 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1981 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1982 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1983 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1985 protocol_error(c);
1986 goto finish;
1990 if (c->version >= 13) {
1992 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1993 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1994 pa_tagstruct_get_proplist(t, p) < 0) {
1996 protocol_error(c);
1997 goto finish;
2001 if (c->version >= 14) {
2003 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2004 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2006 protocol_error(c);
2007 goto finish;
2011 if (c->version >= 15) {
2013 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2014 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2015 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2017 protocol_error(c);
2018 goto finish;
2022 if (c->version >= 17) {
2024 if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
2026 protocol_error(c);
2027 goto finish;
2031 if (c->version >= 18) {
2033 if (pa_tagstruct_get_boolean(t, &passthrough) < 0 ) {
2034 protocol_error(c);
2035 goto finish;
2039 if (c->version >= 21) {
2041 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2042 protocol_error(c);
2043 goto finish;
2046 if (n_formats)
2047 formats = pa_idxset_new(NULL, NULL);
2049 for (i = 0; i < n_formats; i++) {
2050 format = pa_format_info_new();
2051 if (pa_tagstruct_get_format_info(t, format) < 0) {
2052 protocol_error(c);
2053 goto finish;
2055 pa_idxset_put(formats, format, NULL);
2059 if (n_formats == 0) {
2060 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2061 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2062 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2063 } else {
2064 PA_IDXSET_FOREACH(format, formats, i) {
2065 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2069 if (!pa_tagstruct_eof(t)) {
2070 protocol_error(c);
2071 goto finish;
2074 if (sink_index != PA_INVALID_INDEX) {
2076 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
2077 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2078 goto finish;
2081 } else if (sink_name) {
2083 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
2084 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2085 goto finish;
2089 flags =
2090 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
2091 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
2092 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
2093 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
2094 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
2095 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
2096 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
2097 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
2098 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2099 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
2100 (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0);
2102 /* Only since protocol version 15 there's a separate muted_set
2103 * flag. For older versions we synthesize it here */
2104 muted_set = muted_set || muted;
2106 s = playback_stream_new(c, sink, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, p, adjust_latency, early_requests, relative_volume, syncid, &missing, &ret);
2107 /* We no longer own the formats idxset */
2108 formats = NULL;
2110 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2112 reply = reply_new(tag);
2113 pa_tagstruct_putu32(reply, s->index);
2114 pa_assert(s->sink_input);
2115 pa_tagstruct_putu32(reply, s->sink_input->index);
2116 pa_tagstruct_putu32(reply, missing);
2118 /* pa_log("initial request is %u", missing); */
2120 if (c->version >= 9) {
2121 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2123 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2124 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2125 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2126 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2129 if (c->version >= 12) {
2130 /* Since 0.9.8 we support sending the chosen sample
2131 * spec/channel map/device/suspend status back to the
2132 * client */
2134 pa_tagstruct_put_sample_spec(reply, &ss);
2135 pa_tagstruct_put_channel_map(reply, &map);
2137 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2138 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2140 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2143 if (c->version >= 13)
2144 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2146 if (c->version >= 21) {
2147 /* Send back the format we negotiated */
2148 if (s->sink_input->format)
2149 pa_tagstruct_put_format_info(reply, s->sink_input->format);
2150 else {
2151 pa_format_info *f = pa_format_info_new();
2152 pa_tagstruct_put_format_info(reply, f);
2153 pa_format_info_free(f);
2157 pa_pstream_send_tagstruct(c->pstream, reply);
2159 finish:
2160 if (p)
2161 pa_proplist_free(p);
2162 if (formats)
2163 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
2166 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2167 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2168 uint32_t channel;
2170 pa_native_connection_assert_ref(c);
2171 pa_assert(t);
2173 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2174 !pa_tagstruct_eof(t)) {
2175 protocol_error(c);
2176 return;
2179 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2181 switch (command) {
2183 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2184 playback_stream *s;
2185 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2186 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2187 return;
2190 playback_stream_unlink(s);
2191 break;
2194 case PA_COMMAND_DELETE_RECORD_STREAM: {
2195 record_stream *s;
2196 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2197 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2198 return;
2201 record_stream_unlink(s);
2202 break;
2205 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2206 upload_stream *s;
2208 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2209 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2210 return;
2213 upload_stream_unlink(s);
2214 break;
2217 default:
2218 pa_assert_not_reached();
2221 pa_pstream_send_simple_ack(c->pstream, tag);
2224 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2225 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2226 record_stream *s;
2227 pa_buffer_attr attr;
2228 uint32_t source_index;
2229 const char *name = NULL, *source_name;
2230 pa_sample_spec ss;
2231 pa_channel_map map;
2232 pa_tagstruct *reply;
2233 pa_source *source = NULL;
2234 pa_cvolume volume;
2235 pa_bool_t
2236 corked = FALSE,
2237 no_remap = FALSE,
2238 no_remix = FALSE,
2239 fix_format = FALSE,
2240 fix_rate = FALSE,
2241 fix_channels = FALSE,
2242 no_move = FALSE,
2243 variable_rate = FALSE,
2244 muted = FALSE,
2245 adjust_latency = FALSE,
2246 peak_detect = FALSE,
2247 early_requests = FALSE,
2248 dont_inhibit_auto_suspend = FALSE,
2249 volume_set = FALSE,
2250 muted_set = FALSE,
2251 fail_on_suspend = FALSE,
2252 relative_volume = FALSE,
2253 passthrough = FALSE;
2255 pa_source_output_flags_t flags = 0;
2256 pa_proplist *p = NULL;
2257 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2258 pa_sink_input *direct_on_input = NULL;
2259 int ret = PA_ERR_INVALID;
2260 uint8_t n_formats = 0;
2261 pa_format_info *format;
2262 pa_idxset *formats = NULL;
2263 uint32_t i;
2265 pa_native_connection_assert_ref(c);
2266 pa_assert(t);
2268 memset(&attr, 0, sizeof(attr));
2270 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2271 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2272 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2273 pa_tagstruct_getu32(t, &source_index) < 0 ||
2274 pa_tagstruct_gets(t, &source_name) < 0 ||
2275 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2276 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2277 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2279 protocol_error(c);
2280 goto finish;
2283 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
2284 CHECK_VALIDITY_GOTO(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID, finish);
2285 CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID, finish);
2286 CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
2288 p = pa_proplist_new();
2290 if (name)
2291 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2293 if (c->version >= 12) {
2294 /* Since 0.9.8 the user can ask for a couple of additional flags */
2296 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2297 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2298 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2299 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2300 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2301 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2302 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2304 protocol_error(c);
2305 goto finish;
2309 if (c->version >= 13) {
2311 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2312 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2313 pa_tagstruct_get_proplist(t, p) < 0 ||
2314 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2316 protocol_error(c);
2317 goto finish;
2321 if (c->version >= 14) {
2323 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2324 protocol_error(c);
2325 goto finish;
2329 if (c->version >= 15) {
2331 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2332 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2334 protocol_error(c);
2335 goto finish;
2339 if (c->version >= 22) {
2340 /* For newer client versions (with per-source-output volumes), we try
2341 * to make the behaviour for playback and record streams the same. */
2342 volume_set = TRUE;
2344 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2345 protocol_error(c);
2346 goto finish;
2349 if (n_formats)
2350 formats = pa_idxset_new(NULL, NULL);
2352 for (i = 0; i < n_formats; i++) {
2353 format = pa_format_info_new();
2354 if (pa_tagstruct_get_format_info(t, format) < 0) {
2355 protocol_error(c);
2356 goto finish;
2358 pa_idxset_put(formats, format, NULL);
2361 if (pa_tagstruct_get_cvolume(t, &volume) < 0 ||
2362 pa_tagstruct_get_boolean(t, &muted) < 0 ||
2363 pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2364 pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2365 pa_tagstruct_get_boolean(t, &relative_volume) < 0 ||
2366 pa_tagstruct_get_boolean(t, &passthrough) < 0) {
2368 protocol_error(c);
2369 goto finish;
2372 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
2375 if (n_formats == 0) {
2376 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2377 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2378 CHECK_VALIDITY_GOTO(c->pstream, c->version < 22 || (volume.channels == ss.channels), tag, PA_ERR_INVALID, finish);
2379 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2380 } else {
2381 PA_IDXSET_FOREACH(format, formats, i) {
2382 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2387 if (!pa_tagstruct_eof(t)) {
2388 protocol_error(c);
2389 goto finish;
2392 if (source_index != PA_INVALID_INDEX) {
2394 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2395 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2396 goto finish;
2399 } else if (source_name) {
2401 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2402 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2403 goto finish;
2407 if (direct_on_input_idx != PA_INVALID_INDEX) {
2409 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2410 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2411 goto finish;
2415 flags =
2416 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2417 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2418 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2419 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2420 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2421 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2422 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2423 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2424 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2425 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0) |
2426 (passthrough ? PA_SOURCE_OUTPUT_PASSTHROUGH : 0);
2428 s = record_stream_new(c, source, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, p, adjust_latency, early_requests, relative_volume, peak_detect, direct_on_input, &ret);
2430 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2432 reply = reply_new(tag);
2433 pa_tagstruct_putu32(reply, s->index);
2434 pa_assert(s->source_output);
2435 pa_tagstruct_putu32(reply, s->source_output->index);
2437 if (c->version >= 9) {
2438 /* Since 0.9 we support sending the buffer metrics back to the client */
2440 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2441 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2444 if (c->version >= 12) {
2445 /* Since 0.9.8 we support sending the chosen sample
2446 * spec/channel map/device/suspend status back to the
2447 * client */
2449 pa_tagstruct_put_sample_spec(reply, &ss);
2450 pa_tagstruct_put_channel_map(reply, &map);
2452 pa_tagstruct_putu32(reply, s->source_output->source->index);
2453 pa_tagstruct_puts(reply, s->source_output->source->name);
2455 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2458 if (c->version >= 13)
2459 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2461 if (c->version >= 22) {
2462 /* Send back the format we negotiated */
2463 if (s->source_output->format)
2464 pa_tagstruct_put_format_info(reply, s->source_output->format);
2465 else {
2466 pa_format_info *f = pa_format_info_new();
2467 pa_tagstruct_put_format_info(reply, f);
2468 pa_format_info_free(f);
2472 pa_pstream_send_tagstruct(c->pstream, reply);
2474 finish:
2475 if (p)
2476 pa_proplist_free(p);
2477 if (formats)
2478 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
2481 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2482 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2483 int ret;
2485 pa_native_connection_assert_ref(c);
2486 pa_assert(t);
2488 if (!pa_tagstruct_eof(t)) {
2489 protocol_error(c);
2490 return;
2493 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2494 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2495 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2497 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2499 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2502 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2503 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2504 const void*cookie;
2505 pa_tagstruct *reply;
2506 pa_bool_t shm_on_remote = FALSE, do_shm;
2508 pa_native_connection_assert_ref(c);
2509 pa_assert(t);
2511 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2512 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2513 !pa_tagstruct_eof(t)) {
2514 protocol_error(c);
2515 return;
2518 /* Minimum supported version */
2519 if (c->version < 8) {
2520 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2521 return;
2524 /* Starting with protocol version 13 the MSB of the version tag
2525 reflects if shm is available for this pa_native_connection or
2526 not. */
2527 if (c->version >= 13) {
2528 shm_on_remote = !!(c->version & 0x80000000U);
2529 c->version &= 0x7FFFFFFFU;
2532 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2534 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2536 if (!c->authorized) {
2537 pa_bool_t success = FALSE;
2539 #ifdef HAVE_CREDS
2540 const pa_creds *creds;
2542 if ((creds = pa_pdispatch_creds(pd))) {
2543 if (creds->uid == getuid())
2544 success = TRUE;
2545 else if (c->options->auth_group) {
2546 int r;
2547 gid_t gid;
2549 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2550 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2551 else if (gid == creds->gid)
2552 success = TRUE;
2554 if (!success) {
2555 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2556 pa_log_warn("Failed to check group membership.");
2557 else if (r > 0)
2558 success = TRUE;
2562 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2563 (unsigned long) creds->uid,
2564 (unsigned long) creds->gid,
2565 (int) success);
2567 #endif
2569 if (!success && c->options->auth_cookie) {
2570 const uint8_t *ac;
2572 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2573 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2574 success = TRUE;
2577 if (!success) {
2578 pa_log_warn("Denied access to client with invalid authorization data.");
2579 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2580 return;
2583 c->authorized = TRUE;
2584 if (c->auth_timeout_event) {
2585 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2586 c->auth_timeout_event = NULL;
2590 /* Enable shared memory support if possible */
2591 do_shm =
2592 pa_mempool_is_shared(c->protocol->core->mempool) &&
2593 c->is_local;
2595 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2597 if (do_shm)
2598 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2599 do_shm = FALSE;
2601 #ifdef HAVE_CREDS
2602 if (do_shm) {
2603 /* Only enable SHM if both sides are owned by the same
2604 * user. This is a security measure because otherwise data
2605 * private to the user might leak. */
2607 const pa_creds *creds;
2608 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2609 do_shm = FALSE;
2611 #endif
2613 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2614 pa_pstream_enable_shm(c->pstream, do_shm);
2616 reply = reply_new(tag);
2617 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2619 #ifdef HAVE_CREDS
2621 /* SHM support is only enabled after both sides made sure they are the same user. */
2623 pa_creds ucred;
2625 ucred.uid = getuid();
2626 ucred.gid = getgid();
2628 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2630 #else
2631 pa_pstream_send_tagstruct(c->pstream, reply);
2632 #endif
2635 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2636 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2637 const char *name = NULL;
2638 pa_proplist *p;
2639 pa_tagstruct *reply;
2641 pa_native_connection_assert_ref(c);
2642 pa_assert(t);
2644 p = pa_proplist_new();
2646 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2647 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2648 !pa_tagstruct_eof(t)) {
2650 protocol_error(c);
2651 pa_proplist_free(p);
2652 return;
2655 if (name)
2656 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2657 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2658 pa_proplist_free(p);
2659 return;
2662 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2663 pa_proplist_free(p);
2665 reply = reply_new(tag);
2667 if (c->version >= 13)
2668 pa_tagstruct_putu32(reply, c->client->index);
2670 pa_pstream_send_tagstruct(c->pstream, reply);
2673 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2674 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2675 const char *name;
2676 uint32_t idx = PA_IDXSET_INVALID;
2678 pa_native_connection_assert_ref(c);
2679 pa_assert(t);
2681 if (pa_tagstruct_gets(t, &name) < 0 ||
2682 !pa_tagstruct_eof(t)) {
2683 protocol_error(c);
2684 return;
2687 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2688 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);
2690 if (command == PA_COMMAND_LOOKUP_SINK) {
2691 pa_sink *sink;
2692 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2693 idx = sink->index;
2694 } else {
2695 pa_source *source;
2696 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2697 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2698 idx = source->index;
2701 if (idx == PA_IDXSET_INVALID)
2702 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2703 else {
2704 pa_tagstruct *reply;
2705 reply = reply_new(tag);
2706 pa_tagstruct_putu32(reply, idx);
2707 pa_pstream_send_tagstruct(c->pstream, reply);
2711 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2712 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2713 uint32_t idx;
2714 playback_stream *s;
2716 pa_native_connection_assert_ref(c);
2717 pa_assert(t);
2719 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2720 !pa_tagstruct_eof(t)) {
2721 protocol_error(c);
2722 return;
2725 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2726 s = pa_idxset_get_by_index(c->output_streams, idx);
2727 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2728 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2730 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);
2733 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2734 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2735 pa_tagstruct *reply;
2736 const pa_mempool_stat *stat;
2738 pa_native_connection_assert_ref(c);
2739 pa_assert(t);
2741 if (!pa_tagstruct_eof(t)) {
2742 protocol_error(c);
2743 return;
2746 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2748 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2750 reply = reply_new(tag);
2751 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2752 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2753 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2754 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2755 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2756 pa_pstream_send_tagstruct(c->pstream, reply);
2759 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2760 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2761 pa_tagstruct *reply;
2762 playback_stream *s;
2763 struct timeval tv, now;
2764 uint32_t idx;
2766 pa_native_connection_assert_ref(c);
2767 pa_assert(t);
2769 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2770 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2771 !pa_tagstruct_eof(t)) {
2772 protocol_error(c);
2773 return;
2776 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2777 s = pa_idxset_get_by_index(c->output_streams, idx);
2778 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2779 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2781 /* Get an atomic snapshot of all timing parameters */
2782 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);
2784 reply = reply_new(tag);
2785 pa_tagstruct_put_usec(reply,
2786 s->current_sink_latency +
2787 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2788 pa_tagstruct_put_usec(reply, 0);
2789 pa_tagstruct_put_boolean(reply,
2790 s->playing_for > 0 &&
2791 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2792 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2793 pa_tagstruct_put_timeval(reply, &tv);
2794 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2795 pa_tagstruct_puts64(reply, s->write_index);
2796 pa_tagstruct_puts64(reply, s->read_index);
2798 if (c->version >= 13) {
2799 pa_tagstruct_putu64(reply, s->underrun_for);
2800 pa_tagstruct_putu64(reply, s->playing_for);
2803 pa_pstream_send_tagstruct(c->pstream, reply);
2806 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2807 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2808 pa_tagstruct *reply;
2809 record_stream *s;
2810 struct timeval tv, now;
2811 uint32_t idx;
2813 pa_native_connection_assert_ref(c);
2814 pa_assert(t);
2816 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2817 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2818 !pa_tagstruct_eof(t)) {
2819 protocol_error(c);
2820 return;
2823 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2824 s = pa_idxset_get_by_index(c->record_streams, idx);
2825 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2827 /* Get an atomic snapshot of all timing parameters */
2828 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);
2830 reply = reply_new(tag);
2831 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2832 pa_tagstruct_put_usec(reply,
2833 s->current_source_latency +
2834 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec));
2835 pa_tagstruct_put_boolean(reply,
2836 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2837 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2838 pa_tagstruct_put_timeval(reply, &tv);
2839 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2840 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2841 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2842 pa_pstream_send_tagstruct(c->pstream, reply);
2845 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2846 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2847 upload_stream *s;
2848 uint32_t length;
2849 const char *name = NULL;
2850 pa_sample_spec ss;
2851 pa_channel_map map;
2852 pa_tagstruct *reply;
2853 pa_proplist *p;
2855 pa_native_connection_assert_ref(c);
2856 pa_assert(t);
2858 if (pa_tagstruct_gets(t, &name) < 0 ||
2859 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2860 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2861 pa_tagstruct_getu32(t, &length) < 0) {
2862 protocol_error(c);
2863 return;
2866 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2867 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2868 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2869 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2870 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2871 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2873 p = pa_proplist_new();
2875 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2876 !pa_tagstruct_eof(t)) {
2878 protocol_error(c);
2879 pa_proplist_free(p);
2880 return;
2883 if (c->version < 13)
2884 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2885 else if (!name)
2886 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2887 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2889 if (!name || !pa_namereg_is_valid_name(name)) {
2890 pa_proplist_free(p);
2891 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2894 s = upload_stream_new(c, &ss, &map, name, length, p);
2895 pa_proplist_free(p);
2897 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2899 reply = reply_new(tag);
2900 pa_tagstruct_putu32(reply, s->index);
2901 pa_tagstruct_putu32(reply, length);
2902 pa_pstream_send_tagstruct(c->pstream, reply);
2905 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2906 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2907 uint32_t channel;
2908 upload_stream *s;
2909 uint32_t idx;
2911 pa_native_connection_assert_ref(c);
2912 pa_assert(t);
2914 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2915 !pa_tagstruct_eof(t)) {
2916 protocol_error(c);
2917 return;
2920 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2922 s = pa_idxset_get_by_index(c->output_streams, channel);
2923 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2924 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2926 if (!s->memchunk.memblock)
2927 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2928 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2929 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2930 else
2931 pa_pstream_send_simple_ack(c->pstream, tag);
2933 upload_stream_unlink(s);
2936 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2937 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2938 uint32_t sink_index;
2939 pa_volume_t volume;
2940 pa_sink *sink;
2941 const char *name, *sink_name;
2942 uint32_t idx;
2943 pa_proplist *p;
2944 pa_tagstruct *reply;
2946 pa_native_connection_assert_ref(c);
2947 pa_assert(t);
2949 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2951 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2952 pa_tagstruct_gets(t, &sink_name) < 0 ||
2953 pa_tagstruct_getu32(t, &volume) < 0 ||
2954 pa_tagstruct_gets(t, &name) < 0) {
2955 protocol_error(c);
2956 return;
2959 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2960 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2961 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2962 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2964 if (sink_index != PA_INVALID_INDEX)
2965 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2966 else
2967 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2969 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2971 p = pa_proplist_new();
2973 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2974 !pa_tagstruct_eof(t)) {
2975 protocol_error(c);
2976 pa_proplist_free(p);
2977 return;
2980 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2982 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2983 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2984 pa_proplist_free(p);
2985 return;
2988 pa_proplist_free(p);
2990 reply = reply_new(tag);
2992 if (c->version >= 13)
2993 pa_tagstruct_putu32(reply, idx);
2995 pa_pstream_send_tagstruct(c->pstream, reply);
2998 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2999 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3000 const char *name;
3002 pa_native_connection_assert_ref(c);
3003 pa_assert(t);
3005 if (pa_tagstruct_gets(t, &name) < 0 ||
3006 !pa_tagstruct_eof(t)) {
3007 protocol_error(c);
3008 return;
3011 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3012 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3014 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
3015 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3016 return;
3019 pa_pstream_send_simple_ack(c->pstream, tag);
3022 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
3023 pa_assert(c);
3024 pa_assert(fixed);
3025 pa_assert(original);
3027 *fixed = *original;
3029 if (c->version < 12) {
3030 /* Before protocol version 12 we didn't support S32 samples,
3031 * so we need to lie about this to the client */
3033 if (fixed->format == PA_SAMPLE_S32LE)
3034 fixed->format = PA_SAMPLE_FLOAT32LE;
3035 if (fixed->format == PA_SAMPLE_S32BE)
3036 fixed->format = PA_SAMPLE_FLOAT32BE;
3039 if (c->version < 15) {
3040 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
3041 fixed->format = PA_SAMPLE_FLOAT32LE;
3042 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
3043 fixed->format = PA_SAMPLE_FLOAT32BE;
3047 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
3048 pa_sample_spec fixed_ss;
3050 pa_assert(t);
3051 pa_sink_assert_ref(sink);
3053 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
3055 pa_tagstruct_put(
3057 PA_TAG_U32, sink->index,
3058 PA_TAG_STRING, sink->name,
3059 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3060 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3061 PA_TAG_CHANNEL_MAP, &sink->channel_map,
3062 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
3063 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
3064 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
3065 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
3066 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
3067 PA_TAG_USEC, pa_sink_get_latency(sink),
3068 PA_TAG_STRING, sink->driver,
3069 PA_TAG_U32, sink->flags & PA_SINK_CLIENT_FLAGS_MASK,
3070 PA_TAG_INVALID);
3072 if (c->version >= 13) {
3073 pa_tagstruct_put_proplist(t, sink->proplist);
3074 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
3077 if (c->version >= 15) {
3078 pa_tagstruct_put_volume(t, sink->base_volume);
3079 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
3080 pa_log_error("Internal sink state is invalid.");
3081 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
3082 pa_tagstruct_putu32(t, sink->n_volume_steps);
3083 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
3086 if (c->version >= 16) {
3087 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
3089 if (sink->ports) {
3090 void *state;
3091 pa_device_port *p;
3093 PA_HASHMAP_FOREACH(p, sink->ports, state) {
3094 pa_tagstruct_puts(t, p->name);
3095 pa_tagstruct_puts(t, p->description);
3096 pa_tagstruct_putu32(t, p->priority);
3100 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
3103 if (c->version >= 21) {
3104 uint32_t i;
3105 pa_format_info *f;
3106 pa_idxset *formats = pa_sink_get_formats(sink);
3108 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3109 PA_IDXSET_FOREACH(f, formats, i) {
3110 pa_tagstruct_put_format_info(t, f);
3113 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
3117 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
3118 pa_sample_spec fixed_ss;
3120 pa_assert(t);
3121 pa_source_assert_ref(source);
3123 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
3125 pa_tagstruct_put(
3127 PA_TAG_U32, source->index,
3128 PA_TAG_STRING, source->name,
3129 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3130 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3131 PA_TAG_CHANNEL_MAP, &source->channel_map,
3132 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
3133 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
3134 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
3135 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
3136 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
3137 PA_TAG_USEC, pa_source_get_latency(source),
3138 PA_TAG_STRING, source->driver,
3139 PA_TAG_U32, source->flags & PA_SOURCE_CLIENT_FLAGS_MASK,
3140 PA_TAG_INVALID);
3142 if (c->version >= 13) {
3143 pa_tagstruct_put_proplist(t, source->proplist);
3144 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
3147 if (c->version >= 15) {
3148 pa_tagstruct_put_volume(t, source->base_volume);
3149 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
3150 pa_log_error("Internal source state is invalid.");
3151 pa_tagstruct_putu32(t, pa_source_get_state(source));
3152 pa_tagstruct_putu32(t, source->n_volume_steps);
3153 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
3156 if (c->version >= 16) {
3158 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
3160 if (source->ports) {
3161 void *state;
3162 pa_device_port *p;
3164 PA_HASHMAP_FOREACH(p, source->ports, state) {
3165 pa_tagstruct_puts(t, p->name);
3166 pa_tagstruct_puts(t, p->description);
3167 pa_tagstruct_putu32(t, p->priority);
3171 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
3174 if (c->version >= 22) {
3175 uint32_t i;
3176 pa_format_info *f;
3177 pa_idxset *formats = pa_source_get_formats(source);
3179 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3180 PA_IDXSET_FOREACH(f, formats, i) {
3181 pa_tagstruct_put_format_info(t, f);
3184 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
3188 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
3189 pa_assert(t);
3190 pa_assert(client);
3192 pa_tagstruct_putu32(t, client->index);
3193 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
3194 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
3195 pa_tagstruct_puts(t, client->driver);
3197 if (c->version >= 13)
3198 pa_tagstruct_put_proplist(t, client->proplist);
3201 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
3202 void *state = NULL;
3203 pa_card_profile *p;
3205 pa_assert(t);
3206 pa_assert(card);
3208 pa_tagstruct_putu32(t, card->index);
3209 pa_tagstruct_puts(t, card->name);
3210 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
3211 pa_tagstruct_puts(t, card->driver);
3213 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
3215 if (card->profiles) {
3216 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
3217 pa_tagstruct_puts(t, p->name);
3218 pa_tagstruct_puts(t, p->description);
3219 pa_tagstruct_putu32(t, p->n_sinks);
3220 pa_tagstruct_putu32(t, p->n_sources);
3221 pa_tagstruct_putu32(t, p->priority);
3225 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
3226 pa_tagstruct_put_proplist(t, card->proplist);
3229 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3230 pa_assert(t);
3231 pa_assert(module);
3233 pa_tagstruct_putu32(t, module->index);
3234 pa_tagstruct_puts(t, module->name);
3235 pa_tagstruct_puts(t, module->argument);
3236 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3238 if (c->version < 15)
3239 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
3241 if (c->version >= 15)
3242 pa_tagstruct_put_proplist(t, module->proplist);
3245 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3246 pa_sample_spec fixed_ss;
3247 pa_usec_t sink_latency;
3248 pa_cvolume v;
3249 pa_bool_t has_volume = FALSE;
3251 pa_assert(t);
3252 pa_sink_input_assert_ref(s);
3254 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3256 has_volume = pa_sink_input_is_volume_readable(s);
3257 if (has_volume)
3258 pa_sink_input_get_volume(s, &v, TRUE);
3259 else
3260 pa_cvolume_reset(&v, fixed_ss.channels);
3262 pa_tagstruct_putu32(t, s->index);
3263 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3264 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3265 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3266 pa_tagstruct_putu32(t, s->sink->index);
3267 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3268 pa_tagstruct_put_channel_map(t, &s->channel_map);
3269 pa_tagstruct_put_cvolume(t, &v);
3270 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3271 pa_tagstruct_put_usec(t, sink_latency);
3272 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3273 pa_tagstruct_puts(t, s->driver);
3274 if (c->version >= 11)
3275 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3276 if (c->version >= 13)
3277 pa_tagstruct_put_proplist(t, s->proplist);
3278 if (c->version >= 19)
3279 pa_tagstruct_put_boolean(t, (pa_sink_input_get_state(s) == PA_SINK_INPUT_CORKED));
3280 if (c->version >= 20) {
3281 pa_tagstruct_put_boolean(t, has_volume);
3282 pa_tagstruct_put_boolean(t, s->volume_writable);
3284 if (c->version >= 21)
3285 pa_tagstruct_put_format_info(t, s->format);
3288 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3289 pa_sample_spec fixed_ss;
3290 pa_usec_t source_latency;
3291 pa_cvolume v;
3292 pa_bool_t has_volume = FALSE;
3294 pa_assert(t);
3295 pa_source_output_assert_ref(s);
3297 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3299 has_volume = pa_source_output_is_volume_readable(s);
3300 if (has_volume)
3301 pa_source_output_get_volume(s, &v, TRUE);
3302 else
3303 pa_cvolume_reset(&v, fixed_ss.channels);
3305 pa_tagstruct_putu32(t, s->index);
3306 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3307 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3308 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3309 pa_tagstruct_putu32(t, s->source->index);
3310 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3311 pa_tagstruct_put_channel_map(t, &s->channel_map);
3312 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3313 pa_tagstruct_put_usec(t, source_latency);
3314 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3315 pa_tagstruct_puts(t, s->driver);
3316 if (c->version >= 13)
3317 pa_tagstruct_put_proplist(t, s->proplist);
3318 if (c->version >= 19)
3319 pa_tagstruct_put_boolean(t, (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_CORKED));
3320 if (c->version >= 22) {
3321 pa_tagstruct_put_cvolume(t, &v);
3322 pa_tagstruct_put_boolean(t, pa_source_output_get_mute(s));
3323 pa_tagstruct_put_boolean(t, has_volume);
3324 pa_tagstruct_put_boolean(t, s->volume_writable);
3325 pa_tagstruct_put_format_info(t, s->format);
3329 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3330 pa_sample_spec fixed_ss;
3331 pa_cvolume v;
3333 pa_assert(t);
3334 pa_assert(e);
3336 if (e->memchunk.memblock)
3337 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3338 else
3339 memset(&fixed_ss, 0, sizeof(fixed_ss));
3341 pa_tagstruct_putu32(t, e->index);
3342 pa_tagstruct_puts(t, e->name);
3344 if (e->volume_is_set)
3345 v = e->volume;
3346 else
3347 pa_cvolume_init(&v);
3349 pa_tagstruct_put_cvolume(t, &v);
3350 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3351 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3352 pa_tagstruct_put_channel_map(t, &e->channel_map);
3353 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3354 pa_tagstruct_put_boolean(t, e->lazy);
3355 pa_tagstruct_puts(t, e->filename);
3357 if (c->version >= 13)
3358 pa_tagstruct_put_proplist(t, e->proplist);
3361 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3362 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3363 uint32_t idx;
3364 pa_sink *sink = NULL;
3365 pa_source *source = NULL;
3366 pa_client *client = NULL;
3367 pa_card *card = NULL;
3368 pa_module *module = NULL;
3369 pa_sink_input *si = NULL;
3370 pa_source_output *so = NULL;
3371 pa_scache_entry *sce = NULL;
3372 const char *name = NULL;
3373 pa_tagstruct *reply;
3375 pa_native_connection_assert_ref(c);
3376 pa_assert(t);
3378 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3379 (command != PA_COMMAND_GET_CLIENT_INFO &&
3380 command != PA_COMMAND_GET_MODULE_INFO &&
3381 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3382 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3383 pa_tagstruct_gets(t, &name) < 0) ||
3384 !pa_tagstruct_eof(t)) {
3385 protocol_error(c);
3386 return;
3389 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3390 CHECK_VALIDITY(c->pstream, !name ||
3391 (command == PA_COMMAND_GET_SINK_INFO &&
3392 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3393 (command == PA_COMMAND_GET_SOURCE_INFO &&
3394 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3395 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3396 CHECK_VALIDITY(c->pstream, command == PA_COMMAND_GET_SINK_INFO ||
3397 command == PA_COMMAND_GET_SOURCE_INFO ||
3398 (idx != PA_INVALID_INDEX || name), tag, PA_ERR_INVALID);
3399 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3400 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3402 if (command == PA_COMMAND_GET_SINK_INFO) {
3403 if (idx != PA_INVALID_INDEX)
3404 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3405 else
3406 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3407 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3408 if (idx != PA_INVALID_INDEX)
3409 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3410 else
3411 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3412 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3413 if (idx != PA_INVALID_INDEX)
3414 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3415 else
3416 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3417 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3418 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3419 else if (command == PA_COMMAND_GET_MODULE_INFO)
3420 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3421 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3422 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3423 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3424 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3425 else {
3426 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3427 if (idx != PA_INVALID_INDEX)
3428 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3429 else
3430 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3433 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3434 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3435 return;
3438 reply = reply_new(tag);
3439 if (sink)
3440 sink_fill_tagstruct(c, reply, sink);
3441 else if (source)
3442 source_fill_tagstruct(c, reply, source);
3443 else if (client)
3444 client_fill_tagstruct(c, reply, client);
3445 else if (card)
3446 card_fill_tagstruct(c, reply, card);
3447 else if (module)
3448 module_fill_tagstruct(c, reply, module);
3449 else if (si)
3450 sink_input_fill_tagstruct(c, reply, si);
3451 else if (so)
3452 source_output_fill_tagstruct(c, reply, so);
3453 else
3454 scache_fill_tagstruct(c, reply, sce);
3455 pa_pstream_send_tagstruct(c->pstream, reply);
3458 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3459 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3460 pa_idxset *i;
3461 uint32_t idx;
3462 void *p;
3463 pa_tagstruct *reply;
3465 pa_native_connection_assert_ref(c);
3466 pa_assert(t);
3468 if (!pa_tagstruct_eof(t)) {
3469 protocol_error(c);
3470 return;
3473 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3475 reply = reply_new(tag);
3477 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3478 i = c->protocol->core->sinks;
3479 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3480 i = c->protocol->core->sources;
3481 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3482 i = c->protocol->core->clients;
3483 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3484 i = c->protocol->core->cards;
3485 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3486 i = c->protocol->core->modules;
3487 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3488 i = c->protocol->core->sink_inputs;
3489 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3490 i = c->protocol->core->source_outputs;
3491 else {
3492 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3493 i = c->protocol->core->scache;
3496 if (i) {
3497 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3498 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3499 sink_fill_tagstruct(c, reply, p);
3500 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3501 source_fill_tagstruct(c, reply, p);
3502 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3503 client_fill_tagstruct(c, reply, p);
3504 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3505 card_fill_tagstruct(c, reply, p);
3506 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3507 module_fill_tagstruct(c, reply, p);
3508 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3509 sink_input_fill_tagstruct(c, reply, p);
3510 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3511 source_output_fill_tagstruct(c, reply, p);
3512 else {
3513 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3514 scache_fill_tagstruct(c, reply, p);
3519 pa_pstream_send_tagstruct(c->pstream, reply);
3522 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3523 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3524 pa_tagstruct *reply;
3525 pa_sink *def_sink;
3526 pa_source *def_source;
3527 pa_sample_spec fixed_ss;
3528 char *h, *u;
3530 pa_native_connection_assert_ref(c);
3531 pa_assert(t);
3533 if (!pa_tagstruct_eof(t)) {
3534 protocol_error(c);
3535 return;
3538 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3540 reply = reply_new(tag);
3541 pa_tagstruct_puts(reply, PACKAGE_NAME);
3542 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3544 u = pa_get_user_name_malloc();
3545 pa_tagstruct_puts(reply, u);
3546 pa_xfree(u);
3548 h = pa_get_host_name_malloc();
3549 pa_tagstruct_puts(reply, h);
3550 pa_xfree(h);
3552 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3553 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3555 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3556 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3557 def_source = pa_namereg_get_default_source(c->protocol->core);
3558 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3560 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3562 if (c->version >= 15)
3563 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3565 pa_pstream_send_tagstruct(c->pstream, reply);
3568 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3569 pa_tagstruct *t;
3570 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3572 pa_native_connection_assert_ref(c);
3574 t = pa_tagstruct_new(NULL, 0);
3575 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3576 pa_tagstruct_putu32(t, (uint32_t) -1);
3577 pa_tagstruct_putu32(t, e);
3578 pa_tagstruct_putu32(t, idx);
3579 pa_pstream_send_tagstruct(c->pstream, t);
3582 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3583 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3584 pa_subscription_mask_t m;
3586 pa_native_connection_assert_ref(c);
3587 pa_assert(t);
3589 if (pa_tagstruct_getu32(t, &m) < 0 ||
3590 !pa_tagstruct_eof(t)) {
3591 protocol_error(c);
3592 return;
3595 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3596 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3598 if (c->subscription)
3599 pa_subscription_free(c->subscription);
3601 if (m != 0) {
3602 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3603 pa_assert(c->subscription);
3604 } else
3605 c->subscription = NULL;
3607 pa_pstream_send_simple_ack(c->pstream, tag);
3610 static void command_set_volume(
3611 pa_pdispatch *pd,
3612 uint32_t command,
3613 uint32_t tag,
3614 pa_tagstruct *t,
3615 void *userdata) {
3617 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3618 uint32_t idx;
3619 pa_cvolume volume;
3620 pa_sink *sink = NULL;
3621 pa_source *source = NULL;
3622 pa_sink_input *si = NULL;
3623 pa_source_output *so = NULL;
3624 const char *name = NULL;
3625 const char *client_name;
3627 pa_native_connection_assert_ref(c);
3628 pa_assert(t);
3630 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3631 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3632 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3633 pa_tagstruct_get_cvolume(t, &volume) ||
3634 !pa_tagstruct_eof(t)) {
3635 protocol_error(c);
3636 return;
3639 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3640 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);
3641 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3642 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3643 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3644 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3646 switch (command) {
3648 case PA_COMMAND_SET_SINK_VOLUME:
3649 if (idx != PA_INVALID_INDEX)
3650 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3651 else
3652 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3653 break;
3655 case PA_COMMAND_SET_SOURCE_VOLUME:
3656 if (idx != PA_INVALID_INDEX)
3657 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3658 else
3659 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3660 break;
3662 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3663 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3664 break;
3666 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME:
3667 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3668 break;
3670 default:
3671 pa_assert_not_reached();
3674 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
3676 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3678 if (sink) {
3679 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3681 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3682 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3683 } else if (source) {
3684 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3686 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3687 pa_source_set_volume(source, &volume, TRUE, TRUE);
3688 } else if (si) {
3689 CHECK_VALIDITY(c->pstream, si->volume_writable, tag, PA_ERR_BADSTATE);
3690 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3692 pa_log_debug("Client %s changes volume of sink input %s.",
3693 client_name,
3694 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3695 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3696 } else if (so) {
3697 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &so->sample_spec), tag, PA_ERR_INVALID);
3699 pa_log_debug("Client %s changes volume of source output %s.",
3700 client_name,
3701 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
3702 pa_source_output_set_volume(so, &volume, TRUE, TRUE);
3705 pa_pstream_send_simple_ack(c->pstream, tag);
3708 static void command_set_mute(
3709 pa_pdispatch *pd,
3710 uint32_t command,
3711 uint32_t tag,
3712 pa_tagstruct *t,
3713 void *userdata) {
3715 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3716 uint32_t idx;
3717 pa_bool_t mute;
3718 pa_sink *sink = NULL;
3719 pa_source *source = NULL;
3720 pa_sink_input *si = NULL;
3721 pa_source_output *so = NULL;
3722 const char *name = NULL, *client_name;
3724 pa_native_connection_assert_ref(c);
3725 pa_assert(t);
3727 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3728 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3729 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3730 pa_tagstruct_get_boolean(t, &mute) ||
3731 !pa_tagstruct_eof(t)) {
3732 protocol_error(c);
3733 return;
3736 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3737 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);
3738 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3739 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3740 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3742 switch (command) {
3744 case PA_COMMAND_SET_SINK_MUTE:
3745 if (idx != PA_INVALID_INDEX)
3746 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3747 else
3748 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3750 break;
3752 case PA_COMMAND_SET_SOURCE_MUTE:
3753 if (idx != PA_INVALID_INDEX)
3754 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3755 else
3756 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3758 break;
3760 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3761 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3762 break;
3764 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE:
3765 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3766 break;
3768 default:
3769 pa_assert_not_reached();
3772 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
3774 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3776 if (sink) {
3777 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3778 pa_sink_set_mute(sink, mute, TRUE);
3779 } else if (source) {
3780 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3781 pa_source_set_mute(source, mute, TRUE);
3782 } else if (si) {
3783 pa_log_debug("Client %s changes mute of sink input %s.",
3784 client_name,
3785 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3786 pa_sink_input_set_mute(si, mute, TRUE);
3787 } else if (so) {
3788 pa_log_debug("Client %s changes mute of source output %s.",
3789 client_name,
3790 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
3791 pa_source_output_set_mute(so, mute, TRUE);
3794 pa_pstream_send_simple_ack(c->pstream, tag);
3797 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3798 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3799 uint32_t idx;
3800 pa_bool_t b;
3801 playback_stream *s;
3803 pa_native_connection_assert_ref(c);
3804 pa_assert(t);
3806 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3807 pa_tagstruct_get_boolean(t, &b) < 0 ||
3808 !pa_tagstruct_eof(t)) {
3809 protocol_error(c);
3810 return;
3813 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3814 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3815 s = pa_idxset_get_by_index(c->output_streams, idx);
3816 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3817 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3819 pa_sink_input_cork(s->sink_input, b);
3821 if (b)
3822 s->is_underrun = TRUE;
3824 pa_pstream_send_simple_ack(c->pstream, tag);
3827 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3828 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3829 uint32_t idx;
3830 playback_stream *s;
3832 pa_native_connection_assert_ref(c);
3833 pa_assert(t);
3835 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3836 !pa_tagstruct_eof(t)) {
3837 protocol_error(c);
3838 return;
3841 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3842 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3843 s = pa_idxset_get_by_index(c->output_streams, idx);
3844 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3845 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3847 switch (command) {
3848 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3849 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3850 break;
3852 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3853 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3854 break;
3856 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3857 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3858 break;
3860 default:
3861 pa_assert_not_reached();
3864 pa_pstream_send_simple_ack(c->pstream, tag);
3867 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3868 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3869 uint32_t idx;
3870 record_stream *s;
3871 pa_bool_t b;
3873 pa_native_connection_assert_ref(c);
3874 pa_assert(t);
3876 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3877 pa_tagstruct_get_boolean(t, &b) < 0 ||
3878 !pa_tagstruct_eof(t)) {
3879 protocol_error(c);
3880 return;
3883 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3884 s = pa_idxset_get_by_index(c->record_streams, idx);
3885 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3887 pa_source_output_cork(s->source_output, b);
3888 pa_memblockq_prebuf_force(s->memblockq);
3889 pa_pstream_send_simple_ack(c->pstream, tag);
3892 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3893 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3894 uint32_t idx;
3895 record_stream *s;
3897 pa_native_connection_assert_ref(c);
3898 pa_assert(t);
3900 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3901 !pa_tagstruct_eof(t)) {
3902 protocol_error(c);
3903 return;
3906 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3907 s = pa_idxset_get_by_index(c->record_streams, idx);
3908 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3910 pa_memblockq_flush_read(s->memblockq);
3911 pa_pstream_send_simple_ack(c->pstream, tag);
3914 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3915 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3916 uint32_t idx;
3917 pa_buffer_attr a;
3918 pa_tagstruct *reply;
3920 pa_native_connection_assert_ref(c);
3921 pa_assert(t);
3923 memset(&a, 0, sizeof(a));
3925 if (pa_tagstruct_getu32(t, &idx) < 0) {
3926 protocol_error(c);
3927 return;
3930 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3932 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3933 playback_stream *s;
3934 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3936 s = pa_idxset_get_by_index(c->output_streams, idx);
3937 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3938 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3940 if (pa_tagstruct_get(
3942 PA_TAG_U32, &a.maxlength,
3943 PA_TAG_U32, &a.tlength,
3944 PA_TAG_U32, &a.prebuf,
3945 PA_TAG_U32, &a.minreq,
3946 PA_TAG_INVALID) < 0 ||
3947 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3948 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3949 !pa_tagstruct_eof(t)) {
3950 protocol_error(c);
3951 return;
3954 s->adjust_latency = adjust_latency;
3955 s->early_requests = early_requests;
3956 s->buffer_attr_req = a;
3958 fix_playback_buffer_attr(s);
3959 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);
3961 reply = reply_new(tag);
3962 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3963 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3964 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3965 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3967 if (c->version >= 13)
3968 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3970 } else {
3971 record_stream *s;
3972 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3973 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3975 s = pa_idxset_get_by_index(c->record_streams, idx);
3976 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3978 if (pa_tagstruct_get(
3980 PA_TAG_U32, &a.maxlength,
3981 PA_TAG_U32, &a.fragsize,
3982 PA_TAG_INVALID) < 0 ||
3983 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3984 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3985 !pa_tagstruct_eof(t)) {
3986 protocol_error(c);
3987 return;
3990 s->adjust_latency = adjust_latency;
3991 s->early_requests = early_requests;
3992 s->buffer_attr_req = a;
3994 fix_record_buffer_attr_pre(s);
3995 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3996 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3997 fix_record_buffer_attr_post(s);
3999 reply = reply_new(tag);
4000 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
4001 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
4003 if (c->version >= 13)
4004 pa_tagstruct_put_usec(reply, s->configured_source_latency);
4007 pa_pstream_send_tagstruct(c->pstream, reply);
4010 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4011 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4012 uint32_t idx;
4013 uint32_t rate;
4015 pa_native_connection_assert_ref(c);
4016 pa_assert(t);
4018 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4019 pa_tagstruct_getu32(t, &rate) < 0 ||
4020 !pa_tagstruct_eof(t)) {
4021 protocol_error(c);
4022 return;
4025 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4026 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
4028 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
4029 playback_stream *s;
4031 s = pa_idxset_get_by_index(c->output_streams, idx);
4032 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4033 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4035 pa_sink_input_set_rate(s->sink_input, rate);
4037 } else {
4038 record_stream *s;
4039 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
4041 s = pa_idxset_get_by_index(c->record_streams, idx);
4042 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4044 pa_source_output_set_rate(s->source_output, rate);
4047 pa_pstream_send_simple_ack(c->pstream, tag);
4050 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4051 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4052 uint32_t idx;
4053 uint32_t mode;
4054 pa_proplist *p;
4056 pa_native_connection_assert_ref(c);
4057 pa_assert(t);
4059 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4061 p = pa_proplist_new();
4063 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
4065 if (pa_tagstruct_getu32(t, &mode) < 0 ||
4066 pa_tagstruct_get_proplist(t, p) < 0 ||
4067 !pa_tagstruct_eof(t)) {
4068 protocol_error(c);
4069 pa_proplist_free(p);
4070 return;
4073 } else {
4075 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4076 pa_tagstruct_getu32(t, &mode) < 0 ||
4077 pa_tagstruct_get_proplist(t, p) < 0 ||
4078 !pa_tagstruct_eof(t)) {
4079 protocol_error(c);
4080 pa_proplist_free(p);
4081 return;
4085 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
4086 pa_proplist_free(p);
4087 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
4090 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
4091 playback_stream *s;
4093 s = pa_idxset_get_by_index(c->output_streams, idx);
4094 if (!s || !playback_stream_isinstance(s)) {
4095 pa_proplist_free(p);
4096 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
4098 pa_sink_input_update_proplist(s->sink_input, mode, p);
4100 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
4101 record_stream *s;
4103 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
4104 pa_proplist_free(p);
4105 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
4107 pa_source_output_update_proplist(s->source_output, mode, p);
4109 } else {
4110 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
4112 pa_client_update_proplist(c->client, mode, p);
4115 pa_pstream_send_simple_ack(c->pstream, tag);
4116 pa_proplist_free(p);
4119 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4120 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4121 uint32_t idx;
4122 unsigned changed = 0;
4123 pa_proplist *p;
4124 pa_strlist *l = NULL;
4126 pa_native_connection_assert_ref(c);
4127 pa_assert(t);
4129 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4131 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
4133 if (pa_tagstruct_getu32(t, &idx) < 0) {
4134 protocol_error(c);
4135 return;
4139 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4140 playback_stream *s;
4142 s = pa_idxset_get_by_index(c->output_streams, idx);
4143 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4144 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4146 p = s->sink_input->proplist;
4148 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4149 record_stream *s;
4151 s = pa_idxset_get_by_index(c->record_streams, idx);
4152 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4154 p = s->source_output->proplist;
4155 } else {
4156 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4158 p = c->client->proplist;
4161 for (;;) {
4162 const char *k;
4164 if (pa_tagstruct_gets(t, &k) < 0) {
4165 protocol_error(c);
4166 pa_strlist_free(l);
4167 return;
4170 if (!k)
4171 break;
4173 l = pa_strlist_prepend(l, k);
4176 if (!pa_tagstruct_eof(t)) {
4177 protocol_error(c);
4178 pa_strlist_free(l);
4179 return;
4182 for (;;) {
4183 char *z;
4185 l = pa_strlist_pop(l, &z);
4187 if (!z)
4188 break;
4190 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
4191 pa_xfree(z);
4194 pa_pstream_send_simple_ack(c->pstream, tag);
4196 if (changed) {
4197 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4198 playback_stream *s;
4200 s = pa_idxset_get_by_index(c->output_streams, idx);
4201 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
4203 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4204 record_stream *s;
4206 s = pa_idxset_get_by_index(c->record_streams, idx);
4207 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
4209 } else {
4210 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4211 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
4216 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4217 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4218 const char *s;
4220 pa_native_connection_assert_ref(c);
4221 pa_assert(t);
4223 if (pa_tagstruct_gets(t, &s) < 0 ||
4224 !pa_tagstruct_eof(t)) {
4225 protocol_error(c);
4226 return;
4229 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4230 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
4232 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
4233 pa_source *source;
4235 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
4236 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4238 pa_namereg_set_default_source(c->protocol->core, source);
4239 } else {
4240 pa_sink *sink;
4241 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
4243 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
4244 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4246 pa_namereg_set_default_sink(c->protocol->core, sink);
4249 pa_pstream_send_simple_ack(c->pstream, tag);
4252 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4253 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4254 uint32_t idx;
4255 const char *name;
4257 pa_native_connection_assert_ref(c);
4258 pa_assert(t);
4260 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4261 pa_tagstruct_gets(t, &name) < 0 ||
4262 !pa_tagstruct_eof(t)) {
4263 protocol_error(c);
4264 return;
4267 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4268 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
4270 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
4271 playback_stream *s;
4273 s = pa_idxset_get_by_index(c->output_streams, idx);
4274 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4275 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4277 pa_sink_input_set_name(s->sink_input, name);
4279 } else {
4280 record_stream *s;
4281 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4283 s = pa_idxset_get_by_index(c->record_streams, idx);
4284 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4286 pa_source_output_set_name(s->source_output, name);
4289 pa_pstream_send_simple_ack(c->pstream, tag);
4292 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4293 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4294 uint32_t idx;
4296 pa_native_connection_assert_ref(c);
4297 pa_assert(t);
4299 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4300 !pa_tagstruct_eof(t)) {
4301 protocol_error(c);
4302 return;
4305 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4307 if (command == PA_COMMAND_KILL_CLIENT) {
4308 pa_client *client;
4310 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4311 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4313 pa_native_connection_ref(c);
4314 pa_client_kill(client);
4316 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4317 pa_sink_input *s;
4319 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4320 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4322 pa_native_connection_ref(c);
4323 pa_sink_input_kill(s);
4324 } else {
4325 pa_source_output *s;
4327 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4329 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4330 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4332 pa_native_connection_ref(c);
4333 pa_source_output_kill(s);
4336 pa_pstream_send_simple_ack(c->pstream, tag);
4337 pa_native_connection_unref(c);
4340 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4341 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4342 pa_module *m;
4343 const char *name, *argument;
4344 pa_tagstruct *reply;
4346 pa_native_connection_assert_ref(c);
4347 pa_assert(t);
4349 if (pa_tagstruct_gets(t, &name) < 0 ||
4350 pa_tagstruct_gets(t, &argument) < 0 ||
4351 !pa_tagstruct_eof(t)) {
4352 protocol_error(c);
4353 return;
4356 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4357 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4358 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4360 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4361 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4362 return;
4365 reply = reply_new(tag);
4366 pa_tagstruct_putu32(reply, m->index);
4367 pa_pstream_send_tagstruct(c->pstream, reply);
4370 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4371 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4372 uint32_t idx;
4373 pa_module *m;
4375 pa_native_connection_assert_ref(c);
4376 pa_assert(t);
4378 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4379 !pa_tagstruct_eof(t)) {
4380 protocol_error(c);
4381 return;
4384 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4385 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4386 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4388 pa_module_unload_request(m, FALSE);
4389 pa_pstream_send_simple_ack(c->pstream, tag);
4392 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4393 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4394 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4395 const char *name_device = NULL;
4397 pa_native_connection_assert_ref(c);
4398 pa_assert(t);
4400 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4401 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4402 pa_tagstruct_gets(t, &name_device) < 0 ||
4403 !pa_tagstruct_eof(t)) {
4404 protocol_error(c);
4405 return;
4408 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4409 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4411 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);
4412 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4413 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4414 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4416 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4417 pa_sink_input *si = NULL;
4418 pa_sink *sink = NULL;
4420 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4422 if (idx_device != PA_INVALID_INDEX)
4423 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4424 else
4425 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4427 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4429 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4430 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4431 return;
4433 } else {
4434 pa_source_output *so = NULL;
4435 pa_source *source;
4437 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4439 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4441 if (idx_device != PA_INVALID_INDEX)
4442 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4443 else
4444 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4446 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4448 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4449 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4450 return;
4454 pa_pstream_send_simple_ack(c->pstream, tag);
4457 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4458 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4459 uint32_t idx = PA_INVALID_INDEX;
4460 const char *name = NULL;
4461 pa_bool_t b;
4463 pa_native_connection_assert_ref(c);
4464 pa_assert(t);
4466 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4467 pa_tagstruct_gets(t, &name) < 0 ||
4468 pa_tagstruct_get_boolean(t, &b) < 0 ||
4469 !pa_tagstruct_eof(t)) {
4470 protocol_error(c);
4471 return;
4474 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4475 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);
4476 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4477 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4478 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4480 if (command == PA_COMMAND_SUSPEND_SINK) {
4482 if (idx == PA_INVALID_INDEX && name && !*name) {
4484 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4486 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4487 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4488 return;
4490 } else {
4491 pa_sink *sink = NULL;
4493 if (idx != PA_INVALID_INDEX)
4494 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4495 else
4496 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4498 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4500 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4501 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4502 return;
4505 } else {
4507 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4509 if (idx == PA_INVALID_INDEX && name && !*name) {
4511 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4513 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4514 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4515 return;
4518 } else {
4519 pa_source *source;
4521 if (idx != PA_INVALID_INDEX)
4522 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4523 else
4524 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4526 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4528 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4529 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4530 return;
4535 pa_pstream_send_simple_ack(c->pstream, tag);
4538 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4539 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4540 uint32_t idx = PA_INVALID_INDEX;
4541 const char *name = NULL;
4542 pa_module *m;
4543 pa_native_protocol_ext_cb_t cb;
4545 pa_native_connection_assert_ref(c);
4546 pa_assert(t);
4548 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4549 pa_tagstruct_gets(t, &name) < 0) {
4550 protocol_error(c);
4551 return;
4554 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4555 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4556 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4557 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4558 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4560 if (idx != PA_INVALID_INDEX)
4561 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4562 else {
4563 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4564 if (strcmp(name, m->name) == 0)
4565 break;
4568 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4569 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4571 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4572 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4574 if (cb(c->protocol, m, c, tag, t) < 0)
4575 protocol_error(c);
4578 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4579 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4580 uint32_t idx = PA_INVALID_INDEX;
4581 const char *name = NULL, *profile = NULL;
4582 pa_card *card = NULL;
4583 int ret;
4585 pa_native_connection_assert_ref(c);
4586 pa_assert(t);
4588 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4589 pa_tagstruct_gets(t, &name) < 0 ||
4590 pa_tagstruct_gets(t, &profile) < 0 ||
4591 !pa_tagstruct_eof(t)) {
4592 protocol_error(c);
4593 return;
4596 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4597 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4598 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4599 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4600 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4602 if (idx != PA_INVALID_INDEX)
4603 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4604 else
4605 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4607 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4609 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4610 pa_pstream_send_error(c->pstream, tag, -ret);
4611 return;
4614 pa_pstream_send_simple_ack(c->pstream, tag);
4617 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4618 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4619 uint32_t idx = PA_INVALID_INDEX;
4620 const char *name = NULL, *port = NULL;
4621 int ret;
4623 pa_native_connection_assert_ref(c);
4624 pa_assert(t);
4626 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4627 pa_tagstruct_gets(t, &name) < 0 ||
4628 pa_tagstruct_gets(t, &port) < 0 ||
4629 !pa_tagstruct_eof(t)) {
4630 protocol_error(c);
4631 return;
4634 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4635 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);
4636 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4637 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4638 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4640 if (command == PA_COMMAND_SET_SINK_PORT) {
4641 pa_sink *sink;
4643 if (idx != PA_INVALID_INDEX)
4644 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4645 else
4646 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4648 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4650 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4651 pa_pstream_send_error(c->pstream, tag, -ret);
4652 return;
4654 } else {
4655 pa_source *source;
4657 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4659 if (idx != PA_INVALID_INDEX)
4660 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4661 else
4662 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4664 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4666 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4667 pa_pstream_send_error(c->pstream, tag, -ret);
4668 return;
4672 pa_pstream_send_simple_ack(c->pstream, tag);
4675 /*** pstream callbacks ***/
4677 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4678 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4680 pa_assert(p);
4681 pa_assert(packet);
4682 pa_native_connection_assert_ref(c);
4684 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4685 pa_log("invalid packet.");
4686 native_connection_unlink(c);
4690 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) {
4691 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4692 output_stream *stream;
4694 pa_assert(p);
4695 pa_assert(chunk);
4696 pa_native_connection_assert_ref(c);
4698 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4699 pa_log_debug("Client sent block for invalid stream.");
4700 /* Ignoring */
4701 return;
4704 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4706 if (playback_stream_isinstance(stream)) {
4707 playback_stream *ps = PLAYBACK_STREAM(stream);
4709 pa_atomic_inc(&ps->seek_or_post_in_queue);
4710 if (chunk->memblock) {
4711 if (seek != PA_SEEK_RELATIVE || offset != 0)
4712 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, chunk, NULL);
4713 else
4714 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4715 } else
4716 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset+chunk->length, NULL, NULL);
4718 } else {
4719 upload_stream *u = UPLOAD_STREAM(stream);
4720 size_t l;
4722 if (!u->memchunk.memblock) {
4723 if (u->length == chunk->length && chunk->memblock) {
4724 u->memchunk = *chunk;
4725 pa_memblock_ref(u->memchunk.memblock);
4726 u->length = 0;
4727 } else {
4728 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4729 u->memchunk.index = u->memchunk.length = 0;
4733 pa_assert(u->memchunk.memblock);
4735 l = u->length;
4736 if (l > chunk->length)
4737 l = chunk->length;
4739 if (l > 0) {
4740 void *dst;
4741 dst = pa_memblock_acquire(u->memchunk.memblock);
4743 if (chunk->memblock) {
4744 void *src;
4745 src = pa_memblock_acquire(chunk->memblock);
4747 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4748 (uint8_t*) src + chunk->index, l);
4750 pa_memblock_release(chunk->memblock);
4751 } else
4752 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4754 pa_memblock_release(u->memchunk.memblock);
4756 u->memchunk.length += l;
4757 u->length -= l;
4762 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4763 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4765 pa_assert(p);
4766 pa_native_connection_assert_ref(c);
4768 native_connection_unlink(c);
4769 pa_log_info("Connection died.");
4772 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4773 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4775 pa_assert(p);
4776 pa_native_connection_assert_ref(c);
4778 native_connection_send_memblock(c);
4781 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4782 pa_thread_mq *q;
4784 if (!(q = pa_thread_mq_get()))
4785 pa_pstream_send_revoke(p, block_id);
4786 else
4787 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4790 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4791 pa_thread_mq *q;
4793 if (!(q = pa_thread_mq_get()))
4794 pa_pstream_send_release(p, block_id);
4795 else
4796 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4799 /*** client callbacks ***/
4801 static void client_kill_cb(pa_client *c) {
4802 pa_assert(c);
4804 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4805 pa_log_info("Connection killed.");
4808 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4809 pa_tagstruct *t;
4810 pa_native_connection *c;
4812 pa_assert(client);
4813 c = PA_NATIVE_CONNECTION(client->userdata);
4814 pa_native_connection_assert_ref(c);
4816 if (c->version < 15)
4817 return;
4819 t = pa_tagstruct_new(NULL, 0);
4820 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4821 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4822 pa_tagstruct_puts(t, event);
4823 pa_tagstruct_put_proplist(t, pl);
4824 pa_pstream_send_tagstruct(c->pstream, t);
4827 /*** module entry points ***/
4829 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4830 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4832 pa_assert(m);
4833 pa_native_connection_assert_ref(c);
4834 pa_assert(c->auth_timeout_event == e);
4836 if (!c->authorized) {
4837 native_connection_unlink(c);
4838 pa_log_info("Connection terminated due to authentication timeout.");
4842 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4843 pa_native_connection *c;
4844 char pname[128];
4845 pa_client *client;
4846 pa_client_new_data data;
4848 pa_assert(p);
4849 pa_assert(io);
4850 pa_assert(o);
4852 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4853 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4854 pa_iochannel_free(io);
4855 return;
4858 pa_client_new_data_init(&data);
4859 data.module = o->module;
4860 data.driver = __FILE__;
4861 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4862 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4863 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4864 client = pa_client_new(p->core, &data);
4865 pa_client_new_data_done(&data);
4867 if (!client)
4868 return;
4870 c = pa_msgobject_new(pa_native_connection);
4871 c->parent.parent.free = native_connection_free;
4872 c->parent.process_msg = native_connection_process_msg;
4873 c->protocol = p;
4874 c->options = pa_native_options_ref(o);
4875 c->authorized = FALSE;
4877 if (o->auth_anonymous) {
4878 pa_log_info("Client authenticated anonymously.");
4879 c->authorized = TRUE;
4882 if (!c->authorized &&
4883 o->auth_ip_acl &&
4884 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4886 pa_log_info("Client authenticated by IP ACL.");
4887 c->authorized = TRUE;
4890 if (!c->authorized)
4891 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4892 else
4893 c->auth_timeout_event = NULL;
4895 c->is_local = pa_iochannel_socket_is_local(io);
4896 c->version = 8;
4898 c->client = client;
4899 c->client->kill = client_kill_cb;
4900 c->client->send_event = client_send_event_cb;
4901 c->client->userdata = c;
4903 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4904 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4905 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4906 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4907 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4908 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4909 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4911 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4913 c->record_streams = pa_idxset_new(NULL, NULL);
4914 c->output_streams = pa_idxset_new(NULL, NULL);
4916 c->rrobin_index = PA_IDXSET_INVALID;
4917 c->subscription = NULL;
4919 pa_idxset_put(p->connections, c, NULL);
4921 #ifdef HAVE_CREDS
4922 if (pa_iochannel_creds_supported(io))
4923 pa_iochannel_creds_enable(io);
4924 #endif
4926 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4929 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4930 pa_native_connection *c;
4931 void *state = NULL;
4933 pa_assert(p);
4934 pa_assert(m);
4936 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4937 if (c->options->module == m)
4938 native_connection_unlink(c);
4941 static pa_native_protocol* native_protocol_new(pa_core *c) {
4942 pa_native_protocol *p;
4943 pa_native_hook_t h;
4945 pa_assert(c);
4947 p = pa_xnew(pa_native_protocol, 1);
4948 PA_REFCNT_INIT(p);
4949 p->core = c;
4950 p->connections = pa_idxset_new(NULL, NULL);
4952 p->servers = NULL;
4954 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4956 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4957 pa_hook_init(&p->hooks[h], p);
4959 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4961 return p;
4964 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4965 pa_native_protocol *p;
4967 if ((p = pa_shared_get(c, "native-protocol")))
4968 return pa_native_protocol_ref(p);
4970 return native_protocol_new(c);
4973 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4974 pa_assert(p);
4975 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4977 PA_REFCNT_INC(p);
4979 return p;
4982 void pa_native_protocol_unref(pa_native_protocol *p) {
4983 pa_native_connection *c;
4984 pa_native_hook_t h;
4986 pa_assert(p);
4987 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4989 if (PA_REFCNT_DEC(p) > 0)
4990 return;
4992 while ((c = pa_idxset_first(p->connections, NULL)))
4993 native_connection_unlink(c);
4995 pa_idxset_free(p->connections, NULL, NULL);
4997 pa_strlist_free(p->servers);
4999 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
5000 pa_hook_done(&p->hooks[h]);
5002 pa_hashmap_free(p->extensions, NULL, NULL);
5004 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
5006 pa_xfree(p);
5009 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
5010 pa_assert(p);
5011 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5012 pa_assert(name);
5014 p->servers = pa_strlist_prepend(p->servers, name);
5016 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5019 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
5020 pa_assert(p);
5021 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5022 pa_assert(name);
5024 p->servers = pa_strlist_remove(p->servers, name);
5026 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5029 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
5030 pa_assert(p);
5031 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5033 return p->hooks;
5036 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
5037 pa_assert(p);
5038 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5040 return p->servers;
5043 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
5044 pa_assert(p);
5045 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5046 pa_assert(m);
5047 pa_assert(cb);
5048 pa_assert(!pa_hashmap_get(p->extensions, m));
5050 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
5051 return 0;
5054 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
5055 pa_assert(p);
5056 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5057 pa_assert(m);
5059 pa_assert_se(pa_hashmap_remove(p->extensions, m));
5062 pa_native_options* pa_native_options_new(void) {
5063 pa_native_options *o;
5065 o = pa_xnew0(pa_native_options, 1);
5066 PA_REFCNT_INIT(o);
5068 return o;
5071 pa_native_options* pa_native_options_ref(pa_native_options *o) {
5072 pa_assert(o);
5073 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5075 PA_REFCNT_INC(o);
5077 return o;
5080 void pa_native_options_unref(pa_native_options *o) {
5081 pa_assert(o);
5082 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5084 if (PA_REFCNT_DEC(o) > 0)
5085 return;
5087 pa_xfree(o->auth_group);
5089 if (o->auth_ip_acl)
5090 pa_ip_acl_free(o->auth_ip_acl);
5092 if (o->auth_cookie)
5093 pa_auth_cookie_unref(o->auth_cookie);
5095 pa_xfree(o);
5098 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
5099 pa_bool_t enabled;
5100 const char *acl;
5102 pa_assert(o);
5103 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5104 pa_assert(ma);
5106 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
5107 pa_log("auth-anonymous= expects a boolean argument.");
5108 return -1;
5111 enabled = TRUE;
5112 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
5113 pa_log("auth-group-enabled= expects a boolean argument.");
5114 return -1;
5117 pa_xfree(o->auth_group);
5118 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
5120 #ifndef HAVE_CREDS
5121 if (o->auth_group)
5122 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5123 #endif
5125 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
5126 pa_ip_acl *ipa;
5128 if (!(ipa = pa_ip_acl_new(acl))) {
5129 pa_log("Failed to parse IP ACL '%s'", acl);
5130 return -1;
5133 if (o->auth_ip_acl)
5134 pa_ip_acl_free(o->auth_ip_acl);
5136 o->auth_ip_acl = ipa;
5139 enabled = TRUE;
5140 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
5141 pa_log("auth-cookie-enabled= expects a boolean argument.");
5142 return -1;
5145 if (o->auth_cookie)
5146 pa_auth_cookie_unref(o->auth_cookie);
5148 if (enabled) {
5149 const char *cn;
5151 /* The new name for this is 'auth-cookie', for compat reasons
5152 * we check the old name too */
5153 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
5154 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
5155 cn = PA_NATIVE_COOKIE_FILE;
5157 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
5158 return -1;
5160 } else
5161 o->auth_cookie = NULL;
5163 return 0;
5166 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
5167 pa_native_connection_assert_ref(c);
5169 return c->pstream;
5172 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
5173 pa_native_connection_assert_ref(c);
5175 return c->client;