introspect: Get format of source output
[pulseaudio-mirror.git] / src / pulsecore / protocol-native.c
blob6c7c89797a6e18104367dfb3db01100a4070a9d4
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/authkey.h>
50 #include <pulsecore/namereg.h>
51 #include <pulsecore/core-scache.h>
52 #include <pulsecore/core-subscribe.h>
53 #include <pulsecore/log.h>
54 #include <pulsecore/strlist.h>
55 #include <pulsecore/shared.h>
56 #include <pulsecore/sample-util.h>
57 #include <pulsecore/llist.h>
58 #include <pulsecore/creds.h>
59 #include <pulsecore/core-util.h>
60 #include <pulsecore/ipacl.h>
61 #include <pulsecore/thread-mq.h>
63 #include "protocol-native.h"
65 /* Kick a client if it doesn't authenticate within this time */
66 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
68 /* Don't accept more connection than this */
69 #define MAX_CONNECTIONS 64
71 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
72 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
73 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
74 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
76 struct pa_native_protocol;
78 typedef struct record_stream {
79 pa_msgobject parent;
81 pa_native_connection *connection;
82 uint32_t index;
84 pa_source_output *source_output;
85 pa_memblockq *memblockq;
87 pa_bool_t adjust_latency:1;
88 pa_bool_t early_requests:1;
90 /* Requested buffer attributes */
91 pa_buffer_attr buffer_attr_req;
92 /* Fixed-up and adjusted buffer attributes */
93 pa_buffer_attr buffer_attr;
95 pa_atomic_t on_the_fly;
96 pa_usec_t configured_source_latency;
97 size_t drop_initial;
99 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
100 size_t on_the_fly_snapshot;
101 pa_usec_t current_monitor_latency;
102 pa_usec_t current_source_latency;
103 } record_stream;
105 #define RECORD_STREAM(o) (record_stream_cast(o))
106 PA_DEFINE_PRIVATE_CLASS(record_stream, pa_msgobject);
108 typedef struct output_stream {
109 pa_msgobject parent;
110 } output_stream;
112 #define OUTPUT_STREAM(o) (output_stream_cast(o))
113 PA_DEFINE_PRIVATE_CLASS(output_stream, pa_msgobject);
115 typedef struct playback_stream {
116 output_stream parent;
118 pa_native_connection *connection;
119 uint32_t index;
121 pa_sink_input *sink_input;
122 pa_memblockq *memblockq;
124 pa_bool_t adjust_latency:1;
125 pa_bool_t early_requests:1;
127 pa_bool_t is_underrun:1;
128 pa_bool_t drain_request:1;
129 uint32_t drain_tag;
130 uint32_t syncid;
132 /* Optimization to avoid too many rewinds with a lot of small blocks */
133 pa_atomic_t seek_or_post_in_queue;
134 int64_t seek_windex;
136 pa_atomic_t missing;
137 pa_usec_t configured_sink_latency;
138 /* Requested buffer attributes */
139 pa_buffer_attr buffer_attr_req;
140 /* Fixed-up and adjusted buffer attributes */
141 pa_buffer_attr buffer_attr;
143 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
144 int64_t read_index, write_index;
145 size_t render_memblockq_length;
146 pa_usec_t current_sink_latency;
147 uint64_t playing_for, underrun_for;
148 } playback_stream;
150 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
151 PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
153 typedef struct upload_stream {
154 output_stream parent;
156 pa_native_connection *connection;
157 uint32_t index;
159 pa_memchunk memchunk;
160 size_t length;
161 char *name;
162 pa_sample_spec sample_spec;
163 pa_channel_map channel_map;
164 pa_proplist *proplist;
165 } upload_stream;
167 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
168 PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
170 struct pa_native_connection {
171 pa_msgobject parent;
172 pa_native_protocol *protocol;
173 pa_native_options *options;
174 pa_bool_t authorized:1;
175 pa_bool_t is_local:1;
176 uint32_t version;
177 pa_client *client;
178 pa_pstream *pstream;
179 pa_pdispatch *pdispatch;
180 pa_idxset *record_streams, *output_streams;
181 uint32_t rrobin_index;
182 pa_subscription *subscription;
183 pa_time_event *auth_timeout_event;
186 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
187 PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
189 struct pa_native_protocol {
190 PA_REFCNT_DECLARE;
192 pa_core *core;
193 pa_idxset *connections;
195 pa_strlist *servers;
196 pa_hook hooks[PA_NATIVE_HOOK_MAX];
198 pa_hashmap *extensions;
201 enum {
202 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
205 enum {
206 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
207 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
208 SINK_INPUT_MESSAGE_FLUSH,
209 SINK_INPUT_MESSAGE_TRIGGER,
210 SINK_INPUT_MESSAGE_SEEK,
211 SINK_INPUT_MESSAGE_PREBUF_FORCE,
212 SINK_INPUT_MESSAGE_UPDATE_LATENCY,
213 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
216 enum {
217 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
218 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
219 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
220 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
221 PLAYBACK_STREAM_MESSAGE_STARTED,
222 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
225 enum {
226 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
229 enum {
230 CONNECTION_MESSAGE_RELEASE,
231 CONNECTION_MESSAGE_REVOKE
234 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
235 static void sink_input_kill_cb(pa_sink_input *i);
236 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
237 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
238 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
239 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
240 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
241 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
243 static void native_connection_send_memblock(pa_native_connection *c);
244 static void playback_stream_request_bytes(struct playback_stream*s);
246 static void source_output_kill_cb(pa_source_output *o);
247 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
248 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend);
249 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
250 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
251 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
253 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
254 static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
256 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
257 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
258 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
259 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
260 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
261 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
262 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
263 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
264 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
265 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
266 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
267 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
268 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
269 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
270 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
271 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
272 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
273 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
274 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
275 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
276 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
277 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
278 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
279 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
280 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
281 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
282 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
283 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
284 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
285 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
286 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
287 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
288 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
289 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
290 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
291 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
292 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
293 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
294 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
296 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
297 [PA_COMMAND_ERROR] = NULL,
298 [PA_COMMAND_TIMEOUT] = NULL,
299 [PA_COMMAND_REPLY] = NULL,
300 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
301 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
302 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
303 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
304 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
305 [PA_COMMAND_AUTH] = command_auth,
306 [PA_COMMAND_REQUEST] = NULL,
307 [PA_COMMAND_EXIT] = command_exit,
308 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
309 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
310 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
311 [PA_COMMAND_STAT] = command_stat,
312 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
313 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
314 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
315 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
316 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
317 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
318 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
319 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
320 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
321 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
322 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
323 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
324 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
325 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
326 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
327 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
328 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
329 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
330 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
331 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
332 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
333 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
334 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
335 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
336 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
338 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
339 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
340 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
341 [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = command_set_volume,
343 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
344 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
345 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
346 [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = command_set_mute,
348 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
349 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
351 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
352 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
353 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
354 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
356 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
357 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
359 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
360 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
361 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
362 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
363 [PA_COMMAND_KILL_CLIENT] = command_kill,
364 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
365 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
366 [PA_COMMAND_LOAD_MODULE] = command_load_module,
367 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
369 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
370 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
371 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
372 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
374 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
375 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
377 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
378 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
380 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
381 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
383 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
384 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
385 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
387 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
388 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
389 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
391 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
393 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
394 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
396 [PA_COMMAND_EXTENSION] = command_extension
399 /* structure management */
401 /* Called from main context */
402 static void upload_stream_unlink(upload_stream *s) {
403 pa_assert(s);
405 if (!s->connection)
406 return;
408 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
409 s->connection = NULL;
410 upload_stream_unref(s);
413 /* Called from main context */
414 static void upload_stream_free(pa_object *o) {
415 upload_stream *s = UPLOAD_STREAM(o);
416 pa_assert(s);
418 upload_stream_unlink(s);
420 pa_xfree(s->name);
422 if (s->proplist)
423 pa_proplist_free(s->proplist);
425 if (s->memchunk.memblock)
426 pa_memblock_unref(s->memchunk.memblock);
428 pa_xfree(s);
431 /* Called from main context */
432 static upload_stream* upload_stream_new(
433 pa_native_connection *c,
434 const pa_sample_spec *ss,
435 const pa_channel_map *map,
436 const char *name,
437 size_t length,
438 pa_proplist *p) {
440 upload_stream *s;
442 pa_assert(c);
443 pa_assert(ss);
444 pa_assert(name);
445 pa_assert(length > 0);
446 pa_assert(p);
448 s = pa_msgobject_new(upload_stream);
449 s->parent.parent.parent.free = upload_stream_free;
450 s->connection = c;
451 s->sample_spec = *ss;
452 s->channel_map = *map;
453 s->name = pa_xstrdup(name);
454 pa_memchunk_reset(&s->memchunk);
455 s->length = length;
456 s->proplist = pa_proplist_copy(p);
457 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
459 pa_idxset_put(c->output_streams, s, &s->index);
461 return s;
464 /* Called from main context */
465 static void record_stream_unlink(record_stream *s) {
466 pa_assert(s);
468 if (!s->connection)
469 return;
471 if (s->source_output) {
472 pa_source_output_unlink(s->source_output);
473 pa_source_output_unref(s->source_output);
474 s->source_output = NULL;
477 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
478 s->connection = NULL;
479 record_stream_unref(s);
482 /* Called from main context */
483 static void record_stream_free(pa_object *o) {
484 record_stream *s = RECORD_STREAM(o);
485 pa_assert(s);
487 record_stream_unlink(s);
489 pa_memblockq_free(s->memblockq);
490 pa_xfree(s);
493 /* Called from main context */
494 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
495 record_stream *s = RECORD_STREAM(o);
496 record_stream_assert_ref(s);
498 if (!s->connection)
499 return -1;
501 switch (code) {
503 case RECORD_STREAM_MESSAGE_POST_DATA:
505 /* We try to keep up to date with how many bytes are
506 * currently on the fly */
507 pa_atomic_sub(&s->on_the_fly, chunk->length);
509 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
510 /* pa_log_warn("Failed to push data into output queue."); */
511 return -1;
514 if (!pa_pstream_is_pending(s->connection->pstream))
515 native_connection_send_memblock(s->connection);
517 break;
520 return 0;
523 /* Called from main context */
524 static void fix_record_buffer_attr_pre(record_stream *s) {
526 size_t frame_size;
527 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
529 pa_assert(s);
531 /* This function will be called from the main thread, before as
532 * well as after the source output has been activated using
533 * pa_source_output_put()! That means it may not touch any
534 * ->thread_info data! */
536 frame_size = pa_frame_size(&s->source_output->sample_spec);
537 s->buffer_attr = s->buffer_attr_req;
539 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
540 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
541 if (s->buffer_attr.maxlength <= 0)
542 s->buffer_attr.maxlength = (uint32_t) frame_size;
544 if (s->buffer_attr.fragsize == (uint32_t) -1)
545 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
546 if (s->buffer_attr.fragsize <= 0)
547 s->buffer_attr.fragsize = (uint32_t) frame_size;
549 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
551 if (s->early_requests) {
553 /* In early request mode we need to emulate the classic
554 * fragment-based playback model. We do this setting the source
555 * latency to the fragment size. */
557 source_usec = fragsize_usec;
559 } else if (s->adjust_latency) {
561 /* So, the user asked us to adjust the latency according to
562 * what the source can provide. Half the latency will be
563 * spent on the hw buffer, half of it in the async buffer
564 * queue we maintain for each client. */
566 source_usec = fragsize_usec/2;
568 } else {
570 /* Ok, the user didn't ask us to adjust the latency, hence we
571 * don't */
573 source_usec = (pa_usec_t) -1;
576 if (source_usec != (pa_usec_t) -1)
577 s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
578 else
579 s->configured_source_latency = 0;
581 if (s->early_requests) {
583 /* Ok, we didn't necessarily get what we were asking for, so
584 * let's tell the user */
586 fragsize_usec = s->configured_source_latency;
588 } else if (s->adjust_latency) {
590 /* Now subtract what we actually got */
592 if (fragsize_usec >= s->configured_source_latency*2)
593 fragsize_usec -= s->configured_source_latency;
594 else
595 fragsize_usec = s->configured_source_latency;
598 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
599 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
601 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
603 if (s->buffer_attr.fragsize <= 0)
604 s->buffer_attr.fragsize = (uint32_t) frame_size;
607 /* Called from main context */
608 static void fix_record_buffer_attr_post(record_stream *s) {
609 size_t base;
611 pa_assert(s);
613 /* This function will be called from the main thread, before as
614 * well as after the source output has been activated using
615 * pa_source_output_put()! That means it may not touch and
616 * ->thread_info data! */
618 base = pa_frame_size(&s->source_output->sample_spec);
620 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
621 if (s->buffer_attr.fragsize <= 0)
622 s->buffer_attr.fragsize = base;
624 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
625 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
628 /* Called from main context */
629 static record_stream* record_stream_new(
630 pa_native_connection *c,
631 pa_source *source,
632 pa_sample_spec *ss,
633 pa_channel_map *map,
634 pa_idxset *formats,
635 pa_buffer_attr *attr,
636 pa_cvolume *volume,
637 pa_bool_t muted,
638 pa_bool_t muted_set,
639 pa_source_output_flags_t flags,
640 pa_proplist *p,
641 pa_bool_t adjust_latency,
642 pa_bool_t early_requests,
643 pa_bool_t relative_volume,
644 pa_bool_t peak_detect,
645 pa_sink_input *direct_on_input,
646 int *ret) {
648 record_stream *s;
649 pa_source_output *source_output = NULL;
650 pa_source_output_new_data data;
652 pa_assert(c);
653 pa_assert(ss);
654 pa_assert(p);
655 pa_assert(ret);
657 pa_source_output_new_data_init(&data);
659 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
660 data.driver = __FILE__;
661 data.module = c->options->module;
662 data.client = c->client;
663 if (source)
664 pa_source_output_new_data_set_source(&data, source, TRUE);
665 if (pa_sample_spec_valid(ss))
666 pa_source_output_new_data_set_sample_spec(&data, ss);
667 if (pa_channel_map_valid(map))
668 pa_source_output_new_data_set_channel_map(&data, map);
669 if (formats)
670 pa_source_output_new_data_set_formats(&data, formats);
671 data.direct_on_input = direct_on_input;
672 if (volume) {
673 pa_source_output_new_data_set_volume(&data, volume);
674 data.volume_is_absolute = !relative_volume;
675 data.save_volume = TRUE;
677 if (muted_set) {
678 pa_source_output_new_data_set_muted(&data, muted);
679 data.save_muted = TRUE;
681 if (peak_detect)
682 data.resample_method = PA_RESAMPLER_PEAKS;
683 data.flags = flags;
685 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
687 pa_source_output_new_data_done(&data);
689 if (!source_output)
690 return NULL;
692 s = pa_msgobject_new(record_stream);
693 s->parent.parent.free = record_stream_free;
694 s->parent.process_msg = record_stream_process_msg;
695 s->connection = c;
696 s->source_output = source_output;
697 s->buffer_attr_req = *attr;
698 s->adjust_latency = adjust_latency;
699 s->early_requests = early_requests;
700 pa_atomic_store(&s->on_the_fly, 0);
702 s->source_output->parent.process_msg = source_output_process_msg;
703 s->source_output->push = source_output_push_cb;
704 s->source_output->kill = source_output_kill_cb;
705 s->source_output->get_latency = source_output_get_latency_cb;
706 s->source_output->moving = source_output_moving_cb;
707 s->source_output->suspend = source_output_suspend_cb;
708 s->source_output->send_event = source_output_send_event_cb;
709 s->source_output->userdata = s;
711 fix_record_buffer_attr_pre(s);
713 s->memblockq = pa_memblockq_new(
715 s->buffer_attr.maxlength,
717 pa_frame_size(&source_output->sample_spec),
721 NULL);
723 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
724 fix_record_buffer_attr_post(s);
726 *ss = s->source_output->sample_spec;
727 *map = s->source_output->channel_map;
729 pa_idxset_put(c->record_streams, s, &s->index);
731 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
732 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
733 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
734 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
736 pa_source_output_put(s->source_output);
737 return s;
740 /* Called from main context */
741 static void record_stream_send_killed(record_stream *r) {
742 pa_tagstruct *t;
743 record_stream_assert_ref(r);
745 t = pa_tagstruct_new(NULL, 0);
746 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
747 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
748 pa_tagstruct_putu32(t, r->index);
749 pa_pstream_send_tagstruct(r->connection->pstream, t);
752 /* Called from main context */
753 static void playback_stream_unlink(playback_stream *s) {
754 pa_assert(s);
756 if (!s->connection)
757 return;
759 if (s->sink_input) {
760 pa_sink_input_unlink(s->sink_input);
761 pa_sink_input_unref(s->sink_input);
762 s->sink_input = NULL;
765 if (s->drain_request)
766 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
768 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
769 s->connection = NULL;
770 playback_stream_unref(s);
773 /* Called from main context */
774 static void playback_stream_free(pa_object* o) {
775 playback_stream *s = PLAYBACK_STREAM(o);
776 pa_assert(s);
778 playback_stream_unlink(s);
780 pa_memblockq_free(s->memblockq);
781 pa_xfree(s);
784 /* Called from main context */
785 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
786 playback_stream *s = PLAYBACK_STREAM(o);
787 playback_stream_assert_ref(s);
789 if (!s->connection)
790 return -1;
792 switch (code) {
794 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
795 pa_tagstruct *t;
796 int l = 0;
798 for (;;) {
799 if ((l = pa_atomic_load(&s->missing)) <= 0)
800 return 0;
802 if (pa_atomic_cmpxchg(&s->missing, l, 0))
803 break;
806 t = pa_tagstruct_new(NULL, 0);
807 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
808 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
809 pa_tagstruct_putu32(t, s->index);
810 pa_tagstruct_putu32(t, (uint32_t) l);
811 pa_pstream_send_tagstruct(s->connection->pstream, t);
813 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
814 break;
817 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
818 pa_tagstruct *t;
820 /* pa_log("signalling underflow"); */
822 /* Report that we're empty */
823 t = pa_tagstruct_new(NULL, 0);
824 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
825 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
826 pa_tagstruct_putu32(t, s->index);
827 pa_pstream_send_tagstruct(s->connection->pstream, t);
828 break;
831 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
832 pa_tagstruct *t;
834 /* Notify the user we're overflowed*/
835 t = pa_tagstruct_new(NULL, 0);
836 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
837 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
838 pa_tagstruct_putu32(t, s->index);
839 pa_pstream_send_tagstruct(s->connection->pstream, t);
840 break;
843 case PLAYBACK_STREAM_MESSAGE_STARTED:
845 if (s->connection->version >= 13) {
846 pa_tagstruct *t;
848 /* Notify the user we started playback */
849 t = pa_tagstruct_new(NULL, 0);
850 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
851 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
852 pa_tagstruct_putu32(t, s->index);
853 pa_pstream_send_tagstruct(s->connection->pstream, t);
856 break;
858 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
859 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
860 break;
862 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
864 s->buffer_attr.tlength = (uint32_t) offset;
866 if (s->connection->version >= 15) {
867 pa_tagstruct *t;
869 t = pa_tagstruct_new(NULL, 0);
870 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
871 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
872 pa_tagstruct_putu32(t, s->index);
873 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
874 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
875 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
876 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
877 pa_tagstruct_put_usec(t, s->configured_sink_latency);
878 pa_pstream_send_tagstruct(s->connection->pstream, t);
881 break;
884 return 0;
887 /* Called from main context */
888 static void fix_playback_buffer_attr(playback_stream *s) {
889 size_t frame_size, max_prebuf;
890 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
892 pa_assert(s);
894 /* pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", */
895 /* (long) s->buffer_attr.maxlength, */
896 /* (long) s->buffer_attr.tlength, */
897 /* (long) s->buffer_attr.minreq, */
898 /* (long) s->buffer_attr.prebuf); */
900 /* pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
901 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
902 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
903 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
904 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
906 /* This function will be called from the main thread, before as
907 * well as after the sink input has been activated using
908 * pa_sink_input_put()! That means it may not touch any
909 * ->thread_info data, such as the memblockq! */
911 frame_size = pa_frame_size(&s->sink_input->sample_spec);
912 s->buffer_attr = s->buffer_attr_req;
914 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
915 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
916 if (s->buffer_attr.maxlength <= 0)
917 s->buffer_attr.maxlength = (uint32_t) frame_size;
919 if (s->buffer_attr.tlength == (uint32_t) -1)
920 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
921 if (s->buffer_attr.tlength <= 0)
922 s->buffer_attr.tlength = (uint32_t) frame_size;
924 if (s->buffer_attr.minreq == (uint32_t) -1)
925 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
926 if (s->buffer_attr.minreq <= 0)
927 s->buffer_attr.minreq = (uint32_t) frame_size;
929 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
930 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
932 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
933 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
935 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
936 (double) tlength_usec / PA_USEC_PER_MSEC,
937 (double) minreq_usec / PA_USEC_PER_MSEC);
939 if (s->early_requests) {
941 /* In early request mode we need to emulate the classic
942 * fragment-based playback model. We do this setting the sink
943 * latency to the fragment size. */
945 sink_usec = minreq_usec;
946 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
948 } else if (s->adjust_latency) {
950 /* So, the user asked us to adjust the latency of the stream
951 * buffer according to the what the sink can provide. The
952 * tlength passed in shall be the overall latency. Roughly
953 * half the latency will be spent on the hw buffer, the other
954 * half of it in the async buffer queue we maintain for each
955 * client. In between we'll have a safety space of size
956 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
957 * empty and needs to be filled, then our buffer must have
958 * enough data to fulfill this request immediatly and thus
959 * have at least the same tlength as the size of the hw
960 * buffer. It additionally needs space for 2 times minreq
961 * because if the buffer ran empty and a partial fillup
962 * happens immediately on the next iteration we need to be
963 * able to fulfill it and give the application also minreq
964 * time to fill it up again for the next request Makes 2 times
965 * minreq in plus.. */
967 if (tlength_usec > minreq_usec*2)
968 sink_usec = (tlength_usec - minreq_usec*2)/2;
969 else
970 sink_usec = 0;
972 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
974 } else {
976 /* Ok, the user didn't ask us to adjust the latency, but we
977 * still need to make sure that the parameters from the user
978 * do make sense. */
980 if (tlength_usec > minreq_usec*2)
981 sink_usec = (tlength_usec - minreq_usec*2);
982 else
983 sink_usec = 0;
985 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
988 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
990 if (s->early_requests) {
992 /* Ok, we didn't necessarily get what we were asking for, so
993 * let's tell the user */
995 minreq_usec = s->configured_sink_latency;
997 } else if (s->adjust_latency) {
999 /* Ok, we didn't necessarily get what we were asking for, so
1000 * let's subtract from what we asked for for the remaining
1001 * buffer space */
1003 if (tlength_usec >= s->configured_sink_latency)
1004 tlength_usec -= s->configured_sink_latency;
1007 /* FIXME: This is actually larger than necessary, since not all of
1008 * the sink latency is actually rewritable. */
1009 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
1010 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
1012 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
1013 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
1014 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
1016 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
1017 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
1018 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
1020 if (s->buffer_attr.minreq <= 0) {
1021 s->buffer_attr.minreq = (uint32_t) frame_size;
1022 s->buffer_attr.tlength += (uint32_t) frame_size*2;
1025 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
1026 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
1028 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
1030 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
1031 s->buffer_attr.prebuf > max_prebuf)
1032 s->buffer_attr.prebuf = max_prebuf;
1034 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1035 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1036 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1037 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1038 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1041 /* Called from main context */
1042 static playback_stream* playback_stream_new(
1043 pa_native_connection *c,
1044 pa_sink *sink,
1045 pa_sample_spec *ss,
1046 pa_channel_map *map,
1047 pa_idxset *formats,
1048 pa_buffer_attr *a,
1049 pa_cvolume *volume,
1050 pa_bool_t muted,
1051 pa_bool_t muted_set,
1052 pa_sink_input_flags_t flags,
1053 pa_proplist *p,
1054 pa_bool_t adjust_latency,
1055 pa_bool_t early_requests,
1056 pa_bool_t relative_volume,
1057 uint32_t syncid,
1058 uint32_t *missing,
1059 int *ret) {
1061 /* Note: This function takes ownership of the 'formats' param, so we need
1062 * to take extra care to not leak it */
1064 playback_stream *s, *ssync;
1065 pa_sink_input *sink_input = NULL;
1066 pa_memchunk silence;
1067 uint32_t idx;
1068 int64_t start_index;
1069 pa_sink_input_new_data data;
1071 pa_assert(c);
1072 pa_assert(ss);
1073 pa_assert(missing);
1074 pa_assert(p);
1075 pa_assert(ret);
1077 /* Find syncid group */
1078 PA_IDXSET_FOREACH(ssync, c->output_streams, idx) {
1080 if (!playback_stream_isinstance(ssync))
1081 continue;
1083 if (ssync->syncid == syncid)
1084 break;
1087 /* Synced streams must connect to the same sink */
1088 if (ssync) {
1090 if (!sink)
1091 sink = ssync->sink_input->sink;
1092 else if (sink != ssync->sink_input->sink) {
1093 *ret = PA_ERR_INVALID;
1094 goto out;
1098 pa_sink_input_new_data_init(&data);
1100 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1101 data.driver = __FILE__;
1102 data.module = c->options->module;
1103 data.client = c->client;
1104 if (sink)
1105 pa_sink_input_new_data_set_sink(&data, sink, TRUE);
1106 if (pa_sample_spec_valid(ss))
1107 pa_sink_input_new_data_set_sample_spec(&data, ss);
1108 if (pa_channel_map_valid(map))
1109 pa_sink_input_new_data_set_channel_map(&data, map);
1110 if (formats) {
1111 pa_sink_input_new_data_set_formats(&data, formats);
1112 /* Ownership transferred to new_data, so we don't free it ourseleves */
1113 formats = NULL;
1115 if (volume) {
1116 pa_sink_input_new_data_set_volume(&data, volume);
1117 data.volume_is_absolute = !relative_volume;
1118 data.save_volume = TRUE;
1120 if (muted_set) {
1121 pa_sink_input_new_data_set_muted(&data, muted);
1122 data.save_muted = TRUE;
1124 data.sync_base = ssync ? ssync->sink_input : NULL;
1125 data.flags = flags;
1127 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1129 pa_sink_input_new_data_done(&data);
1131 if (!sink_input)
1132 goto out;
1134 s = pa_msgobject_new(playback_stream);
1135 s->parent.parent.parent.free = playback_stream_free;
1136 s->parent.parent.process_msg = playback_stream_process_msg;
1137 s->connection = c;
1138 s->syncid = syncid;
1139 s->sink_input = sink_input;
1140 s->is_underrun = TRUE;
1141 s->drain_request = FALSE;
1142 pa_atomic_store(&s->missing, 0);
1143 s->buffer_attr_req = *a;
1144 s->adjust_latency = adjust_latency;
1145 s->early_requests = early_requests;
1146 pa_atomic_store(&s->seek_or_post_in_queue, 0);
1147 s->seek_windex = -1;
1149 s->sink_input->parent.process_msg = sink_input_process_msg;
1150 s->sink_input->pop = sink_input_pop_cb;
1151 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1152 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1153 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1154 s->sink_input->kill = sink_input_kill_cb;
1155 s->sink_input->moving = sink_input_moving_cb;
1156 s->sink_input->suspend = sink_input_suspend_cb;
1157 s->sink_input->send_event = sink_input_send_event_cb;
1158 s->sink_input->userdata = s;
1160 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1162 fix_playback_buffer_attr(s);
1164 pa_sink_input_get_silence(sink_input, &silence);
1165 s->memblockq = pa_memblockq_new(
1166 start_index,
1167 s->buffer_attr.maxlength,
1168 s->buffer_attr.tlength,
1169 pa_frame_size(&sink_input->sample_spec),
1170 s->buffer_attr.prebuf,
1171 s->buffer_attr.minreq,
1173 &silence);
1174 pa_memblock_unref(silence.memblock);
1176 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1178 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1180 /* pa_log("missing original: %li", (long int) *missing); */
1182 *ss = s->sink_input->sample_spec;
1183 *map = s->sink_input->channel_map;
1185 pa_idxset_put(c->output_streams, s, &s->index);
1187 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1188 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1189 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1190 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1191 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1193 pa_sink_input_put(s->sink_input);
1195 out:
1196 if (formats)
1197 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
1199 return s;
1202 /* Called from IO context */
1203 static void playback_stream_request_bytes(playback_stream *s) {
1204 size_t m, minreq;
1205 int previous_missing;
1207 playback_stream_assert_ref(s);
1209 m = pa_memblockq_pop_missing(s->memblockq);
1211 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1212 /* (unsigned long) m, */
1213 /* pa_memblockq_get_tlength(s->memblockq), */
1214 /* pa_memblockq_get_minreq(s->memblockq), */
1215 /* pa_memblockq_get_length(s->memblockq), */
1216 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1218 if (m <= 0)
1219 return;
1221 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1223 previous_missing = pa_atomic_add(&s->missing, (int) m);
1224 minreq = pa_memblockq_get_minreq(s->memblockq);
1226 if (pa_memblockq_prebuf_active(s->memblockq) ||
1227 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1228 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1231 /* Called from main context */
1232 static void playback_stream_send_killed(playback_stream *p) {
1233 pa_tagstruct *t;
1234 playback_stream_assert_ref(p);
1236 t = pa_tagstruct_new(NULL, 0);
1237 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1238 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1239 pa_tagstruct_putu32(t, p->index);
1240 pa_pstream_send_tagstruct(p->connection->pstream, t);
1243 /* Called from main context */
1244 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1245 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1246 pa_native_connection_assert_ref(c);
1248 if (!c->protocol)
1249 return -1;
1251 switch (code) {
1253 case CONNECTION_MESSAGE_REVOKE:
1254 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1255 break;
1257 case CONNECTION_MESSAGE_RELEASE:
1258 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1259 break;
1262 return 0;
1265 /* Called from main context */
1266 static void native_connection_unlink(pa_native_connection *c) {
1267 record_stream *r;
1268 output_stream *o;
1270 pa_assert(c);
1272 if (!c->protocol)
1273 return;
1275 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1277 if (c->options)
1278 pa_native_options_unref(c->options);
1280 while ((r = pa_idxset_first(c->record_streams, NULL)))
1281 record_stream_unlink(r);
1283 while ((o = pa_idxset_first(c->output_streams, NULL)))
1284 if (playback_stream_isinstance(o))
1285 playback_stream_unlink(PLAYBACK_STREAM(o));
1286 else
1287 upload_stream_unlink(UPLOAD_STREAM(o));
1289 if (c->subscription)
1290 pa_subscription_free(c->subscription);
1292 if (c->pstream)
1293 pa_pstream_unlink(c->pstream);
1295 if (c->auth_timeout_event) {
1296 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1297 c->auth_timeout_event = NULL;
1300 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1301 c->protocol = NULL;
1302 pa_native_connection_unref(c);
1305 /* Called from main context */
1306 static void native_connection_free(pa_object *o) {
1307 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1309 pa_assert(c);
1311 native_connection_unlink(c);
1313 pa_idxset_free(c->record_streams, NULL, NULL);
1314 pa_idxset_free(c->output_streams, NULL, NULL);
1316 pa_pdispatch_unref(c->pdispatch);
1317 pa_pstream_unref(c->pstream);
1318 pa_client_free(c->client);
1320 pa_xfree(c);
1323 /* Called from main context */
1324 static void native_connection_send_memblock(pa_native_connection *c) {
1325 uint32_t start;
1326 record_stream *r;
1328 start = PA_IDXSET_INVALID;
1329 for (;;) {
1330 pa_memchunk chunk;
1332 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1333 return;
1335 if (start == PA_IDXSET_INVALID)
1336 start = c->rrobin_index;
1337 else if (start == c->rrobin_index)
1338 return;
1340 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1341 pa_memchunk schunk = chunk;
1343 if (schunk.length > r->buffer_attr.fragsize)
1344 schunk.length = r->buffer_attr.fragsize;
1346 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1348 pa_memblockq_drop(r->memblockq, schunk.length);
1349 pa_memblock_unref(schunk.memblock);
1351 return;
1356 /*** sink input callbacks ***/
1358 /* Called from thread context */
1359 static void handle_seek(playback_stream *s, int64_t indexw) {
1360 playback_stream_assert_ref(s);
1362 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1364 if (s->sink_input->thread_info.underrun_for > 0) {
1366 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1368 if (pa_memblockq_is_readable(s->memblockq)) {
1370 /* We just ended an underrun, let's ask the sink
1371 * for a complete rewind rewrite */
1373 pa_log_debug("Requesting rewind due to end of underrun.");
1374 pa_sink_input_request_rewind(s->sink_input,
1375 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1376 s->sink_input->thread_info.underrun_for),
1377 FALSE, TRUE, FALSE);
1380 } else {
1381 int64_t indexr;
1383 indexr = pa_memblockq_get_read_index(s->memblockq);
1385 if (indexw < indexr) {
1386 /* OK, the sink already asked for this data, so
1387 * let's have it usk us again */
1389 pa_log_debug("Requesting rewind due to rewrite.");
1390 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1394 playback_stream_request_bytes(s);
1397 static void flush_write_no_account(pa_memblockq *q) {
1398 pa_memblockq_flush_write(q, FALSE);
1401 /* Called from thread context */
1402 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1403 pa_sink_input *i = PA_SINK_INPUT(o);
1404 playback_stream *s;
1406 pa_sink_input_assert_ref(i);
1407 s = PLAYBACK_STREAM(i->userdata);
1408 playback_stream_assert_ref(s);
1410 switch (code) {
1412 case SINK_INPUT_MESSAGE_SEEK:
1413 case SINK_INPUT_MESSAGE_POST_DATA: {
1414 int64_t windex = pa_memblockq_get_write_index(s->memblockq);
1416 if (code == SINK_INPUT_MESSAGE_SEEK) {
1417 /* The client side is incapable of accounting correctly
1418 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1419 * able to deal with that. */
1421 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1422 windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
1425 if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1426 if (pa_log_ratelimit(PA_LOG_WARN))
1427 pa_log_warn("Failed to push data into queue");
1428 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1429 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1432 /* If more data is in queue, we rewind later instead. */
1433 if (s->seek_windex != -1)
1434 windex = PA_MIN(windex, s->seek_windex);
1435 if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
1436 s->seek_windex = windex;
1437 else {
1438 s->seek_windex = -1;
1439 handle_seek(s, windex);
1441 return 0;
1444 case SINK_INPUT_MESSAGE_DRAIN:
1445 case SINK_INPUT_MESSAGE_FLUSH:
1446 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1447 case SINK_INPUT_MESSAGE_TRIGGER: {
1449 int64_t windex;
1450 pa_sink_input *isync;
1451 void (*func)(pa_memblockq *bq);
1453 switch (code) {
1454 case SINK_INPUT_MESSAGE_FLUSH:
1455 func = flush_write_no_account;
1456 break;
1458 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1459 func = pa_memblockq_prebuf_force;
1460 break;
1462 case SINK_INPUT_MESSAGE_DRAIN:
1463 case SINK_INPUT_MESSAGE_TRIGGER:
1464 func = pa_memblockq_prebuf_disable;
1465 break;
1467 default:
1468 pa_assert_not_reached();
1471 windex = pa_memblockq_get_write_index(s->memblockq);
1472 func(s->memblockq);
1473 handle_seek(s, windex);
1475 /* Do the same for all other members in the sync group */
1476 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1477 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1478 windex = pa_memblockq_get_write_index(ssync->memblockq);
1479 func(ssync->memblockq);
1480 handle_seek(ssync, windex);
1483 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1484 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1485 windex = pa_memblockq_get_write_index(ssync->memblockq);
1486 func(ssync->memblockq);
1487 handle_seek(ssync, windex);
1490 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1491 if (!pa_memblockq_is_readable(s->memblockq))
1492 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1493 else {
1494 s->drain_tag = PA_PTR_TO_UINT(userdata);
1495 s->drain_request = TRUE;
1499 return 0;
1502 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1503 /* Atomically get a snapshot of all timing parameters... */
1504 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1505 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1506 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1507 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1508 s->underrun_for = s->sink_input->thread_info.underrun_for;
1509 s->playing_for = s->sink_input->thread_info.playing_for;
1511 return 0;
1513 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1514 int64_t windex;
1516 windex = pa_memblockq_get_write_index(s->memblockq);
1518 pa_memblockq_prebuf_force(s->memblockq);
1520 handle_seek(s, windex);
1522 /* Fall through to the default handler */
1523 break;
1526 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1527 pa_usec_t *r = userdata;
1529 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1531 /* Fall through, the default handler will add in the extra
1532 * latency added by the resampler */
1533 break;
1536 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1537 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1538 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1539 return 0;
1543 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1546 /* Called from thread context */
1547 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1548 playback_stream *s;
1550 pa_sink_input_assert_ref(i);
1551 s = PLAYBACK_STREAM(i->userdata);
1552 playback_stream_assert_ref(s);
1553 pa_assert(chunk);
1555 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1557 if (pa_memblockq_is_readable(s->memblockq))
1558 s->is_underrun = FALSE;
1559 else {
1560 if (!s->is_underrun)
1561 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));
1563 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1564 s->drain_request = FALSE;
1565 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);
1566 } else if (!s->is_underrun)
1567 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1569 s->is_underrun = TRUE;
1571 playback_stream_request_bytes(s);
1574 /* This call will not fail with prebuf=0, hence we check for
1575 underrun explicitly above */
1576 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1577 return -1;
1579 chunk->length = PA_MIN(nbytes, chunk->length);
1581 if (i->thread_info.underrun_for > 0)
1582 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1584 pa_memblockq_drop(s->memblockq, chunk->length);
1585 playback_stream_request_bytes(s);
1587 return 0;
1590 /* Called from thread context */
1591 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1592 playback_stream *s;
1594 pa_sink_input_assert_ref(i);
1595 s = PLAYBACK_STREAM(i->userdata);
1596 playback_stream_assert_ref(s);
1598 /* If we are in an underrun, then we don't rewind */
1599 if (i->thread_info.underrun_for > 0)
1600 return;
1602 pa_memblockq_rewind(s->memblockq, nbytes);
1605 /* Called from thread context */
1606 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1607 playback_stream *s;
1609 pa_sink_input_assert_ref(i);
1610 s = PLAYBACK_STREAM(i->userdata);
1611 playback_stream_assert_ref(s);
1613 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1616 /* Called from thread context */
1617 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1618 playback_stream *s;
1619 size_t new_tlength, old_tlength;
1621 pa_sink_input_assert_ref(i);
1622 s = PLAYBACK_STREAM(i->userdata);
1623 playback_stream_assert_ref(s);
1625 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1626 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1628 if (old_tlength < new_tlength) {
1629 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1630 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1631 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1633 if (new_tlength == old_tlength)
1634 pa_log_debug("Failed to increase tlength");
1635 else {
1636 pa_log_debug("Notifying client about increased tlength");
1637 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);
1642 /* Called from main context */
1643 static void sink_input_kill_cb(pa_sink_input *i) {
1644 playback_stream *s;
1646 pa_sink_input_assert_ref(i);
1647 s = PLAYBACK_STREAM(i->userdata);
1648 playback_stream_assert_ref(s);
1650 playback_stream_send_killed(s);
1651 playback_stream_unlink(s);
1654 /* Called from main context */
1655 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1656 playback_stream *s;
1657 pa_tagstruct *t;
1659 pa_sink_input_assert_ref(i);
1660 s = PLAYBACK_STREAM(i->userdata);
1661 playback_stream_assert_ref(s);
1663 if (s->connection->version < 15)
1664 return;
1666 t = pa_tagstruct_new(NULL, 0);
1667 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1668 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1669 pa_tagstruct_putu32(t, s->index);
1670 pa_tagstruct_puts(t, event);
1671 pa_tagstruct_put_proplist(t, pl);
1672 pa_pstream_send_tagstruct(s->connection->pstream, t);
1675 /* Called from main context */
1676 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1677 playback_stream *s;
1678 pa_tagstruct *t;
1680 pa_sink_input_assert_ref(i);
1681 s = PLAYBACK_STREAM(i->userdata);
1682 playback_stream_assert_ref(s);
1684 if (s->connection->version < 12)
1685 return;
1687 t = pa_tagstruct_new(NULL, 0);
1688 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1689 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1690 pa_tagstruct_putu32(t, s->index);
1691 pa_tagstruct_put_boolean(t, suspend);
1692 pa_pstream_send_tagstruct(s->connection->pstream, t);
1695 /* Called from main context */
1696 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1697 playback_stream *s;
1698 pa_tagstruct *t;
1700 pa_sink_input_assert_ref(i);
1701 s = PLAYBACK_STREAM(i->userdata);
1702 playback_stream_assert_ref(s);
1704 if (!dest)
1705 return;
1707 fix_playback_buffer_attr(s);
1708 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1709 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1711 if (s->connection->version < 12)
1712 return;
1714 t = pa_tagstruct_new(NULL, 0);
1715 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1716 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1717 pa_tagstruct_putu32(t, s->index);
1718 pa_tagstruct_putu32(t, dest->index);
1719 pa_tagstruct_puts(t, dest->name);
1720 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1722 if (s->connection->version >= 13) {
1723 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1724 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1725 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1726 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1727 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1730 pa_pstream_send_tagstruct(s->connection->pstream, t);
1733 /*** source_output callbacks ***/
1735 /* Called from thread context */
1736 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1737 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1738 record_stream *s;
1740 pa_source_output_assert_ref(o);
1741 s = RECORD_STREAM(o->userdata);
1742 record_stream_assert_ref(s);
1744 switch (code) {
1745 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1746 /* Atomically get a snapshot of all timing parameters... */
1747 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1748 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1749 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1750 return 0;
1753 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1756 /* Called from thread context */
1757 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1758 record_stream *s;
1760 pa_source_output_assert_ref(o);
1761 s = RECORD_STREAM(o->userdata);
1762 record_stream_assert_ref(s);
1763 pa_assert(chunk);
1765 pa_atomic_add(&s->on_the_fly, chunk->length);
1766 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1769 static void source_output_kill_cb(pa_source_output *o) {
1770 record_stream *s;
1772 pa_source_output_assert_ref(o);
1773 s = RECORD_STREAM(o->userdata);
1774 record_stream_assert_ref(s);
1776 record_stream_send_killed(s);
1777 record_stream_unlink(s);
1780 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1781 record_stream *s;
1783 pa_source_output_assert_ref(o);
1784 s = RECORD_STREAM(o->userdata);
1785 record_stream_assert_ref(s);
1787 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1789 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1792 /* Called from main context */
1793 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1794 record_stream *s;
1795 pa_tagstruct *t;
1797 pa_source_output_assert_ref(o);
1798 s = RECORD_STREAM(o->userdata);
1799 record_stream_assert_ref(s);
1801 if (s->connection->version < 15)
1802 return;
1804 t = pa_tagstruct_new(NULL, 0);
1805 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1806 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1807 pa_tagstruct_putu32(t, s->index);
1808 pa_tagstruct_puts(t, event);
1809 pa_tagstruct_put_proplist(t, pl);
1810 pa_pstream_send_tagstruct(s->connection->pstream, t);
1813 /* Called from main context */
1814 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1815 record_stream *s;
1816 pa_tagstruct *t;
1818 pa_source_output_assert_ref(o);
1819 s = RECORD_STREAM(o->userdata);
1820 record_stream_assert_ref(s);
1822 if (s->connection->version < 12)
1823 return;
1825 t = pa_tagstruct_new(NULL, 0);
1826 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1827 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1828 pa_tagstruct_putu32(t, s->index);
1829 pa_tagstruct_put_boolean(t, suspend);
1830 pa_pstream_send_tagstruct(s->connection->pstream, t);
1833 /* Called from main context */
1834 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1835 record_stream *s;
1836 pa_tagstruct *t;
1838 pa_source_output_assert_ref(o);
1839 s = RECORD_STREAM(o->userdata);
1840 record_stream_assert_ref(s);
1842 if (!dest)
1843 return;
1845 fix_record_buffer_attr_pre(s);
1846 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1847 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1848 fix_record_buffer_attr_post(s);
1850 if (s->connection->version < 12)
1851 return;
1853 t = pa_tagstruct_new(NULL, 0);
1854 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1855 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1856 pa_tagstruct_putu32(t, s->index);
1857 pa_tagstruct_putu32(t, dest->index);
1858 pa_tagstruct_puts(t, dest->name);
1859 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1861 if (s->connection->version >= 13) {
1862 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1863 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1864 pa_tagstruct_put_usec(t, s->configured_source_latency);
1867 pa_pstream_send_tagstruct(s->connection->pstream, t);
1870 /*** pdispatch callbacks ***/
1872 static void protocol_error(pa_native_connection *c) {
1873 pa_log("protocol error, kicking client");
1874 native_connection_unlink(c);
1877 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1878 if (!(expression)) { \
1879 pa_pstream_send_error((pstream), (tag), (error)); \
1880 return; \
1882 } while(0);
1884 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
1885 if (!(expression)) { \
1886 pa_pstream_send_error((pstream), (tag), (error)); \
1887 goto label; \
1889 } while(0);
1891 static pa_tagstruct *reply_new(uint32_t tag) {
1892 pa_tagstruct *reply;
1894 reply = pa_tagstruct_new(NULL, 0);
1895 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1896 pa_tagstruct_putu32(reply, tag);
1897 return reply;
1900 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1901 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1902 playback_stream *s;
1903 uint32_t sink_index, syncid, missing;
1904 pa_buffer_attr attr;
1905 const char *name = NULL, *sink_name;
1906 pa_sample_spec ss;
1907 pa_channel_map map;
1908 pa_tagstruct *reply;
1909 pa_sink *sink = NULL;
1910 pa_cvolume volume;
1911 pa_bool_t
1912 corked = FALSE,
1913 no_remap = FALSE,
1914 no_remix = FALSE,
1915 fix_format = FALSE,
1916 fix_rate = FALSE,
1917 fix_channels = FALSE,
1918 no_move = FALSE,
1919 variable_rate = FALSE,
1920 muted = FALSE,
1921 adjust_latency = FALSE,
1922 early_requests = FALSE,
1923 dont_inhibit_auto_suspend = FALSE,
1924 volume_set = TRUE,
1925 muted_set = FALSE,
1926 fail_on_suspend = FALSE,
1927 relative_volume = FALSE,
1928 passthrough = FALSE;
1930 pa_sink_input_flags_t flags = 0;
1931 pa_proplist *p = NULL;
1932 int ret = PA_ERR_INVALID;
1933 uint8_t n_formats = 0;
1934 pa_format_info *format;
1935 pa_idxset *formats = NULL;
1936 uint32_t i;
1938 pa_native_connection_assert_ref(c);
1939 pa_assert(t);
1940 memset(&attr, 0, sizeof(attr));
1942 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1943 pa_tagstruct_get(
1945 PA_TAG_SAMPLE_SPEC, &ss,
1946 PA_TAG_CHANNEL_MAP, &map,
1947 PA_TAG_U32, &sink_index,
1948 PA_TAG_STRING, &sink_name,
1949 PA_TAG_U32, &attr.maxlength,
1950 PA_TAG_BOOLEAN, &corked,
1951 PA_TAG_U32, &attr.tlength,
1952 PA_TAG_U32, &attr.prebuf,
1953 PA_TAG_U32, &attr.minreq,
1954 PA_TAG_U32, &syncid,
1955 PA_TAG_CVOLUME, &volume,
1956 PA_TAG_INVALID) < 0) {
1958 protocol_error(c);
1959 goto finish;
1962 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
1963 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID, finish);
1964 CHECK_VALIDITY_GOTO(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID, finish);
1965 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
1966 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
1968 p = pa_proplist_new();
1970 if (name)
1971 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1973 if (c->version >= 12) {
1974 /* Since 0.9.8 the user can ask for a couple of additional flags */
1976 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1977 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1978 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1979 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1980 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1981 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1982 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1984 protocol_error(c);
1985 goto finish;
1989 if (c->version >= 13) {
1991 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1992 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1993 pa_tagstruct_get_proplist(t, p) < 0) {
1995 protocol_error(c);
1996 goto finish;
2000 if (c->version >= 14) {
2002 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2003 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2005 protocol_error(c);
2006 goto finish;
2010 if (c->version >= 15) {
2012 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2013 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2014 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2016 protocol_error(c);
2017 goto finish;
2021 if (c->version >= 17) {
2023 if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
2025 protocol_error(c);
2026 goto finish;
2030 if (c->version >= 18) {
2032 if (pa_tagstruct_get_boolean(t, &passthrough) < 0 ) {
2033 protocol_error(c);
2034 goto finish;
2038 if (c->version >= 21) {
2040 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2041 protocol_error(c);
2042 goto finish;
2045 if (n_formats)
2046 formats = pa_idxset_new(NULL, NULL);
2048 for (i = 0; i < n_formats; i++) {
2049 format = pa_format_info_new();
2050 if (pa_tagstruct_get_format_info(t, format) < 0) {
2051 protocol_error(c);
2052 goto finish;
2054 pa_idxset_put(formats, format, NULL);
2058 if (n_formats == 0) {
2059 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2060 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2061 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2062 } else {
2063 PA_IDXSET_FOREACH(format, formats, i) {
2064 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2068 if (!pa_tagstruct_eof(t)) {
2069 protocol_error(c);
2070 goto finish;
2073 if (sink_index != PA_INVALID_INDEX) {
2075 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
2076 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2077 goto finish;
2080 } else if (sink_name) {
2082 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
2083 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2084 goto finish;
2088 flags =
2089 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
2090 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
2091 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
2092 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
2093 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
2094 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
2095 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
2096 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
2097 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2098 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
2099 (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0);
2101 /* Only since protocol version 15 there's a seperate muted_set
2102 * flag. For older versions we synthesize it here */
2103 muted_set = muted_set || muted;
2105 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);
2106 /* We no longer own the formats idxset */
2107 formats = NULL;
2109 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2111 reply = reply_new(tag);
2112 pa_tagstruct_putu32(reply, s->index);
2113 pa_assert(s->sink_input);
2114 pa_tagstruct_putu32(reply, s->sink_input->index);
2115 pa_tagstruct_putu32(reply, missing);
2117 /* pa_log("initial request is %u", missing); */
2119 if (c->version >= 9) {
2120 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2122 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2123 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2124 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2125 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2128 if (c->version >= 12) {
2129 /* Since 0.9.8 we support sending the chosen sample
2130 * spec/channel map/device/suspend status back to the
2131 * client */
2133 pa_tagstruct_put_sample_spec(reply, &ss);
2134 pa_tagstruct_put_channel_map(reply, &map);
2136 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2137 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2139 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2142 if (c->version >= 13)
2143 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2145 if (c->version >= 21) {
2146 /* Send back the format we negotiated */
2147 if (s->sink_input->format)
2148 pa_tagstruct_put_format_info(reply, s->sink_input->format);
2149 else {
2150 pa_format_info *f = pa_format_info_new();
2151 pa_tagstruct_put_format_info(reply, f);
2152 pa_format_info_free(f);
2156 pa_pstream_send_tagstruct(c->pstream, reply);
2158 finish:
2159 if (p)
2160 pa_proplist_free(p);
2161 if (formats)
2162 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
2165 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2166 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2167 uint32_t channel;
2169 pa_native_connection_assert_ref(c);
2170 pa_assert(t);
2172 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2173 !pa_tagstruct_eof(t)) {
2174 protocol_error(c);
2175 return;
2178 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2180 switch (command) {
2182 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2183 playback_stream *s;
2184 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2185 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2186 return;
2189 playback_stream_unlink(s);
2190 break;
2193 case PA_COMMAND_DELETE_RECORD_STREAM: {
2194 record_stream *s;
2195 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2196 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2197 return;
2200 record_stream_unlink(s);
2201 break;
2204 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2205 upload_stream *s;
2207 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2208 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2209 return;
2212 upload_stream_unlink(s);
2213 break;
2216 default:
2217 pa_assert_not_reached();
2220 pa_pstream_send_simple_ack(c->pstream, tag);
2223 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2224 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2225 record_stream *s;
2226 pa_buffer_attr attr;
2227 uint32_t source_index;
2228 const char *name = NULL, *source_name;
2229 pa_sample_spec ss;
2230 pa_channel_map map;
2231 pa_tagstruct *reply;
2232 pa_source *source = NULL;
2233 pa_cvolume volume;
2234 pa_bool_t
2235 corked = FALSE,
2236 no_remap = FALSE,
2237 no_remix = FALSE,
2238 fix_format = FALSE,
2239 fix_rate = FALSE,
2240 fix_channels = FALSE,
2241 no_move = FALSE,
2242 variable_rate = FALSE,
2243 muted = FALSE,
2244 adjust_latency = FALSE,
2245 peak_detect = FALSE,
2246 early_requests = FALSE,
2247 dont_inhibit_auto_suspend = FALSE,
2248 volume_set = TRUE,
2249 muted_set = FALSE,
2250 fail_on_suspend = FALSE,
2251 relative_volume = FALSE,
2252 passthrough = FALSE;
2254 pa_source_output_flags_t flags = 0;
2255 pa_proplist *p = NULL;
2256 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2257 pa_sink_input *direct_on_input = NULL;
2258 int ret = PA_ERR_INVALID;
2259 uint8_t n_formats = 0;
2260 pa_format_info *format;
2261 pa_idxset *formats = NULL;
2262 uint32_t i;
2264 pa_native_connection_assert_ref(c);
2265 pa_assert(t);
2267 memset(&attr, 0, sizeof(attr));
2269 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2270 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2271 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2272 pa_tagstruct_getu32(t, &source_index) < 0 ||
2273 pa_tagstruct_gets(t, &source_name) < 0 ||
2274 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2275 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2276 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2278 protocol_error(c);
2279 goto finish;
2282 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
2283 CHECK_VALIDITY_GOTO(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID, finish);
2284 CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID, finish);
2285 CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
2287 p = pa_proplist_new();
2289 if (name)
2290 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2292 if (c->version >= 12) {
2293 /* Since 0.9.8 the user can ask for a couple of additional flags */
2295 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2296 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2297 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2298 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2299 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2300 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2301 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2303 protocol_error(c);
2304 goto finish;
2308 if (c->version >= 13) {
2310 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2311 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2312 pa_tagstruct_get_proplist(t, p) < 0 ||
2313 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2315 protocol_error(c);
2316 goto finish;
2320 if (c->version >= 14) {
2322 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2323 protocol_error(c);
2324 goto finish;
2328 if (c->version >= 15) {
2330 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2331 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2333 protocol_error(c);
2334 goto finish;
2338 if (c->version >= 22) {
2340 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2341 protocol_error(c);
2342 goto finish;
2345 if (n_formats)
2346 formats = pa_idxset_new(NULL, NULL);
2348 for (i = 0; i < n_formats; i++) {
2349 format = pa_format_info_new();
2350 if (pa_tagstruct_get_format_info(t, format) < 0) {
2351 protocol_error(c);
2352 goto finish;
2354 pa_idxset_put(formats, format, NULL);
2357 if (pa_tagstruct_get_cvolume(t, &volume) < 0 ||
2358 pa_tagstruct_get_boolean(t, &muted) < 0 ||
2359 pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2360 pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2361 pa_tagstruct_get_boolean(t, &relative_volume) < 0 ||
2362 pa_tagstruct_get_boolean(t, &passthrough) < 0) {
2364 protocol_error(c);
2365 goto finish;
2368 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
2371 if (n_formats == 0) {
2372 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2373 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2374 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2375 } else {
2376 PA_IDXSET_FOREACH(format, formats, i) {
2377 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2382 if (!pa_tagstruct_eof(t)) {
2383 protocol_error(c);
2384 goto finish;
2387 if (source_index != PA_INVALID_INDEX) {
2389 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2390 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2391 goto finish;
2394 } else if (source_name) {
2396 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2397 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2398 goto finish;
2402 if (direct_on_input_idx != PA_INVALID_INDEX) {
2404 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2405 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2406 goto finish;
2410 flags =
2411 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2412 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2413 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2414 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2415 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2416 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2417 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2418 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2419 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2420 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0) |
2421 (passthrough ? PA_SOURCE_OUTPUT_PASSTHROUGH : 0);
2423 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);
2425 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2427 reply = reply_new(tag);
2428 pa_tagstruct_putu32(reply, s->index);
2429 pa_assert(s->source_output);
2430 pa_tagstruct_putu32(reply, s->source_output->index);
2432 if (c->version >= 9) {
2433 /* Since 0.9 we support sending the buffer metrics back to the client */
2435 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2436 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2439 if (c->version >= 12) {
2440 /* Since 0.9.8 we support sending the chosen sample
2441 * spec/channel map/device/suspend status back to the
2442 * client */
2444 pa_tagstruct_put_sample_spec(reply, &ss);
2445 pa_tagstruct_put_channel_map(reply, &map);
2447 pa_tagstruct_putu32(reply, s->source_output->source->index);
2448 pa_tagstruct_puts(reply, s->source_output->source->name);
2450 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2453 if (c->version >= 13)
2454 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2456 if (c->version >= 22) {
2457 /* Send back the format we negotiated */
2458 if (s->source_output->format)
2459 pa_tagstruct_put_format_info(reply, s->source_output->format);
2460 else {
2461 pa_format_info *f = pa_format_info_new();
2462 pa_tagstruct_put_format_info(reply, f);
2463 pa_format_info_free(f);
2467 pa_pstream_send_tagstruct(c->pstream, reply);
2469 finish:
2470 if (p)
2471 pa_proplist_free(p);
2472 if (formats)
2473 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
2476 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2477 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2478 int ret;
2480 pa_native_connection_assert_ref(c);
2481 pa_assert(t);
2483 if (!pa_tagstruct_eof(t)) {
2484 protocol_error(c);
2485 return;
2488 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2489 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2490 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2492 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2494 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2497 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2498 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2499 const void*cookie;
2500 pa_tagstruct *reply;
2501 pa_bool_t shm_on_remote = FALSE, do_shm;
2503 pa_native_connection_assert_ref(c);
2504 pa_assert(t);
2506 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2507 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2508 !pa_tagstruct_eof(t)) {
2509 protocol_error(c);
2510 return;
2513 /* Minimum supported version */
2514 if (c->version < 8) {
2515 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2516 return;
2519 /* Starting with protocol version 13 the MSB of the version tag
2520 reflects if shm is available for this pa_native_connection or
2521 not. */
2522 if (c->version >= 13) {
2523 shm_on_remote = !!(c->version & 0x80000000U);
2524 c->version &= 0x7FFFFFFFU;
2527 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2529 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2531 if (!c->authorized) {
2532 pa_bool_t success = FALSE;
2534 #ifdef HAVE_CREDS
2535 const pa_creds *creds;
2537 if ((creds = pa_pdispatch_creds(pd))) {
2538 if (creds->uid == getuid())
2539 success = TRUE;
2540 else if (c->options->auth_group) {
2541 int r;
2542 gid_t gid;
2544 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2545 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2546 else if (gid == creds->gid)
2547 success = TRUE;
2549 if (!success) {
2550 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2551 pa_log_warn("Failed to check group membership.");
2552 else if (r > 0)
2553 success = TRUE;
2557 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2558 (unsigned long) creds->uid,
2559 (unsigned long) creds->gid,
2560 (int) success);
2562 #endif
2564 if (!success && c->options->auth_cookie) {
2565 const uint8_t *ac;
2567 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2568 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2569 success = TRUE;
2572 if (!success) {
2573 pa_log_warn("Denied access to client with invalid authorization data.");
2574 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2575 return;
2578 c->authorized = TRUE;
2579 if (c->auth_timeout_event) {
2580 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2581 c->auth_timeout_event = NULL;
2585 /* Enable shared memory support if possible */
2586 do_shm =
2587 pa_mempool_is_shared(c->protocol->core->mempool) &&
2588 c->is_local;
2590 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2592 if (do_shm)
2593 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2594 do_shm = FALSE;
2596 #ifdef HAVE_CREDS
2597 if (do_shm) {
2598 /* Only enable SHM if both sides are owned by the same
2599 * user. This is a security measure because otherwise data
2600 * private to the user might leak. */
2602 const pa_creds *creds;
2603 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2604 do_shm = FALSE;
2606 #endif
2608 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2609 pa_pstream_enable_shm(c->pstream, do_shm);
2611 reply = reply_new(tag);
2612 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2614 #ifdef HAVE_CREDS
2616 /* SHM support is only enabled after both sides made sure they are the same user. */
2618 pa_creds ucred;
2620 ucred.uid = getuid();
2621 ucred.gid = getgid();
2623 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2625 #else
2626 pa_pstream_send_tagstruct(c->pstream, reply);
2627 #endif
2630 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2631 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2632 const char *name = NULL;
2633 pa_proplist *p;
2634 pa_tagstruct *reply;
2636 pa_native_connection_assert_ref(c);
2637 pa_assert(t);
2639 p = pa_proplist_new();
2641 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2642 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2643 !pa_tagstruct_eof(t)) {
2645 protocol_error(c);
2646 pa_proplist_free(p);
2647 return;
2650 if (name)
2651 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2652 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2653 pa_proplist_free(p);
2654 return;
2657 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2658 pa_proplist_free(p);
2660 reply = reply_new(tag);
2662 if (c->version >= 13)
2663 pa_tagstruct_putu32(reply, c->client->index);
2665 pa_pstream_send_tagstruct(c->pstream, reply);
2668 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2669 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2670 const char *name;
2671 uint32_t idx = PA_IDXSET_INVALID;
2673 pa_native_connection_assert_ref(c);
2674 pa_assert(t);
2676 if (pa_tagstruct_gets(t, &name) < 0 ||
2677 !pa_tagstruct_eof(t)) {
2678 protocol_error(c);
2679 return;
2682 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2683 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);
2685 if (command == PA_COMMAND_LOOKUP_SINK) {
2686 pa_sink *sink;
2687 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2688 idx = sink->index;
2689 } else {
2690 pa_source *source;
2691 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2692 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2693 idx = source->index;
2696 if (idx == PA_IDXSET_INVALID)
2697 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2698 else {
2699 pa_tagstruct *reply;
2700 reply = reply_new(tag);
2701 pa_tagstruct_putu32(reply, idx);
2702 pa_pstream_send_tagstruct(c->pstream, reply);
2706 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2707 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2708 uint32_t idx;
2709 playback_stream *s;
2711 pa_native_connection_assert_ref(c);
2712 pa_assert(t);
2714 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2715 !pa_tagstruct_eof(t)) {
2716 protocol_error(c);
2717 return;
2720 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2721 s = pa_idxset_get_by_index(c->output_streams, idx);
2722 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2723 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2725 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);
2728 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2729 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2730 pa_tagstruct *reply;
2731 const pa_mempool_stat *stat;
2733 pa_native_connection_assert_ref(c);
2734 pa_assert(t);
2736 if (!pa_tagstruct_eof(t)) {
2737 protocol_error(c);
2738 return;
2741 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2743 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2745 reply = reply_new(tag);
2746 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2747 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2748 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2749 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2750 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2751 pa_pstream_send_tagstruct(c->pstream, reply);
2754 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2755 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2756 pa_tagstruct *reply;
2757 playback_stream *s;
2758 struct timeval tv, now;
2759 uint32_t idx;
2761 pa_native_connection_assert_ref(c);
2762 pa_assert(t);
2764 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2765 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2766 !pa_tagstruct_eof(t)) {
2767 protocol_error(c);
2768 return;
2771 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2772 s = pa_idxset_get_by_index(c->output_streams, idx);
2773 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2774 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2776 /* Get an atomic snapshot of all timing parameters */
2777 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);
2779 reply = reply_new(tag);
2780 pa_tagstruct_put_usec(reply,
2781 s->current_sink_latency +
2782 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2783 pa_tagstruct_put_usec(reply, 0);
2784 pa_tagstruct_put_boolean(reply,
2785 s->playing_for > 0 &&
2786 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2787 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2788 pa_tagstruct_put_timeval(reply, &tv);
2789 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2790 pa_tagstruct_puts64(reply, s->write_index);
2791 pa_tagstruct_puts64(reply, s->read_index);
2793 if (c->version >= 13) {
2794 pa_tagstruct_putu64(reply, s->underrun_for);
2795 pa_tagstruct_putu64(reply, s->playing_for);
2798 pa_pstream_send_tagstruct(c->pstream, reply);
2801 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2802 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2803 pa_tagstruct *reply;
2804 record_stream *s;
2805 struct timeval tv, now;
2806 uint32_t idx;
2808 pa_native_connection_assert_ref(c);
2809 pa_assert(t);
2811 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2812 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2813 !pa_tagstruct_eof(t)) {
2814 protocol_error(c);
2815 return;
2818 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2819 s = pa_idxset_get_by_index(c->record_streams, idx);
2820 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2822 /* Get an atomic snapshot of all timing parameters */
2823 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);
2825 reply = reply_new(tag);
2826 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2827 pa_tagstruct_put_usec(reply,
2828 s->current_source_latency +
2829 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec));
2830 pa_tagstruct_put_boolean(reply,
2831 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2832 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2833 pa_tagstruct_put_timeval(reply, &tv);
2834 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2835 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2836 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2837 pa_pstream_send_tagstruct(c->pstream, reply);
2840 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2841 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2842 upload_stream *s;
2843 uint32_t length;
2844 const char *name = NULL;
2845 pa_sample_spec ss;
2846 pa_channel_map map;
2847 pa_tagstruct *reply;
2848 pa_proplist *p;
2850 pa_native_connection_assert_ref(c);
2851 pa_assert(t);
2853 if (pa_tagstruct_gets(t, &name) < 0 ||
2854 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2855 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2856 pa_tagstruct_getu32(t, &length) < 0) {
2857 protocol_error(c);
2858 return;
2861 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2862 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2863 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2864 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2865 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2866 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2868 p = pa_proplist_new();
2870 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2871 !pa_tagstruct_eof(t)) {
2873 protocol_error(c);
2874 pa_proplist_free(p);
2875 return;
2878 if (c->version < 13)
2879 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2880 else if (!name)
2881 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2882 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2884 if (!name || !pa_namereg_is_valid_name(name)) {
2885 pa_proplist_free(p);
2886 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2889 s = upload_stream_new(c, &ss, &map, name, length, p);
2890 pa_proplist_free(p);
2892 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2894 reply = reply_new(tag);
2895 pa_tagstruct_putu32(reply, s->index);
2896 pa_tagstruct_putu32(reply, length);
2897 pa_pstream_send_tagstruct(c->pstream, reply);
2900 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2901 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2902 uint32_t channel;
2903 upload_stream *s;
2904 uint32_t idx;
2906 pa_native_connection_assert_ref(c);
2907 pa_assert(t);
2909 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2910 !pa_tagstruct_eof(t)) {
2911 protocol_error(c);
2912 return;
2915 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2917 s = pa_idxset_get_by_index(c->output_streams, channel);
2918 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2919 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2921 if (!s->memchunk.memblock)
2922 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2923 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2924 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2925 else
2926 pa_pstream_send_simple_ack(c->pstream, tag);
2928 upload_stream_unlink(s);
2931 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2932 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2933 uint32_t sink_index;
2934 pa_volume_t volume;
2935 pa_sink *sink;
2936 const char *name, *sink_name;
2937 uint32_t idx;
2938 pa_proplist *p;
2939 pa_tagstruct *reply;
2941 pa_native_connection_assert_ref(c);
2942 pa_assert(t);
2944 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2946 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2947 pa_tagstruct_gets(t, &sink_name) < 0 ||
2948 pa_tagstruct_getu32(t, &volume) < 0 ||
2949 pa_tagstruct_gets(t, &name) < 0) {
2950 protocol_error(c);
2951 return;
2954 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2955 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2956 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2957 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2959 if (sink_index != PA_INVALID_INDEX)
2960 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2961 else
2962 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2964 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2966 p = pa_proplist_new();
2968 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2969 !pa_tagstruct_eof(t)) {
2970 protocol_error(c);
2971 pa_proplist_free(p);
2972 return;
2975 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2977 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2978 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2979 pa_proplist_free(p);
2980 return;
2983 pa_proplist_free(p);
2985 reply = reply_new(tag);
2987 if (c->version >= 13)
2988 pa_tagstruct_putu32(reply, idx);
2990 pa_pstream_send_tagstruct(c->pstream, reply);
2993 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2994 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2995 const char *name;
2997 pa_native_connection_assert_ref(c);
2998 pa_assert(t);
3000 if (pa_tagstruct_gets(t, &name) < 0 ||
3001 !pa_tagstruct_eof(t)) {
3002 protocol_error(c);
3003 return;
3006 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3007 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3009 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
3010 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3011 return;
3014 pa_pstream_send_simple_ack(c->pstream, tag);
3017 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
3018 pa_assert(c);
3019 pa_assert(fixed);
3020 pa_assert(original);
3022 *fixed = *original;
3024 if (c->version < 12) {
3025 /* Before protocol version 12 we didn't support S32 samples,
3026 * so we need to lie about this to the client */
3028 if (fixed->format == PA_SAMPLE_S32LE)
3029 fixed->format = PA_SAMPLE_FLOAT32LE;
3030 if (fixed->format == PA_SAMPLE_S32BE)
3031 fixed->format = PA_SAMPLE_FLOAT32BE;
3034 if (c->version < 15) {
3035 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
3036 fixed->format = PA_SAMPLE_FLOAT32LE;
3037 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
3038 fixed->format = PA_SAMPLE_FLOAT32BE;
3042 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
3043 pa_sample_spec fixed_ss;
3045 pa_assert(t);
3046 pa_sink_assert_ref(sink);
3048 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
3050 pa_tagstruct_put(
3052 PA_TAG_U32, sink->index,
3053 PA_TAG_STRING, sink->name,
3054 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3055 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3056 PA_TAG_CHANNEL_MAP, &sink->channel_map,
3057 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
3058 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
3059 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
3060 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
3061 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
3062 PA_TAG_USEC, pa_sink_get_latency(sink),
3063 PA_TAG_STRING, sink->driver,
3064 PA_TAG_U32, sink->flags & ~PA_SINK_SHARE_VOLUME_WITH_MASTER,
3065 PA_TAG_INVALID);
3067 if (c->version >= 13) {
3068 pa_tagstruct_put_proplist(t, sink->proplist);
3069 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
3072 if (c->version >= 15) {
3073 pa_tagstruct_put_volume(t, sink->base_volume);
3074 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
3075 pa_log_error("Internal sink state is invalid.");
3076 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
3077 pa_tagstruct_putu32(t, sink->n_volume_steps);
3078 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
3081 if (c->version >= 16) {
3082 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
3084 if (sink->ports) {
3085 void *state;
3086 pa_device_port *p;
3088 PA_HASHMAP_FOREACH(p, sink->ports, state) {
3089 pa_tagstruct_puts(t, p->name);
3090 pa_tagstruct_puts(t, p->description);
3091 pa_tagstruct_putu32(t, p->priority);
3095 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
3098 if (c->version >= 21) {
3099 uint32_t i;
3100 pa_format_info *f;
3101 pa_idxset *formats = pa_sink_get_formats(sink);
3103 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3104 PA_IDXSET_FOREACH(f, formats, i) {
3105 pa_tagstruct_put_format_info(t, f);
3108 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
3112 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
3113 pa_sample_spec fixed_ss;
3115 pa_assert(t);
3116 pa_source_assert_ref(source);
3118 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
3120 pa_tagstruct_put(
3122 PA_TAG_U32, source->index,
3123 PA_TAG_STRING, source->name,
3124 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3125 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3126 PA_TAG_CHANNEL_MAP, &source->channel_map,
3127 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
3128 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
3129 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
3130 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
3131 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
3132 PA_TAG_USEC, pa_source_get_latency(source),
3133 PA_TAG_STRING, source->driver,
3134 PA_TAG_U32, source->flags,
3135 PA_TAG_INVALID);
3137 if (c->version >= 13) {
3138 pa_tagstruct_put_proplist(t, source->proplist);
3139 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
3142 if (c->version >= 15) {
3143 pa_tagstruct_put_volume(t, source->base_volume);
3144 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
3145 pa_log_error("Internal source state is invalid.");
3146 pa_tagstruct_putu32(t, pa_source_get_state(source));
3147 pa_tagstruct_putu32(t, source->n_volume_steps);
3148 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
3151 if (c->version >= 16) {
3153 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
3155 if (source->ports) {
3156 void *state;
3157 pa_device_port *p;
3159 PA_HASHMAP_FOREACH(p, source->ports, state) {
3160 pa_tagstruct_puts(t, p->name);
3161 pa_tagstruct_puts(t, p->description);
3162 pa_tagstruct_putu32(t, p->priority);
3166 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
3169 if (c->version >= 22) {
3170 uint32_t i;
3171 pa_format_info *f;
3172 pa_idxset *formats = pa_source_get_formats(source);
3174 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3175 PA_IDXSET_FOREACH(f, formats, i) {
3176 pa_tagstruct_put_format_info(t, f);
3179 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
3183 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
3184 pa_assert(t);
3185 pa_assert(client);
3187 pa_tagstruct_putu32(t, client->index);
3188 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
3189 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
3190 pa_tagstruct_puts(t, client->driver);
3192 if (c->version >= 13)
3193 pa_tagstruct_put_proplist(t, client->proplist);
3196 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
3197 void *state = NULL;
3198 pa_card_profile *p;
3200 pa_assert(t);
3201 pa_assert(card);
3203 pa_tagstruct_putu32(t, card->index);
3204 pa_tagstruct_puts(t, card->name);
3205 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
3206 pa_tagstruct_puts(t, card->driver);
3208 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
3210 if (card->profiles) {
3211 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
3212 pa_tagstruct_puts(t, p->name);
3213 pa_tagstruct_puts(t, p->description);
3214 pa_tagstruct_putu32(t, p->n_sinks);
3215 pa_tagstruct_putu32(t, p->n_sources);
3216 pa_tagstruct_putu32(t, p->priority);
3220 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
3221 pa_tagstruct_put_proplist(t, card->proplist);
3224 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3225 pa_assert(t);
3226 pa_assert(module);
3228 pa_tagstruct_putu32(t, module->index);
3229 pa_tagstruct_puts(t, module->name);
3230 pa_tagstruct_puts(t, module->argument);
3231 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3233 if (c->version < 15)
3234 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
3236 if (c->version >= 15)
3237 pa_tagstruct_put_proplist(t, module->proplist);
3240 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3241 pa_sample_spec fixed_ss;
3242 pa_usec_t sink_latency;
3243 pa_cvolume v;
3244 pa_bool_t has_volume = FALSE;
3246 pa_assert(t);
3247 pa_sink_input_assert_ref(s);
3249 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3251 has_volume = pa_sink_input_is_volume_readable(s);
3252 if (has_volume)
3253 pa_sink_input_get_volume(s, &v, TRUE);
3254 else
3255 pa_cvolume_reset(&v, fixed_ss.channels);
3257 pa_tagstruct_putu32(t, s->index);
3258 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3259 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3260 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3261 pa_tagstruct_putu32(t, s->sink->index);
3262 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3263 pa_tagstruct_put_channel_map(t, &s->channel_map);
3264 pa_tagstruct_put_cvolume(t, &v);
3265 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3266 pa_tagstruct_put_usec(t, sink_latency);
3267 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3268 pa_tagstruct_puts(t, s->driver);
3269 if (c->version >= 11)
3270 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3271 if (c->version >= 13)
3272 pa_tagstruct_put_proplist(t, s->proplist);
3273 if (c->version >= 19)
3274 pa_tagstruct_put_boolean(t, (pa_sink_input_get_state(s) == PA_SINK_INPUT_CORKED));
3275 if (c->version >= 20) {
3276 pa_tagstruct_put_boolean(t, has_volume);
3277 pa_tagstruct_put_boolean(t, s->volume_writable);
3279 if (c->version >= 21)
3280 pa_tagstruct_put_format_info(t, s->format);
3283 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3284 pa_sample_spec fixed_ss;
3285 pa_usec_t source_latency;
3286 pa_cvolume v;
3287 pa_bool_t has_volume = FALSE;
3289 pa_assert(t);
3290 pa_source_output_assert_ref(s);
3292 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3294 has_volume = pa_source_output_is_volume_readable(s);
3295 if (has_volume)
3296 pa_source_output_get_volume(s, &v, TRUE);
3297 else
3298 pa_cvolume_reset(&v, fixed_ss.channels);
3300 pa_tagstruct_putu32(t, s->index);
3301 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3302 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3303 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3304 pa_tagstruct_putu32(t, s->source->index);
3305 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3306 pa_tagstruct_put_channel_map(t, &s->channel_map);
3307 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3308 pa_tagstruct_put_usec(t, source_latency);
3309 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3310 pa_tagstruct_puts(t, s->driver);
3311 if (c->version >= 13)
3312 pa_tagstruct_put_proplist(t, s->proplist);
3313 if (c->version >= 19)
3314 pa_tagstruct_put_boolean(t, (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_CORKED));
3315 if (c->version >= 22) {
3316 pa_tagstruct_put_cvolume(t, &v);
3317 pa_tagstruct_put_boolean(t, pa_source_output_get_mute(s));
3318 pa_tagstruct_put_boolean(t, has_volume);
3319 pa_tagstruct_put_boolean(t, s->volume_writable);
3320 pa_tagstruct_put_format_info(t, s->format);
3324 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3325 pa_sample_spec fixed_ss;
3326 pa_cvolume v;
3328 pa_assert(t);
3329 pa_assert(e);
3331 if (e->memchunk.memblock)
3332 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3333 else
3334 memset(&fixed_ss, 0, sizeof(fixed_ss));
3336 pa_tagstruct_putu32(t, e->index);
3337 pa_tagstruct_puts(t, e->name);
3339 if (e->volume_is_set)
3340 v = e->volume;
3341 else
3342 pa_cvolume_init(&v);
3344 pa_tagstruct_put_cvolume(t, &v);
3345 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3346 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3347 pa_tagstruct_put_channel_map(t, &e->channel_map);
3348 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3349 pa_tagstruct_put_boolean(t, e->lazy);
3350 pa_tagstruct_puts(t, e->filename);
3352 if (c->version >= 13)
3353 pa_tagstruct_put_proplist(t, e->proplist);
3356 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3357 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3358 uint32_t idx;
3359 pa_sink *sink = NULL;
3360 pa_source *source = NULL;
3361 pa_client *client = NULL;
3362 pa_card *card = NULL;
3363 pa_module *module = NULL;
3364 pa_sink_input *si = NULL;
3365 pa_source_output *so = NULL;
3366 pa_scache_entry *sce = NULL;
3367 const char *name = NULL;
3368 pa_tagstruct *reply;
3370 pa_native_connection_assert_ref(c);
3371 pa_assert(t);
3373 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3374 (command != PA_COMMAND_GET_CLIENT_INFO &&
3375 command != PA_COMMAND_GET_MODULE_INFO &&
3376 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3377 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3378 pa_tagstruct_gets(t, &name) < 0) ||
3379 !pa_tagstruct_eof(t)) {
3380 protocol_error(c);
3381 return;
3384 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3385 CHECK_VALIDITY(c->pstream, !name ||
3386 (command == PA_COMMAND_GET_SINK_INFO &&
3387 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3388 (command == PA_COMMAND_GET_SOURCE_INFO &&
3389 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3390 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3391 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3392 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3393 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3395 if (command == PA_COMMAND_GET_SINK_INFO) {
3396 if (idx != PA_INVALID_INDEX)
3397 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3398 else
3399 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3400 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3401 if (idx != PA_INVALID_INDEX)
3402 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3403 else
3404 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3405 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3406 if (idx != PA_INVALID_INDEX)
3407 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3408 else
3409 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3410 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3411 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3412 else if (command == PA_COMMAND_GET_MODULE_INFO)
3413 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3414 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3415 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3416 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3417 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3418 else {
3419 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3420 if (idx != PA_INVALID_INDEX)
3421 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3422 else
3423 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3426 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3427 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3428 return;
3431 reply = reply_new(tag);
3432 if (sink)
3433 sink_fill_tagstruct(c, reply, sink);
3434 else if (source)
3435 source_fill_tagstruct(c, reply, source);
3436 else if (client)
3437 client_fill_tagstruct(c, reply, client);
3438 else if (card)
3439 card_fill_tagstruct(c, reply, card);
3440 else if (module)
3441 module_fill_tagstruct(c, reply, module);
3442 else if (si)
3443 sink_input_fill_tagstruct(c, reply, si);
3444 else if (so)
3445 source_output_fill_tagstruct(c, reply, so);
3446 else
3447 scache_fill_tagstruct(c, reply, sce);
3448 pa_pstream_send_tagstruct(c->pstream, reply);
3451 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3452 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3453 pa_idxset *i;
3454 uint32_t idx;
3455 void *p;
3456 pa_tagstruct *reply;
3458 pa_native_connection_assert_ref(c);
3459 pa_assert(t);
3461 if (!pa_tagstruct_eof(t)) {
3462 protocol_error(c);
3463 return;
3466 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3468 reply = reply_new(tag);
3470 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3471 i = c->protocol->core->sinks;
3472 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3473 i = c->protocol->core->sources;
3474 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3475 i = c->protocol->core->clients;
3476 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3477 i = c->protocol->core->cards;
3478 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3479 i = c->protocol->core->modules;
3480 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3481 i = c->protocol->core->sink_inputs;
3482 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3483 i = c->protocol->core->source_outputs;
3484 else {
3485 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3486 i = c->protocol->core->scache;
3489 if (i) {
3490 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3491 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3492 sink_fill_tagstruct(c, reply, p);
3493 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3494 source_fill_tagstruct(c, reply, p);
3495 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3496 client_fill_tagstruct(c, reply, p);
3497 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3498 card_fill_tagstruct(c, reply, p);
3499 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3500 module_fill_tagstruct(c, reply, p);
3501 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3502 sink_input_fill_tagstruct(c, reply, p);
3503 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3504 source_output_fill_tagstruct(c, reply, p);
3505 else {
3506 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3507 scache_fill_tagstruct(c, reply, p);
3512 pa_pstream_send_tagstruct(c->pstream, reply);
3515 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3516 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3517 pa_tagstruct *reply;
3518 pa_sink *def_sink;
3519 pa_source *def_source;
3520 pa_sample_spec fixed_ss;
3521 char *h, *u;
3523 pa_native_connection_assert_ref(c);
3524 pa_assert(t);
3526 if (!pa_tagstruct_eof(t)) {
3527 protocol_error(c);
3528 return;
3531 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3533 reply = reply_new(tag);
3534 pa_tagstruct_puts(reply, PACKAGE_NAME);
3535 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3537 u = pa_get_user_name_malloc();
3538 pa_tagstruct_puts(reply, u);
3539 pa_xfree(u);
3541 h = pa_get_host_name_malloc();
3542 pa_tagstruct_puts(reply, h);
3543 pa_xfree(h);
3545 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3546 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3548 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3549 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3550 def_source = pa_namereg_get_default_source(c->protocol->core);
3551 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3553 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3555 if (c->version >= 15)
3556 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3558 pa_pstream_send_tagstruct(c->pstream, reply);
3561 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3562 pa_tagstruct *t;
3563 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3565 pa_native_connection_assert_ref(c);
3567 t = pa_tagstruct_new(NULL, 0);
3568 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3569 pa_tagstruct_putu32(t, (uint32_t) -1);
3570 pa_tagstruct_putu32(t, e);
3571 pa_tagstruct_putu32(t, idx);
3572 pa_pstream_send_tagstruct(c->pstream, t);
3575 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3576 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3577 pa_subscription_mask_t m;
3579 pa_native_connection_assert_ref(c);
3580 pa_assert(t);
3582 if (pa_tagstruct_getu32(t, &m) < 0 ||
3583 !pa_tagstruct_eof(t)) {
3584 protocol_error(c);
3585 return;
3588 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3589 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3591 if (c->subscription)
3592 pa_subscription_free(c->subscription);
3594 if (m != 0) {
3595 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3596 pa_assert(c->subscription);
3597 } else
3598 c->subscription = NULL;
3600 pa_pstream_send_simple_ack(c->pstream, tag);
3603 static void command_set_volume(
3604 pa_pdispatch *pd,
3605 uint32_t command,
3606 uint32_t tag,
3607 pa_tagstruct *t,
3608 void *userdata) {
3610 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3611 uint32_t idx;
3612 pa_cvolume volume;
3613 pa_sink *sink = NULL;
3614 pa_source *source = NULL;
3615 pa_sink_input *si = NULL;
3616 pa_source_output *so = NULL;
3617 const char *name = NULL;
3618 const char *client_name;
3620 pa_native_connection_assert_ref(c);
3621 pa_assert(t);
3623 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3624 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3625 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3626 pa_tagstruct_get_cvolume(t, &volume) ||
3627 !pa_tagstruct_eof(t)) {
3628 protocol_error(c);
3629 return;
3632 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3633 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);
3634 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3635 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3636 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3637 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3639 switch (command) {
3641 case PA_COMMAND_SET_SINK_VOLUME:
3642 if (idx != PA_INVALID_INDEX)
3643 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3644 else
3645 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3646 break;
3648 case PA_COMMAND_SET_SOURCE_VOLUME:
3649 if (idx != PA_INVALID_INDEX)
3650 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3651 else
3652 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3653 break;
3655 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3656 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3657 break;
3659 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME:
3660 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3661 break;
3663 default:
3664 pa_assert_not_reached();
3667 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
3669 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3671 if (sink) {
3672 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3674 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3675 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3676 } else if (source) {
3677 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3679 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3680 pa_source_set_volume(source, &volume, TRUE, TRUE);
3681 } else if (si) {
3682 CHECK_VALIDITY(c->pstream, si->volume_writable, tag, PA_ERR_BADSTATE);
3683 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3685 pa_log_debug("Client %s changes volume of sink input %s.",
3686 client_name,
3687 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3688 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3689 } else if (so) {
3690 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &so->sample_spec), tag, PA_ERR_INVALID);
3692 pa_log_debug("Client %s changes volume of source output %s.",
3693 client_name,
3694 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
3695 pa_source_output_set_volume(so, &volume, TRUE, TRUE);
3698 pa_pstream_send_simple_ack(c->pstream, tag);
3701 static void command_set_mute(
3702 pa_pdispatch *pd,
3703 uint32_t command,
3704 uint32_t tag,
3705 pa_tagstruct *t,
3706 void *userdata) {
3708 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3709 uint32_t idx;
3710 pa_bool_t mute;
3711 pa_sink *sink = NULL;
3712 pa_source *source = NULL;
3713 pa_sink_input *si = NULL;
3714 pa_source_output *so = NULL;
3715 const char *name = NULL, *client_name;
3717 pa_native_connection_assert_ref(c);
3718 pa_assert(t);
3720 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3721 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3722 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3723 pa_tagstruct_get_boolean(t, &mute) ||
3724 !pa_tagstruct_eof(t)) {
3725 protocol_error(c);
3726 return;
3729 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3730 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);
3731 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3732 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3733 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3735 switch (command) {
3737 case PA_COMMAND_SET_SINK_MUTE:
3738 if (idx != PA_INVALID_INDEX)
3739 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3740 else
3741 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3743 break;
3745 case PA_COMMAND_SET_SOURCE_MUTE:
3746 if (idx != PA_INVALID_INDEX)
3747 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3748 else
3749 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3751 break;
3753 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3754 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3755 break;
3757 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE:
3758 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3759 break;
3761 default:
3762 pa_assert_not_reached();
3765 CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
3767 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3769 if (sink) {
3770 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3771 pa_sink_set_mute(sink, mute, TRUE);
3772 } else if (source) {
3773 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3774 pa_source_set_mute(source, mute, TRUE);
3775 } else if (si) {
3776 pa_log_debug("Client %s changes mute of sink input %s.",
3777 client_name,
3778 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3779 pa_sink_input_set_mute(si, mute, TRUE);
3780 } else if (so) {
3781 pa_log_debug("Client %s changes mute of source output %s.",
3782 client_name,
3783 pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
3784 pa_source_output_set_mute(so, mute, TRUE);
3787 pa_pstream_send_simple_ack(c->pstream, tag);
3790 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3791 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3792 uint32_t idx;
3793 pa_bool_t b;
3794 playback_stream *s;
3796 pa_native_connection_assert_ref(c);
3797 pa_assert(t);
3799 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3800 pa_tagstruct_get_boolean(t, &b) < 0 ||
3801 !pa_tagstruct_eof(t)) {
3802 protocol_error(c);
3803 return;
3806 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3807 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3808 s = pa_idxset_get_by_index(c->output_streams, idx);
3809 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3810 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3812 pa_sink_input_cork(s->sink_input, b);
3814 if (b)
3815 s->is_underrun = TRUE;
3817 pa_pstream_send_simple_ack(c->pstream, tag);
3820 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3821 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3822 uint32_t idx;
3823 playback_stream *s;
3825 pa_native_connection_assert_ref(c);
3826 pa_assert(t);
3828 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3829 !pa_tagstruct_eof(t)) {
3830 protocol_error(c);
3831 return;
3834 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3835 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3836 s = pa_idxset_get_by_index(c->output_streams, idx);
3837 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3838 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3840 switch (command) {
3841 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3842 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3843 break;
3845 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3846 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3847 break;
3849 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3850 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3851 break;
3853 default:
3854 pa_assert_not_reached();
3857 pa_pstream_send_simple_ack(c->pstream, tag);
3860 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3861 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3862 uint32_t idx;
3863 record_stream *s;
3864 pa_bool_t b;
3866 pa_native_connection_assert_ref(c);
3867 pa_assert(t);
3869 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3870 pa_tagstruct_get_boolean(t, &b) < 0 ||
3871 !pa_tagstruct_eof(t)) {
3872 protocol_error(c);
3873 return;
3876 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3877 s = pa_idxset_get_by_index(c->record_streams, idx);
3878 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3880 pa_source_output_cork(s->source_output, b);
3881 pa_memblockq_prebuf_force(s->memblockq);
3882 pa_pstream_send_simple_ack(c->pstream, tag);
3885 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3886 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3887 uint32_t idx;
3888 record_stream *s;
3890 pa_native_connection_assert_ref(c);
3891 pa_assert(t);
3893 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3894 !pa_tagstruct_eof(t)) {
3895 protocol_error(c);
3896 return;
3899 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3900 s = pa_idxset_get_by_index(c->record_streams, idx);
3901 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3903 pa_memblockq_flush_read(s->memblockq);
3904 pa_pstream_send_simple_ack(c->pstream, tag);
3907 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3908 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3909 uint32_t idx;
3910 pa_buffer_attr a;
3911 pa_tagstruct *reply;
3913 pa_native_connection_assert_ref(c);
3914 pa_assert(t);
3916 memset(&a, 0, sizeof(a));
3918 if (pa_tagstruct_getu32(t, &idx) < 0) {
3919 protocol_error(c);
3920 return;
3923 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3925 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3926 playback_stream *s;
3927 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3929 s = pa_idxset_get_by_index(c->output_streams, idx);
3930 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3931 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3933 if (pa_tagstruct_get(
3935 PA_TAG_U32, &a.maxlength,
3936 PA_TAG_U32, &a.tlength,
3937 PA_TAG_U32, &a.prebuf,
3938 PA_TAG_U32, &a.minreq,
3939 PA_TAG_INVALID) < 0 ||
3940 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3941 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3942 !pa_tagstruct_eof(t)) {
3943 protocol_error(c);
3944 return;
3947 s->adjust_latency = adjust_latency;
3948 s->early_requests = early_requests;
3949 s->buffer_attr_req = a;
3951 fix_playback_buffer_attr(s);
3952 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);
3954 reply = reply_new(tag);
3955 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3956 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3957 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3958 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3960 if (c->version >= 13)
3961 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3963 } else {
3964 record_stream *s;
3965 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3966 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3968 s = pa_idxset_get_by_index(c->record_streams, idx);
3969 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3971 if (pa_tagstruct_get(
3973 PA_TAG_U32, &a.maxlength,
3974 PA_TAG_U32, &a.fragsize,
3975 PA_TAG_INVALID) < 0 ||
3976 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3977 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3978 !pa_tagstruct_eof(t)) {
3979 protocol_error(c);
3980 return;
3983 s->adjust_latency = adjust_latency;
3984 s->early_requests = early_requests;
3985 s->buffer_attr_req = a;
3987 fix_record_buffer_attr_pre(s);
3988 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3989 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3990 fix_record_buffer_attr_post(s);
3992 reply = reply_new(tag);
3993 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3994 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3996 if (c->version >= 13)
3997 pa_tagstruct_put_usec(reply, s->configured_source_latency);
4000 pa_pstream_send_tagstruct(c->pstream, reply);
4003 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4004 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4005 uint32_t idx;
4006 uint32_t rate;
4008 pa_native_connection_assert_ref(c);
4009 pa_assert(t);
4011 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4012 pa_tagstruct_getu32(t, &rate) < 0 ||
4013 !pa_tagstruct_eof(t)) {
4014 protocol_error(c);
4015 return;
4018 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4019 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
4021 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
4022 playback_stream *s;
4024 s = pa_idxset_get_by_index(c->output_streams, idx);
4025 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4026 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4028 pa_sink_input_set_rate(s->sink_input, rate);
4030 } else {
4031 record_stream *s;
4032 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
4034 s = pa_idxset_get_by_index(c->record_streams, idx);
4035 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4037 pa_source_output_set_rate(s->source_output, rate);
4040 pa_pstream_send_simple_ack(c->pstream, tag);
4043 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4044 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4045 uint32_t idx;
4046 uint32_t mode;
4047 pa_proplist *p;
4049 pa_native_connection_assert_ref(c);
4050 pa_assert(t);
4052 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4054 p = pa_proplist_new();
4056 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
4058 if (pa_tagstruct_getu32(t, &mode) < 0 ||
4059 pa_tagstruct_get_proplist(t, p) < 0 ||
4060 !pa_tagstruct_eof(t)) {
4061 protocol_error(c);
4062 pa_proplist_free(p);
4063 return;
4066 } else {
4068 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4069 pa_tagstruct_getu32(t, &mode) < 0 ||
4070 pa_tagstruct_get_proplist(t, p) < 0 ||
4071 !pa_tagstruct_eof(t)) {
4072 protocol_error(c);
4073 pa_proplist_free(p);
4074 return;
4078 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
4079 pa_proplist_free(p);
4080 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
4083 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
4084 playback_stream *s;
4086 s = pa_idxset_get_by_index(c->output_streams, idx);
4087 if (!s || !playback_stream_isinstance(s)) {
4088 pa_proplist_free(p);
4089 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
4091 pa_sink_input_update_proplist(s->sink_input, mode, p);
4093 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
4094 record_stream *s;
4096 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
4097 pa_proplist_free(p);
4098 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
4100 pa_source_output_update_proplist(s->source_output, mode, p);
4102 } else {
4103 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
4105 pa_client_update_proplist(c->client, mode, p);
4108 pa_pstream_send_simple_ack(c->pstream, tag);
4109 pa_proplist_free(p);
4112 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4113 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4114 uint32_t idx;
4115 unsigned changed = 0;
4116 pa_proplist *p;
4117 pa_strlist *l = NULL;
4119 pa_native_connection_assert_ref(c);
4120 pa_assert(t);
4122 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4124 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
4126 if (pa_tagstruct_getu32(t, &idx) < 0) {
4127 protocol_error(c);
4128 return;
4132 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4133 playback_stream *s;
4135 s = pa_idxset_get_by_index(c->output_streams, idx);
4136 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4137 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4139 p = s->sink_input->proplist;
4141 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4142 record_stream *s;
4144 s = pa_idxset_get_by_index(c->record_streams, idx);
4145 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4147 p = s->source_output->proplist;
4148 } else {
4149 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4151 p = c->client->proplist;
4154 for (;;) {
4155 const char *k;
4157 if (pa_tagstruct_gets(t, &k) < 0) {
4158 protocol_error(c);
4159 pa_strlist_free(l);
4160 return;
4163 if (!k)
4164 break;
4166 l = pa_strlist_prepend(l, k);
4169 if (!pa_tagstruct_eof(t)) {
4170 protocol_error(c);
4171 pa_strlist_free(l);
4172 return;
4175 for (;;) {
4176 char *z;
4178 l = pa_strlist_pop(l, &z);
4180 if (!z)
4181 break;
4183 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
4184 pa_xfree(z);
4187 pa_pstream_send_simple_ack(c->pstream, tag);
4189 if (changed) {
4190 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4191 playback_stream *s;
4193 s = pa_idxset_get_by_index(c->output_streams, idx);
4194 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
4196 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4197 record_stream *s;
4199 s = pa_idxset_get_by_index(c->record_streams, idx);
4200 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
4202 } else {
4203 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4204 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
4209 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4210 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4211 const char *s;
4213 pa_native_connection_assert_ref(c);
4214 pa_assert(t);
4216 if (pa_tagstruct_gets(t, &s) < 0 ||
4217 !pa_tagstruct_eof(t)) {
4218 protocol_error(c);
4219 return;
4222 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4223 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
4225 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
4226 pa_source *source;
4228 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
4229 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4231 pa_namereg_set_default_source(c->protocol->core, source);
4232 } else {
4233 pa_sink *sink;
4234 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
4236 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
4237 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4239 pa_namereg_set_default_sink(c->protocol->core, sink);
4242 pa_pstream_send_simple_ack(c->pstream, tag);
4245 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4246 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4247 uint32_t idx;
4248 const char *name;
4250 pa_native_connection_assert_ref(c);
4251 pa_assert(t);
4253 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4254 pa_tagstruct_gets(t, &name) < 0 ||
4255 !pa_tagstruct_eof(t)) {
4256 protocol_error(c);
4257 return;
4260 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4261 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
4263 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
4264 playback_stream *s;
4266 s = pa_idxset_get_by_index(c->output_streams, idx);
4267 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4268 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4270 pa_sink_input_set_name(s->sink_input, name);
4272 } else {
4273 record_stream *s;
4274 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4276 s = pa_idxset_get_by_index(c->record_streams, idx);
4277 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4279 pa_source_output_set_name(s->source_output, name);
4282 pa_pstream_send_simple_ack(c->pstream, tag);
4285 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4286 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4287 uint32_t idx;
4289 pa_native_connection_assert_ref(c);
4290 pa_assert(t);
4292 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4293 !pa_tagstruct_eof(t)) {
4294 protocol_error(c);
4295 return;
4298 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4300 if (command == PA_COMMAND_KILL_CLIENT) {
4301 pa_client *client;
4303 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4304 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4306 pa_native_connection_ref(c);
4307 pa_client_kill(client);
4309 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4310 pa_sink_input *s;
4312 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4313 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4315 pa_native_connection_ref(c);
4316 pa_sink_input_kill(s);
4317 } else {
4318 pa_source_output *s;
4320 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4322 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4323 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4325 pa_native_connection_ref(c);
4326 pa_source_output_kill(s);
4329 pa_pstream_send_simple_ack(c->pstream, tag);
4330 pa_native_connection_unref(c);
4333 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4334 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4335 pa_module *m;
4336 const char *name, *argument;
4337 pa_tagstruct *reply;
4339 pa_native_connection_assert_ref(c);
4340 pa_assert(t);
4342 if (pa_tagstruct_gets(t, &name) < 0 ||
4343 pa_tagstruct_gets(t, &argument) < 0 ||
4344 !pa_tagstruct_eof(t)) {
4345 protocol_error(c);
4346 return;
4349 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4350 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4351 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4353 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4354 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4355 return;
4358 reply = reply_new(tag);
4359 pa_tagstruct_putu32(reply, m->index);
4360 pa_pstream_send_tagstruct(c->pstream, reply);
4363 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4364 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4365 uint32_t idx;
4366 pa_module *m;
4368 pa_native_connection_assert_ref(c);
4369 pa_assert(t);
4371 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4372 !pa_tagstruct_eof(t)) {
4373 protocol_error(c);
4374 return;
4377 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4378 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4379 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4381 pa_module_unload_request(m, FALSE);
4382 pa_pstream_send_simple_ack(c->pstream, tag);
4385 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4386 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4387 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4388 const char *name_device = NULL;
4390 pa_native_connection_assert_ref(c);
4391 pa_assert(t);
4393 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4394 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4395 pa_tagstruct_gets(t, &name_device) < 0 ||
4396 !pa_tagstruct_eof(t)) {
4397 protocol_error(c);
4398 return;
4401 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4402 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4404 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);
4405 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4406 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4407 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4409 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4410 pa_sink_input *si = NULL;
4411 pa_sink *sink = NULL;
4413 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4415 if (idx_device != PA_INVALID_INDEX)
4416 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4417 else
4418 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4420 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4422 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4423 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4424 return;
4426 } else {
4427 pa_source_output *so = NULL;
4428 pa_source *source;
4430 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4432 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4434 if (idx_device != PA_INVALID_INDEX)
4435 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4436 else
4437 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4439 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4441 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4442 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4443 return;
4447 pa_pstream_send_simple_ack(c->pstream, tag);
4450 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4451 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4452 uint32_t idx = PA_INVALID_INDEX;
4453 const char *name = NULL;
4454 pa_bool_t b;
4456 pa_native_connection_assert_ref(c);
4457 pa_assert(t);
4459 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4460 pa_tagstruct_gets(t, &name) < 0 ||
4461 pa_tagstruct_get_boolean(t, &b) < 0 ||
4462 !pa_tagstruct_eof(t)) {
4463 protocol_error(c);
4464 return;
4467 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4468 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);
4469 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4470 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4471 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4473 if (command == PA_COMMAND_SUSPEND_SINK) {
4475 if (idx == PA_INVALID_INDEX && name && !*name) {
4477 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4479 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4480 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4481 return;
4483 } else {
4484 pa_sink *sink = NULL;
4486 if (idx != PA_INVALID_INDEX)
4487 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4488 else
4489 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4491 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4493 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4494 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4495 return;
4498 } else {
4500 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4502 if (idx == PA_INVALID_INDEX && name && !*name) {
4504 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4506 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4507 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4508 return;
4511 } else {
4512 pa_source *source;
4514 if (idx != PA_INVALID_INDEX)
4515 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4516 else
4517 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4519 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4521 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4522 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4523 return;
4528 pa_pstream_send_simple_ack(c->pstream, tag);
4531 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4532 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4533 uint32_t idx = PA_INVALID_INDEX;
4534 const char *name = NULL;
4535 pa_module *m;
4536 pa_native_protocol_ext_cb_t cb;
4538 pa_native_connection_assert_ref(c);
4539 pa_assert(t);
4541 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4542 pa_tagstruct_gets(t, &name) < 0) {
4543 protocol_error(c);
4544 return;
4547 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4548 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4549 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4550 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4551 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4553 if (idx != PA_INVALID_INDEX)
4554 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4555 else {
4556 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4557 if (strcmp(name, m->name) == 0)
4558 break;
4561 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4562 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4564 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4565 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4567 if (cb(c->protocol, m, c, tag, t) < 0)
4568 protocol_error(c);
4571 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4572 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4573 uint32_t idx = PA_INVALID_INDEX;
4574 const char *name = NULL, *profile = NULL;
4575 pa_card *card = NULL;
4576 int ret;
4578 pa_native_connection_assert_ref(c);
4579 pa_assert(t);
4581 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4582 pa_tagstruct_gets(t, &name) < 0 ||
4583 pa_tagstruct_gets(t, &profile) < 0 ||
4584 !pa_tagstruct_eof(t)) {
4585 protocol_error(c);
4586 return;
4589 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4590 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4591 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4592 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4593 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4595 if (idx != PA_INVALID_INDEX)
4596 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4597 else
4598 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4600 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4602 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4603 pa_pstream_send_error(c->pstream, tag, -ret);
4604 return;
4607 pa_pstream_send_simple_ack(c->pstream, tag);
4610 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4611 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4612 uint32_t idx = PA_INVALID_INDEX;
4613 const char *name = NULL, *port = NULL;
4614 int ret;
4616 pa_native_connection_assert_ref(c);
4617 pa_assert(t);
4619 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4620 pa_tagstruct_gets(t, &name) < 0 ||
4621 pa_tagstruct_gets(t, &port) < 0 ||
4622 !pa_tagstruct_eof(t)) {
4623 protocol_error(c);
4624 return;
4627 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4628 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);
4629 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4630 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4631 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4633 if (command == PA_COMMAND_SET_SINK_PORT) {
4634 pa_sink *sink;
4636 if (idx != PA_INVALID_INDEX)
4637 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4638 else
4639 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4641 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4643 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4644 pa_pstream_send_error(c->pstream, tag, -ret);
4645 return;
4647 } else {
4648 pa_source *source;
4650 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4652 if (idx != PA_INVALID_INDEX)
4653 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4654 else
4655 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4657 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4659 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4660 pa_pstream_send_error(c->pstream, tag, -ret);
4661 return;
4665 pa_pstream_send_simple_ack(c->pstream, tag);
4668 /*** pstream callbacks ***/
4670 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4671 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4673 pa_assert(p);
4674 pa_assert(packet);
4675 pa_native_connection_assert_ref(c);
4677 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4678 pa_log("invalid packet.");
4679 native_connection_unlink(c);
4683 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) {
4684 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4685 output_stream *stream;
4687 pa_assert(p);
4688 pa_assert(chunk);
4689 pa_native_connection_assert_ref(c);
4691 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4692 pa_log_debug("Client sent block for invalid stream.");
4693 /* Ignoring */
4694 return;
4697 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4699 if (playback_stream_isinstance(stream)) {
4700 playback_stream *ps = PLAYBACK_STREAM(stream);
4702 pa_atomic_inc(&ps->seek_or_post_in_queue);
4703 if (chunk->memblock) {
4704 if (seek != PA_SEEK_RELATIVE || offset != 0)
4705 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);
4706 else
4707 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4708 } else
4709 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);
4711 } else {
4712 upload_stream *u = UPLOAD_STREAM(stream);
4713 size_t l;
4715 if (!u->memchunk.memblock) {
4716 if (u->length == chunk->length && chunk->memblock) {
4717 u->memchunk = *chunk;
4718 pa_memblock_ref(u->memchunk.memblock);
4719 u->length = 0;
4720 } else {
4721 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4722 u->memchunk.index = u->memchunk.length = 0;
4726 pa_assert(u->memchunk.memblock);
4728 l = u->length;
4729 if (l > chunk->length)
4730 l = chunk->length;
4732 if (l > 0) {
4733 void *dst;
4734 dst = pa_memblock_acquire(u->memchunk.memblock);
4736 if (chunk->memblock) {
4737 void *src;
4738 src = pa_memblock_acquire(chunk->memblock);
4740 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4741 (uint8_t*) src + chunk->index, l);
4743 pa_memblock_release(chunk->memblock);
4744 } else
4745 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4747 pa_memblock_release(u->memchunk.memblock);
4749 u->memchunk.length += l;
4750 u->length -= l;
4755 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4756 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4758 pa_assert(p);
4759 pa_native_connection_assert_ref(c);
4761 native_connection_unlink(c);
4762 pa_log_info("Connection died.");
4765 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4766 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4768 pa_assert(p);
4769 pa_native_connection_assert_ref(c);
4771 native_connection_send_memblock(c);
4774 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4775 pa_thread_mq *q;
4777 if (!(q = pa_thread_mq_get()))
4778 pa_pstream_send_revoke(p, block_id);
4779 else
4780 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4783 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4784 pa_thread_mq *q;
4786 if (!(q = pa_thread_mq_get()))
4787 pa_pstream_send_release(p, block_id);
4788 else
4789 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4792 /*** client callbacks ***/
4794 static void client_kill_cb(pa_client *c) {
4795 pa_assert(c);
4797 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4798 pa_log_info("Connection killed.");
4801 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4802 pa_tagstruct *t;
4803 pa_native_connection *c;
4805 pa_assert(client);
4806 c = PA_NATIVE_CONNECTION(client->userdata);
4807 pa_native_connection_assert_ref(c);
4809 if (c->version < 15)
4810 return;
4812 t = pa_tagstruct_new(NULL, 0);
4813 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4814 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4815 pa_tagstruct_puts(t, event);
4816 pa_tagstruct_put_proplist(t, pl);
4817 pa_pstream_send_tagstruct(c->pstream, t);
4820 /*** module entry points ***/
4822 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4823 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4825 pa_assert(m);
4826 pa_native_connection_assert_ref(c);
4827 pa_assert(c->auth_timeout_event == e);
4829 if (!c->authorized) {
4830 native_connection_unlink(c);
4831 pa_log_info("Connection terminated due to authentication timeout.");
4835 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4836 pa_native_connection *c;
4837 char pname[128];
4838 pa_client *client;
4839 pa_client_new_data data;
4841 pa_assert(p);
4842 pa_assert(io);
4843 pa_assert(o);
4845 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4846 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4847 pa_iochannel_free(io);
4848 return;
4851 pa_client_new_data_init(&data);
4852 data.module = o->module;
4853 data.driver = __FILE__;
4854 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4855 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4856 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4857 client = pa_client_new(p->core, &data);
4858 pa_client_new_data_done(&data);
4860 if (!client)
4861 return;
4863 c = pa_msgobject_new(pa_native_connection);
4864 c->parent.parent.free = native_connection_free;
4865 c->parent.process_msg = native_connection_process_msg;
4866 c->protocol = p;
4867 c->options = pa_native_options_ref(o);
4868 c->authorized = FALSE;
4870 if (o->auth_anonymous) {
4871 pa_log_info("Client authenticated anonymously.");
4872 c->authorized = TRUE;
4875 if (!c->authorized &&
4876 o->auth_ip_acl &&
4877 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4879 pa_log_info("Client authenticated by IP ACL.");
4880 c->authorized = TRUE;
4883 if (!c->authorized)
4884 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4885 else
4886 c->auth_timeout_event = NULL;
4888 c->is_local = pa_iochannel_socket_is_local(io);
4889 c->version = 8;
4891 c->client = client;
4892 c->client->kill = client_kill_cb;
4893 c->client->send_event = client_send_event_cb;
4894 c->client->userdata = c;
4896 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4897 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4898 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4899 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4900 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4901 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4902 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4904 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4906 c->record_streams = pa_idxset_new(NULL, NULL);
4907 c->output_streams = pa_idxset_new(NULL, NULL);
4909 c->rrobin_index = PA_IDXSET_INVALID;
4910 c->subscription = NULL;
4912 pa_idxset_put(p->connections, c, NULL);
4914 #ifdef HAVE_CREDS
4915 if (pa_iochannel_creds_supported(io))
4916 pa_iochannel_creds_enable(io);
4917 #endif
4919 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4922 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4923 pa_native_connection *c;
4924 void *state = NULL;
4926 pa_assert(p);
4927 pa_assert(m);
4929 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4930 if (c->options->module == m)
4931 native_connection_unlink(c);
4934 static pa_native_protocol* native_protocol_new(pa_core *c) {
4935 pa_native_protocol *p;
4936 pa_native_hook_t h;
4938 pa_assert(c);
4940 p = pa_xnew(pa_native_protocol, 1);
4941 PA_REFCNT_INIT(p);
4942 p->core = c;
4943 p->connections = pa_idxset_new(NULL, NULL);
4945 p->servers = NULL;
4947 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4949 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4950 pa_hook_init(&p->hooks[h], p);
4952 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4954 return p;
4957 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4958 pa_native_protocol *p;
4960 if ((p = pa_shared_get(c, "native-protocol")))
4961 return pa_native_protocol_ref(p);
4963 return native_protocol_new(c);
4966 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4967 pa_assert(p);
4968 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4970 PA_REFCNT_INC(p);
4972 return p;
4975 void pa_native_protocol_unref(pa_native_protocol *p) {
4976 pa_native_connection *c;
4977 pa_native_hook_t h;
4979 pa_assert(p);
4980 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4982 if (PA_REFCNT_DEC(p) > 0)
4983 return;
4985 while ((c = pa_idxset_first(p->connections, NULL)))
4986 native_connection_unlink(c);
4988 pa_idxset_free(p->connections, NULL, NULL);
4990 pa_strlist_free(p->servers);
4992 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4993 pa_hook_done(&p->hooks[h]);
4995 pa_hashmap_free(p->extensions, NULL, NULL);
4997 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4999 pa_xfree(p);
5002 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
5003 pa_assert(p);
5004 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5005 pa_assert(name);
5007 p->servers = pa_strlist_prepend(p->servers, name);
5009 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5012 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
5013 pa_assert(p);
5014 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5015 pa_assert(name);
5017 p->servers = pa_strlist_remove(p->servers, name);
5019 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5022 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
5023 pa_assert(p);
5024 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5026 return p->hooks;
5029 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
5030 pa_assert(p);
5031 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5033 return p->servers;
5036 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
5037 pa_assert(p);
5038 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5039 pa_assert(m);
5040 pa_assert(cb);
5041 pa_assert(!pa_hashmap_get(p->extensions, m));
5043 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
5044 return 0;
5047 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
5048 pa_assert(p);
5049 pa_assert(PA_REFCNT_VALUE(p) >= 1);
5050 pa_assert(m);
5052 pa_assert_se(pa_hashmap_remove(p->extensions, m));
5055 pa_native_options* pa_native_options_new(void) {
5056 pa_native_options *o;
5058 o = pa_xnew0(pa_native_options, 1);
5059 PA_REFCNT_INIT(o);
5061 return o;
5064 pa_native_options* pa_native_options_ref(pa_native_options *o) {
5065 pa_assert(o);
5066 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5068 PA_REFCNT_INC(o);
5070 return o;
5073 void pa_native_options_unref(pa_native_options *o) {
5074 pa_assert(o);
5075 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5077 if (PA_REFCNT_DEC(o) > 0)
5078 return;
5080 pa_xfree(o->auth_group);
5082 if (o->auth_ip_acl)
5083 pa_ip_acl_free(o->auth_ip_acl);
5085 if (o->auth_cookie)
5086 pa_auth_cookie_unref(o->auth_cookie);
5088 pa_xfree(o);
5091 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
5092 pa_bool_t enabled;
5093 const char *acl;
5095 pa_assert(o);
5096 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5097 pa_assert(ma);
5099 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
5100 pa_log("auth-anonymous= expects a boolean argument.");
5101 return -1;
5104 enabled = TRUE;
5105 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
5106 pa_log("auth-group-enabled= expects a boolean argument.");
5107 return -1;
5110 pa_xfree(o->auth_group);
5111 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
5113 #ifndef HAVE_CREDS
5114 if (o->auth_group)
5115 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5116 #endif
5118 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
5119 pa_ip_acl *ipa;
5121 if (!(ipa = pa_ip_acl_new(acl))) {
5122 pa_log("Failed to parse IP ACL '%s'", acl);
5123 return -1;
5126 if (o->auth_ip_acl)
5127 pa_ip_acl_free(o->auth_ip_acl);
5129 o->auth_ip_acl = ipa;
5132 enabled = TRUE;
5133 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
5134 pa_log("auth-cookie-enabled= expects a boolean argument.");
5135 return -1;
5138 if (o->auth_cookie)
5139 pa_auth_cookie_unref(o->auth_cookie);
5141 if (enabled) {
5142 const char *cn;
5144 /* The new name for this is 'auth-cookie', for compat reasons
5145 * we check the old name too */
5146 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
5147 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
5148 cn = PA_NATIVE_COOKIE_FILE;
5150 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
5151 return -1;
5153 } else
5154 o->auth_cookie = NULL;
5156 return 0;
5159 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
5160 pa_native_connection_assert_ref(c);
5162 return c->pstream;
5165 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
5166 pa_native_connection_assert_ref(c);
5168 return c->client;