build-sys: Use ax_check_flag macros from autoconf archive
[pulseaudio-mirror.git] / src / pulsecore / protocol-native.c
blob6b98175444cff8169c448c1cbc17d0ce5fc094f4
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 pa_pstream_send_tagstruct(s->connection->pstream, t);
826 break;
829 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
830 pa_tagstruct *t;
832 /* Notify the user we're overflowed*/
833 t = pa_tagstruct_new(NULL, 0);
834 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
835 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
836 pa_tagstruct_putu32(t, s->index);
837 pa_pstream_send_tagstruct(s->connection->pstream, t);
838 break;
841 case PLAYBACK_STREAM_MESSAGE_STARTED:
843 if (s->connection->version >= 13) {
844 pa_tagstruct *t;
846 /* Notify the user we started playback */
847 t = pa_tagstruct_new(NULL, 0);
848 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
849 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
850 pa_tagstruct_putu32(t, s->index);
851 pa_pstream_send_tagstruct(s->connection->pstream, t);
854 break;
856 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
857 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
858 break;
860 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
862 s->buffer_attr.tlength = (uint32_t) offset;
864 if (s->connection->version >= 15) {
865 pa_tagstruct *t;
867 t = pa_tagstruct_new(NULL, 0);
868 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
869 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
870 pa_tagstruct_putu32(t, s->index);
871 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
872 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
873 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
874 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
875 pa_tagstruct_put_usec(t, s->configured_sink_latency);
876 pa_pstream_send_tagstruct(s->connection->pstream, t);
879 break;
882 return 0;
885 /* Called from main context */
886 static void fix_playback_buffer_attr(playback_stream *s) {
887 size_t frame_size, max_prebuf;
888 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
890 pa_assert(s);
892 /* pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", */
893 /* (long) s->buffer_attr.maxlength, */
894 /* (long) s->buffer_attr.tlength, */
895 /* (long) s->buffer_attr.minreq, */
896 /* (long) s->buffer_attr.prebuf); */
898 /* pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
899 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
900 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
901 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
902 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
904 /* This function will be called from the main thread, before as
905 * well as after the sink input has been activated using
906 * pa_sink_input_put()! That means it may not touch any
907 * ->thread_info data, such as the memblockq! */
909 frame_size = pa_frame_size(&s->sink_input->sample_spec);
910 s->buffer_attr = s->buffer_attr_req;
912 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
913 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
914 if (s->buffer_attr.maxlength <= 0)
915 s->buffer_attr.maxlength = (uint32_t) frame_size;
917 if (s->buffer_attr.tlength == (uint32_t) -1)
918 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
919 if (s->buffer_attr.tlength <= 0)
920 s->buffer_attr.tlength = (uint32_t) frame_size;
922 if (s->buffer_attr.minreq == (uint32_t) -1)
923 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
924 if (s->buffer_attr.minreq <= 0)
925 s->buffer_attr.minreq = (uint32_t) frame_size;
927 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
928 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
930 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
931 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
933 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
934 (double) tlength_usec / PA_USEC_PER_MSEC,
935 (double) minreq_usec / PA_USEC_PER_MSEC);
937 if (s->early_requests) {
939 /* In early request mode we need to emulate the classic
940 * fragment-based playback model. We do this setting the sink
941 * latency to the fragment size. */
943 sink_usec = minreq_usec;
944 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
946 } else if (s->adjust_latency) {
948 /* So, the user asked us to adjust the latency of the stream
949 * buffer according to the what the sink can provide. The
950 * tlength passed in shall be the overall latency. Roughly
951 * half the latency will be spent on the hw buffer, the other
952 * half of it in the async buffer queue we maintain for each
953 * client. In between we'll have a safety space of size
954 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
955 * empty and needs to be filled, then our buffer must have
956 * enough data to fulfill this request immediatly and thus
957 * have at least the same tlength as the size of the hw
958 * buffer. It additionally needs space for 2 times minreq
959 * because if the buffer ran empty and a partial fillup
960 * happens immediately on the next iteration we need to be
961 * able to fulfill it and give the application also minreq
962 * time to fill it up again for the next request Makes 2 times
963 * minreq in plus.. */
965 if (tlength_usec > minreq_usec*2)
966 sink_usec = (tlength_usec - minreq_usec*2)/2;
967 else
968 sink_usec = 0;
970 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
972 } else {
974 /* Ok, the user didn't ask us to adjust the latency, but we
975 * still need to make sure that the parameters from the user
976 * do make sense. */
978 if (tlength_usec > minreq_usec*2)
979 sink_usec = (tlength_usec - minreq_usec*2);
980 else
981 sink_usec = 0;
983 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
986 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
988 if (s->early_requests) {
990 /* Ok, we didn't necessarily get what we were asking for, so
991 * let's tell the user */
993 minreq_usec = s->configured_sink_latency;
995 } else if (s->adjust_latency) {
997 /* Ok, we didn't necessarily get what we were asking for, so
998 * let's subtract from what we asked for for the remaining
999 * buffer space */
1001 if (tlength_usec >= s->configured_sink_latency)
1002 tlength_usec -= s->configured_sink_latency;
1005 /* FIXME: This is actually larger than necessary, since not all of
1006 * the sink latency is actually rewritable. */
1007 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
1008 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
1010 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
1011 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
1012 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
1014 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
1015 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
1016 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
1018 if (s->buffer_attr.minreq <= 0) {
1019 s->buffer_attr.minreq = (uint32_t) frame_size;
1020 s->buffer_attr.tlength += (uint32_t) frame_size*2;
1023 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
1024 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
1026 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
1028 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
1029 s->buffer_attr.prebuf > max_prebuf)
1030 s->buffer_attr.prebuf = max_prebuf;
1032 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1033 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1034 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1035 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1036 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1039 /* Called from main context */
1040 static playback_stream* playback_stream_new(
1041 pa_native_connection *c,
1042 pa_sink *sink,
1043 pa_sample_spec *ss,
1044 pa_channel_map *map,
1045 pa_idxset *formats,
1046 pa_buffer_attr *a,
1047 pa_cvolume *volume,
1048 pa_bool_t muted,
1049 pa_bool_t muted_set,
1050 pa_sink_input_flags_t flags,
1051 pa_proplist *p,
1052 pa_bool_t adjust_latency,
1053 pa_bool_t early_requests,
1054 pa_bool_t relative_volume,
1055 uint32_t syncid,
1056 uint32_t *missing,
1057 int *ret) {
1059 /* Note: This function takes ownership of the 'formats' param, so we need
1060 * to take extra care to not leak it */
1062 playback_stream *s, *ssync;
1063 pa_sink_input *sink_input = NULL;
1064 pa_memchunk silence;
1065 uint32_t idx;
1066 int64_t start_index;
1067 pa_sink_input_new_data data;
1069 pa_assert(c);
1070 pa_assert(ss);
1071 pa_assert(missing);
1072 pa_assert(p);
1073 pa_assert(ret);
1075 /* Find syncid group */
1076 PA_IDXSET_FOREACH(ssync, c->output_streams, idx) {
1078 if (!playback_stream_isinstance(ssync))
1079 continue;
1081 if (ssync->syncid == syncid)
1082 break;
1085 /* Synced streams must connect to the same sink */
1086 if (ssync) {
1088 if (!sink)
1089 sink = ssync->sink_input->sink;
1090 else if (sink != ssync->sink_input->sink) {
1091 *ret = PA_ERR_INVALID;
1092 goto out;
1096 pa_sink_input_new_data_init(&data);
1098 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1099 data.driver = __FILE__;
1100 data.module = c->options->module;
1101 data.client = c->client;
1102 if (sink)
1103 pa_sink_input_new_data_set_sink(&data, sink, TRUE);
1104 if (pa_sample_spec_valid(ss))
1105 pa_sink_input_new_data_set_sample_spec(&data, ss);
1106 if (pa_channel_map_valid(map))
1107 pa_sink_input_new_data_set_channel_map(&data, map);
1108 if (formats) {
1109 pa_sink_input_new_data_set_formats(&data, formats);
1110 /* Ownership transferred to new_data, so we don't free it ourseleves */
1111 formats = NULL;
1113 if (volume) {
1114 pa_sink_input_new_data_set_volume(&data, volume);
1115 data.volume_is_absolute = !relative_volume;
1116 data.save_volume = TRUE;
1118 if (muted_set) {
1119 pa_sink_input_new_data_set_muted(&data, muted);
1120 data.save_muted = TRUE;
1122 data.sync_base = ssync ? ssync->sink_input : NULL;
1123 data.flags = flags;
1125 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1127 pa_sink_input_new_data_done(&data);
1129 if (!sink_input)
1130 goto out;
1132 s = pa_msgobject_new(playback_stream);
1133 s->parent.parent.parent.free = playback_stream_free;
1134 s->parent.parent.process_msg = playback_stream_process_msg;
1135 s->connection = c;
1136 s->syncid = syncid;
1137 s->sink_input = sink_input;
1138 s->is_underrun = TRUE;
1139 s->drain_request = FALSE;
1140 pa_atomic_store(&s->missing, 0);
1141 s->buffer_attr_req = *a;
1142 s->adjust_latency = adjust_latency;
1143 s->early_requests = early_requests;
1144 pa_atomic_store(&s->seek_or_post_in_queue, 0);
1145 s->seek_windex = -1;
1147 s->sink_input->parent.process_msg = sink_input_process_msg;
1148 s->sink_input->pop = sink_input_pop_cb;
1149 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1150 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1151 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1152 s->sink_input->kill = sink_input_kill_cb;
1153 s->sink_input->moving = sink_input_moving_cb;
1154 s->sink_input->suspend = sink_input_suspend_cb;
1155 s->sink_input->send_event = sink_input_send_event_cb;
1156 s->sink_input->userdata = s;
1158 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1160 fix_playback_buffer_attr(s);
1162 pa_sink_input_get_silence(sink_input, &silence);
1163 s->memblockq = pa_memblockq_new(
1164 start_index,
1165 s->buffer_attr.maxlength,
1166 s->buffer_attr.tlength,
1167 pa_frame_size(&sink_input->sample_spec),
1168 s->buffer_attr.prebuf,
1169 s->buffer_attr.minreq,
1171 &silence);
1172 pa_memblock_unref(silence.memblock);
1174 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1176 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1178 /* pa_log("missing original: %li", (long int) *missing); */
1180 *ss = s->sink_input->sample_spec;
1181 *map = s->sink_input->channel_map;
1183 pa_idxset_put(c->output_streams, s, &s->index);
1185 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1186 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1187 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1188 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1189 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1191 pa_sink_input_put(s->sink_input);
1193 out:
1194 if (formats)
1195 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
1197 return s;
1200 /* Called from IO context */
1201 static void playback_stream_request_bytes(playback_stream *s) {
1202 size_t m, minreq;
1203 int previous_missing;
1205 playback_stream_assert_ref(s);
1207 m = pa_memblockq_pop_missing(s->memblockq);
1209 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1210 /* (unsigned long) m, */
1211 /* pa_memblockq_get_tlength(s->memblockq), */
1212 /* pa_memblockq_get_minreq(s->memblockq), */
1213 /* pa_memblockq_get_length(s->memblockq), */
1214 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1216 if (m <= 0)
1217 return;
1219 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1221 previous_missing = pa_atomic_add(&s->missing, (int) m);
1222 minreq = pa_memblockq_get_minreq(s->memblockq);
1224 if (pa_memblockq_prebuf_active(s->memblockq) ||
1225 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1226 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1229 /* Called from main context */
1230 static void playback_stream_send_killed(playback_stream *p) {
1231 pa_tagstruct *t;
1232 playback_stream_assert_ref(p);
1234 t = pa_tagstruct_new(NULL, 0);
1235 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1236 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1237 pa_tagstruct_putu32(t, p->index);
1238 pa_pstream_send_tagstruct(p->connection->pstream, t);
1241 /* Called from main context */
1242 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1243 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1244 pa_native_connection_assert_ref(c);
1246 if (!c->protocol)
1247 return -1;
1249 switch (code) {
1251 case CONNECTION_MESSAGE_REVOKE:
1252 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1253 break;
1255 case CONNECTION_MESSAGE_RELEASE:
1256 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1257 break;
1260 return 0;
1263 /* Called from main context */
1264 static void native_connection_unlink(pa_native_connection *c) {
1265 record_stream *r;
1266 output_stream *o;
1268 pa_assert(c);
1270 if (!c->protocol)
1271 return;
1273 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1275 if (c->options)
1276 pa_native_options_unref(c->options);
1278 while ((r = pa_idxset_first(c->record_streams, NULL)))
1279 record_stream_unlink(r);
1281 while ((o = pa_idxset_first(c->output_streams, NULL)))
1282 if (playback_stream_isinstance(o))
1283 playback_stream_unlink(PLAYBACK_STREAM(o));
1284 else
1285 upload_stream_unlink(UPLOAD_STREAM(o));
1287 if (c->subscription)
1288 pa_subscription_free(c->subscription);
1290 if (c->pstream)
1291 pa_pstream_unlink(c->pstream);
1293 if (c->auth_timeout_event) {
1294 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1295 c->auth_timeout_event = NULL;
1298 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1299 c->protocol = NULL;
1300 pa_native_connection_unref(c);
1303 /* Called from main context */
1304 static void native_connection_free(pa_object *o) {
1305 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1307 pa_assert(c);
1309 native_connection_unlink(c);
1311 pa_idxset_free(c->record_streams, NULL, NULL);
1312 pa_idxset_free(c->output_streams, NULL, NULL);
1314 pa_pdispatch_unref(c->pdispatch);
1315 pa_pstream_unref(c->pstream);
1316 pa_client_free(c->client);
1318 pa_xfree(c);
1321 /* Called from main context */
1322 static void native_connection_send_memblock(pa_native_connection *c) {
1323 uint32_t start;
1324 record_stream *r;
1326 start = PA_IDXSET_INVALID;
1327 for (;;) {
1328 pa_memchunk chunk;
1330 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1331 return;
1333 if (start == PA_IDXSET_INVALID)
1334 start = c->rrobin_index;
1335 else if (start == c->rrobin_index)
1336 return;
1338 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1339 pa_memchunk schunk = chunk;
1341 if (schunk.length > r->buffer_attr.fragsize)
1342 schunk.length = r->buffer_attr.fragsize;
1344 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1346 pa_memblockq_drop(r->memblockq, schunk.length);
1347 pa_memblock_unref(schunk.memblock);
1349 return;
1354 /*** sink input callbacks ***/
1356 /* Called from thread context */
1357 static void handle_seek(playback_stream *s, int64_t indexw) {
1358 playback_stream_assert_ref(s);
1360 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1362 if (s->sink_input->thread_info.underrun_for > 0) {
1364 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1366 if (pa_memblockq_is_readable(s->memblockq)) {
1368 /* We just ended an underrun, let's ask the sink
1369 * for a complete rewind rewrite */
1371 pa_log_debug("Requesting rewind due to end of underrun.");
1372 pa_sink_input_request_rewind(s->sink_input,
1373 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1374 s->sink_input->thread_info.underrun_for),
1375 FALSE, TRUE, FALSE);
1378 } else {
1379 int64_t indexr;
1381 indexr = pa_memblockq_get_read_index(s->memblockq);
1383 if (indexw < indexr) {
1384 /* OK, the sink already asked for this data, so
1385 * let's have it usk us again */
1387 pa_log_debug("Requesting rewind due to rewrite.");
1388 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1392 playback_stream_request_bytes(s);
1395 static void flush_write_no_account(pa_memblockq *q) {
1396 pa_memblockq_flush_write(q, FALSE);
1399 /* Called from thread context */
1400 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1401 pa_sink_input *i = PA_SINK_INPUT(o);
1402 playback_stream *s;
1404 pa_sink_input_assert_ref(i);
1405 s = PLAYBACK_STREAM(i->userdata);
1406 playback_stream_assert_ref(s);
1408 switch (code) {
1410 case SINK_INPUT_MESSAGE_SEEK:
1411 case SINK_INPUT_MESSAGE_POST_DATA: {
1412 int64_t windex = pa_memblockq_get_write_index(s->memblockq);
1414 if (code == SINK_INPUT_MESSAGE_SEEK) {
1415 /* The client side is incapable of accounting correctly
1416 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1417 * able to deal with that. */
1419 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1420 windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
1423 if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1424 if (pa_log_ratelimit(PA_LOG_WARN))
1425 pa_log_warn("Failed to push data into queue");
1426 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1427 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1430 /* If more data is in queue, we rewind later instead. */
1431 if (s->seek_windex != -1)
1432 windex = PA_MIN(windex, s->seek_windex);
1433 if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
1434 s->seek_windex = windex;
1435 else {
1436 s->seek_windex = -1;
1437 handle_seek(s, windex);
1439 return 0;
1442 case SINK_INPUT_MESSAGE_DRAIN:
1443 case SINK_INPUT_MESSAGE_FLUSH:
1444 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1445 case SINK_INPUT_MESSAGE_TRIGGER: {
1447 int64_t windex;
1448 pa_sink_input *isync;
1449 void (*func)(pa_memblockq *bq);
1451 switch (code) {
1452 case SINK_INPUT_MESSAGE_FLUSH:
1453 func = flush_write_no_account;
1454 break;
1456 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1457 func = pa_memblockq_prebuf_force;
1458 break;
1460 case SINK_INPUT_MESSAGE_DRAIN:
1461 case SINK_INPUT_MESSAGE_TRIGGER:
1462 func = pa_memblockq_prebuf_disable;
1463 break;
1465 default:
1466 pa_assert_not_reached();
1469 windex = pa_memblockq_get_write_index(s->memblockq);
1470 func(s->memblockq);
1471 handle_seek(s, windex);
1473 /* Do the same for all other members in the sync group */
1474 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1475 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1476 windex = pa_memblockq_get_write_index(ssync->memblockq);
1477 func(ssync->memblockq);
1478 handle_seek(ssync, windex);
1481 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1482 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1483 windex = pa_memblockq_get_write_index(ssync->memblockq);
1484 func(ssync->memblockq);
1485 handle_seek(ssync, windex);
1488 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1489 if (!pa_memblockq_is_readable(s->memblockq))
1490 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1491 else {
1492 s->drain_tag = PA_PTR_TO_UINT(userdata);
1493 s->drain_request = TRUE;
1497 return 0;
1500 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1501 /* Atomically get a snapshot of all timing parameters... */
1502 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1503 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1504 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1505 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1506 s->underrun_for = s->sink_input->thread_info.underrun_for;
1507 s->playing_for = s->sink_input->thread_info.playing_for;
1509 return 0;
1511 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1512 int64_t windex;
1514 windex = pa_memblockq_get_write_index(s->memblockq);
1516 pa_memblockq_prebuf_force(s->memblockq);
1518 handle_seek(s, windex);
1520 /* Fall through to the default handler */
1521 break;
1524 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1525 pa_usec_t *r = userdata;
1527 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1529 /* Fall through, the default handler will add in the extra
1530 * latency added by the resampler */
1531 break;
1534 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1535 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1536 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1537 return 0;
1541 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1544 /* Called from thread context */
1545 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1546 playback_stream *s;
1548 pa_sink_input_assert_ref(i);
1549 s = PLAYBACK_STREAM(i->userdata);
1550 playback_stream_assert_ref(s);
1551 pa_assert(chunk);
1553 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1555 if (pa_memblockq_is_readable(s->memblockq))
1556 s->is_underrun = FALSE;
1557 else {
1558 if (!s->is_underrun)
1559 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));
1561 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1562 s->drain_request = FALSE;
1563 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);
1564 } else if (!s->is_underrun)
1565 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1567 s->is_underrun = TRUE;
1569 playback_stream_request_bytes(s);
1572 /* This call will not fail with prebuf=0, hence we check for
1573 underrun explicitly above */
1574 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1575 return -1;
1577 chunk->length = PA_MIN(nbytes, chunk->length);
1579 if (i->thread_info.underrun_for > 0)
1580 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1582 pa_memblockq_drop(s->memblockq, chunk->length);
1583 playback_stream_request_bytes(s);
1585 return 0;
1588 /* Called from thread context */
1589 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1590 playback_stream *s;
1592 pa_sink_input_assert_ref(i);
1593 s = PLAYBACK_STREAM(i->userdata);
1594 playback_stream_assert_ref(s);
1596 /* If we are in an underrun, then we don't rewind */
1597 if (i->thread_info.underrun_for > 0)
1598 return;
1600 pa_memblockq_rewind(s->memblockq, nbytes);
1603 /* Called from thread context */
1604 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1605 playback_stream *s;
1607 pa_sink_input_assert_ref(i);
1608 s = PLAYBACK_STREAM(i->userdata);
1609 playback_stream_assert_ref(s);
1611 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1614 /* Called from thread context */
1615 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1616 playback_stream *s;
1617 size_t new_tlength, old_tlength;
1619 pa_sink_input_assert_ref(i);
1620 s = PLAYBACK_STREAM(i->userdata);
1621 playback_stream_assert_ref(s);
1623 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1624 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1626 if (old_tlength < new_tlength) {
1627 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1628 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1629 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1631 if (new_tlength == old_tlength)
1632 pa_log_debug("Failed to increase tlength");
1633 else {
1634 pa_log_debug("Notifying client about increased tlength");
1635 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);
1640 /* Called from main context */
1641 static void sink_input_kill_cb(pa_sink_input *i) {
1642 playback_stream *s;
1644 pa_sink_input_assert_ref(i);
1645 s = PLAYBACK_STREAM(i->userdata);
1646 playback_stream_assert_ref(s);
1648 playback_stream_send_killed(s);
1649 playback_stream_unlink(s);
1652 /* Called from main context */
1653 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1654 playback_stream *s;
1655 pa_tagstruct *t;
1657 pa_sink_input_assert_ref(i);
1658 s = PLAYBACK_STREAM(i->userdata);
1659 playback_stream_assert_ref(s);
1661 if (s->connection->version < 15)
1662 return;
1664 t = pa_tagstruct_new(NULL, 0);
1665 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1666 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1667 pa_tagstruct_putu32(t, s->index);
1668 pa_tagstruct_puts(t, event);
1669 pa_tagstruct_put_proplist(t, pl);
1670 pa_pstream_send_tagstruct(s->connection->pstream, t);
1673 /* Called from main context */
1674 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1675 playback_stream *s;
1676 pa_tagstruct *t;
1678 pa_sink_input_assert_ref(i);
1679 s = PLAYBACK_STREAM(i->userdata);
1680 playback_stream_assert_ref(s);
1682 if (s->connection->version < 12)
1683 return;
1685 t = pa_tagstruct_new(NULL, 0);
1686 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1687 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1688 pa_tagstruct_putu32(t, s->index);
1689 pa_tagstruct_put_boolean(t, suspend);
1690 pa_pstream_send_tagstruct(s->connection->pstream, t);
1693 /* Called from main context */
1694 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1695 playback_stream *s;
1696 pa_tagstruct *t;
1698 pa_sink_input_assert_ref(i);
1699 s = PLAYBACK_STREAM(i->userdata);
1700 playback_stream_assert_ref(s);
1702 if (!dest)
1703 return;
1705 fix_playback_buffer_attr(s);
1706 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1707 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1709 if (s->connection->version < 12)
1710 return;
1712 t = pa_tagstruct_new(NULL, 0);
1713 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1714 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1715 pa_tagstruct_putu32(t, s->index);
1716 pa_tagstruct_putu32(t, dest->index);
1717 pa_tagstruct_puts(t, dest->name);
1718 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1720 if (s->connection->version >= 13) {
1721 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1722 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1723 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1724 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1725 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1728 pa_pstream_send_tagstruct(s->connection->pstream, t);
1731 /*** source_output callbacks ***/
1733 /* Called from thread context */
1734 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1735 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1736 record_stream *s;
1738 pa_source_output_assert_ref(o);
1739 s = RECORD_STREAM(o->userdata);
1740 record_stream_assert_ref(s);
1742 switch (code) {
1743 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1744 /* Atomically get a snapshot of all timing parameters... */
1745 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1746 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1747 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1748 return 0;
1751 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1754 /* Called from thread context */
1755 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1756 record_stream *s;
1758 pa_source_output_assert_ref(o);
1759 s = RECORD_STREAM(o->userdata);
1760 record_stream_assert_ref(s);
1761 pa_assert(chunk);
1763 pa_atomic_add(&s->on_the_fly, chunk->length);
1764 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1767 static void source_output_kill_cb(pa_source_output *o) {
1768 record_stream *s;
1770 pa_source_output_assert_ref(o);
1771 s = RECORD_STREAM(o->userdata);
1772 record_stream_assert_ref(s);
1774 record_stream_send_killed(s);
1775 record_stream_unlink(s);
1778 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1779 record_stream *s;
1781 pa_source_output_assert_ref(o);
1782 s = RECORD_STREAM(o->userdata);
1783 record_stream_assert_ref(s);
1785 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1787 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1790 /* Called from main context */
1791 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1792 record_stream *s;
1793 pa_tagstruct *t;
1795 pa_source_output_assert_ref(o);
1796 s = RECORD_STREAM(o->userdata);
1797 record_stream_assert_ref(s);
1799 if (s->connection->version < 15)
1800 return;
1802 t = pa_tagstruct_new(NULL, 0);
1803 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1804 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1805 pa_tagstruct_putu32(t, s->index);
1806 pa_tagstruct_puts(t, event);
1807 pa_tagstruct_put_proplist(t, pl);
1808 pa_pstream_send_tagstruct(s->connection->pstream, t);
1811 /* Called from main context */
1812 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1813 record_stream *s;
1814 pa_tagstruct *t;
1816 pa_source_output_assert_ref(o);
1817 s = RECORD_STREAM(o->userdata);
1818 record_stream_assert_ref(s);
1820 if (s->connection->version < 12)
1821 return;
1823 t = pa_tagstruct_new(NULL, 0);
1824 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1825 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1826 pa_tagstruct_putu32(t, s->index);
1827 pa_tagstruct_put_boolean(t, suspend);
1828 pa_pstream_send_tagstruct(s->connection->pstream, t);
1831 /* Called from main context */
1832 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1833 record_stream *s;
1834 pa_tagstruct *t;
1836 pa_source_output_assert_ref(o);
1837 s = RECORD_STREAM(o->userdata);
1838 record_stream_assert_ref(s);
1840 if (!dest)
1841 return;
1843 fix_record_buffer_attr_pre(s);
1844 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1845 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1846 fix_record_buffer_attr_post(s);
1848 if (s->connection->version < 12)
1849 return;
1851 t = pa_tagstruct_new(NULL, 0);
1852 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1853 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1854 pa_tagstruct_putu32(t, s->index);
1855 pa_tagstruct_putu32(t, dest->index);
1856 pa_tagstruct_puts(t, dest->name);
1857 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1859 if (s->connection->version >= 13) {
1860 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1861 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1862 pa_tagstruct_put_usec(t, s->configured_source_latency);
1865 pa_pstream_send_tagstruct(s->connection->pstream, t);
1868 /*** pdispatch callbacks ***/
1870 static void protocol_error(pa_native_connection *c) {
1871 pa_log("protocol error, kicking client");
1872 native_connection_unlink(c);
1875 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1876 if (!(expression)) { \
1877 pa_pstream_send_error((pstream), (tag), (error)); \
1878 return; \
1880 } while(0);
1882 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
1883 if (!(expression)) { \
1884 pa_pstream_send_error((pstream), (tag), (error)); \
1885 goto label; \
1887 } while(0);
1889 static pa_tagstruct *reply_new(uint32_t tag) {
1890 pa_tagstruct *reply;
1892 reply = pa_tagstruct_new(NULL, 0);
1893 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1894 pa_tagstruct_putu32(reply, tag);
1895 return reply;
1898 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1899 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1900 playback_stream *s;
1901 uint32_t sink_index, syncid, missing;
1902 pa_buffer_attr attr;
1903 const char *name = NULL, *sink_name;
1904 pa_sample_spec ss;
1905 pa_channel_map map;
1906 pa_tagstruct *reply;
1907 pa_sink *sink = NULL;
1908 pa_cvolume volume;
1909 pa_bool_t
1910 corked = FALSE,
1911 no_remap = FALSE,
1912 no_remix = FALSE,
1913 fix_format = FALSE,
1914 fix_rate = FALSE,
1915 fix_channels = FALSE,
1916 no_move = FALSE,
1917 variable_rate = FALSE,
1918 muted = FALSE,
1919 adjust_latency = FALSE,
1920 early_requests = FALSE,
1921 dont_inhibit_auto_suspend = FALSE,
1922 volume_set = TRUE,
1923 muted_set = FALSE,
1924 fail_on_suspend = FALSE,
1925 relative_volume = FALSE,
1926 passthrough = FALSE;
1928 pa_sink_input_flags_t flags = 0;
1929 pa_proplist *p = NULL;
1930 int ret = PA_ERR_INVALID;
1931 uint8_t n_formats = 0;
1932 pa_format_info *format;
1933 pa_idxset *formats = NULL;
1934 uint32_t i;
1936 pa_native_connection_assert_ref(c);
1937 pa_assert(t);
1938 memset(&attr, 0, sizeof(attr));
1940 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1941 pa_tagstruct_get(
1943 PA_TAG_SAMPLE_SPEC, &ss,
1944 PA_TAG_CHANNEL_MAP, &map,
1945 PA_TAG_U32, &sink_index,
1946 PA_TAG_STRING, &sink_name,
1947 PA_TAG_U32, &attr.maxlength,
1948 PA_TAG_BOOLEAN, &corked,
1949 PA_TAG_U32, &attr.tlength,
1950 PA_TAG_U32, &attr.prebuf,
1951 PA_TAG_U32, &attr.minreq,
1952 PA_TAG_U32, &syncid,
1953 PA_TAG_CVOLUME, &volume,
1954 PA_TAG_INVALID) < 0) {
1956 protocol_error(c);
1957 goto finish;
1960 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
1961 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID, finish);
1962 CHECK_VALIDITY_GOTO(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID, finish);
1963 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
1964 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
1966 p = pa_proplist_new();
1968 if (name)
1969 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1971 if (c->version >= 12) {
1972 /* Since 0.9.8 the user can ask for a couple of additional flags */
1974 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1975 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1976 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1977 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1978 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1979 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1980 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1982 protocol_error(c);
1983 goto finish;
1987 if (c->version >= 13) {
1989 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1990 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1991 pa_tagstruct_get_proplist(t, p) < 0) {
1993 protocol_error(c);
1994 goto finish;
1998 if (c->version >= 14) {
2000 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2001 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2003 protocol_error(c);
2004 goto finish;
2008 if (c->version >= 15) {
2010 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2011 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2012 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2014 protocol_error(c);
2015 goto finish;
2019 if (c->version >= 17) {
2021 if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
2023 protocol_error(c);
2024 goto finish;
2028 if (c->version >= 18) {
2030 if (pa_tagstruct_get_boolean(t, &passthrough) < 0 ) {
2031 protocol_error(c);
2032 goto finish;
2036 if (c->version >= 21) {
2038 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2039 protocol_error(c);
2040 goto finish;
2043 if (n_formats)
2044 formats = pa_idxset_new(NULL, NULL);
2046 for (i = 0; i < n_formats; i++) {
2047 format = pa_format_info_new();
2048 if (pa_tagstruct_get_format_info(t, format) < 0) {
2049 protocol_error(c);
2050 goto finish;
2052 pa_idxset_put(formats, format, NULL);
2056 if (n_formats == 0) {
2057 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2058 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2059 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2060 } else {
2061 PA_IDXSET_FOREACH(format, formats, i) {
2062 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2066 if (!pa_tagstruct_eof(t)) {
2067 protocol_error(c);
2068 goto finish;
2071 if (sink_index != PA_INVALID_INDEX) {
2073 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
2074 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2075 goto finish;
2078 } else if (sink_name) {
2080 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
2081 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2082 goto finish;
2086 flags =
2087 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
2088 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
2089 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
2090 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
2091 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
2092 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
2093 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
2094 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
2095 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2096 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
2097 (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0);
2099 /* Only since protocol version 15 there's a seperate muted_set
2100 * flag. For older versions we synthesize it here */
2101 muted_set = muted_set || muted;
2103 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);
2104 /* We no longer own the formats idxset */
2105 formats = NULL;
2107 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2109 reply = reply_new(tag);
2110 pa_tagstruct_putu32(reply, s->index);
2111 pa_assert(s->sink_input);
2112 pa_tagstruct_putu32(reply, s->sink_input->index);
2113 pa_tagstruct_putu32(reply, missing);
2115 /* pa_log("initial request is %u", missing); */
2117 if (c->version >= 9) {
2118 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2120 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2121 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2122 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2123 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2126 if (c->version >= 12) {
2127 /* Since 0.9.8 we support sending the chosen sample
2128 * spec/channel map/device/suspend status back to the
2129 * client */
2131 pa_tagstruct_put_sample_spec(reply, &ss);
2132 pa_tagstruct_put_channel_map(reply, &map);
2134 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2135 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2137 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2140 if (c->version >= 13)
2141 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2143 if (c->version >= 21) {
2144 /* Send back the format we negotiated */
2145 if (s->sink_input->format)
2146 pa_tagstruct_put_format_info(reply, s->sink_input->format);
2147 else {
2148 pa_format_info *f = pa_format_info_new();
2149 pa_tagstruct_put_format_info(reply, f);
2150 pa_format_info_free(f);
2154 pa_pstream_send_tagstruct(c->pstream, reply);
2156 finish:
2157 if (p)
2158 pa_proplist_free(p);
2159 if (formats)
2160 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
2163 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2164 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2165 uint32_t channel;
2167 pa_native_connection_assert_ref(c);
2168 pa_assert(t);
2170 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2171 !pa_tagstruct_eof(t)) {
2172 protocol_error(c);
2173 return;
2176 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2178 switch (command) {
2180 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2181 playback_stream *s;
2182 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2183 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2184 return;
2187 playback_stream_unlink(s);
2188 break;
2191 case PA_COMMAND_DELETE_RECORD_STREAM: {
2192 record_stream *s;
2193 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2194 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2195 return;
2198 record_stream_unlink(s);
2199 break;
2202 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2203 upload_stream *s;
2205 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2206 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2207 return;
2210 upload_stream_unlink(s);
2211 break;
2214 default:
2215 pa_assert_not_reached();
2218 pa_pstream_send_simple_ack(c->pstream, tag);
2221 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2222 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2223 record_stream *s;
2224 pa_buffer_attr attr;
2225 uint32_t source_index;
2226 const char *name = NULL, *source_name;
2227 pa_sample_spec ss;
2228 pa_channel_map map;
2229 pa_tagstruct *reply;
2230 pa_source *source = NULL;
2231 pa_cvolume volume;
2232 pa_bool_t
2233 corked = FALSE,
2234 no_remap = FALSE,
2235 no_remix = FALSE,
2236 fix_format = FALSE,
2237 fix_rate = FALSE,
2238 fix_channels = FALSE,
2239 no_move = FALSE,
2240 variable_rate = FALSE,
2241 muted = FALSE,
2242 adjust_latency = FALSE,
2243 peak_detect = FALSE,
2244 early_requests = FALSE,
2245 dont_inhibit_auto_suspend = FALSE,
2246 volume_set = TRUE,
2247 muted_set = FALSE,
2248 fail_on_suspend = FALSE,
2249 relative_volume = FALSE,
2250 passthrough = FALSE;
2252 pa_source_output_flags_t flags = 0;
2253 pa_proplist *p = NULL;
2254 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2255 pa_sink_input *direct_on_input = NULL;
2256 int ret = PA_ERR_INVALID;
2257 uint8_t n_formats = 0;
2258 pa_format_info *format;
2259 pa_idxset *formats = NULL;
2260 uint32_t i;
2262 pa_native_connection_assert_ref(c);
2263 pa_assert(t);
2265 memset(&attr, 0, sizeof(attr));
2267 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2268 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2269 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2270 pa_tagstruct_getu32(t, &source_index) < 0 ||
2271 pa_tagstruct_gets(t, &source_name) < 0 ||
2272 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2273 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2274 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2276 protocol_error(c);
2277 goto finish;
2280 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
2281 CHECK_VALIDITY_GOTO(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID, finish);
2282 CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID, finish);
2283 CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
2285 p = pa_proplist_new();
2287 if (name)
2288 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2290 if (c->version >= 12) {
2291 /* Since 0.9.8 the user can ask for a couple of additional flags */
2293 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2294 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2295 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2296 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2297 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2298 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2299 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2301 protocol_error(c);
2302 goto finish;
2306 if (c->version >= 13) {
2308 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2309 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2310 pa_tagstruct_get_proplist(t, p) < 0 ||
2311 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2313 protocol_error(c);
2314 goto finish;
2318 if (c->version >= 14) {
2320 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2321 protocol_error(c);
2322 goto finish;
2326 if (c->version >= 15) {
2328 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2329 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2331 protocol_error(c);
2332 goto finish;
2336 if (c->version >= 22) {
2338 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2339 protocol_error(c);
2340 goto finish;
2343 if (n_formats)
2344 formats = pa_idxset_new(NULL, NULL);
2346 for (i = 0; i < n_formats; i++) {
2347 format = pa_format_info_new();
2348 if (pa_tagstruct_get_format_info(t, format) < 0) {
2349 protocol_error(c);
2350 goto finish;
2352 pa_idxset_put(formats, format, NULL);
2355 if (pa_tagstruct_get_cvolume(t, &volume) < 0 ||
2356 pa_tagstruct_get_boolean(t, &muted) < 0 ||
2357 pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2358 pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2359 pa_tagstruct_get_boolean(t, &relative_volume) < 0 ||
2360 pa_tagstruct_get_boolean(t, &passthrough) < 0) {
2362 protocol_error(c);
2363 goto finish;
2366 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
2369 if (n_formats == 0) {
2370 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2371 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2372 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2373 } else {
2374 PA_IDXSET_FOREACH(format, formats, i) {
2375 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2380 if (!pa_tagstruct_eof(t)) {
2381 protocol_error(c);
2382 goto finish;
2385 if (source_index != PA_INVALID_INDEX) {
2387 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2388 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2389 goto finish;
2392 } else if (source_name) {
2394 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2395 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2396 goto finish;
2400 if (direct_on_input_idx != PA_INVALID_INDEX) {
2402 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2403 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2404 goto finish;
2408 flags =
2409 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2410 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2411 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2412 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2413 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2414 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2415 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2416 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2417 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2418 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0) |
2419 (passthrough ? PA_SOURCE_OUTPUT_PASSTHROUGH : 0);
2421 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);
2423 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2425 reply = reply_new(tag);
2426 pa_tagstruct_putu32(reply, s->index);
2427 pa_assert(s->source_output);
2428 pa_tagstruct_putu32(reply, s->source_output->index);
2430 if (c->version >= 9) {
2431 /* Since 0.9 we support sending the buffer metrics back to the client */
2433 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2434 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2437 if (c->version >= 12) {
2438 /* Since 0.9.8 we support sending the chosen sample
2439 * spec/channel map/device/suspend status back to the
2440 * client */
2442 pa_tagstruct_put_sample_spec(reply, &ss);
2443 pa_tagstruct_put_channel_map(reply, &map);
2445 pa_tagstruct_putu32(reply, s->source_output->source->index);
2446 pa_tagstruct_puts(reply, s->source_output->source->name);
2448 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2451 if (c->version >= 13)
2452 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2454 if (c->version >= 22) {
2455 /* Send back the format we negotiated */
2456 if (s->source_output->format)
2457 pa_tagstruct_put_format_info(reply, s->source_output->format);
2458 else {
2459 pa_format_info *f = pa_format_info_new();
2460 pa_tagstruct_put_format_info(reply, f);
2461 pa_format_info_free(f);
2465 pa_pstream_send_tagstruct(c->pstream, reply);
2467 finish:
2468 if (p)
2469 pa_proplist_free(p);
2470 if (formats)
2471 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
2474 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2475 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2476 int ret;
2478 pa_native_connection_assert_ref(c);
2479 pa_assert(t);
2481 if (!pa_tagstruct_eof(t)) {
2482 protocol_error(c);
2483 return;
2486 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2487 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2488 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2490 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2492 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2495 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2496 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2497 const void*cookie;
2498 pa_tagstruct *reply;
2499 pa_bool_t shm_on_remote = FALSE, do_shm;
2501 pa_native_connection_assert_ref(c);
2502 pa_assert(t);
2504 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2505 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2506 !pa_tagstruct_eof(t)) {
2507 protocol_error(c);
2508 return;
2511 /* Minimum supported version */
2512 if (c->version < 8) {
2513 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2514 return;
2517 /* Starting with protocol version 13 the MSB of the version tag
2518 reflects if shm is available for this pa_native_connection or
2519 not. */
2520 if (c->version >= 13) {
2521 shm_on_remote = !!(c->version & 0x80000000U);
2522 c->version &= 0x7FFFFFFFU;
2525 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2527 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2529 if (!c->authorized) {
2530 pa_bool_t success = FALSE;
2532 #ifdef HAVE_CREDS
2533 const pa_creds *creds;
2535 if ((creds = pa_pdispatch_creds(pd))) {
2536 if (creds->uid == getuid())
2537 success = TRUE;
2538 else if (c->options->auth_group) {
2539 int r;
2540 gid_t gid;
2542 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2543 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2544 else if (gid == creds->gid)
2545 success = TRUE;
2547 if (!success) {
2548 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2549 pa_log_warn("Failed to check group membership.");
2550 else if (r > 0)
2551 success = TRUE;
2555 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2556 (unsigned long) creds->uid,
2557 (unsigned long) creds->gid,
2558 (int) success);
2560 #endif
2562 if (!success && c->options->auth_cookie) {
2563 const uint8_t *ac;
2565 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2566 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2567 success = TRUE;
2570 if (!success) {
2571 pa_log_warn("Denied access to client with invalid authorization data.");
2572 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2573 return;
2576 c->authorized = TRUE;
2577 if (c->auth_timeout_event) {
2578 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2579 c->auth_timeout_event = NULL;
2583 /* Enable shared memory support if possible */
2584 do_shm =
2585 pa_mempool_is_shared(c->protocol->core->mempool) &&
2586 c->is_local;
2588 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2590 if (do_shm)
2591 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2592 do_shm = FALSE;
2594 #ifdef HAVE_CREDS
2595 if (do_shm) {
2596 /* Only enable SHM if both sides are owned by the same
2597 * user. This is a security measure because otherwise data
2598 * private to the user might leak. */
2600 const pa_creds *creds;
2601 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2602 do_shm = FALSE;
2604 #endif
2606 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2607 pa_pstream_enable_shm(c->pstream, do_shm);
2609 reply = reply_new(tag);
2610 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2612 #ifdef HAVE_CREDS
2614 /* SHM support is only enabled after both sides made sure they are the same user. */
2616 pa_creds ucred;
2618 ucred.uid = getuid();
2619 ucred.gid = getgid();
2621 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2623 #else
2624 pa_pstream_send_tagstruct(c->pstream, reply);
2625 #endif
2628 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2629 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2630 const char *name = NULL;
2631 pa_proplist *p;
2632 pa_tagstruct *reply;
2634 pa_native_connection_assert_ref(c);
2635 pa_assert(t);
2637 p = pa_proplist_new();
2639 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2640 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2641 !pa_tagstruct_eof(t)) {
2643 protocol_error(c);
2644 pa_proplist_free(p);
2645 return;
2648 if (name)
2649 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2650 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2651 pa_proplist_free(p);
2652 return;
2655 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2656 pa_proplist_free(p);
2658 reply = reply_new(tag);
2660 if (c->version >= 13)
2661 pa_tagstruct_putu32(reply, c->client->index);
2663 pa_pstream_send_tagstruct(c->pstream, reply);
2666 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2667 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2668 const char *name;
2669 uint32_t idx = PA_IDXSET_INVALID;
2671 pa_native_connection_assert_ref(c);
2672 pa_assert(t);
2674 if (pa_tagstruct_gets(t, &name) < 0 ||
2675 !pa_tagstruct_eof(t)) {
2676 protocol_error(c);
2677 return;
2680 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2681 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);
2683 if (command == PA_COMMAND_LOOKUP_SINK) {
2684 pa_sink *sink;
2685 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2686 idx = sink->index;
2687 } else {
2688 pa_source *source;
2689 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2690 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2691 idx = source->index;
2694 if (idx == PA_IDXSET_INVALID)
2695 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2696 else {
2697 pa_tagstruct *reply;
2698 reply = reply_new(tag);
2699 pa_tagstruct_putu32(reply, idx);
2700 pa_pstream_send_tagstruct(c->pstream, reply);
2704 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2705 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2706 uint32_t idx;
2707 playback_stream *s;
2709 pa_native_connection_assert_ref(c);
2710 pa_assert(t);
2712 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2713 !pa_tagstruct_eof(t)) {
2714 protocol_error(c);
2715 return;
2718 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2719 s = pa_idxset_get_by_index(c->output_streams, idx);
2720 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2721 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2723 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);
2726 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2727 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2728 pa_tagstruct *reply;
2729 const pa_mempool_stat *stat;
2731 pa_native_connection_assert_ref(c);
2732 pa_assert(t);
2734 if (!pa_tagstruct_eof(t)) {
2735 protocol_error(c);
2736 return;
2739 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2741 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2743 reply = reply_new(tag);
2744 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2745 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2746 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2747 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2748 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2749 pa_pstream_send_tagstruct(c->pstream, reply);
2752 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2753 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2754 pa_tagstruct *reply;
2755 playback_stream *s;
2756 struct timeval tv, now;
2757 uint32_t idx;
2759 pa_native_connection_assert_ref(c);
2760 pa_assert(t);
2762 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2763 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2764 !pa_tagstruct_eof(t)) {
2765 protocol_error(c);
2766 return;
2769 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2770 s = pa_idxset_get_by_index(c->output_streams, idx);
2771 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2772 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2774 /* Get an atomic snapshot of all timing parameters */
2775 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);
2777 reply = reply_new(tag);
2778 pa_tagstruct_put_usec(reply,
2779 s->current_sink_latency +
2780 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2781 pa_tagstruct_put_usec(reply, 0);
2782 pa_tagstruct_put_boolean(reply,
2783 s->playing_for > 0 &&
2784 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2785 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2786 pa_tagstruct_put_timeval(reply, &tv);
2787 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2788 pa_tagstruct_puts64(reply, s->write_index);
2789 pa_tagstruct_puts64(reply, s->read_index);
2791 if (c->version >= 13) {
2792 pa_tagstruct_putu64(reply, s->underrun_for);
2793 pa_tagstruct_putu64(reply, s->playing_for);
2796 pa_pstream_send_tagstruct(c->pstream, reply);
2799 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2800 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2801 pa_tagstruct *reply;
2802 record_stream *s;
2803 struct timeval tv, now;
2804 uint32_t idx;
2806 pa_native_connection_assert_ref(c);
2807 pa_assert(t);
2809 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2810 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2811 !pa_tagstruct_eof(t)) {
2812 protocol_error(c);
2813 return;
2816 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2817 s = pa_idxset_get_by_index(c->record_streams, idx);
2818 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2820 /* Get an atomic snapshot of all timing parameters */
2821 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);
2823 reply = reply_new(tag);
2824 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2825 pa_tagstruct_put_usec(reply,
2826 s->current_source_latency +
2827 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec));
2828 pa_tagstruct_put_boolean(reply,
2829 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2830 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2831 pa_tagstruct_put_timeval(reply, &tv);
2832 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2833 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2834 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2835 pa_pstream_send_tagstruct(c->pstream, reply);
2838 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2839 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2840 upload_stream *s;
2841 uint32_t length;
2842 const char *name = NULL;
2843 pa_sample_spec ss;
2844 pa_channel_map map;
2845 pa_tagstruct *reply;
2846 pa_proplist *p;
2848 pa_native_connection_assert_ref(c);
2849 pa_assert(t);
2851 if (pa_tagstruct_gets(t, &name) < 0 ||
2852 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2853 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2854 pa_tagstruct_getu32(t, &length) < 0) {
2855 protocol_error(c);
2856 return;
2859 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2860 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2861 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2862 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2863 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2864 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2866 p = pa_proplist_new();
2868 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2869 !pa_tagstruct_eof(t)) {
2871 protocol_error(c);
2872 pa_proplist_free(p);
2873 return;
2876 if (c->version < 13)
2877 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2878 else if (!name)
2879 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2880 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2882 if (!name || !pa_namereg_is_valid_name(name)) {
2883 pa_proplist_free(p);
2884 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2887 s = upload_stream_new(c, &ss, &map, name, length, p);
2888 pa_proplist_free(p);
2890 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2892 reply = reply_new(tag);
2893 pa_tagstruct_putu32(reply, s->index);
2894 pa_tagstruct_putu32(reply, length);
2895 pa_pstream_send_tagstruct(c->pstream, reply);
2898 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2899 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2900 uint32_t channel;
2901 upload_stream *s;
2902 uint32_t idx;
2904 pa_native_connection_assert_ref(c);
2905 pa_assert(t);
2907 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2908 !pa_tagstruct_eof(t)) {
2909 protocol_error(c);
2910 return;
2913 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2915 s = pa_idxset_get_by_index(c->output_streams, channel);
2916 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2917 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2919 if (!s->memchunk.memblock)
2920 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2921 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2922 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2923 else
2924 pa_pstream_send_simple_ack(c->pstream, tag);
2926 upload_stream_unlink(s);
2929 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2930 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2931 uint32_t sink_index;
2932 pa_volume_t volume;
2933 pa_sink *sink;
2934 const char *name, *sink_name;
2935 uint32_t idx;
2936 pa_proplist *p;
2937 pa_tagstruct *reply;
2939 pa_native_connection_assert_ref(c);
2940 pa_assert(t);
2942 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2944 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2945 pa_tagstruct_gets(t, &sink_name) < 0 ||
2946 pa_tagstruct_getu32(t, &volume) < 0 ||
2947 pa_tagstruct_gets(t, &name) < 0) {
2948 protocol_error(c);
2949 return;
2952 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2953 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2954 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2955 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2957 if (sink_index != PA_INVALID_INDEX)
2958 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2959 else
2960 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2962 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2964 p = pa_proplist_new();
2966 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2967 !pa_tagstruct_eof(t)) {
2968 protocol_error(c);
2969 pa_proplist_free(p);
2970 return;
2973 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2975 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2976 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2977 pa_proplist_free(p);
2978 return;
2981 pa_proplist_free(p);
2983 reply = reply_new(tag);
2985 if (c->version >= 13)
2986 pa_tagstruct_putu32(reply, idx);
2988 pa_pstream_send_tagstruct(c->pstream, reply);
2991 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2992 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2993 const char *name;
2995 pa_native_connection_assert_ref(c);
2996 pa_assert(t);
2998 if (pa_tagstruct_gets(t, &name) < 0 ||
2999 !pa_tagstruct_eof(t)) {
3000 protocol_error(c);
3001 return;
3004 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3005 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3007 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
3008 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3009 return;
3012 pa_pstream_send_simple_ack(c->pstream, tag);
3015 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
3016 pa_assert(c);
3017 pa_assert(fixed);
3018 pa_assert(original);
3020 *fixed = *original;
3022 if (c->version < 12) {
3023 /* Before protocol version 12 we didn't support S32 samples,
3024 * so we need to lie about this to the client */
3026 if (fixed->format == PA_SAMPLE_S32LE)
3027 fixed->format = PA_SAMPLE_FLOAT32LE;
3028 if (fixed->format == PA_SAMPLE_S32BE)
3029 fixed->format = PA_SAMPLE_FLOAT32BE;
3032 if (c->version < 15) {
3033 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
3034 fixed->format = PA_SAMPLE_FLOAT32LE;
3035 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
3036 fixed->format = PA_SAMPLE_FLOAT32BE;
3040 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
3041 pa_sample_spec fixed_ss;
3043 pa_assert(t);
3044 pa_sink_assert_ref(sink);
3046 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
3048 pa_tagstruct_put(
3050 PA_TAG_U32, sink->index,
3051 PA_TAG_STRING, sink->name,
3052 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3053 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3054 PA_TAG_CHANNEL_MAP, &sink->channel_map,
3055 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
3056 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
3057 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
3058 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
3059 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
3060 PA_TAG_USEC, pa_sink_get_latency(sink),
3061 PA_TAG_STRING, sink->driver,
3062 PA_TAG_U32, sink->flags & ~PA_SINK_SHARE_VOLUME_WITH_MASTER,
3063 PA_TAG_INVALID);
3065 if (c->version >= 13) {
3066 pa_tagstruct_put_proplist(t, sink->proplist);
3067 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
3070 if (c->version >= 15) {
3071 pa_tagstruct_put_volume(t, sink->base_volume);
3072 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
3073 pa_log_error("Internal sink state is invalid.");
3074 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
3075 pa_tagstruct_putu32(t, sink->n_volume_steps);
3076 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
3079 if (c->version >= 16) {
3080 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
3082 if (sink->ports) {
3083 void *state;
3084 pa_device_port *p;
3086 PA_HASHMAP_FOREACH(p, sink->ports, state) {
3087 pa_tagstruct_puts(t, p->name);
3088 pa_tagstruct_puts(t, p->description);
3089 pa_tagstruct_putu32(t, p->priority);
3093 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
3096 if (c->version >= 21) {
3097 uint32_t i;
3098 pa_format_info *f;
3099 pa_idxset *formats = pa_sink_get_formats(sink);
3101 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3102 PA_IDXSET_FOREACH(f, formats, i) {
3103 pa_tagstruct_put_format_info(t, f);
3106 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
3110 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
3111 pa_sample_spec fixed_ss;
3113 pa_assert(t);
3114 pa_source_assert_ref(source);
3116 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
3118 pa_tagstruct_put(
3120 PA_TAG_U32, source->index,
3121 PA_TAG_STRING, source->name,
3122 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3123 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3124 PA_TAG_CHANNEL_MAP, &source->channel_map,
3125 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
3126 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
3127 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
3128 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
3129 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
3130 PA_TAG_USEC, pa_source_get_latency(source),
3131 PA_TAG_STRING, source->driver,
3132 PA_TAG_U32, source->flags,
3133 PA_TAG_INVALID);
3135 if (c->version >= 13) {
3136 pa_tagstruct_put_proplist(t, source->proplist);
3137 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
3140 if (c->version >= 15) {
3141 pa_tagstruct_put_volume(t, source->base_volume);
3142 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
3143 pa_log_error("Internal source state is invalid.");
3144 pa_tagstruct_putu32(t, pa_source_get_state(source));
3145 pa_tagstruct_putu32(t, source->n_volume_steps);
3146 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
3149 if (c->version >= 16) {
3151 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
3153 if (source->ports) {
3154 void *state;
3155 pa_device_port *p;
3157 PA_HASHMAP_FOREACH(p, source->ports, state) {
3158 pa_tagstruct_puts(t, p->name);
3159 pa_tagstruct_puts(t, p->description);
3160 pa_tagstruct_putu32(t, p->priority);
3164 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
3167 if (c->version >= 22) {
3168 uint32_t i;
3169 pa_format_info *f;
3170 pa_idxset *formats = pa_source_get_formats(source);
3172 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3173 PA_IDXSET_FOREACH(f, formats, i) {
3174 pa_tagstruct_put_format_info(t, f);
3177 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
3181 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
3182 pa_assert(t);
3183 pa_assert(client);
3185 pa_tagstruct_putu32(t, client->index);
3186 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
3187 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
3188 pa_tagstruct_puts(t, client->driver);
3190 if (c->version >= 13)
3191 pa_tagstruct_put_proplist(t, client->proplist);
3194 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
3195 void *state = NULL;
3196 pa_card_profile *p;
3198 pa_assert(t);
3199 pa_assert(card);
3201 pa_tagstruct_putu32(t, card->index);
3202 pa_tagstruct_puts(t, card->name);
3203 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
3204 pa_tagstruct_puts(t, card->driver);
3206 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
3208 if (card->profiles) {
3209 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
3210 pa_tagstruct_puts(t, p->name);
3211 pa_tagstruct_puts(t, p->description);
3212 pa_tagstruct_putu32(t, p->n_sinks);
3213 pa_tagstruct_putu32(t, p->n_sources);
3214 pa_tagstruct_putu32(t, p->priority);
3218 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
3219 pa_tagstruct_put_proplist(t, card->proplist);
3222 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3223 pa_assert(t);
3224 pa_assert(module);
3226 pa_tagstruct_putu32(t, module->index);
3227 pa_tagstruct_puts(t, module->name);
3228 pa_tagstruct_puts(t, module->argument);
3229 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3231 if (c->version < 15)
3232 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
3234 if (c->version >= 15)
3235 pa_tagstruct_put_proplist(t, module->proplist);
3238 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3239 pa_sample_spec fixed_ss;
3240 pa_usec_t sink_latency;
3241 pa_cvolume v;
3242 pa_bool_t has_volume = FALSE;
3244 pa_assert(t);
3245 pa_sink_input_assert_ref(s);
3247 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3249 has_volume = pa_sink_input_is_volume_readable(s);
3250 if (has_volume)
3251 pa_sink_input_get_volume(s, &v, TRUE);
3252 else
3253 pa_cvolume_reset(&v, fixed_ss.channels);
3255 pa_tagstruct_putu32(t, s->index);
3256 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3257 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3258 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3259 pa_tagstruct_putu32(t, s->sink->index);
3260 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3261 pa_tagstruct_put_channel_map(t, &s->channel_map);
3262 pa_tagstruct_put_cvolume(t, &v);
3263 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3264 pa_tagstruct_put_usec(t, sink_latency);
3265 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3266 pa_tagstruct_puts(t, s->driver);
3267 if (c->version >= 11)
3268 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3269 if (c->version >= 13)
3270 pa_tagstruct_put_proplist(t, s->proplist);
3271 if (c->version >= 19)
3272 pa_tagstruct_put_boolean(t, (pa_sink_input_get_state(s) == PA_SINK_INPUT_CORKED));
3273 if (c->version >= 20) {
3274 pa_tagstruct_put_boolean(t, has_volume);
3275 pa_tagstruct_put_boolean(t, s->volume_writable);
3277 if (c->version >= 21)
3278 pa_tagstruct_put_format_info(t, s->format);
3281 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3282 pa_sample_spec fixed_ss;
3283 pa_usec_t source_latency;
3284 pa_cvolume v;
3285 pa_bool_t has_volume = FALSE;
3287 pa_assert(t);
3288 pa_source_output_assert_ref(s);
3290 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3292 has_volume = pa_source_output_is_volume_readable(s);
3293 if (has_volume)
3294 pa_source_output_get_volume(s, &v, TRUE);
3295 else
3296 pa_cvolume_reset(&v, fixed_ss.channels);
3298 pa_tagstruct_putu32(t, s->index);
3299 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3300 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3301 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3302 pa_tagstruct_putu32(t, s->source->index);
3303 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3304 pa_tagstruct_put_channel_map(t, &s->channel_map);
3305 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3306 pa_tagstruct_put_usec(t, source_latency);
3307 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3308 pa_tagstruct_puts(t, s->driver);
3309 if (c->version >= 13)
3310 pa_tagstruct_put_proplist(t, s->proplist);
3311 if (c->version >= 19)
3312 pa_tagstruct_put_boolean(t, (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_CORKED));
3313 if (c->version >= 22) {
3314 pa_tagstruct_put_cvolume(t, &v);
3315 pa_tagstruct_put_boolean(t, pa_source_output_get_mute(s));
3316 pa_tagstruct_put_boolean(t, has_volume);
3317 pa_tagstruct_put_boolean(t, s->volume_writable);
3318 pa_tagstruct_put_format_info(t, s->format);
3322 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3323 pa_sample_spec fixed_ss;
3324 pa_cvolume v;
3326 pa_assert(t);
3327 pa_assert(e);
3329 if (e->memchunk.memblock)
3330 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3331 else
3332 memset(&fixed_ss, 0, sizeof(fixed_ss));
3334 pa_tagstruct_putu32(t, e->index);
3335 pa_tagstruct_puts(t, e->name);
3337 if (e->volume_is_set)
3338 v = e->volume;
3339 else
3340 pa_cvolume_init(&v);
3342 pa_tagstruct_put_cvolume(t, &v);
3343 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3344 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3345 pa_tagstruct_put_channel_map(t, &e->channel_map);
3346 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3347 pa_tagstruct_put_boolean(t, e->lazy);
3348 pa_tagstruct_puts(t, e->filename);
3350 if (c->version >= 13)
3351 pa_tagstruct_put_proplist(t, e->proplist);
3354 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3355 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3356 uint32_t idx;
3357 pa_sink *sink = NULL;
3358 pa_source *source = NULL;
3359 pa_client *client = NULL;
3360 pa_card *card = NULL;
3361 pa_module *module = NULL;
3362 pa_sink_input *si = NULL;
3363 pa_source_output *so = NULL;
3364 pa_scache_entry *sce = NULL;
3365 const char *name = NULL;
3366 pa_tagstruct *reply;
3368 pa_native_connection_assert_ref(c);
3369 pa_assert(t);
3371 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3372 (command != PA_COMMAND_GET_CLIENT_INFO &&
3373 command != PA_COMMAND_GET_MODULE_INFO &&
3374 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3375 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3376 pa_tagstruct_gets(t, &name) < 0) ||
3377 !pa_tagstruct_eof(t)) {
3378 protocol_error(c);
3379 return;
3382 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3383 CHECK_VALIDITY(c->pstream, !name ||
3384 (command == PA_COMMAND_GET_SINK_INFO &&
3385 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3386 (command == PA_COMMAND_GET_SOURCE_INFO &&
3387 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3388 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3389 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3390 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3391 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3393 if (command == PA_COMMAND_GET_SINK_INFO) {
3394 if (idx != PA_INVALID_INDEX)
3395 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3396 else
3397 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3398 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3399 if (idx != PA_INVALID_INDEX)
3400 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3401 else
3402 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3403 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3404 if (idx != PA_INVALID_INDEX)
3405 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3406 else
3407 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3408 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3409 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3410 else if (command == PA_COMMAND_GET_MODULE_INFO)
3411 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3412 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3413 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3414 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3415 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3416 else {
3417 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3418 if (idx != PA_INVALID_INDEX)
3419 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3420 else
3421 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3424 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3425 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3426 return;
3429 reply = reply_new(tag);
3430 if (sink)
3431 sink_fill_tagstruct(c, reply, sink);
3432 else if (source)
3433 source_fill_tagstruct(c, reply, source);
3434 else if (client)
3435 client_fill_tagstruct(c, reply, client);
3436 else if (card)
3437 card_fill_tagstruct(c, reply, card);
3438 else if (module)
3439 module_fill_tagstruct(c, reply, module);
3440 else if (si)
3441 sink_input_fill_tagstruct(c, reply, si);
3442 else if (so)
3443 source_output_fill_tagstruct(c, reply, so);
3444 else
3445 scache_fill_tagstruct(c, reply, sce);
3446 pa_pstream_send_tagstruct(c->pstream, reply);
3449 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3450 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3451 pa_idxset *i;
3452 uint32_t idx;
3453 void *p;
3454 pa_tagstruct *reply;
3456 pa_native_connection_assert_ref(c);
3457 pa_assert(t);
3459 if (!pa_tagstruct_eof(t)) {
3460 protocol_error(c);
3461 return;
3464 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3466 reply = reply_new(tag);
3468 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3469 i = c->protocol->core->sinks;
3470 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3471 i = c->protocol->core->sources;
3472 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3473 i = c->protocol->core->clients;
3474 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3475 i = c->protocol->core->cards;
3476 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3477 i = c->protocol->core->modules;
3478 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3479 i = c->protocol->core->sink_inputs;
3480 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3481 i = c->protocol->core->source_outputs;
3482 else {
3483 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3484 i = c->protocol->core->scache;
3487 if (i) {
3488 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3489 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3490 sink_fill_tagstruct(c, reply, p);
3491 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3492 source_fill_tagstruct(c, reply, p);
3493 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3494 client_fill_tagstruct(c, reply, p);
3495 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3496 card_fill_tagstruct(c, reply, p);
3497 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3498 module_fill_tagstruct(c, reply, p);
3499 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3500 sink_input_fill_tagstruct(c, reply, p);
3501 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3502 source_output_fill_tagstruct(c, reply, p);
3503 else {
3504 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3505 scache_fill_tagstruct(c, reply, p);
3510 pa_pstream_send_tagstruct(c->pstream, reply);
3513 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3514 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3515 pa_tagstruct *reply;
3516 pa_sink *def_sink;
3517 pa_source *def_source;
3518 pa_sample_spec fixed_ss;
3519 char *h, *u;
3521 pa_native_connection_assert_ref(c);
3522 pa_assert(t);
3524 if (!pa_tagstruct_eof(t)) {
3525 protocol_error(c);
3526 return;
3529 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3531 reply = reply_new(tag);
3532 pa_tagstruct_puts(reply, PACKAGE_NAME);
3533 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3535 u = pa_get_user_name_malloc();
3536 pa_tagstruct_puts(reply, u);
3537 pa_xfree(u);
3539 h = pa_get_host_name_malloc();
3540 pa_tagstruct_puts(reply, h);
3541 pa_xfree(h);
3543 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3544 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3546 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3547 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3548 def_source = pa_namereg_get_default_source(c->protocol->core);
3549 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3551 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3553 if (c->version >= 15)
3554 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3556 pa_pstream_send_tagstruct(c->pstream, reply);
3559 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3560 pa_tagstruct *t;
3561 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3563 pa_native_connection_assert_ref(c);
3565 t = pa_tagstruct_new(NULL, 0);
3566 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3567 pa_tagstruct_putu32(t, (uint32_t) -1);
3568 pa_tagstruct_putu32(t, e);
3569 pa_tagstruct_putu32(t, idx);
3570 pa_pstream_send_tagstruct(c->pstream, t);
3573 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3574 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3575 pa_subscription_mask_t m;
3577 pa_native_connection_assert_ref(c);
3578 pa_assert(t);
3580 if (pa_tagstruct_getu32(t, &m) < 0 ||
3581 !pa_tagstruct_eof(t)) {
3582 protocol_error(c);
3583 return;
3586 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3587 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3589 if (c->subscription)
3590 pa_subscription_free(c->subscription);
3592 if (m != 0) {
3593 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3594 pa_assert(c->subscription);
3595 } else
3596 c->subscription = NULL;
3598 pa_pstream_send_simple_ack(c->pstream, tag);
3601 static void command_set_volume(
3602 pa_pdispatch *pd,
3603 uint32_t command,
3604 uint32_t tag,
3605 pa_tagstruct *t,
3606 void *userdata) {
3608 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3609 uint32_t idx;
3610 pa_cvolume volume;
3611 pa_sink *sink = NULL;
3612 pa_source *source = NULL;
3613 pa_sink_input *si = NULL;
3614 pa_source_output *so = NULL;
3615 const char *name = NULL;
3616 const char *client_name;
3618 pa_native_connection_assert_ref(c);
3619 pa_assert(t);
3621 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3622 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3623 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3624 pa_tagstruct_get_cvolume(t, &volume) ||
3625 !pa_tagstruct_eof(t)) {
3626 protocol_error(c);
3627 return;
3630 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3631 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);
3632 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3633 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3634 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3635 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3637 switch (command) {
3639 case PA_COMMAND_SET_SINK_VOLUME:
3640 if (idx != PA_INVALID_INDEX)
3641 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3642 else
3643 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3644 break;
3646 case PA_COMMAND_SET_SOURCE_VOLUME:
3647 if (idx != PA_INVALID_INDEX)
3648 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3649 else
3650 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3651 break;
3653 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3654 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3655 break;
3657 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME:
3658 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3659 break;
3661 default:
3662 pa_assert_not_reached();
3665 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
3667 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3669 if (sink) {
3670 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3672 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3673 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3674 } else if (source) {
3675 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3677 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3678 pa_source_set_volume(source, &volume, TRUE, TRUE);
3679 } else if (si) {
3680 CHECK_VALIDITY(c->pstream, si->volume_writable, tag, PA_ERR_BADSTATE);
3681 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3683 pa_log_debug("Client %s changes volume of sink input %s.",
3684 client_name,
3685 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3686 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3687 } else if (so) {
3688 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &so->sample_spec), tag, PA_ERR_INVALID);
3690 pa_log_debug("Client %s changes volume of source output %s.",
3691 client_name,
3692 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
3693 pa_source_output_set_volume(so, &volume, TRUE, TRUE);
3696 pa_pstream_send_simple_ack(c->pstream, tag);
3699 static void command_set_mute(
3700 pa_pdispatch *pd,
3701 uint32_t command,
3702 uint32_t tag,
3703 pa_tagstruct *t,
3704 void *userdata) {
3706 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3707 uint32_t idx;
3708 pa_bool_t mute;
3709 pa_sink *sink = NULL;
3710 pa_source *source = NULL;
3711 pa_sink_input *si = NULL;
3712 pa_source_output *so = NULL;
3713 const char *name = NULL, *client_name;
3715 pa_native_connection_assert_ref(c);
3716 pa_assert(t);
3718 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3719 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3720 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3721 pa_tagstruct_get_boolean(t, &mute) ||
3722 !pa_tagstruct_eof(t)) {
3723 protocol_error(c);
3724 return;
3727 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3728 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);
3729 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3730 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3731 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3733 switch (command) {
3735 case PA_COMMAND_SET_SINK_MUTE:
3736 if (idx != PA_INVALID_INDEX)
3737 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3738 else
3739 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3741 break;
3743 case PA_COMMAND_SET_SOURCE_MUTE:
3744 if (idx != PA_INVALID_INDEX)
3745 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3746 else
3747 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3749 break;
3751 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3752 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3753 break;
3755 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE:
3756 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3757 break;
3759 default:
3760 pa_assert_not_reached();
3763 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
3765 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3767 if (sink) {
3768 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3769 pa_sink_set_mute(sink, mute, TRUE);
3770 } else if (source) {
3771 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3772 pa_source_set_mute(source, mute, TRUE);
3773 } else if (si) {
3774 pa_log_debug("Client %s changes mute of sink input %s.",
3775 client_name,
3776 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3777 pa_sink_input_set_mute(si, mute, TRUE);
3778 } else if (so) {
3779 pa_log_debug("Client %s changes mute of source output %s.",
3780 client_name,
3781 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
3782 pa_source_output_set_mute(so, mute, TRUE);
3785 pa_pstream_send_simple_ack(c->pstream, tag);
3788 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3789 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3790 uint32_t idx;
3791 pa_bool_t b;
3792 playback_stream *s;
3794 pa_native_connection_assert_ref(c);
3795 pa_assert(t);
3797 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3798 pa_tagstruct_get_boolean(t, &b) < 0 ||
3799 !pa_tagstruct_eof(t)) {
3800 protocol_error(c);
3801 return;
3804 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3805 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3806 s = pa_idxset_get_by_index(c->output_streams, idx);
3807 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3808 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3810 pa_sink_input_cork(s->sink_input, b);
3812 if (b)
3813 s->is_underrun = TRUE;
3815 pa_pstream_send_simple_ack(c->pstream, tag);
3818 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3819 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3820 uint32_t idx;
3821 playback_stream *s;
3823 pa_native_connection_assert_ref(c);
3824 pa_assert(t);
3826 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3827 !pa_tagstruct_eof(t)) {
3828 protocol_error(c);
3829 return;
3832 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3833 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3834 s = pa_idxset_get_by_index(c->output_streams, idx);
3835 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3836 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3838 switch (command) {
3839 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3840 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3841 break;
3843 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3844 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3845 break;
3847 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3848 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3849 break;
3851 default:
3852 pa_assert_not_reached();
3855 pa_pstream_send_simple_ack(c->pstream, tag);
3858 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3859 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3860 uint32_t idx;
3861 record_stream *s;
3862 pa_bool_t b;
3864 pa_native_connection_assert_ref(c);
3865 pa_assert(t);
3867 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3868 pa_tagstruct_get_boolean(t, &b) < 0 ||
3869 !pa_tagstruct_eof(t)) {
3870 protocol_error(c);
3871 return;
3874 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3875 s = pa_idxset_get_by_index(c->record_streams, idx);
3876 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3878 pa_source_output_cork(s->source_output, b);
3879 pa_memblockq_prebuf_force(s->memblockq);
3880 pa_pstream_send_simple_ack(c->pstream, tag);
3883 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3884 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3885 uint32_t idx;
3886 record_stream *s;
3888 pa_native_connection_assert_ref(c);
3889 pa_assert(t);
3891 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3892 !pa_tagstruct_eof(t)) {
3893 protocol_error(c);
3894 return;
3897 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3898 s = pa_idxset_get_by_index(c->record_streams, idx);
3899 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3901 pa_memblockq_flush_read(s->memblockq);
3902 pa_pstream_send_simple_ack(c->pstream, tag);
3905 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3906 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3907 uint32_t idx;
3908 pa_buffer_attr a;
3909 pa_tagstruct *reply;
3911 pa_native_connection_assert_ref(c);
3912 pa_assert(t);
3914 memset(&a, 0, sizeof(a));
3916 if (pa_tagstruct_getu32(t, &idx) < 0) {
3917 protocol_error(c);
3918 return;
3921 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3923 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3924 playback_stream *s;
3925 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3927 s = pa_idxset_get_by_index(c->output_streams, idx);
3928 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3929 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3931 if (pa_tagstruct_get(
3933 PA_TAG_U32, &a.maxlength,
3934 PA_TAG_U32, &a.tlength,
3935 PA_TAG_U32, &a.prebuf,
3936 PA_TAG_U32, &a.minreq,
3937 PA_TAG_INVALID) < 0 ||
3938 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3939 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3940 !pa_tagstruct_eof(t)) {
3941 protocol_error(c);
3942 return;
3945 s->adjust_latency = adjust_latency;
3946 s->early_requests = early_requests;
3947 s->buffer_attr_req = a;
3949 fix_playback_buffer_attr(s);
3950 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);
3952 reply = reply_new(tag);
3953 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3954 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3955 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3956 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3958 if (c->version >= 13)
3959 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3961 } else {
3962 record_stream *s;
3963 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3964 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3966 s = pa_idxset_get_by_index(c->record_streams, idx);
3967 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3969 if (pa_tagstruct_get(
3971 PA_TAG_U32, &a.maxlength,
3972 PA_TAG_U32, &a.fragsize,
3973 PA_TAG_INVALID) < 0 ||
3974 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3975 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3976 !pa_tagstruct_eof(t)) {
3977 protocol_error(c);
3978 return;
3981 s->adjust_latency = adjust_latency;
3982 s->early_requests = early_requests;
3983 s->buffer_attr_req = a;
3985 fix_record_buffer_attr_pre(s);
3986 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3987 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3988 fix_record_buffer_attr_post(s);
3990 reply = reply_new(tag);
3991 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3992 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3994 if (c->version >= 13)
3995 pa_tagstruct_put_usec(reply, s->configured_source_latency);
3998 pa_pstream_send_tagstruct(c->pstream, reply);
4001 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4002 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4003 uint32_t idx;
4004 uint32_t rate;
4006 pa_native_connection_assert_ref(c);
4007 pa_assert(t);
4009 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4010 pa_tagstruct_getu32(t, &rate) < 0 ||
4011 !pa_tagstruct_eof(t)) {
4012 protocol_error(c);
4013 return;
4016 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4017 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
4019 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
4020 playback_stream *s;
4022 s = pa_idxset_get_by_index(c->output_streams, idx);
4023 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4024 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4026 pa_sink_input_set_rate(s->sink_input, rate);
4028 } else {
4029 record_stream *s;
4030 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
4032 s = pa_idxset_get_by_index(c->record_streams, idx);
4033 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4035 pa_source_output_set_rate(s->source_output, rate);
4038 pa_pstream_send_simple_ack(c->pstream, tag);
4041 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4042 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4043 uint32_t idx;
4044 uint32_t mode;
4045 pa_proplist *p;
4047 pa_native_connection_assert_ref(c);
4048 pa_assert(t);
4050 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4052 p = pa_proplist_new();
4054 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
4056 if (pa_tagstruct_getu32(t, &mode) < 0 ||
4057 pa_tagstruct_get_proplist(t, p) < 0 ||
4058 !pa_tagstruct_eof(t)) {
4059 protocol_error(c);
4060 pa_proplist_free(p);
4061 return;
4064 } else {
4066 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4067 pa_tagstruct_getu32(t, &mode) < 0 ||
4068 pa_tagstruct_get_proplist(t, p) < 0 ||
4069 !pa_tagstruct_eof(t)) {
4070 protocol_error(c);
4071 pa_proplist_free(p);
4072 return;
4076 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
4077 pa_proplist_free(p);
4078 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
4081 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
4082 playback_stream *s;
4084 s = pa_idxset_get_by_index(c->output_streams, idx);
4085 if (!s || !playback_stream_isinstance(s)) {
4086 pa_proplist_free(p);
4087 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
4089 pa_sink_input_update_proplist(s->sink_input, mode, p);
4091 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
4092 record_stream *s;
4094 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
4095 pa_proplist_free(p);
4096 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
4098 pa_source_output_update_proplist(s->source_output, mode, p);
4100 } else {
4101 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
4103 pa_client_update_proplist(c->client, mode, p);
4106 pa_pstream_send_simple_ack(c->pstream, tag);
4107 pa_proplist_free(p);
4110 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4111 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4112 uint32_t idx;
4113 unsigned changed = 0;
4114 pa_proplist *p;
4115 pa_strlist *l = NULL;
4117 pa_native_connection_assert_ref(c);
4118 pa_assert(t);
4120 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4122 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
4124 if (pa_tagstruct_getu32(t, &idx) < 0) {
4125 protocol_error(c);
4126 return;
4130 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4131 playback_stream *s;
4133 s = pa_idxset_get_by_index(c->output_streams, idx);
4134 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4135 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4137 p = s->sink_input->proplist;
4139 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4140 record_stream *s;
4142 s = pa_idxset_get_by_index(c->record_streams, idx);
4143 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4145 p = s->source_output->proplist;
4146 } else {
4147 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4149 p = c->client->proplist;
4152 for (;;) {
4153 const char *k;
4155 if (pa_tagstruct_gets(t, &k) < 0) {
4156 protocol_error(c);
4157 pa_strlist_free(l);
4158 return;
4161 if (!k)
4162 break;
4164 l = pa_strlist_prepend(l, k);
4167 if (!pa_tagstruct_eof(t)) {
4168 protocol_error(c);
4169 pa_strlist_free(l);
4170 return;
4173 for (;;) {
4174 char *z;
4176 l = pa_strlist_pop(l, &z);
4178 if (!z)
4179 break;
4181 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
4182 pa_xfree(z);
4185 pa_pstream_send_simple_ack(c->pstream, tag);
4187 if (changed) {
4188 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4189 playback_stream *s;
4191 s = pa_idxset_get_by_index(c->output_streams, idx);
4192 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
4194 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4195 record_stream *s;
4197 s = pa_idxset_get_by_index(c->record_streams, idx);
4198 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
4200 } else {
4201 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4202 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
4207 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4208 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4209 const char *s;
4211 pa_native_connection_assert_ref(c);
4212 pa_assert(t);
4214 if (pa_tagstruct_gets(t, &s) < 0 ||
4215 !pa_tagstruct_eof(t)) {
4216 protocol_error(c);
4217 return;
4220 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4221 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
4223 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
4224 pa_source *source;
4226 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
4227 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4229 pa_namereg_set_default_source(c->protocol->core, source);
4230 } else {
4231 pa_sink *sink;
4232 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
4234 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
4235 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4237 pa_namereg_set_default_sink(c->protocol->core, sink);
4240 pa_pstream_send_simple_ack(c->pstream, tag);
4243 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4244 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4245 uint32_t idx;
4246 const char *name;
4248 pa_native_connection_assert_ref(c);
4249 pa_assert(t);
4251 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4252 pa_tagstruct_gets(t, &name) < 0 ||
4253 !pa_tagstruct_eof(t)) {
4254 protocol_error(c);
4255 return;
4258 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4259 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
4261 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
4262 playback_stream *s;
4264 s = pa_idxset_get_by_index(c->output_streams, idx);
4265 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4266 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4268 pa_sink_input_set_name(s->sink_input, name);
4270 } else {
4271 record_stream *s;
4272 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4274 s = pa_idxset_get_by_index(c->record_streams, idx);
4275 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4277 pa_source_output_set_name(s->source_output, name);
4280 pa_pstream_send_simple_ack(c->pstream, tag);
4283 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4284 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4285 uint32_t idx;
4287 pa_native_connection_assert_ref(c);
4288 pa_assert(t);
4290 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4291 !pa_tagstruct_eof(t)) {
4292 protocol_error(c);
4293 return;
4296 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4298 if (command == PA_COMMAND_KILL_CLIENT) {
4299 pa_client *client;
4301 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4302 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4304 pa_native_connection_ref(c);
4305 pa_client_kill(client);
4307 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4308 pa_sink_input *s;
4310 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4311 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4313 pa_native_connection_ref(c);
4314 pa_sink_input_kill(s);
4315 } else {
4316 pa_source_output *s;
4318 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4320 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4321 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4323 pa_native_connection_ref(c);
4324 pa_source_output_kill(s);
4327 pa_pstream_send_simple_ack(c->pstream, tag);
4328 pa_native_connection_unref(c);
4331 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4332 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4333 pa_module *m;
4334 const char *name, *argument;
4335 pa_tagstruct *reply;
4337 pa_native_connection_assert_ref(c);
4338 pa_assert(t);
4340 if (pa_tagstruct_gets(t, &name) < 0 ||
4341 pa_tagstruct_gets(t, &argument) < 0 ||
4342 !pa_tagstruct_eof(t)) {
4343 protocol_error(c);
4344 return;
4347 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4348 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4349 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4351 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4352 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4353 return;
4356 reply = reply_new(tag);
4357 pa_tagstruct_putu32(reply, m->index);
4358 pa_pstream_send_tagstruct(c->pstream, reply);
4361 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4362 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4363 uint32_t idx;
4364 pa_module *m;
4366 pa_native_connection_assert_ref(c);
4367 pa_assert(t);
4369 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4370 !pa_tagstruct_eof(t)) {
4371 protocol_error(c);
4372 return;
4375 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4376 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4377 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4379 pa_module_unload_request(m, FALSE);
4380 pa_pstream_send_simple_ack(c->pstream, tag);
4383 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4384 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4385 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4386 const char *name_device = NULL;
4388 pa_native_connection_assert_ref(c);
4389 pa_assert(t);
4391 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4392 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4393 pa_tagstruct_gets(t, &name_device) < 0 ||
4394 !pa_tagstruct_eof(t)) {
4395 protocol_error(c);
4396 return;
4399 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4400 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4402 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);
4403 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4404 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4405 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4407 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4408 pa_sink_input *si = NULL;
4409 pa_sink *sink = NULL;
4411 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4413 if (idx_device != PA_INVALID_INDEX)
4414 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4415 else
4416 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4418 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4420 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4421 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4422 return;
4424 } else {
4425 pa_source_output *so = NULL;
4426 pa_source *source;
4428 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4430 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4432 if (idx_device != PA_INVALID_INDEX)
4433 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4434 else
4435 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4437 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4439 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4440 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4441 return;
4445 pa_pstream_send_simple_ack(c->pstream, tag);
4448 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4449 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4450 uint32_t idx = PA_INVALID_INDEX;
4451 const char *name = NULL;
4452 pa_bool_t b;
4454 pa_native_connection_assert_ref(c);
4455 pa_assert(t);
4457 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4458 pa_tagstruct_gets(t, &name) < 0 ||
4459 pa_tagstruct_get_boolean(t, &b) < 0 ||
4460 !pa_tagstruct_eof(t)) {
4461 protocol_error(c);
4462 return;
4465 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4466 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);
4467 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4468 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4469 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4471 if (command == PA_COMMAND_SUSPEND_SINK) {
4473 if (idx == PA_INVALID_INDEX && name && !*name) {
4475 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4477 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4478 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4479 return;
4481 } else {
4482 pa_sink *sink = NULL;
4484 if (idx != PA_INVALID_INDEX)
4485 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4486 else
4487 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4489 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4491 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4492 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4493 return;
4496 } else {
4498 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4500 if (idx == PA_INVALID_INDEX && name && !*name) {
4502 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4504 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4505 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4506 return;
4509 } else {
4510 pa_source *source;
4512 if (idx != PA_INVALID_INDEX)
4513 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4514 else
4515 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4517 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4519 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4520 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4521 return;
4526 pa_pstream_send_simple_ack(c->pstream, tag);
4529 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4530 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4531 uint32_t idx = PA_INVALID_INDEX;
4532 const char *name = NULL;
4533 pa_module *m;
4534 pa_native_protocol_ext_cb_t cb;
4536 pa_native_connection_assert_ref(c);
4537 pa_assert(t);
4539 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4540 pa_tagstruct_gets(t, &name) < 0) {
4541 protocol_error(c);
4542 return;
4545 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4546 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4547 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4548 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4549 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4551 if (idx != PA_INVALID_INDEX)
4552 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4553 else {
4554 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4555 if (strcmp(name, m->name) == 0)
4556 break;
4559 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4560 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4562 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4563 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4565 if (cb(c->protocol, m, c, tag, t) < 0)
4566 protocol_error(c);
4569 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4570 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4571 uint32_t idx = PA_INVALID_INDEX;
4572 const char *name = NULL, *profile = NULL;
4573 pa_card *card = NULL;
4574 int ret;
4576 pa_native_connection_assert_ref(c);
4577 pa_assert(t);
4579 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4580 pa_tagstruct_gets(t, &name) < 0 ||
4581 pa_tagstruct_gets(t, &profile) < 0 ||
4582 !pa_tagstruct_eof(t)) {
4583 protocol_error(c);
4584 return;
4587 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4588 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4589 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4590 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4591 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4593 if (idx != PA_INVALID_INDEX)
4594 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4595 else
4596 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4598 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4600 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4601 pa_pstream_send_error(c->pstream, tag, -ret);
4602 return;
4605 pa_pstream_send_simple_ack(c->pstream, tag);
4608 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4609 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4610 uint32_t idx = PA_INVALID_INDEX;
4611 const char *name = NULL, *port = NULL;
4612 int ret;
4614 pa_native_connection_assert_ref(c);
4615 pa_assert(t);
4617 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4618 pa_tagstruct_gets(t, &name) < 0 ||
4619 pa_tagstruct_gets(t, &port) < 0 ||
4620 !pa_tagstruct_eof(t)) {
4621 protocol_error(c);
4622 return;
4625 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4626 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);
4627 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4628 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4629 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4631 if (command == PA_COMMAND_SET_SINK_PORT) {
4632 pa_sink *sink;
4634 if (idx != PA_INVALID_INDEX)
4635 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4636 else
4637 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4639 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4641 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4642 pa_pstream_send_error(c->pstream, tag, -ret);
4643 return;
4645 } else {
4646 pa_source *source;
4648 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4650 if (idx != PA_INVALID_INDEX)
4651 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4652 else
4653 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4655 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4657 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4658 pa_pstream_send_error(c->pstream, tag, -ret);
4659 return;
4663 pa_pstream_send_simple_ack(c->pstream, tag);
4666 /*** pstream callbacks ***/
4668 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4669 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4671 pa_assert(p);
4672 pa_assert(packet);
4673 pa_native_connection_assert_ref(c);
4675 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4676 pa_log("invalid packet.");
4677 native_connection_unlink(c);
4681 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) {
4682 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4683 output_stream *stream;
4685 pa_assert(p);
4686 pa_assert(chunk);
4687 pa_native_connection_assert_ref(c);
4689 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4690 pa_log_debug("Client sent block for invalid stream.");
4691 /* Ignoring */
4692 return;
4695 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4697 if (playback_stream_isinstance(stream)) {
4698 playback_stream *ps = PLAYBACK_STREAM(stream);
4700 pa_atomic_inc(&ps->seek_or_post_in_queue);
4701 if (chunk->memblock) {
4702 if (seek != PA_SEEK_RELATIVE || offset != 0)
4703 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);
4704 else
4705 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4706 } else
4707 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);
4709 } else {
4710 upload_stream *u = UPLOAD_STREAM(stream);
4711 size_t l;
4713 if (!u->memchunk.memblock) {
4714 if (u->length == chunk->length && chunk->memblock) {
4715 u->memchunk = *chunk;
4716 pa_memblock_ref(u->memchunk.memblock);
4717 u->length = 0;
4718 } else {
4719 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4720 u->memchunk.index = u->memchunk.length = 0;
4724 pa_assert(u->memchunk.memblock);
4726 l = u->length;
4727 if (l > chunk->length)
4728 l = chunk->length;
4730 if (l > 0) {
4731 void *dst;
4732 dst = pa_memblock_acquire(u->memchunk.memblock);
4734 if (chunk->memblock) {
4735 void *src;
4736 src = pa_memblock_acquire(chunk->memblock);
4738 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4739 (uint8_t*) src + chunk->index, l);
4741 pa_memblock_release(chunk->memblock);
4742 } else
4743 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4745 pa_memblock_release(u->memchunk.memblock);
4747 u->memchunk.length += l;
4748 u->length -= l;
4753 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4754 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4756 pa_assert(p);
4757 pa_native_connection_assert_ref(c);
4759 native_connection_unlink(c);
4760 pa_log_info("Connection died.");
4763 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4764 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4766 pa_assert(p);
4767 pa_native_connection_assert_ref(c);
4769 native_connection_send_memblock(c);
4772 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4773 pa_thread_mq *q;
4775 if (!(q = pa_thread_mq_get()))
4776 pa_pstream_send_revoke(p, block_id);
4777 else
4778 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4781 static void pstream_release_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_release(p, block_id);
4786 else
4787 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4790 /*** client callbacks ***/
4792 static void client_kill_cb(pa_client *c) {
4793 pa_assert(c);
4795 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4796 pa_log_info("Connection killed.");
4799 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4800 pa_tagstruct *t;
4801 pa_native_connection *c;
4803 pa_assert(client);
4804 c = PA_NATIVE_CONNECTION(client->userdata);
4805 pa_native_connection_assert_ref(c);
4807 if (c->version < 15)
4808 return;
4810 t = pa_tagstruct_new(NULL, 0);
4811 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4812 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4813 pa_tagstruct_puts(t, event);
4814 pa_tagstruct_put_proplist(t, pl);
4815 pa_pstream_send_tagstruct(c->pstream, t);
4818 /*** module entry points ***/
4820 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4821 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4823 pa_assert(m);
4824 pa_native_connection_assert_ref(c);
4825 pa_assert(c->auth_timeout_event == e);
4827 if (!c->authorized) {
4828 native_connection_unlink(c);
4829 pa_log_info("Connection terminated due to authentication timeout.");
4833 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4834 pa_native_connection *c;
4835 char pname[128];
4836 pa_client *client;
4837 pa_client_new_data data;
4839 pa_assert(p);
4840 pa_assert(io);
4841 pa_assert(o);
4843 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4844 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4845 pa_iochannel_free(io);
4846 return;
4849 pa_client_new_data_init(&data);
4850 data.module = o->module;
4851 data.driver = __FILE__;
4852 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4853 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4854 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4855 client = pa_client_new(p->core, &data);
4856 pa_client_new_data_done(&data);
4858 if (!client)
4859 return;
4861 c = pa_msgobject_new(pa_native_connection);
4862 c->parent.parent.free = native_connection_free;
4863 c->parent.process_msg = native_connection_process_msg;
4864 c->protocol = p;
4865 c->options = pa_native_options_ref(o);
4866 c->authorized = FALSE;
4868 if (o->auth_anonymous) {
4869 pa_log_info("Client authenticated anonymously.");
4870 c->authorized = TRUE;
4873 if (!c->authorized &&
4874 o->auth_ip_acl &&
4875 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4877 pa_log_info("Client authenticated by IP ACL.");
4878 c->authorized = TRUE;
4881 if (!c->authorized)
4882 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4883 else
4884 c->auth_timeout_event = NULL;
4886 c->is_local = pa_iochannel_socket_is_local(io);
4887 c->version = 8;
4889 c->client = client;
4890 c->client->kill = client_kill_cb;
4891 c->client->send_event = client_send_event_cb;
4892 c->client->userdata = c;
4894 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4895 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4896 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4897 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4898 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4899 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4900 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4902 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4904 c->record_streams = pa_idxset_new(NULL, NULL);
4905 c->output_streams = pa_idxset_new(NULL, NULL);
4907 c->rrobin_index = PA_IDXSET_INVALID;
4908 c->subscription = NULL;
4910 pa_idxset_put(p->connections, c, NULL);
4912 #ifdef HAVE_CREDS
4913 if (pa_iochannel_creds_supported(io))
4914 pa_iochannel_creds_enable(io);
4915 #endif
4917 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4920 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4921 pa_native_connection *c;
4922 void *state = NULL;
4924 pa_assert(p);
4925 pa_assert(m);
4927 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4928 if (c->options->module == m)
4929 native_connection_unlink(c);
4932 static pa_native_protocol* native_protocol_new(pa_core *c) {
4933 pa_native_protocol *p;
4934 pa_native_hook_t h;
4936 pa_assert(c);
4938 p = pa_xnew(pa_native_protocol, 1);
4939 PA_REFCNT_INIT(p);
4940 p->core = c;
4941 p->connections = pa_idxset_new(NULL, NULL);
4943 p->servers = NULL;
4945 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4947 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4948 pa_hook_init(&p->hooks[h], p);
4950 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4952 return p;
4955 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4956 pa_native_protocol *p;
4958 if ((p = pa_shared_get(c, "native-protocol")))
4959 return pa_native_protocol_ref(p);
4961 return native_protocol_new(c);
4964 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4965 pa_assert(p);
4966 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4968 PA_REFCNT_INC(p);
4970 return p;
4973 void pa_native_protocol_unref(pa_native_protocol *p) {
4974 pa_native_connection *c;
4975 pa_native_hook_t h;
4977 pa_assert(p);
4978 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4980 if (PA_REFCNT_DEC(p) > 0)
4981 return;
4983 while ((c = pa_idxset_first(p->connections, NULL)))
4984 native_connection_unlink(c);
4986 pa_idxset_free(p->connections, NULL, NULL);
4988 pa_strlist_free(p->servers);
4990 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4991 pa_hook_done(&p->hooks[h]);
4993 pa_hashmap_free(p->extensions, NULL, NULL);
4995 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4997 pa_xfree(p);
5000 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
5001 pa_assert(p);
5002 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5003 pa_assert(name);
5005 p->servers = pa_strlist_prepend(p->servers, name);
5007 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5010 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
5011 pa_assert(p);
5012 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5013 pa_assert(name);
5015 p->servers = pa_strlist_remove(p->servers, name);
5017 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5020 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
5021 pa_assert(p);
5022 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5024 return p->hooks;
5027 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
5028 pa_assert(p);
5029 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5031 return p->servers;
5034 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
5035 pa_assert(p);
5036 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5037 pa_assert(m);
5038 pa_assert(cb);
5039 pa_assert(!pa_hashmap_get(p->extensions, m));
5041 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
5042 return 0;
5045 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
5046 pa_assert(p);
5047 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5048 pa_assert(m);
5050 pa_assert_se(pa_hashmap_remove(p->extensions, m));
5053 pa_native_options* pa_native_options_new(void) {
5054 pa_native_options *o;
5056 o = pa_xnew0(pa_native_options, 1);
5057 PA_REFCNT_INIT(o);
5059 return o;
5062 pa_native_options* pa_native_options_ref(pa_native_options *o) {
5063 pa_assert(o);
5064 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5066 PA_REFCNT_INC(o);
5068 return o;
5071 void pa_native_options_unref(pa_native_options *o) {
5072 pa_assert(o);
5073 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5075 if (PA_REFCNT_DEC(o) > 0)
5076 return;
5078 pa_xfree(o->auth_group);
5080 if (o->auth_ip_acl)
5081 pa_ip_acl_free(o->auth_ip_acl);
5083 if (o->auth_cookie)
5084 pa_auth_cookie_unref(o->auth_cookie);
5086 pa_xfree(o);
5089 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
5090 pa_bool_t enabled;
5091 const char *acl;
5093 pa_assert(o);
5094 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5095 pa_assert(ma);
5097 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
5098 pa_log("auth-anonymous= expects a boolean argument.");
5099 return -1;
5102 enabled = TRUE;
5103 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
5104 pa_log("auth-group-enabled= expects a boolean argument.");
5105 return -1;
5108 pa_xfree(o->auth_group);
5109 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
5111 #ifndef HAVE_CREDS
5112 if (o->auth_group)
5113 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5114 #endif
5116 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
5117 pa_ip_acl *ipa;
5119 if (!(ipa = pa_ip_acl_new(acl))) {
5120 pa_log("Failed to parse IP ACL '%s'", acl);
5121 return -1;
5124 if (o->auth_ip_acl)
5125 pa_ip_acl_free(o->auth_ip_acl);
5127 o->auth_ip_acl = ipa;
5130 enabled = TRUE;
5131 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
5132 pa_log("auth-cookie-enabled= expects a boolean argument.");
5133 return -1;
5136 if (o->auth_cookie)
5137 pa_auth_cookie_unref(o->auth_cookie);
5139 if (enabled) {
5140 const char *cn;
5142 /* The new name for this is 'auth-cookie', for compat reasons
5143 * we check the old name too */
5144 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
5145 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
5146 cn = PA_NATIVE_COOKIE_FILE;
5148 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
5149 return -1;
5151 } else
5152 o->auth_cookie = NULL;
5154 return 0;
5157 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
5158 pa_native_connection_assert_ref(c);
5160 return c->pstream;
5163 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
5164 pa_native_connection_assert_ref(c);
5166 return c->client;