introspect: Get formats for sources
[pulseaudio-mirror.git] / src / pulsecore / protocol-native.c
blob3574ca98fdc6926137f4621cfecd04887d5d9d95
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,
342 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
343 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
344 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
346 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
347 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
349 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
350 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
351 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
352 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
354 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
355 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
357 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
358 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
359 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
360 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
361 [PA_COMMAND_KILL_CLIENT] = command_kill,
362 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
363 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
364 [PA_COMMAND_LOAD_MODULE] = command_load_module,
365 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
367 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
368 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
369 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
370 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
372 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
373 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
375 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
376 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
378 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
379 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
381 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
382 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
383 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
385 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
386 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
387 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
389 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
391 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
392 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
394 [PA_COMMAND_EXTENSION] = command_extension
397 /* structure management */
399 /* Called from main context */
400 static void upload_stream_unlink(upload_stream *s) {
401 pa_assert(s);
403 if (!s->connection)
404 return;
406 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
407 s->connection = NULL;
408 upload_stream_unref(s);
411 /* Called from main context */
412 static void upload_stream_free(pa_object *o) {
413 upload_stream *s = UPLOAD_STREAM(o);
414 pa_assert(s);
416 upload_stream_unlink(s);
418 pa_xfree(s->name);
420 if (s->proplist)
421 pa_proplist_free(s->proplist);
423 if (s->memchunk.memblock)
424 pa_memblock_unref(s->memchunk.memblock);
426 pa_xfree(s);
429 /* Called from main context */
430 static upload_stream* upload_stream_new(
431 pa_native_connection *c,
432 const pa_sample_spec *ss,
433 const pa_channel_map *map,
434 const char *name,
435 size_t length,
436 pa_proplist *p) {
438 upload_stream *s;
440 pa_assert(c);
441 pa_assert(ss);
442 pa_assert(name);
443 pa_assert(length > 0);
444 pa_assert(p);
446 s = pa_msgobject_new(upload_stream);
447 s->parent.parent.parent.free = upload_stream_free;
448 s->connection = c;
449 s->sample_spec = *ss;
450 s->channel_map = *map;
451 s->name = pa_xstrdup(name);
452 pa_memchunk_reset(&s->memchunk);
453 s->length = length;
454 s->proplist = pa_proplist_copy(p);
455 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
457 pa_idxset_put(c->output_streams, s, &s->index);
459 return s;
462 /* Called from main context */
463 static void record_stream_unlink(record_stream *s) {
464 pa_assert(s);
466 if (!s->connection)
467 return;
469 if (s->source_output) {
470 pa_source_output_unlink(s->source_output);
471 pa_source_output_unref(s->source_output);
472 s->source_output = NULL;
475 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
476 s->connection = NULL;
477 record_stream_unref(s);
480 /* Called from main context */
481 static void record_stream_free(pa_object *o) {
482 record_stream *s = RECORD_STREAM(o);
483 pa_assert(s);
485 record_stream_unlink(s);
487 pa_memblockq_free(s->memblockq);
488 pa_xfree(s);
491 /* Called from main context */
492 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
493 record_stream *s = RECORD_STREAM(o);
494 record_stream_assert_ref(s);
496 if (!s->connection)
497 return -1;
499 switch (code) {
501 case RECORD_STREAM_MESSAGE_POST_DATA:
503 /* We try to keep up to date with how many bytes are
504 * currently on the fly */
505 pa_atomic_sub(&s->on_the_fly, chunk->length);
507 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
508 /* pa_log_warn("Failed to push data into output queue."); */
509 return -1;
512 if (!pa_pstream_is_pending(s->connection->pstream))
513 native_connection_send_memblock(s->connection);
515 break;
518 return 0;
521 /* Called from main context */
522 static void fix_record_buffer_attr_pre(record_stream *s) {
524 size_t frame_size;
525 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
527 pa_assert(s);
529 /* This function will be called from the main thread, before as
530 * well as after the source output has been activated using
531 * pa_source_output_put()! That means it may not touch any
532 * ->thread_info data! */
534 frame_size = pa_frame_size(&s->source_output->sample_spec);
535 s->buffer_attr = s->buffer_attr_req;
537 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
538 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
539 if (s->buffer_attr.maxlength <= 0)
540 s->buffer_attr.maxlength = (uint32_t) frame_size;
542 if (s->buffer_attr.fragsize == (uint32_t) -1)
543 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
544 if (s->buffer_attr.fragsize <= 0)
545 s->buffer_attr.fragsize = (uint32_t) frame_size;
547 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
549 if (s->early_requests) {
551 /* In early request mode we need to emulate the classic
552 * fragment-based playback model. We do this setting the source
553 * latency to the fragment size. */
555 source_usec = fragsize_usec;
557 } else if (s->adjust_latency) {
559 /* So, the user asked us to adjust the latency according to
560 * what the source can provide. Half the latency will be
561 * spent on the hw buffer, half of it in the async buffer
562 * queue we maintain for each client. */
564 source_usec = fragsize_usec/2;
566 } else {
568 /* Ok, the user didn't ask us to adjust the latency, hence we
569 * don't */
571 source_usec = (pa_usec_t) -1;
574 if (source_usec != (pa_usec_t) -1)
575 s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
576 else
577 s->configured_source_latency = 0;
579 if (s->early_requests) {
581 /* Ok, we didn't necessarily get what we were asking for, so
582 * let's tell the user */
584 fragsize_usec = s->configured_source_latency;
586 } else if (s->adjust_latency) {
588 /* Now subtract what we actually got */
590 if (fragsize_usec >= s->configured_source_latency*2)
591 fragsize_usec -= s->configured_source_latency;
592 else
593 fragsize_usec = s->configured_source_latency;
596 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
597 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
599 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
601 if (s->buffer_attr.fragsize <= 0)
602 s->buffer_attr.fragsize = (uint32_t) frame_size;
605 /* Called from main context */
606 static void fix_record_buffer_attr_post(record_stream *s) {
607 size_t base;
609 pa_assert(s);
611 /* This function will be called from the main thread, before as
612 * well as after the source output has been activated using
613 * pa_source_output_put()! That means it may not touch and
614 * ->thread_info data! */
616 base = pa_frame_size(&s->source_output->sample_spec);
618 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
619 if (s->buffer_attr.fragsize <= 0)
620 s->buffer_attr.fragsize = base;
622 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
623 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
626 /* Called from main context */
627 static record_stream* record_stream_new(
628 pa_native_connection *c,
629 pa_source *source,
630 pa_sample_spec *ss,
631 pa_channel_map *map,
632 pa_idxset *formats,
633 pa_buffer_attr *attr,
634 pa_source_output_flags_t flags,
635 pa_proplist *p,
636 pa_bool_t adjust_latency,
637 pa_bool_t early_requests,
638 pa_bool_t peak_detect,
639 pa_sink_input *direct_on_input,
640 int *ret) {
642 record_stream *s;
643 pa_source_output *source_output = NULL;
644 pa_source_output_new_data data;
646 pa_assert(c);
647 pa_assert(ss);
648 pa_assert(p);
649 pa_assert(ret);
651 pa_source_output_new_data_init(&data);
653 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
654 data.driver = __FILE__;
655 data.module = c->options->module;
656 data.client = c->client;
657 if (source)
658 pa_source_output_new_data_set_source(&data, source, TRUE);
659 if (pa_sample_spec_valid(ss))
660 pa_source_output_new_data_set_sample_spec(&data, ss);
661 if (pa_channel_map_valid(map))
662 pa_source_output_new_data_set_channel_map(&data, map);
663 if (formats)
664 pa_source_output_new_data_set_formats(&data, formats);
665 data.direct_on_input = direct_on_input;
666 if (peak_detect)
667 data.resample_method = PA_RESAMPLER_PEAKS;
668 data.flags = flags;
670 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
672 pa_source_output_new_data_done(&data);
674 if (!source_output)
675 return NULL;
677 s = pa_msgobject_new(record_stream);
678 s->parent.parent.free = record_stream_free;
679 s->parent.process_msg = record_stream_process_msg;
680 s->connection = c;
681 s->source_output = source_output;
682 s->buffer_attr_req = *attr;
683 s->adjust_latency = adjust_latency;
684 s->early_requests = early_requests;
685 pa_atomic_store(&s->on_the_fly, 0);
687 s->source_output->parent.process_msg = source_output_process_msg;
688 s->source_output->push = source_output_push_cb;
689 s->source_output->kill = source_output_kill_cb;
690 s->source_output->get_latency = source_output_get_latency_cb;
691 s->source_output->moving = source_output_moving_cb;
692 s->source_output->suspend = source_output_suspend_cb;
693 s->source_output->send_event = source_output_send_event_cb;
694 s->source_output->userdata = s;
696 fix_record_buffer_attr_pre(s);
698 s->memblockq = pa_memblockq_new(
700 s->buffer_attr.maxlength,
702 pa_frame_size(&source_output->sample_spec),
706 NULL);
708 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
709 fix_record_buffer_attr_post(s);
711 *ss = s->source_output->sample_spec;
712 *map = s->source_output->channel_map;
714 pa_idxset_put(c->record_streams, s, &s->index);
716 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
717 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
718 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
719 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
721 pa_source_output_put(s->source_output);
722 return s;
725 /* Called from main context */
726 static void record_stream_send_killed(record_stream *r) {
727 pa_tagstruct *t;
728 record_stream_assert_ref(r);
730 t = pa_tagstruct_new(NULL, 0);
731 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
732 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
733 pa_tagstruct_putu32(t, r->index);
734 pa_pstream_send_tagstruct(r->connection->pstream, t);
737 /* Called from main context */
738 static void playback_stream_unlink(playback_stream *s) {
739 pa_assert(s);
741 if (!s->connection)
742 return;
744 if (s->sink_input) {
745 pa_sink_input_unlink(s->sink_input);
746 pa_sink_input_unref(s->sink_input);
747 s->sink_input = NULL;
750 if (s->drain_request)
751 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
753 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
754 s->connection = NULL;
755 playback_stream_unref(s);
758 /* Called from main context */
759 static void playback_stream_free(pa_object* o) {
760 playback_stream *s = PLAYBACK_STREAM(o);
761 pa_assert(s);
763 playback_stream_unlink(s);
765 pa_memblockq_free(s->memblockq);
766 pa_xfree(s);
769 /* Called from main context */
770 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
771 playback_stream *s = PLAYBACK_STREAM(o);
772 playback_stream_assert_ref(s);
774 if (!s->connection)
775 return -1;
777 switch (code) {
779 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
780 pa_tagstruct *t;
781 int l = 0;
783 for (;;) {
784 if ((l = pa_atomic_load(&s->missing)) <= 0)
785 return 0;
787 if (pa_atomic_cmpxchg(&s->missing, l, 0))
788 break;
791 t = pa_tagstruct_new(NULL, 0);
792 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
793 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
794 pa_tagstruct_putu32(t, s->index);
795 pa_tagstruct_putu32(t, (uint32_t) l);
796 pa_pstream_send_tagstruct(s->connection->pstream, t);
798 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
799 break;
802 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
803 pa_tagstruct *t;
805 /* pa_log("signalling underflow"); */
807 /* Report that we're empty */
808 t = pa_tagstruct_new(NULL, 0);
809 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
810 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
811 pa_tagstruct_putu32(t, s->index);
812 pa_pstream_send_tagstruct(s->connection->pstream, t);
813 break;
816 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
817 pa_tagstruct *t;
819 /* Notify the user we're overflowed*/
820 t = pa_tagstruct_new(NULL, 0);
821 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
822 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
823 pa_tagstruct_putu32(t, s->index);
824 pa_pstream_send_tagstruct(s->connection->pstream, t);
825 break;
828 case PLAYBACK_STREAM_MESSAGE_STARTED:
830 if (s->connection->version >= 13) {
831 pa_tagstruct *t;
833 /* Notify the user we started playback */
834 t = pa_tagstruct_new(NULL, 0);
835 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
836 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
837 pa_tagstruct_putu32(t, s->index);
838 pa_pstream_send_tagstruct(s->connection->pstream, t);
841 break;
843 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
844 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
845 break;
847 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
849 s->buffer_attr.tlength = (uint32_t) offset;
851 if (s->connection->version >= 15) {
852 pa_tagstruct *t;
854 t = pa_tagstruct_new(NULL, 0);
855 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
856 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
857 pa_tagstruct_putu32(t, s->index);
858 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
859 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
860 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
861 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
862 pa_tagstruct_put_usec(t, s->configured_sink_latency);
863 pa_pstream_send_tagstruct(s->connection->pstream, t);
866 break;
869 return 0;
872 /* Called from main context */
873 static void fix_playback_buffer_attr(playback_stream *s) {
874 size_t frame_size, max_prebuf;
875 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
877 pa_assert(s);
879 /* pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", */
880 /* (long) s->buffer_attr.maxlength, */
881 /* (long) s->buffer_attr.tlength, */
882 /* (long) s->buffer_attr.minreq, */
883 /* (long) s->buffer_attr.prebuf); */
885 /* pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
886 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
887 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
888 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
889 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
891 /* This function will be called from the main thread, before as
892 * well as after the sink input has been activated using
893 * pa_sink_input_put()! That means it may not touch any
894 * ->thread_info data, such as the memblockq! */
896 frame_size = pa_frame_size(&s->sink_input->sample_spec);
897 s->buffer_attr = s->buffer_attr_req;
899 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
900 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
901 if (s->buffer_attr.maxlength <= 0)
902 s->buffer_attr.maxlength = (uint32_t) frame_size;
904 if (s->buffer_attr.tlength == (uint32_t) -1)
905 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
906 if (s->buffer_attr.tlength <= 0)
907 s->buffer_attr.tlength = (uint32_t) frame_size;
909 if (s->buffer_attr.minreq == (uint32_t) -1)
910 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
911 if (s->buffer_attr.minreq <= 0)
912 s->buffer_attr.minreq = (uint32_t) frame_size;
914 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
915 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
917 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
918 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
920 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
921 (double) tlength_usec / PA_USEC_PER_MSEC,
922 (double) minreq_usec / PA_USEC_PER_MSEC);
924 if (s->early_requests) {
926 /* In early request mode we need to emulate the classic
927 * fragment-based playback model. We do this setting the sink
928 * latency to the fragment size. */
930 sink_usec = minreq_usec;
931 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
933 } else if (s->adjust_latency) {
935 /* So, the user asked us to adjust the latency of the stream
936 * buffer according to the what the sink can provide. The
937 * tlength passed in shall be the overall latency. Roughly
938 * half the latency will be spent on the hw buffer, the other
939 * half of it in the async buffer queue we maintain for each
940 * client. In between we'll have a safety space of size
941 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
942 * empty and needs to be filled, then our buffer must have
943 * enough data to fulfill this request immediatly and thus
944 * have at least the same tlength as the size of the hw
945 * buffer. It additionally needs space for 2 times minreq
946 * because if the buffer ran empty and a partial fillup
947 * happens immediately on the next iteration we need to be
948 * able to fulfill it and give the application also minreq
949 * time to fill it up again for the next request Makes 2 times
950 * minreq in plus.. */
952 if (tlength_usec > minreq_usec*2)
953 sink_usec = (tlength_usec - minreq_usec*2)/2;
954 else
955 sink_usec = 0;
957 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
959 } else {
961 /* Ok, the user didn't ask us to adjust the latency, but we
962 * still need to make sure that the parameters from the user
963 * do make sense. */
965 if (tlength_usec > minreq_usec*2)
966 sink_usec = (tlength_usec - minreq_usec*2);
967 else
968 sink_usec = 0;
970 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
973 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
975 if (s->early_requests) {
977 /* Ok, we didn't necessarily get what we were asking for, so
978 * let's tell the user */
980 minreq_usec = s->configured_sink_latency;
982 } else if (s->adjust_latency) {
984 /* Ok, we didn't necessarily get what we were asking for, so
985 * let's subtract from what we asked for for the remaining
986 * buffer space */
988 if (tlength_usec >= s->configured_sink_latency)
989 tlength_usec -= s->configured_sink_latency;
992 /* FIXME: This is actually larger than necessary, since not all of
993 * the sink latency is actually rewritable. */
994 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
995 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
997 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
998 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
999 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
1001 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
1002 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
1003 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
1005 if (s->buffer_attr.minreq <= 0) {
1006 s->buffer_attr.minreq = (uint32_t) frame_size;
1007 s->buffer_attr.tlength += (uint32_t) frame_size*2;
1010 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
1011 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
1013 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
1015 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
1016 s->buffer_attr.prebuf > max_prebuf)
1017 s->buffer_attr.prebuf = max_prebuf;
1019 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1020 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1021 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1022 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1023 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1026 /* Called from main context */
1027 static playback_stream* playback_stream_new(
1028 pa_native_connection *c,
1029 pa_sink *sink,
1030 pa_sample_spec *ss,
1031 pa_channel_map *map,
1032 pa_idxset *formats,
1033 pa_buffer_attr *a,
1034 pa_cvolume *volume,
1035 pa_bool_t muted,
1036 pa_bool_t muted_set,
1037 pa_sink_input_flags_t flags,
1038 pa_proplist *p,
1039 pa_bool_t adjust_latency,
1040 pa_bool_t early_requests,
1041 pa_bool_t relative_volume,
1042 uint32_t syncid,
1043 uint32_t *missing,
1044 int *ret) {
1046 /* Note: This function takes ownership of the 'formats' param, so we need
1047 * to take extra care to not leak it */
1049 playback_stream *s, *ssync;
1050 pa_sink_input *sink_input = NULL;
1051 pa_memchunk silence;
1052 uint32_t idx;
1053 int64_t start_index;
1054 pa_sink_input_new_data data;
1056 pa_assert(c);
1057 pa_assert(ss);
1058 pa_assert(missing);
1059 pa_assert(p);
1060 pa_assert(ret);
1062 /* Find syncid group */
1063 PA_IDXSET_FOREACH(ssync, c->output_streams, idx) {
1065 if (!playback_stream_isinstance(ssync))
1066 continue;
1068 if (ssync->syncid == syncid)
1069 break;
1072 /* Synced streams must connect to the same sink */
1073 if (ssync) {
1075 if (!sink)
1076 sink = ssync->sink_input->sink;
1077 else if (sink != ssync->sink_input->sink) {
1078 *ret = PA_ERR_INVALID;
1079 goto out;
1083 pa_sink_input_new_data_init(&data);
1085 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1086 data.driver = __FILE__;
1087 data.module = c->options->module;
1088 data.client = c->client;
1089 if (sink)
1090 pa_sink_input_new_data_set_sink(&data, sink, TRUE);
1091 if (pa_sample_spec_valid(ss))
1092 pa_sink_input_new_data_set_sample_spec(&data, ss);
1093 if (pa_channel_map_valid(map))
1094 pa_sink_input_new_data_set_channel_map(&data, map);
1095 if (formats) {
1096 pa_sink_input_new_data_set_formats(&data, formats);
1097 /* Ownership transferred to new_data, so we don't free it ourseleves */
1098 formats = NULL;
1100 if (volume) {
1101 pa_sink_input_new_data_set_volume(&data, volume);
1102 data.volume_is_absolute = !relative_volume;
1103 data.save_volume = TRUE;
1105 if (muted_set) {
1106 pa_sink_input_new_data_set_muted(&data, muted);
1107 data.save_muted = TRUE;
1109 data.sync_base = ssync ? ssync->sink_input : NULL;
1110 data.flags = flags;
1112 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1114 pa_sink_input_new_data_done(&data);
1116 if (!sink_input)
1117 goto out;
1119 s = pa_msgobject_new(playback_stream);
1120 s->parent.parent.parent.free = playback_stream_free;
1121 s->parent.parent.process_msg = playback_stream_process_msg;
1122 s->connection = c;
1123 s->syncid = syncid;
1124 s->sink_input = sink_input;
1125 s->is_underrun = TRUE;
1126 s->drain_request = FALSE;
1127 pa_atomic_store(&s->missing, 0);
1128 s->buffer_attr_req = *a;
1129 s->adjust_latency = adjust_latency;
1130 s->early_requests = early_requests;
1131 pa_atomic_store(&s->seek_or_post_in_queue, 0);
1132 s->seek_windex = -1;
1134 s->sink_input->parent.process_msg = sink_input_process_msg;
1135 s->sink_input->pop = sink_input_pop_cb;
1136 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1137 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1138 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1139 s->sink_input->kill = sink_input_kill_cb;
1140 s->sink_input->moving = sink_input_moving_cb;
1141 s->sink_input->suspend = sink_input_suspend_cb;
1142 s->sink_input->send_event = sink_input_send_event_cb;
1143 s->sink_input->userdata = s;
1145 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1147 fix_playback_buffer_attr(s);
1149 pa_sink_input_get_silence(sink_input, &silence);
1150 s->memblockq = pa_memblockq_new(
1151 start_index,
1152 s->buffer_attr.maxlength,
1153 s->buffer_attr.tlength,
1154 pa_frame_size(&sink_input->sample_spec),
1155 s->buffer_attr.prebuf,
1156 s->buffer_attr.minreq,
1158 &silence);
1159 pa_memblock_unref(silence.memblock);
1161 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1163 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1165 /* pa_log("missing original: %li", (long int) *missing); */
1167 *ss = s->sink_input->sample_spec;
1168 *map = s->sink_input->channel_map;
1170 pa_idxset_put(c->output_streams, s, &s->index);
1172 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1173 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1174 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1175 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1176 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1178 pa_sink_input_put(s->sink_input);
1180 out:
1181 if (formats)
1182 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
1184 return s;
1187 /* Called from IO context */
1188 static void playback_stream_request_bytes(playback_stream *s) {
1189 size_t m, minreq;
1190 int previous_missing;
1192 playback_stream_assert_ref(s);
1194 m = pa_memblockq_pop_missing(s->memblockq);
1196 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1197 /* (unsigned long) m, */
1198 /* pa_memblockq_get_tlength(s->memblockq), */
1199 /* pa_memblockq_get_minreq(s->memblockq), */
1200 /* pa_memblockq_get_length(s->memblockq), */
1201 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1203 if (m <= 0)
1204 return;
1206 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1208 previous_missing = pa_atomic_add(&s->missing, (int) m);
1209 minreq = pa_memblockq_get_minreq(s->memblockq);
1211 if (pa_memblockq_prebuf_active(s->memblockq) ||
1212 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1213 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1216 /* Called from main context */
1217 static void playback_stream_send_killed(playback_stream *p) {
1218 pa_tagstruct *t;
1219 playback_stream_assert_ref(p);
1221 t = pa_tagstruct_new(NULL, 0);
1222 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1223 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1224 pa_tagstruct_putu32(t, p->index);
1225 pa_pstream_send_tagstruct(p->connection->pstream, t);
1228 /* Called from main context */
1229 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1230 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1231 pa_native_connection_assert_ref(c);
1233 if (!c->protocol)
1234 return -1;
1236 switch (code) {
1238 case CONNECTION_MESSAGE_REVOKE:
1239 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1240 break;
1242 case CONNECTION_MESSAGE_RELEASE:
1243 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1244 break;
1247 return 0;
1250 /* Called from main context */
1251 static void native_connection_unlink(pa_native_connection *c) {
1252 record_stream *r;
1253 output_stream *o;
1255 pa_assert(c);
1257 if (!c->protocol)
1258 return;
1260 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1262 if (c->options)
1263 pa_native_options_unref(c->options);
1265 while ((r = pa_idxset_first(c->record_streams, NULL)))
1266 record_stream_unlink(r);
1268 while ((o = pa_idxset_first(c->output_streams, NULL)))
1269 if (playback_stream_isinstance(o))
1270 playback_stream_unlink(PLAYBACK_STREAM(o));
1271 else
1272 upload_stream_unlink(UPLOAD_STREAM(o));
1274 if (c->subscription)
1275 pa_subscription_free(c->subscription);
1277 if (c->pstream)
1278 pa_pstream_unlink(c->pstream);
1280 if (c->auth_timeout_event) {
1281 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1282 c->auth_timeout_event = NULL;
1285 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1286 c->protocol = NULL;
1287 pa_native_connection_unref(c);
1290 /* Called from main context */
1291 static void native_connection_free(pa_object *o) {
1292 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1294 pa_assert(c);
1296 native_connection_unlink(c);
1298 pa_idxset_free(c->record_streams, NULL, NULL);
1299 pa_idxset_free(c->output_streams, NULL, NULL);
1301 pa_pdispatch_unref(c->pdispatch);
1302 pa_pstream_unref(c->pstream);
1303 pa_client_free(c->client);
1305 pa_xfree(c);
1308 /* Called from main context */
1309 static void native_connection_send_memblock(pa_native_connection *c) {
1310 uint32_t start;
1311 record_stream *r;
1313 start = PA_IDXSET_INVALID;
1314 for (;;) {
1315 pa_memchunk chunk;
1317 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1318 return;
1320 if (start == PA_IDXSET_INVALID)
1321 start = c->rrobin_index;
1322 else if (start == c->rrobin_index)
1323 return;
1325 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1326 pa_memchunk schunk = chunk;
1328 if (schunk.length > r->buffer_attr.fragsize)
1329 schunk.length = r->buffer_attr.fragsize;
1331 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1333 pa_memblockq_drop(r->memblockq, schunk.length);
1334 pa_memblock_unref(schunk.memblock);
1336 return;
1341 /*** sink input callbacks ***/
1343 /* Called from thread context */
1344 static void handle_seek(playback_stream *s, int64_t indexw) {
1345 playback_stream_assert_ref(s);
1347 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1349 if (s->sink_input->thread_info.underrun_for > 0) {
1351 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1353 if (pa_memblockq_is_readable(s->memblockq)) {
1355 /* We just ended an underrun, let's ask the sink
1356 * for a complete rewind rewrite */
1358 pa_log_debug("Requesting rewind due to end of underrun.");
1359 pa_sink_input_request_rewind(s->sink_input,
1360 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1361 s->sink_input->thread_info.underrun_for),
1362 FALSE, TRUE, FALSE);
1365 } else {
1366 int64_t indexr;
1368 indexr = pa_memblockq_get_read_index(s->memblockq);
1370 if (indexw < indexr) {
1371 /* OK, the sink already asked for this data, so
1372 * let's have it usk us again */
1374 pa_log_debug("Requesting rewind due to rewrite.");
1375 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1379 playback_stream_request_bytes(s);
1382 static void flush_write_no_account(pa_memblockq *q) {
1383 pa_memblockq_flush_write(q, FALSE);
1386 /* Called from thread context */
1387 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1388 pa_sink_input *i = PA_SINK_INPUT(o);
1389 playback_stream *s;
1391 pa_sink_input_assert_ref(i);
1392 s = PLAYBACK_STREAM(i->userdata);
1393 playback_stream_assert_ref(s);
1395 switch (code) {
1397 case SINK_INPUT_MESSAGE_SEEK:
1398 case SINK_INPUT_MESSAGE_POST_DATA: {
1399 int64_t windex = pa_memblockq_get_write_index(s->memblockq);
1401 if (code == SINK_INPUT_MESSAGE_SEEK) {
1402 /* The client side is incapable of accounting correctly
1403 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1404 * able to deal with that. */
1406 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1407 windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
1410 if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1411 if (pa_log_ratelimit(PA_LOG_WARN))
1412 pa_log_warn("Failed to push data into queue");
1413 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1414 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1417 /* If more data is in queue, we rewind later instead. */
1418 if (s->seek_windex != -1)
1419 windex = PA_MIN(windex, s->seek_windex);
1420 if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
1421 s->seek_windex = windex;
1422 else {
1423 s->seek_windex = -1;
1424 handle_seek(s, windex);
1426 return 0;
1429 case SINK_INPUT_MESSAGE_DRAIN:
1430 case SINK_INPUT_MESSAGE_FLUSH:
1431 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1432 case SINK_INPUT_MESSAGE_TRIGGER: {
1434 int64_t windex;
1435 pa_sink_input *isync;
1436 void (*func)(pa_memblockq *bq);
1438 switch (code) {
1439 case SINK_INPUT_MESSAGE_FLUSH:
1440 func = flush_write_no_account;
1441 break;
1443 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1444 func = pa_memblockq_prebuf_force;
1445 break;
1447 case SINK_INPUT_MESSAGE_DRAIN:
1448 case SINK_INPUT_MESSAGE_TRIGGER:
1449 func = pa_memblockq_prebuf_disable;
1450 break;
1452 default:
1453 pa_assert_not_reached();
1456 windex = pa_memblockq_get_write_index(s->memblockq);
1457 func(s->memblockq);
1458 handle_seek(s, windex);
1460 /* Do the same for all other members in the sync group */
1461 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1462 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1463 windex = pa_memblockq_get_write_index(ssync->memblockq);
1464 func(ssync->memblockq);
1465 handle_seek(ssync, windex);
1468 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1469 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1470 windex = pa_memblockq_get_write_index(ssync->memblockq);
1471 func(ssync->memblockq);
1472 handle_seek(ssync, windex);
1475 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1476 if (!pa_memblockq_is_readable(s->memblockq))
1477 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1478 else {
1479 s->drain_tag = PA_PTR_TO_UINT(userdata);
1480 s->drain_request = TRUE;
1484 return 0;
1487 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1488 /* Atomically get a snapshot of all timing parameters... */
1489 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1490 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1491 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1492 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1493 s->underrun_for = s->sink_input->thread_info.underrun_for;
1494 s->playing_for = s->sink_input->thread_info.playing_for;
1496 return 0;
1498 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1499 int64_t windex;
1501 windex = pa_memblockq_get_write_index(s->memblockq);
1503 pa_memblockq_prebuf_force(s->memblockq);
1505 handle_seek(s, windex);
1507 /* Fall through to the default handler */
1508 break;
1511 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1512 pa_usec_t *r = userdata;
1514 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1516 /* Fall through, the default handler will add in the extra
1517 * latency added by the resampler */
1518 break;
1521 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1522 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1523 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1524 return 0;
1528 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1531 /* Called from thread context */
1532 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1533 playback_stream *s;
1535 pa_sink_input_assert_ref(i);
1536 s = PLAYBACK_STREAM(i->userdata);
1537 playback_stream_assert_ref(s);
1538 pa_assert(chunk);
1540 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1542 if (pa_memblockq_is_readable(s->memblockq))
1543 s->is_underrun = FALSE;
1544 else {
1545 if (!s->is_underrun)
1546 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));
1548 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1549 s->drain_request = FALSE;
1550 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);
1551 } else if (!s->is_underrun)
1552 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1554 s->is_underrun = TRUE;
1556 playback_stream_request_bytes(s);
1559 /* This call will not fail with prebuf=0, hence we check for
1560 underrun explicitly above */
1561 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1562 return -1;
1564 chunk->length = PA_MIN(nbytes, chunk->length);
1566 if (i->thread_info.underrun_for > 0)
1567 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1569 pa_memblockq_drop(s->memblockq, chunk->length);
1570 playback_stream_request_bytes(s);
1572 return 0;
1575 /* Called from thread context */
1576 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1577 playback_stream *s;
1579 pa_sink_input_assert_ref(i);
1580 s = PLAYBACK_STREAM(i->userdata);
1581 playback_stream_assert_ref(s);
1583 /* If we are in an underrun, then we don't rewind */
1584 if (i->thread_info.underrun_for > 0)
1585 return;
1587 pa_memblockq_rewind(s->memblockq, nbytes);
1590 /* Called from thread context */
1591 static void sink_input_update_max_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 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1601 /* Called from thread context */
1602 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1603 playback_stream *s;
1604 size_t new_tlength, old_tlength;
1606 pa_sink_input_assert_ref(i);
1607 s = PLAYBACK_STREAM(i->userdata);
1608 playback_stream_assert_ref(s);
1610 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1611 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1613 if (old_tlength < new_tlength) {
1614 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1615 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1616 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1618 if (new_tlength == old_tlength)
1619 pa_log_debug("Failed to increase tlength");
1620 else {
1621 pa_log_debug("Notifying client about increased tlength");
1622 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);
1627 /* Called from main context */
1628 static void sink_input_kill_cb(pa_sink_input *i) {
1629 playback_stream *s;
1631 pa_sink_input_assert_ref(i);
1632 s = PLAYBACK_STREAM(i->userdata);
1633 playback_stream_assert_ref(s);
1635 playback_stream_send_killed(s);
1636 playback_stream_unlink(s);
1639 /* Called from main context */
1640 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1641 playback_stream *s;
1642 pa_tagstruct *t;
1644 pa_sink_input_assert_ref(i);
1645 s = PLAYBACK_STREAM(i->userdata);
1646 playback_stream_assert_ref(s);
1648 if (s->connection->version < 15)
1649 return;
1651 t = pa_tagstruct_new(NULL, 0);
1652 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1653 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1654 pa_tagstruct_putu32(t, s->index);
1655 pa_tagstruct_puts(t, event);
1656 pa_tagstruct_put_proplist(t, pl);
1657 pa_pstream_send_tagstruct(s->connection->pstream, t);
1660 /* Called from main context */
1661 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1662 playback_stream *s;
1663 pa_tagstruct *t;
1665 pa_sink_input_assert_ref(i);
1666 s = PLAYBACK_STREAM(i->userdata);
1667 playback_stream_assert_ref(s);
1669 if (s->connection->version < 12)
1670 return;
1672 t = pa_tagstruct_new(NULL, 0);
1673 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1674 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1675 pa_tagstruct_putu32(t, s->index);
1676 pa_tagstruct_put_boolean(t, suspend);
1677 pa_pstream_send_tagstruct(s->connection->pstream, t);
1680 /* Called from main context */
1681 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1682 playback_stream *s;
1683 pa_tagstruct *t;
1685 pa_sink_input_assert_ref(i);
1686 s = PLAYBACK_STREAM(i->userdata);
1687 playback_stream_assert_ref(s);
1689 if (!dest)
1690 return;
1692 fix_playback_buffer_attr(s);
1693 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1694 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1696 if (s->connection->version < 12)
1697 return;
1699 t = pa_tagstruct_new(NULL, 0);
1700 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1701 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1702 pa_tagstruct_putu32(t, s->index);
1703 pa_tagstruct_putu32(t, dest->index);
1704 pa_tagstruct_puts(t, dest->name);
1705 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1707 if (s->connection->version >= 13) {
1708 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1709 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1710 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1711 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1712 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1715 pa_pstream_send_tagstruct(s->connection->pstream, t);
1718 /*** source_output callbacks ***/
1720 /* Called from thread context */
1721 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1722 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1723 record_stream *s;
1725 pa_source_output_assert_ref(o);
1726 s = RECORD_STREAM(o->userdata);
1727 record_stream_assert_ref(s);
1729 switch (code) {
1730 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1731 /* Atomically get a snapshot of all timing parameters... */
1732 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1733 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1734 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1735 return 0;
1738 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1741 /* Called from thread context */
1742 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1743 record_stream *s;
1745 pa_source_output_assert_ref(o);
1746 s = RECORD_STREAM(o->userdata);
1747 record_stream_assert_ref(s);
1748 pa_assert(chunk);
1750 pa_atomic_add(&s->on_the_fly, chunk->length);
1751 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1754 static void source_output_kill_cb(pa_source_output *o) {
1755 record_stream *s;
1757 pa_source_output_assert_ref(o);
1758 s = RECORD_STREAM(o->userdata);
1759 record_stream_assert_ref(s);
1761 record_stream_send_killed(s);
1762 record_stream_unlink(s);
1765 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1766 record_stream *s;
1768 pa_source_output_assert_ref(o);
1769 s = RECORD_STREAM(o->userdata);
1770 record_stream_assert_ref(s);
1772 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1774 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1777 /* Called from main context */
1778 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1779 record_stream *s;
1780 pa_tagstruct *t;
1782 pa_source_output_assert_ref(o);
1783 s = RECORD_STREAM(o->userdata);
1784 record_stream_assert_ref(s);
1786 if (s->connection->version < 15)
1787 return;
1789 t = pa_tagstruct_new(NULL, 0);
1790 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1791 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1792 pa_tagstruct_putu32(t, s->index);
1793 pa_tagstruct_puts(t, event);
1794 pa_tagstruct_put_proplist(t, pl);
1795 pa_pstream_send_tagstruct(s->connection->pstream, t);
1798 /* Called from main context */
1799 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1800 record_stream *s;
1801 pa_tagstruct *t;
1803 pa_source_output_assert_ref(o);
1804 s = RECORD_STREAM(o->userdata);
1805 record_stream_assert_ref(s);
1807 if (s->connection->version < 12)
1808 return;
1810 t = pa_tagstruct_new(NULL, 0);
1811 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1812 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1813 pa_tagstruct_putu32(t, s->index);
1814 pa_tagstruct_put_boolean(t, suspend);
1815 pa_pstream_send_tagstruct(s->connection->pstream, t);
1818 /* Called from main context */
1819 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1820 record_stream *s;
1821 pa_tagstruct *t;
1823 pa_source_output_assert_ref(o);
1824 s = RECORD_STREAM(o->userdata);
1825 record_stream_assert_ref(s);
1827 if (!dest)
1828 return;
1830 fix_record_buffer_attr_pre(s);
1831 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1832 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1833 fix_record_buffer_attr_post(s);
1835 if (s->connection->version < 12)
1836 return;
1838 t = pa_tagstruct_new(NULL, 0);
1839 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1840 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1841 pa_tagstruct_putu32(t, s->index);
1842 pa_tagstruct_putu32(t, dest->index);
1843 pa_tagstruct_puts(t, dest->name);
1844 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1846 if (s->connection->version >= 13) {
1847 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1848 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1849 pa_tagstruct_put_usec(t, s->configured_source_latency);
1852 pa_pstream_send_tagstruct(s->connection->pstream, t);
1855 /*** pdispatch callbacks ***/
1857 static void protocol_error(pa_native_connection *c) {
1858 pa_log("protocol error, kicking client");
1859 native_connection_unlink(c);
1862 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1863 if (!(expression)) { \
1864 pa_pstream_send_error((pstream), (tag), (error)); \
1865 return; \
1867 } while(0);
1869 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
1870 if (!(expression)) { \
1871 pa_pstream_send_error((pstream), (tag), (error)); \
1872 goto label; \
1874 } while(0);
1876 static pa_tagstruct *reply_new(uint32_t tag) {
1877 pa_tagstruct *reply;
1879 reply = pa_tagstruct_new(NULL, 0);
1880 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1881 pa_tagstruct_putu32(reply, tag);
1882 return reply;
1885 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1886 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1887 playback_stream *s;
1888 uint32_t sink_index, syncid, missing;
1889 pa_buffer_attr attr;
1890 const char *name = NULL, *sink_name;
1891 pa_sample_spec ss;
1892 pa_channel_map map;
1893 pa_tagstruct *reply;
1894 pa_sink *sink = NULL;
1895 pa_cvolume volume;
1896 pa_bool_t
1897 corked = FALSE,
1898 no_remap = FALSE,
1899 no_remix = FALSE,
1900 fix_format = FALSE,
1901 fix_rate = FALSE,
1902 fix_channels = FALSE,
1903 no_move = FALSE,
1904 variable_rate = FALSE,
1905 muted = FALSE,
1906 adjust_latency = FALSE,
1907 early_requests = FALSE,
1908 dont_inhibit_auto_suspend = FALSE,
1909 volume_set = TRUE,
1910 muted_set = FALSE,
1911 fail_on_suspend = FALSE,
1912 relative_volume = FALSE,
1913 passthrough = FALSE;
1915 pa_sink_input_flags_t flags = 0;
1916 pa_proplist *p = NULL;
1917 int ret = PA_ERR_INVALID;
1918 uint8_t n_formats = 0;
1919 pa_format_info *format;
1920 pa_idxset *formats = NULL;
1921 uint32_t i;
1923 pa_native_connection_assert_ref(c);
1924 pa_assert(t);
1925 memset(&attr, 0, sizeof(attr));
1927 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1928 pa_tagstruct_get(
1930 PA_TAG_SAMPLE_SPEC, &ss,
1931 PA_TAG_CHANNEL_MAP, &map,
1932 PA_TAG_U32, &sink_index,
1933 PA_TAG_STRING, &sink_name,
1934 PA_TAG_U32, &attr.maxlength,
1935 PA_TAG_BOOLEAN, &corked,
1936 PA_TAG_U32, &attr.tlength,
1937 PA_TAG_U32, &attr.prebuf,
1938 PA_TAG_U32, &attr.minreq,
1939 PA_TAG_U32, &syncid,
1940 PA_TAG_CVOLUME, &volume,
1941 PA_TAG_INVALID) < 0) {
1943 protocol_error(c);
1944 goto finish;
1947 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
1948 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID, finish);
1949 CHECK_VALIDITY_GOTO(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID, finish);
1950 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
1951 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
1953 p = pa_proplist_new();
1955 if (name)
1956 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1958 if (c->version >= 12) {
1959 /* Since 0.9.8 the user can ask for a couple of additional flags */
1961 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1962 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1963 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1964 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1965 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1966 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1967 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1969 protocol_error(c);
1970 goto finish;
1974 if (c->version >= 13) {
1976 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1977 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1978 pa_tagstruct_get_proplist(t, p) < 0) {
1980 protocol_error(c);
1981 goto finish;
1985 if (c->version >= 14) {
1987 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
1988 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
1990 protocol_error(c);
1991 goto finish;
1995 if (c->version >= 15) {
1997 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
1998 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
1999 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2001 protocol_error(c);
2002 goto finish;
2006 if (c->version >= 17) {
2008 if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
2010 protocol_error(c);
2011 goto finish;
2015 if (c->version >= 18) {
2017 if (pa_tagstruct_get_boolean(t, &passthrough) < 0 ) {
2018 protocol_error(c);
2019 goto finish;
2023 if (c->version >= 21) {
2025 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2026 protocol_error(c);
2027 goto finish;
2030 if (n_formats)
2031 formats = pa_idxset_new(NULL, NULL);
2033 for (i = 0; i < n_formats; i++) {
2034 format = pa_format_info_new();
2035 if (pa_tagstruct_get_format_info(t, format) < 0) {
2036 protocol_error(c);
2037 goto finish;
2039 pa_idxset_put(formats, format, NULL);
2043 if (n_formats == 0) {
2044 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2045 CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2046 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2047 } else {
2048 PA_IDXSET_FOREACH(format, formats, i) {
2049 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2053 if (!pa_tagstruct_eof(t)) {
2054 protocol_error(c);
2055 goto finish;
2058 if (sink_index != PA_INVALID_INDEX) {
2060 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
2061 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2062 goto finish;
2065 } else if (sink_name) {
2067 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
2068 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2069 goto finish;
2073 flags =
2074 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
2075 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
2076 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
2077 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
2078 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
2079 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
2080 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
2081 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
2082 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2083 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
2084 (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0);
2086 /* Only since protocol version 15 there's a seperate muted_set
2087 * flag. For older versions we synthesize it here */
2088 muted_set = muted_set || muted;
2090 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);
2091 /* We no longer own the formats idxset */
2092 formats = NULL;
2094 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2096 reply = reply_new(tag);
2097 pa_tagstruct_putu32(reply, s->index);
2098 pa_assert(s->sink_input);
2099 pa_tagstruct_putu32(reply, s->sink_input->index);
2100 pa_tagstruct_putu32(reply, missing);
2102 /* pa_log("initial request is %u", missing); */
2104 if (c->version >= 9) {
2105 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2107 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2108 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2109 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2110 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2113 if (c->version >= 12) {
2114 /* Since 0.9.8 we support sending the chosen sample
2115 * spec/channel map/device/suspend status back to the
2116 * client */
2118 pa_tagstruct_put_sample_spec(reply, &ss);
2119 pa_tagstruct_put_channel_map(reply, &map);
2121 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2122 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2124 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2127 if (c->version >= 13)
2128 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2130 if (c->version >= 21) {
2131 /* Send back the format we negotiated */
2132 if (s->sink_input->format)
2133 pa_tagstruct_put_format_info(reply, s->sink_input->format);
2134 else {
2135 pa_format_info *f = pa_format_info_new();
2136 pa_tagstruct_put_format_info(reply, f);
2137 pa_format_info_free(f);
2141 pa_pstream_send_tagstruct(c->pstream, reply);
2143 finish:
2144 if (p)
2145 pa_proplist_free(p);
2146 if (formats)
2147 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
2150 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2151 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2152 uint32_t channel;
2154 pa_native_connection_assert_ref(c);
2155 pa_assert(t);
2157 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2158 !pa_tagstruct_eof(t)) {
2159 protocol_error(c);
2160 return;
2163 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2165 switch (command) {
2167 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2168 playback_stream *s;
2169 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2170 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2171 return;
2174 playback_stream_unlink(s);
2175 break;
2178 case PA_COMMAND_DELETE_RECORD_STREAM: {
2179 record_stream *s;
2180 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2181 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2182 return;
2185 record_stream_unlink(s);
2186 break;
2189 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2190 upload_stream *s;
2192 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2193 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2194 return;
2197 upload_stream_unlink(s);
2198 break;
2201 default:
2202 pa_assert_not_reached();
2205 pa_pstream_send_simple_ack(c->pstream, tag);
2208 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2209 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2210 record_stream *s;
2211 pa_buffer_attr attr;
2212 uint32_t source_index;
2213 const char *name = NULL, *source_name;
2214 pa_sample_spec ss;
2215 pa_channel_map map;
2216 pa_tagstruct *reply;
2217 pa_source *source = NULL;
2218 pa_bool_t
2219 corked = FALSE,
2220 no_remap = FALSE,
2221 no_remix = FALSE,
2222 fix_format = FALSE,
2223 fix_rate = FALSE,
2224 fix_channels = FALSE,
2225 no_move = FALSE,
2226 variable_rate = FALSE,
2227 adjust_latency = FALSE,
2228 peak_detect = FALSE,
2229 early_requests = FALSE,
2230 dont_inhibit_auto_suspend = FALSE,
2231 fail_on_suspend = FALSE,
2232 passthrough = FALSE;
2234 pa_source_output_flags_t flags = 0;
2235 pa_proplist *p = NULL;
2236 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2237 pa_sink_input *direct_on_input = NULL;
2238 int ret = PA_ERR_INVALID;
2239 uint8_t n_formats = 0;
2240 pa_format_info *format;
2241 pa_idxset *formats = NULL;
2242 uint32_t i;
2244 pa_native_connection_assert_ref(c);
2245 pa_assert(t);
2247 memset(&attr, 0, sizeof(attr));
2249 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2250 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2251 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2252 pa_tagstruct_getu32(t, &source_index) < 0 ||
2253 pa_tagstruct_gets(t, &source_name) < 0 ||
2254 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2255 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2256 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2258 protocol_error(c);
2259 goto finish;
2262 CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
2263 CHECK_VALIDITY_GOTO(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID, finish);
2264 CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID, finish);
2265 CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
2267 p = pa_proplist_new();
2269 if (name)
2270 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2272 if (c->version >= 12) {
2273 /* Since 0.9.8 the user can ask for a couple of additional flags */
2275 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2276 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2277 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2278 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2279 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2280 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2281 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2283 protocol_error(c);
2284 goto finish;
2288 if (c->version >= 13) {
2290 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2291 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2292 pa_tagstruct_get_proplist(t, p) < 0 ||
2293 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2295 protocol_error(c);
2296 goto finish;
2300 if (c->version >= 14) {
2302 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2303 protocol_error(c);
2304 goto finish;
2308 if (c->version >= 15) {
2310 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2311 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2313 protocol_error(c);
2314 goto finish;
2318 if (c->version >= 22) {
2320 if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2321 protocol_error(c);
2322 goto finish;
2325 if (n_formats)
2326 formats = pa_idxset_new(NULL, NULL);
2328 for (i = 0; i < n_formats; i++) {
2329 format = pa_format_info_new();
2330 if (pa_tagstruct_get_format_info(t, format) < 0) {
2331 protocol_error(c);
2332 goto finish;
2334 pa_idxset_put(formats, format, NULL);
2338 if (n_formats == 0) {
2339 CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2340 CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2341 } else {
2342 PA_IDXSET_FOREACH(format, formats, i) {
2343 CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2348 if (!pa_tagstruct_eof(t)) {
2349 protocol_error(c);
2350 goto finish;
2353 if (source_index != PA_INVALID_INDEX) {
2355 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2356 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2357 goto finish;
2360 } else if (source_name) {
2362 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2363 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2364 goto finish;
2368 if (direct_on_input_idx != PA_INVALID_INDEX) {
2370 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2371 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2372 goto finish;
2376 flags =
2377 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2378 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2379 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2380 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2381 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2382 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2383 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2384 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2385 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2386 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0) |
2387 (passthrough ? PA_SOURCE_OUTPUT_PASSTHROUGH : 0);
2389 s = record_stream_new(c, source, &ss, &map, formats, &attr, flags, p, adjust_latency, early_requests, peak_detect, direct_on_input, &ret);
2391 CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2393 reply = reply_new(tag);
2394 pa_tagstruct_putu32(reply, s->index);
2395 pa_assert(s->source_output);
2396 pa_tagstruct_putu32(reply, s->source_output->index);
2398 if (c->version >= 9) {
2399 /* Since 0.9 we support sending the buffer metrics back to the client */
2401 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2402 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2405 if (c->version >= 12) {
2406 /* Since 0.9.8 we support sending the chosen sample
2407 * spec/channel map/device/suspend status back to the
2408 * client */
2410 pa_tagstruct_put_sample_spec(reply, &ss);
2411 pa_tagstruct_put_channel_map(reply, &map);
2413 pa_tagstruct_putu32(reply, s->source_output->source->index);
2414 pa_tagstruct_puts(reply, s->source_output->source->name);
2416 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2419 if (c->version >= 13)
2420 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2422 if (c->version >= 22) {
2423 /* Send back the format we negotiated */
2424 if (s->source_output->format)
2425 pa_tagstruct_put_format_info(reply, s->source_output->format);
2426 else {
2427 pa_format_info *f = pa_format_info_new();
2428 pa_tagstruct_put_format_info(reply, f);
2429 pa_format_info_free(f);
2433 pa_pstream_send_tagstruct(c->pstream, reply);
2435 finish:
2436 if (p)
2437 pa_proplist_free(p);
2438 if (formats)
2439 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
2442 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2443 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2444 int ret;
2446 pa_native_connection_assert_ref(c);
2447 pa_assert(t);
2449 if (!pa_tagstruct_eof(t)) {
2450 protocol_error(c);
2451 return;
2454 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2455 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2456 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2458 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2460 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2463 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2464 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2465 const void*cookie;
2466 pa_tagstruct *reply;
2467 pa_bool_t shm_on_remote = FALSE, do_shm;
2469 pa_native_connection_assert_ref(c);
2470 pa_assert(t);
2472 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2473 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2474 !pa_tagstruct_eof(t)) {
2475 protocol_error(c);
2476 return;
2479 /* Minimum supported version */
2480 if (c->version < 8) {
2481 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2482 return;
2485 /* Starting with protocol version 13 the MSB of the version tag
2486 reflects if shm is available for this pa_native_connection or
2487 not. */
2488 if (c->version >= 13) {
2489 shm_on_remote = !!(c->version & 0x80000000U);
2490 c->version &= 0x7FFFFFFFU;
2493 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2495 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2497 if (!c->authorized) {
2498 pa_bool_t success = FALSE;
2500 #ifdef HAVE_CREDS
2501 const pa_creds *creds;
2503 if ((creds = pa_pdispatch_creds(pd))) {
2504 if (creds->uid == getuid())
2505 success = TRUE;
2506 else if (c->options->auth_group) {
2507 int r;
2508 gid_t gid;
2510 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2511 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2512 else if (gid == creds->gid)
2513 success = TRUE;
2515 if (!success) {
2516 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2517 pa_log_warn("Failed to check group membership.");
2518 else if (r > 0)
2519 success = TRUE;
2523 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2524 (unsigned long) creds->uid,
2525 (unsigned long) creds->gid,
2526 (int) success);
2528 #endif
2530 if (!success && c->options->auth_cookie) {
2531 const uint8_t *ac;
2533 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2534 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2535 success = TRUE;
2538 if (!success) {
2539 pa_log_warn("Denied access to client with invalid authorization data.");
2540 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2541 return;
2544 c->authorized = TRUE;
2545 if (c->auth_timeout_event) {
2546 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2547 c->auth_timeout_event = NULL;
2551 /* Enable shared memory support if possible */
2552 do_shm =
2553 pa_mempool_is_shared(c->protocol->core->mempool) &&
2554 c->is_local;
2556 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2558 if (do_shm)
2559 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2560 do_shm = FALSE;
2562 #ifdef HAVE_CREDS
2563 if (do_shm) {
2564 /* Only enable SHM if both sides are owned by the same
2565 * user. This is a security measure because otherwise data
2566 * private to the user might leak. */
2568 const pa_creds *creds;
2569 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2570 do_shm = FALSE;
2572 #endif
2574 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2575 pa_pstream_enable_shm(c->pstream, do_shm);
2577 reply = reply_new(tag);
2578 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2580 #ifdef HAVE_CREDS
2582 /* SHM support is only enabled after both sides made sure they are the same user. */
2584 pa_creds ucred;
2586 ucred.uid = getuid();
2587 ucred.gid = getgid();
2589 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2591 #else
2592 pa_pstream_send_tagstruct(c->pstream, reply);
2593 #endif
2596 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2597 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2598 const char *name = NULL;
2599 pa_proplist *p;
2600 pa_tagstruct *reply;
2602 pa_native_connection_assert_ref(c);
2603 pa_assert(t);
2605 p = pa_proplist_new();
2607 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2608 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2609 !pa_tagstruct_eof(t)) {
2611 protocol_error(c);
2612 pa_proplist_free(p);
2613 return;
2616 if (name)
2617 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2618 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2619 pa_proplist_free(p);
2620 return;
2623 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2624 pa_proplist_free(p);
2626 reply = reply_new(tag);
2628 if (c->version >= 13)
2629 pa_tagstruct_putu32(reply, c->client->index);
2631 pa_pstream_send_tagstruct(c->pstream, reply);
2634 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2635 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2636 const char *name;
2637 uint32_t idx = PA_IDXSET_INVALID;
2639 pa_native_connection_assert_ref(c);
2640 pa_assert(t);
2642 if (pa_tagstruct_gets(t, &name) < 0 ||
2643 !pa_tagstruct_eof(t)) {
2644 protocol_error(c);
2645 return;
2648 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2649 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);
2651 if (command == PA_COMMAND_LOOKUP_SINK) {
2652 pa_sink *sink;
2653 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2654 idx = sink->index;
2655 } else {
2656 pa_source *source;
2657 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2658 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2659 idx = source->index;
2662 if (idx == PA_IDXSET_INVALID)
2663 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2664 else {
2665 pa_tagstruct *reply;
2666 reply = reply_new(tag);
2667 pa_tagstruct_putu32(reply, idx);
2668 pa_pstream_send_tagstruct(c->pstream, reply);
2672 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2673 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2674 uint32_t idx;
2675 playback_stream *s;
2677 pa_native_connection_assert_ref(c);
2678 pa_assert(t);
2680 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2681 !pa_tagstruct_eof(t)) {
2682 protocol_error(c);
2683 return;
2686 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2687 s = pa_idxset_get_by_index(c->output_streams, idx);
2688 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2689 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2691 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);
2694 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2695 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2696 pa_tagstruct *reply;
2697 const pa_mempool_stat *stat;
2699 pa_native_connection_assert_ref(c);
2700 pa_assert(t);
2702 if (!pa_tagstruct_eof(t)) {
2703 protocol_error(c);
2704 return;
2707 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2709 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2711 reply = reply_new(tag);
2712 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2713 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2714 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2715 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2716 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2717 pa_pstream_send_tagstruct(c->pstream, reply);
2720 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2721 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2722 pa_tagstruct *reply;
2723 playback_stream *s;
2724 struct timeval tv, now;
2725 uint32_t idx;
2727 pa_native_connection_assert_ref(c);
2728 pa_assert(t);
2730 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2731 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2732 !pa_tagstruct_eof(t)) {
2733 protocol_error(c);
2734 return;
2737 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2738 s = pa_idxset_get_by_index(c->output_streams, idx);
2739 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2740 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2742 /* Get an atomic snapshot of all timing parameters */
2743 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);
2745 reply = reply_new(tag);
2746 pa_tagstruct_put_usec(reply,
2747 s->current_sink_latency +
2748 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2749 pa_tagstruct_put_usec(reply, 0);
2750 pa_tagstruct_put_boolean(reply,
2751 s->playing_for > 0 &&
2752 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2753 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2754 pa_tagstruct_put_timeval(reply, &tv);
2755 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2756 pa_tagstruct_puts64(reply, s->write_index);
2757 pa_tagstruct_puts64(reply, s->read_index);
2759 if (c->version >= 13) {
2760 pa_tagstruct_putu64(reply, s->underrun_for);
2761 pa_tagstruct_putu64(reply, s->playing_for);
2764 pa_pstream_send_tagstruct(c->pstream, reply);
2767 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2768 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2769 pa_tagstruct *reply;
2770 record_stream *s;
2771 struct timeval tv, now;
2772 uint32_t idx;
2774 pa_native_connection_assert_ref(c);
2775 pa_assert(t);
2777 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2778 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2779 !pa_tagstruct_eof(t)) {
2780 protocol_error(c);
2781 return;
2784 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2785 s = pa_idxset_get_by_index(c->record_streams, idx);
2786 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2788 /* Get an atomic snapshot of all timing parameters */
2789 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);
2791 reply = reply_new(tag);
2792 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2793 pa_tagstruct_put_usec(reply,
2794 s->current_source_latency +
2795 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec));
2796 pa_tagstruct_put_boolean(reply,
2797 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2798 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2799 pa_tagstruct_put_timeval(reply, &tv);
2800 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2801 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2802 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2803 pa_pstream_send_tagstruct(c->pstream, reply);
2806 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2807 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2808 upload_stream *s;
2809 uint32_t length;
2810 const char *name = NULL;
2811 pa_sample_spec ss;
2812 pa_channel_map map;
2813 pa_tagstruct *reply;
2814 pa_proplist *p;
2816 pa_native_connection_assert_ref(c);
2817 pa_assert(t);
2819 if (pa_tagstruct_gets(t, &name) < 0 ||
2820 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2821 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2822 pa_tagstruct_getu32(t, &length) < 0) {
2823 protocol_error(c);
2824 return;
2827 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2828 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2829 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2830 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2831 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2832 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2834 p = pa_proplist_new();
2836 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2837 !pa_tagstruct_eof(t)) {
2839 protocol_error(c);
2840 pa_proplist_free(p);
2841 return;
2844 if (c->version < 13)
2845 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2846 else if (!name)
2847 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2848 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2850 if (!name || !pa_namereg_is_valid_name(name)) {
2851 pa_proplist_free(p);
2852 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2855 s = upload_stream_new(c, &ss, &map, name, length, p);
2856 pa_proplist_free(p);
2858 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2860 reply = reply_new(tag);
2861 pa_tagstruct_putu32(reply, s->index);
2862 pa_tagstruct_putu32(reply, length);
2863 pa_pstream_send_tagstruct(c->pstream, reply);
2866 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2867 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2868 uint32_t channel;
2869 upload_stream *s;
2870 uint32_t idx;
2872 pa_native_connection_assert_ref(c);
2873 pa_assert(t);
2875 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2876 !pa_tagstruct_eof(t)) {
2877 protocol_error(c);
2878 return;
2881 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2883 s = pa_idxset_get_by_index(c->output_streams, channel);
2884 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2885 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2887 if (!s->memchunk.memblock)
2888 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2889 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2890 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2891 else
2892 pa_pstream_send_simple_ack(c->pstream, tag);
2894 upload_stream_unlink(s);
2897 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2898 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2899 uint32_t sink_index;
2900 pa_volume_t volume;
2901 pa_sink *sink;
2902 const char *name, *sink_name;
2903 uint32_t idx;
2904 pa_proplist *p;
2905 pa_tagstruct *reply;
2907 pa_native_connection_assert_ref(c);
2908 pa_assert(t);
2910 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2912 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2913 pa_tagstruct_gets(t, &sink_name) < 0 ||
2914 pa_tagstruct_getu32(t, &volume) < 0 ||
2915 pa_tagstruct_gets(t, &name) < 0) {
2916 protocol_error(c);
2917 return;
2920 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2921 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2922 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2923 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2925 if (sink_index != PA_INVALID_INDEX)
2926 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2927 else
2928 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2930 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2932 p = pa_proplist_new();
2934 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2935 !pa_tagstruct_eof(t)) {
2936 protocol_error(c);
2937 pa_proplist_free(p);
2938 return;
2941 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2943 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2944 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2945 pa_proplist_free(p);
2946 return;
2949 pa_proplist_free(p);
2951 reply = reply_new(tag);
2953 if (c->version >= 13)
2954 pa_tagstruct_putu32(reply, idx);
2956 pa_pstream_send_tagstruct(c->pstream, reply);
2959 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2960 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2961 const char *name;
2963 pa_native_connection_assert_ref(c);
2964 pa_assert(t);
2966 if (pa_tagstruct_gets(t, &name) < 0 ||
2967 !pa_tagstruct_eof(t)) {
2968 protocol_error(c);
2969 return;
2972 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2973 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2975 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
2976 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2977 return;
2980 pa_pstream_send_simple_ack(c->pstream, tag);
2983 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
2984 pa_assert(c);
2985 pa_assert(fixed);
2986 pa_assert(original);
2988 *fixed = *original;
2990 if (c->version < 12) {
2991 /* Before protocol version 12 we didn't support S32 samples,
2992 * so we need to lie about this to the client */
2994 if (fixed->format == PA_SAMPLE_S32LE)
2995 fixed->format = PA_SAMPLE_FLOAT32LE;
2996 if (fixed->format == PA_SAMPLE_S32BE)
2997 fixed->format = PA_SAMPLE_FLOAT32BE;
3000 if (c->version < 15) {
3001 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
3002 fixed->format = PA_SAMPLE_FLOAT32LE;
3003 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
3004 fixed->format = PA_SAMPLE_FLOAT32BE;
3008 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
3009 pa_sample_spec fixed_ss;
3011 pa_assert(t);
3012 pa_sink_assert_ref(sink);
3014 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
3016 pa_tagstruct_put(
3018 PA_TAG_U32, sink->index,
3019 PA_TAG_STRING, sink->name,
3020 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3021 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3022 PA_TAG_CHANNEL_MAP, &sink->channel_map,
3023 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
3024 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
3025 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
3026 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
3027 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
3028 PA_TAG_USEC, pa_sink_get_latency(sink),
3029 PA_TAG_STRING, sink->driver,
3030 PA_TAG_U32, sink->flags & ~PA_SINK_SHARE_VOLUME_WITH_MASTER,
3031 PA_TAG_INVALID);
3033 if (c->version >= 13) {
3034 pa_tagstruct_put_proplist(t, sink->proplist);
3035 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
3038 if (c->version >= 15) {
3039 pa_tagstruct_put_volume(t, sink->base_volume);
3040 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
3041 pa_log_error("Internal sink state is invalid.");
3042 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
3043 pa_tagstruct_putu32(t, sink->n_volume_steps);
3044 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
3047 if (c->version >= 16) {
3048 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
3050 if (sink->ports) {
3051 void *state;
3052 pa_device_port *p;
3054 PA_HASHMAP_FOREACH(p, sink->ports, state) {
3055 pa_tagstruct_puts(t, p->name);
3056 pa_tagstruct_puts(t, p->description);
3057 pa_tagstruct_putu32(t, p->priority);
3061 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
3064 if (c->version >= 21) {
3065 uint32_t i;
3066 pa_format_info *f;
3067 pa_idxset *formats = pa_sink_get_formats(sink);
3069 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3070 PA_IDXSET_FOREACH(f, formats, i) {
3071 pa_tagstruct_put_format_info(t, f);
3074 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
3078 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
3079 pa_sample_spec fixed_ss;
3081 pa_assert(t);
3082 pa_source_assert_ref(source);
3084 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
3086 pa_tagstruct_put(
3088 PA_TAG_U32, source->index,
3089 PA_TAG_STRING, source->name,
3090 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3091 PA_TAG_SAMPLE_SPEC, &fixed_ss,
3092 PA_TAG_CHANNEL_MAP, &source->channel_map,
3093 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
3094 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
3095 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
3096 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
3097 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
3098 PA_TAG_USEC, pa_source_get_latency(source),
3099 PA_TAG_STRING, source->driver,
3100 PA_TAG_U32, source->flags,
3101 PA_TAG_INVALID);
3103 if (c->version >= 13) {
3104 pa_tagstruct_put_proplist(t, source->proplist);
3105 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
3108 if (c->version >= 15) {
3109 pa_tagstruct_put_volume(t, source->base_volume);
3110 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
3111 pa_log_error("Internal source state is invalid.");
3112 pa_tagstruct_putu32(t, pa_source_get_state(source));
3113 pa_tagstruct_putu32(t, source->n_volume_steps);
3114 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
3117 if (c->version >= 16) {
3119 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
3121 if (source->ports) {
3122 void *state;
3123 pa_device_port *p;
3125 PA_HASHMAP_FOREACH(p, source->ports, state) {
3126 pa_tagstruct_puts(t, p->name);
3127 pa_tagstruct_puts(t, p->description);
3128 pa_tagstruct_putu32(t, p->priority);
3132 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
3135 if (c->version >= 22) {
3136 uint32_t i;
3137 pa_format_info *f;
3138 pa_idxset *formats = pa_source_get_formats(source);
3140 pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3141 PA_IDXSET_FOREACH(f, formats, i) {
3142 pa_tagstruct_put_format_info(t, f);
3145 pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
3149 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
3150 pa_assert(t);
3151 pa_assert(client);
3153 pa_tagstruct_putu32(t, client->index);
3154 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
3155 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
3156 pa_tagstruct_puts(t, client->driver);
3158 if (c->version >= 13)
3159 pa_tagstruct_put_proplist(t, client->proplist);
3162 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
3163 void *state = NULL;
3164 pa_card_profile *p;
3166 pa_assert(t);
3167 pa_assert(card);
3169 pa_tagstruct_putu32(t, card->index);
3170 pa_tagstruct_puts(t, card->name);
3171 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
3172 pa_tagstruct_puts(t, card->driver);
3174 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
3176 if (card->profiles) {
3177 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
3178 pa_tagstruct_puts(t, p->name);
3179 pa_tagstruct_puts(t, p->description);
3180 pa_tagstruct_putu32(t, p->n_sinks);
3181 pa_tagstruct_putu32(t, p->n_sources);
3182 pa_tagstruct_putu32(t, p->priority);
3186 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
3187 pa_tagstruct_put_proplist(t, card->proplist);
3190 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3191 pa_assert(t);
3192 pa_assert(module);
3194 pa_tagstruct_putu32(t, module->index);
3195 pa_tagstruct_puts(t, module->name);
3196 pa_tagstruct_puts(t, module->argument);
3197 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3199 if (c->version < 15)
3200 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
3202 if (c->version >= 15)
3203 pa_tagstruct_put_proplist(t, module->proplist);
3206 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3207 pa_sample_spec fixed_ss;
3208 pa_usec_t sink_latency;
3209 pa_cvolume v;
3210 pa_bool_t has_volume = FALSE;
3212 pa_assert(t);
3213 pa_sink_input_assert_ref(s);
3215 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3217 has_volume = pa_sink_input_is_volume_readable(s);
3218 if (has_volume)
3219 pa_sink_input_get_volume(s, &v, TRUE);
3220 else
3221 pa_cvolume_reset(&v, fixed_ss.channels);
3223 pa_tagstruct_putu32(t, s->index);
3224 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3225 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3226 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3227 pa_tagstruct_putu32(t, s->sink->index);
3228 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3229 pa_tagstruct_put_channel_map(t, &s->channel_map);
3230 pa_tagstruct_put_cvolume(t, &v);
3231 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3232 pa_tagstruct_put_usec(t, sink_latency);
3233 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3234 pa_tagstruct_puts(t, s->driver);
3235 if (c->version >= 11)
3236 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3237 if (c->version >= 13)
3238 pa_tagstruct_put_proplist(t, s->proplist);
3239 if (c->version >= 19)
3240 pa_tagstruct_put_boolean(t, (pa_sink_input_get_state(s) == PA_SINK_INPUT_CORKED));
3241 if (c->version >= 20) {
3242 pa_tagstruct_put_boolean(t, has_volume);
3243 pa_tagstruct_put_boolean(t, s->volume_writable);
3245 if (c->version >= 21)
3246 pa_tagstruct_put_format_info(t, s->format);
3249 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3250 pa_sample_spec fixed_ss;
3251 pa_usec_t source_latency;
3253 pa_assert(t);
3254 pa_source_output_assert_ref(s);
3256 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3258 pa_tagstruct_putu32(t, s->index);
3259 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3260 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3261 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3262 pa_tagstruct_putu32(t, s->source->index);
3263 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3264 pa_tagstruct_put_channel_map(t, &s->channel_map);
3265 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3266 pa_tagstruct_put_usec(t, source_latency);
3267 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3268 pa_tagstruct_puts(t, s->driver);
3269 if (c->version >= 13)
3270 pa_tagstruct_put_proplist(t, s->proplist);
3271 if (c->version >= 19)
3272 pa_tagstruct_put_boolean(t, (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_CORKED));
3275 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3276 pa_sample_spec fixed_ss;
3277 pa_cvolume v;
3279 pa_assert(t);
3280 pa_assert(e);
3282 if (e->memchunk.memblock)
3283 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3284 else
3285 memset(&fixed_ss, 0, sizeof(fixed_ss));
3287 pa_tagstruct_putu32(t, e->index);
3288 pa_tagstruct_puts(t, e->name);
3290 if (e->volume_is_set)
3291 v = e->volume;
3292 else
3293 pa_cvolume_init(&v);
3295 pa_tagstruct_put_cvolume(t, &v);
3296 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3297 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3298 pa_tagstruct_put_channel_map(t, &e->channel_map);
3299 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3300 pa_tagstruct_put_boolean(t, e->lazy);
3301 pa_tagstruct_puts(t, e->filename);
3303 if (c->version >= 13)
3304 pa_tagstruct_put_proplist(t, e->proplist);
3307 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3308 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3309 uint32_t idx;
3310 pa_sink *sink = NULL;
3311 pa_source *source = NULL;
3312 pa_client *client = NULL;
3313 pa_card *card = NULL;
3314 pa_module *module = NULL;
3315 pa_sink_input *si = NULL;
3316 pa_source_output *so = NULL;
3317 pa_scache_entry *sce = NULL;
3318 const char *name = NULL;
3319 pa_tagstruct *reply;
3321 pa_native_connection_assert_ref(c);
3322 pa_assert(t);
3324 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3325 (command != PA_COMMAND_GET_CLIENT_INFO &&
3326 command != PA_COMMAND_GET_MODULE_INFO &&
3327 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3328 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3329 pa_tagstruct_gets(t, &name) < 0) ||
3330 !pa_tagstruct_eof(t)) {
3331 protocol_error(c);
3332 return;
3335 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3336 CHECK_VALIDITY(c->pstream, !name ||
3337 (command == PA_COMMAND_GET_SINK_INFO &&
3338 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3339 (command == PA_COMMAND_GET_SOURCE_INFO &&
3340 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3341 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3342 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3343 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3344 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3346 if (command == PA_COMMAND_GET_SINK_INFO) {
3347 if (idx != PA_INVALID_INDEX)
3348 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3349 else
3350 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3351 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3352 if (idx != PA_INVALID_INDEX)
3353 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3354 else
3355 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3356 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3357 if (idx != PA_INVALID_INDEX)
3358 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3359 else
3360 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3361 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3362 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3363 else if (command == PA_COMMAND_GET_MODULE_INFO)
3364 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3365 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3366 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3367 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3368 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3369 else {
3370 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3371 if (idx != PA_INVALID_INDEX)
3372 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3373 else
3374 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3377 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3378 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3379 return;
3382 reply = reply_new(tag);
3383 if (sink)
3384 sink_fill_tagstruct(c, reply, sink);
3385 else if (source)
3386 source_fill_tagstruct(c, reply, source);
3387 else if (client)
3388 client_fill_tagstruct(c, reply, client);
3389 else if (card)
3390 card_fill_tagstruct(c, reply, card);
3391 else if (module)
3392 module_fill_tagstruct(c, reply, module);
3393 else if (si)
3394 sink_input_fill_tagstruct(c, reply, si);
3395 else if (so)
3396 source_output_fill_tagstruct(c, reply, so);
3397 else
3398 scache_fill_tagstruct(c, reply, sce);
3399 pa_pstream_send_tagstruct(c->pstream, reply);
3402 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3403 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3404 pa_idxset *i;
3405 uint32_t idx;
3406 void *p;
3407 pa_tagstruct *reply;
3409 pa_native_connection_assert_ref(c);
3410 pa_assert(t);
3412 if (!pa_tagstruct_eof(t)) {
3413 protocol_error(c);
3414 return;
3417 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3419 reply = reply_new(tag);
3421 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3422 i = c->protocol->core->sinks;
3423 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3424 i = c->protocol->core->sources;
3425 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3426 i = c->protocol->core->clients;
3427 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3428 i = c->protocol->core->cards;
3429 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3430 i = c->protocol->core->modules;
3431 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3432 i = c->protocol->core->sink_inputs;
3433 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3434 i = c->protocol->core->source_outputs;
3435 else {
3436 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3437 i = c->protocol->core->scache;
3440 if (i) {
3441 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3442 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3443 sink_fill_tagstruct(c, reply, p);
3444 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3445 source_fill_tagstruct(c, reply, p);
3446 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3447 client_fill_tagstruct(c, reply, p);
3448 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3449 card_fill_tagstruct(c, reply, p);
3450 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3451 module_fill_tagstruct(c, reply, p);
3452 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3453 sink_input_fill_tagstruct(c, reply, p);
3454 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3455 source_output_fill_tagstruct(c, reply, p);
3456 else {
3457 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3458 scache_fill_tagstruct(c, reply, p);
3463 pa_pstream_send_tagstruct(c->pstream, reply);
3466 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3467 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3468 pa_tagstruct *reply;
3469 pa_sink *def_sink;
3470 pa_source *def_source;
3471 pa_sample_spec fixed_ss;
3472 char *h, *u;
3474 pa_native_connection_assert_ref(c);
3475 pa_assert(t);
3477 if (!pa_tagstruct_eof(t)) {
3478 protocol_error(c);
3479 return;
3482 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3484 reply = reply_new(tag);
3485 pa_tagstruct_puts(reply, PACKAGE_NAME);
3486 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3488 u = pa_get_user_name_malloc();
3489 pa_tagstruct_puts(reply, u);
3490 pa_xfree(u);
3492 h = pa_get_host_name_malloc();
3493 pa_tagstruct_puts(reply, h);
3494 pa_xfree(h);
3496 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3497 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3499 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3500 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3501 def_source = pa_namereg_get_default_source(c->protocol->core);
3502 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3504 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3506 if (c->version >= 15)
3507 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3509 pa_pstream_send_tagstruct(c->pstream, reply);
3512 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3513 pa_tagstruct *t;
3514 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3516 pa_native_connection_assert_ref(c);
3518 t = pa_tagstruct_new(NULL, 0);
3519 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3520 pa_tagstruct_putu32(t, (uint32_t) -1);
3521 pa_tagstruct_putu32(t, e);
3522 pa_tagstruct_putu32(t, idx);
3523 pa_pstream_send_tagstruct(c->pstream, t);
3526 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3527 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3528 pa_subscription_mask_t m;
3530 pa_native_connection_assert_ref(c);
3531 pa_assert(t);
3533 if (pa_tagstruct_getu32(t, &m) < 0 ||
3534 !pa_tagstruct_eof(t)) {
3535 protocol_error(c);
3536 return;
3539 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3540 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3542 if (c->subscription)
3543 pa_subscription_free(c->subscription);
3545 if (m != 0) {
3546 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3547 pa_assert(c->subscription);
3548 } else
3549 c->subscription = NULL;
3551 pa_pstream_send_simple_ack(c->pstream, tag);
3554 static void command_set_volume(
3555 pa_pdispatch *pd,
3556 uint32_t command,
3557 uint32_t tag,
3558 pa_tagstruct *t,
3559 void *userdata) {
3561 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3562 uint32_t idx;
3563 pa_cvolume volume;
3564 pa_sink *sink = NULL;
3565 pa_source *source = NULL;
3566 pa_sink_input *si = NULL;
3567 const char *name = NULL;
3568 const char *client_name;
3570 pa_native_connection_assert_ref(c);
3571 pa_assert(t);
3573 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3574 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3575 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3576 pa_tagstruct_get_cvolume(t, &volume) ||
3577 !pa_tagstruct_eof(t)) {
3578 protocol_error(c);
3579 return;
3582 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3583 CHECK_VALIDITY(c->pstream, !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);
3584 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3585 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3586 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3587 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3589 switch (command) {
3591 case PA_COMMAND_SET_SINK_VOLUME:
3592 if (idx != PA_INVALID_INDEX)
3593 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3594 else
3595 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3596 break;
3598 case PA_COMMAND_SET_SOURCE_VOLUME:
3599 if (idx != PA_INVALID_INDEX)
3600 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3601 else
3602 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3603 break;
3605 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3606 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3607 break;
3609 default:
3610 pa_assert_not_reached();
3613 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3615 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3617 if (sink) {
3618 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3620 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3621 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3622 } else if (source) {
3623 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3625 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3626 pa_source_set_volume(source, &volume, TRUE);
3627 } else if (si) {
3628 CHECK_VALIDITY(c->pstream, si->volume_writable, tag, PA_ERR_BADSTATE);
3629 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3631 pa_log_debug("Client %s changes volume of sink input %s.",
3632 client_name,
3633 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3634 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3637 pa_pstream_send_simple_ack(c->pstream, tag);
3640 static void command_set_mute(
3641 pa_pdispatch *pd,
3642 uint32_t command,
3643 uint32_t tag,
3644 pa_tagstruct *t,
3645 void *userdata) {
3647 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3648 uint32_t idx;
3649 pa_bool_t mute;
3650 pa_sink *sink = NULL;
3651 pa_source *source = NULL;
3652 pa_sink_input *si = NULL;
3653 const char *name = NULL, *client_name;
3655 pa_native_connection_assert_ref(c);
3656 pa_assert(t);
3658 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3659 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3660 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3661 pa_tagstruct_get_boolean(t, &mute) ||
3662 !pa_tagstruct_eof(t)) {
3663 protocol_error(c);
3664 return;
3667 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3668 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);
3669 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3670 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3671 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3673 switch (command) {
3675 case PA_COMMAND_SET_SINK_MUTE:
3676 if (idx != PA_INVALID_INDEX)
3677 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3678 else
3679 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3681 break;
3683 case PA_COMMAND_SET_SOURCE_MUTE:
3684 if (idx != PA_INVALID_INDEX)
3685 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3686 else
3687 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3689 break;
3691 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3692 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3693 break;
3695 default:
3696 pa_assert_not_reached();
3699 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3701 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3703 if (sink) {
3704 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3705 pa_sink_set_mute(sink, mute, TRUE);
3706 } else if (source) {
3707 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3708 pa_source_set_mute(source, mute, TRUE);
3709 } else if (si) {
3710 pa_log_debug("Client %s changes mute of sink input %s.",
3711 client_name,
3712 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3713 pa_sink_input_set_mute(si, mute, TRUE);
3716 pa_pstream_send_simple_ack(c->pstream, tag);
3719 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3720 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3721 uint32_t idx;
3722 pa_bool_t b;
3723 playback_stream *s;
3725 pa_native_connection_assert_ref(c);
3726 pa_assert(t);
3728 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3729 pa_tagstruct_get_boolean(t, &b) < 0 ||
3730 !pa_tagstruct_eof(t)) {
3731 protocol_error(c);
3732 return;
3735 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3736 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3737 s = pa_idxset_get_by_index(c->output_streams, idx);
3738 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3739 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3741 pa_sink_input_cork(s->sink_input, b);
3743 if (b)
3744 s->is_underrun = TRUE;
3746 pa_pstream_send_simple_ack(c->pstream, tag);
3749 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3750 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3751 uint32_t idx;
3752 playback_stream *s;
3754 pa_native_connection_assert_ref(c);
3755 pa_assert(t);
3757 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3758 !pa_tagstruct_eof(t)) {
3759 protocol_error(c);
3760 return;
3763 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3764 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3765 s = pa_idxset_get_by_index(c->output_streams, idx);
3766 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3767 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3769 switch (command) {
3770 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3771 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3772 break;
3774 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3775 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3776 break;
3778 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3779 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3780 break;
3782 default:
3783 pa_assert_not_reached();
3786 pa_pstream_send_simple_ack(c->pstream, tag);
3789 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3790 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3791 uint32_t idx;
3792 record_stream *s;
3793 pa_bool_t b;
3795 pa_native_connection_assert_ref(c);
3796 pa_assert(t);
3798 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3799 pa_tagstruct_get_boolean(t, &b) < 0 ||
3800 !pa_tagstruct_eof(t)) {
3801 protocol_error(c);
3802 return;
3805 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3806 s = pa_idxset_get_by_index(c->record_streams, idx);
3807 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3809 pa_source_output_cork(s->source_output, b);
3810 pa_memblockq_prebuf_force(s->memblockq);
3811 pa_pstream_send_simple_ack(c->pstream, tag);
3814 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3815 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3816 uint32_t idx;
3817 record_stream *s;
3819 pa_native_connection_assert_ref(c);
3820 pa_assert(t);
3822 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3823 !pa_tagstruct_eof(t)) {
3824 protocol_error(c);
3825 return;
3828 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3829 s = pa_idxset_get_by_index(c->record_streams, idx);
3830 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3832 pa_memblockq_flush_read(s->memblockq);
3833 pa_pstream_send_simple_ack(c->pstream, tag);
3836 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3837 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3838 uint32_t idx;
3839 pa_buffer_attr a;
3840 pa_tagstruct *reply;
3842 pa_native_connection_assert_ref(c);
3843 pa_assert(t);
3845 memset(&a, 0, sizeof(a));
3847 if (pa_tagstruct_getu32(t, &idx) < 0) {
3848 protocol_error(c);
3849 return;
3852 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3854 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3855 playback_stream *s;
3856 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3858 s = pa_idxset_get_by_index(c->output_streams, idx);
3859 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3860 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3862 if (pa_tagstruct_get(
3864 PA_TAG_U32, &a.maxlength,
3865 PA_TAG_U32, &a.tlength,
3866 PA_TAG_U32, &a.prebuf,
3867 PA_TAG_U32, &a.minreq,
3868 PA_TAG_INVALID) < 0 ||
3869 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3870 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3871 !pa_tagstruct_eof(t)) {
3872 protocol_error(c);
3873 return;
3876 s->adjust_latency = adjust_latency;
3877 s->early_requests = early_requests;
3878 s->buffer_attr_req = a;
3880 fix_playback_buffer_attr(s);
3881 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);
3883 reply = reply_new(tag);
3884 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3885 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3886 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3887 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3889 if (c->version >= 13)
3890 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3892 } else {
3893 record_stream *s;
3894 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3895 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3897 s = pa_idxset_get_by_index(c->record_streams, idx);
3898 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3900 if (pa_tagstruct_get(
3902 PA_TAG_U32, &a.maxlength,
3903 PA_TAG_U32, &a.fragsize,
3904 PA_TAG_INVALID) < 0 ||
3905 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3906 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3907 !pa_tagstruct_eof(t)) {
3908 protocol_error(c);
3909 return;
3912 s->adjust_latency = adjust_latency;
3913 s->early_requests = early_requests;
3914 s->buffer_attr_req = a;
3916 fix_record_buffer_attr_pre(s);
3917 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3918 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3919 fix_record_buffer_attr_post(s);
3921 reply = reply_new(tag);
3922 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3923 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3925 if (c->version >= 13)
3926 pa_tagstruct_put_usec(reply, s->configured_source_latency);
3929 pa_pstream_send_tagstruct(c->pstream, reply);
3932 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3933 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3934 uint32_t idx;
3935 uint32_t rate;
3937 pa_native_connection_assert_ref(c);
3938 pa_assert(t);
3940 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3941 pa_tagstruct_getu32(t, &rate) < 0 ||
3942 !pa_tagstruct_eof(t)) {
3943 protocol_error(c);
3944 return;
3947 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3948 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
3950 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
3951 playback_stream *s;
3953 s = pa_idxset_get_by_index(c->output_streams, idx);
3954 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3955 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3957 pa_sink_input_set_rate(s->sink_input, rate);
3959 } else {
3960 record_stream *s;
3961 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
3963 s = pa_idxset_get_by_index(c->record_streams, idx);
3964 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3966 pa_source_output_set_rate(s->source_output, rate);
3969 pa_pstream_send_simple_ack(c->pstream, tag);
3972 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3973 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3974 uint32_t idx;
3975 uint32_t mode;
3976 pa_proplist *p;
3978 pa_native_connection_assert_ref(c);
3979 pa_assert(t);
3981 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3983 p = pa_proplist_new();
3985 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
3987 if (pa_tagstruct_getu32(t, &mode) < 0 ||
3988 pa_tagstruct_get_proplist(t, p) < 0 ||
3989 !pa_tagstruct_eof(t)) {
3990 protocol_error(c);
3991 pa_proplist_free(p);
3992 return;
3995 } else {
3997 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3998 pa_tagstruct_getu32(t, &mode) < 0 ||
3999 pa_tagstruct_get_proplist(t, p) < 0 ||
4000 !pa_tagstruct_eof(t)) {
4001 protocol_error(c);
4002 pa_proplist_free(p);
4003 return;
4007 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
4008 pa_proplist_free(p);
4009 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
4012 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
4013 playback_stream *s;
4015 s = pa_idxset_get_by_index(c->output_streams, idx);
4016 if (!s || !playback_stream_isinstance(s)) {
4017 pa_proplist_free(p);
4018 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
4020 pa_sink_input_update_proplist(s->sink_input, mode, p);
4022 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
4023 record_stream *s;
4025 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
4026 pa_proplist_free(p);
4027 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
4029 pa_source_output_update_proplist(s->source_output, mode, p);
4031 } else {
4032 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
4034 pa_client_update_proplist(c->client, mode, p);
4037 pa_pstream_send_simple_ack(c->pstream, tag);
4038 pa_proplist_free(p);
4041 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4042 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4043 uint32_t idx;
4044 unsigned changed = 0;
4045 pa_proplist *p;
4046 pa_strlist *l = NULL;
4048 pa_native_connection_assert_ref(c);
4049 pa_assert(t);
4051 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4053 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
4055 if (pa_tagstruct_getu32(t, &idx) < 0) {
4056 protocol_error(c);
4057 return;
4061 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4062 playback_stream *s;
4064 s = pa_idxset_get_by_index(c->output_streams, idx);
4065 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4066 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4068 p = s->sink_input->proplist;
4070 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4071 record_stream *s;
4073 s = pa_idxset_get_by_index(c->record_streams, idx);
4074 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4076 p = s->source_output->proplist;
4077 } else {
4078 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4080 p = c->client->proplist;
4083 for (;;) {
4084 const char *k;
4086 if (pa_tagstruct_gets(t, &k) < 0) {
4087 protocol_error(c);
4088 pa_strlist_free(l);
4089 return;
4092 if (!k)
4093 break;
4095 l = pa_strlist_prepend(l, k);
4098 if (!pa_tagstruct_eof(t)) {
4099 protocol_error(c);
4100 pa_strlist_free(l);
4101 return;
4104 for (;;) {
4105 char *z;
4107 l = pa_strlist_pop(l, &z);
4109 if (!z)
4110 break;
4112 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
4113 pa_xfree(z);
4116 pa_pstream_send_simple_ack(c->pstream, tag);
4118 if (changed) {
4119 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4120 playback_stream *s;
4122 s = pa_idxset_get_by_index(c->output_streams, idx);
4123 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
4125 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4126 record_stream *s;
4128 s = pa_idxset_get_by_index(c->record_streams, idx);
4129 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
4131 } else {
4132 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4133 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
4138 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4139 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4140 const char *s;
4142 pa_native_connection_assert_ref(c);
4143 pa_assert(t);
4145 if (pa_tagstruct_gets(t, &s) < 0 ||
4146 !pa_tagstruct_eof(t)) {
4147 protocol_error(c);
4148 return;
4151 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4152 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
4154 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
4155 pa_source *source;
4157 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
4158 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4160 pa_namereg_set_default_source(c->protocol->core, source);
4161 } else {
4162 pa_sink *sink;
4163 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
4165 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
4166 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4168 pa_namereg_set_default_sink(c->protocol->core, sink);
4171 pa_pstream_send_simple_ack(c->pstream, tag);
4174 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4175 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4176 uint32_t idx;
4177 const char *name;
4179 pa_native_connection_assert_ref(c);
4180 pa_assert(t);
4182 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4183 pa_tagstruct_gets(t, &name) < 0 ||
4184 !pa_tagstruct_eof(t)) {
4185 protocol_error(c);
4186 return;
4189 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4190 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
4192 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
4193 playback_stream *s;
4195 s = pa_idxset_get_by_index(c->output_streams, idx);
4196 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4197 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4199 pa_sink_input_set_name(s->sink_input, name);
4201 } else {
4202 record_stream *s;
4203 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4205 s = pa_idxset_get_by_index(c->record_streams, idx);
4206 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4208 pa_source_output_set_name(s->source_output, name);
4211 pa_pstream_send_simple_ack(c->pstream, tag);
4214 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4215 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4216 uint32_t idx;
4218 pa_native_connection_assert_ref(c);
4219 pa_assert(t);
4221 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4222 !pa_tagstruct_eof(t)) {
4223 protocol_error(c);
4224 return;
4227 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4229 if (command == PA_COMMAND_KILL_CLIENT) {
4230 pa_client *client;
4232 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4233 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4235 pa_native_connection_ref(c);
4236 pa_client_kill(client);
4238 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4239 pa_sink_input *s;
4241 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4242 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4244 pa_native_connection_ref(c);
4245 pa_sink_input_kill(s);
4246 } else {
4247 pa_source_output *s;
4249 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4251 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4252 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4254 pa_native_connection_ref(c);
4255 pa_source_output_kill(s);
4258 pa_pstream_send_simple_ack(c->pstream, tag);
4259 pa_native_connection_unref(c);
4262 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4263 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4264 pa_module *m;
4265 const char *name, *argument;
4266 pa_tagstruct *reply;
4268 pa_native_connection_assert_ref(c);
4269 pa_assert(t);
4271 if (pa_tagstruct_gets(t, &name) < 0 ||
4272 pa_tagstruct_gets(t, &argument) < 0 ||
4273 !pa_tagstruct_eof(t)) {
4274 protocol_error(c);
4275 return;
4278 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4279 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4280 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4282 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4283 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4284 return;
4287 reply = reply_new(tag);
4288 pa_tagstruct_putu32(reply, m->index);
4289 pa_pstream_send_tagstruct(c->pstream, reply);
4292 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4293 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4294 uint32_t idx;
4295 pa_module *m;
4297 pa_native_connection_assert_ref(c);
4298 pa_assert(t);
4300 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4301 !pa_tagstruct_eof(t)) {
4302 protocol_error(c);
4303 return;
4306 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4307 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4308 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4310 pa_module_unload_request(m, FALSE);
4311 pa_pstream_send_simple_ack(c->pstream, tag);
4314 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4315 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4316 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4317 const char *name_device = NULL;
4319 pa_native_connection_assert_ref(c);
4320 pa_assert(t);
4322 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4323 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4324 pa_tagstruct_gets(t, &name_device) < 0 ||
4325 !pa_tagstruct_eof(t)) {
4326 protocol_error(c);
4327 return;
4330 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4331 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4333 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);
4334 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4335 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4336 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4338 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4339 pa_sink_input *si = NULL;
4340 pa_sink *sink = NULL;
4342 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4344 if (idx_device != PA_INVALID_INDEX)
4345 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4346 else
4347 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4349 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4351 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4352 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4353 return;
4355 } else {
4356 pa_source_output *so = NULL;
4357 pa_source *source;
4359 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4361 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4363 if (idx_device != PA_INVALID_INDEX)
4364 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4365 else
4366 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4368 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4370 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4371 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4372 return;
4376 pa_pstream_send_simple_ack(c->pstream, tag);
4379 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4380 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4381 uint32_t idx = PA_INVALID_INDEX;
4382 const char *name = NULL;
4383 pa_bool_t b;
4385 pa_native_connection_assert_ref(c);
4386 pa_assert(t);
4388 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4389 pa_tagstruct_gets(t, &name) < 0 ||
4390 pa_tagstruct_get_boolean(t, &b) < 0 ||
4391 !pa_tagstruct_eof(t)) {
4392 protocol_error(c);
4393 return;
4396 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4397 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);
4398 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4399 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4400 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4402 if (command == PA_COMMAND_SUSPEND_SINK) {
4404 if (idx == PA_INVALID_INDEX && name && !*name) {
4406 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4408 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4409 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4410 return;
4412 } else {
4413 pa_sink *sink = NULL;
4415 if (idx != PA_INVALID_INDEX)
4416 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4417 else
4418 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4420 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4422 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4423 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4424 return;
4427 } else {
4429 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4431 if (idx == PA_INVALID_INDEX && name && !*name) {
4433 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4435 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4436 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4437 return;
4440 } else {
4441 pa_source *source;
4443 if (idx != PA_INVALID_INDEX)
4444 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4445 else
4446 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4448 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4450 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4451 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4452 return;
4457 pa_pstream_send_simple_ack(c->pstream, tag);
4460 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4461 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4462 uint32_t idx = PA_INVALID_INDEX;
4463 const char *name = NULL;
4464 pa_module *m;
4465 pa_native_protocol_ext_cb_t cb;
4467 pa_native_connection_assert_ref(c);
4468 pa_assert(t);
4470 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4471 pa_tagstruct_gets(t, &name) < 0) {
4472 protocol_error(c);
4473 return;
4476 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4477 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4478 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4479 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4480 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4482 if (idx != PA_INVALID_INDEX)
4483 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4484 else {
4485 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4486 if (strcmp(name, m->name) == 0)
4487 break;
4490 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4491 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4493 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4494 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4496 if (cb(c->protocol, m, c, tag, t) < 0)
4497 protocol_error(c);
4500 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4501 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4502 uint32_t idx = PA_INVALID_INDEX;
4503 const char *name = NULL, *profile = NULL;
4504 pa_card *card = NULL;
4505 int ret;
4507 pa_native_connection_assert_ref(c);
4508 pa_assert(t);
4510 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4511 pa_tagstruct_gets(t, &name) < 0 ||
4512 pa_tagstruct_gets(t, &profile) < 0 ||
4513 !pa_tagstruct_eof(t)) {
4514 protocol_error(c);
4515 return;
4518 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4519 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4520 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4521 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4522 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4524 if (idx != PA_INVALID_INDEX)
4525 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4526 else
4527 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4529 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4531 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4532 pa_pstream_send_error(c->pstream, tag, -ret);
4533 return;
4536 pa_pstream_send_simple_ack(c->pstream, tag);
4539 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4540 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4541 uint32_t idx = PA_INVALID_INDEX;
4542 const char *name = NULL, *port = NULL;
4543 int ret;
4545 pa_native_connection_assert_ref(c);
4546 pa_assert(t);
4548 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4549 pa_tagstruct_gets(t, &name) < 0 ||
4550 pa_tagstruct_gets(t, &port) < 0 ||
4551 !pa_tagstruct_eof(t)) {
4552 protocol_error(c);
4553 return;
4556 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4557 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);
4558 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4559 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4560 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4562 if (command == PA_COMMAND_SET_SINK_PORT) {
4563 pa_sink *sink;
4565 if (idx != PA_INVALID_INDEX)
4566 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4567 else
4568 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4570 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4572 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4573 pa_pstream_send_error(c->pstream, tag, -ret);
4574 return;
4576 } else {
4577 pa_source *source;
4579 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4581 if (idx != PA_INVALID_INDEX)
4582 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4583 else
4584 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4586 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4588 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4589 pa_pstream_send_error(c->pstream, tag, -ret);
4590 return;
4594 pa_pstream_send_simple_ack(c->pstream, tag);
4597 /*** pstream callbacks ***/
4599 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4600 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4602 pa_assert(p);
4603 pa_assert(packet);
4604 pa_native_connection_assert_ref(c);
4606 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4607 pa_log("invalid packet.");
4608 native_connection_unlink(c);
4612 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) {
4613 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4614 output_stream *stream;
4616 pa_assert(p);
4617 pa_assert(chunk);
4618 pa_native_connection_assert_ref(c);
4620 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4621 pa_log_debug("Client sent block for invalid stream.");
4622 /* Ignoring */
4623 return;
4626 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4628 if (playback_stream_isinstance(stream)) {
4629 playback_stream *ps = PLAYBACK_STREAM(stream);
4631 pa_atomic_inc(&ps->seek_or_post_in_queue);
4632 if (chunk->memblock) {
4633 if (seek != PA_SEEK_RELATIVE || offset != 0)
4634 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);
4635 else
4636 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4637 } else
4638 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);
4640 } else {
4641 upload_stream *u = UPLOAD_STREAM(stream);
4642 size_t l;
4644 if (!u->memchunk.memblock) {
4645 if (u->length == chunk->length && chunk->memblock) {
4646 u->memchunk = *chunk;
4647 pa_memblock_ref(u->memchunk.memblock);
4648 u->length = 0;
4649 } else {
4650 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4651 u->memchunk.index = u->memchunk.length = 0;
4655 pa_assert(u->memchunk.memblock);
4657 l = u->length;
4658 if (l > chunk->length)
4659 l = chunk->length;
4661 if (l > 0) {
4662 void *dst;
4663 dst = pa_memblock_acquire(u->memchunk.memblock);
4665 if (chunk->memblock) {
4666 void *src;
4667 src = pa_memblock_acquire(chunk->memblock);
4669 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4670 (uint8_t*) src + chunk->index, l);
4672 pa_memblock_release(chunk->memblock);
4673 } else
4674 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4676 pa_memblock_release(u->memchunk.memblock);
4678 u->memchunk.length += l;
4679 u->length -= l;
4684 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4685 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4687 pa_assert(p);
4688 pa_native_connection_assert_ref(c);
4690 native_connection_unlink(c);
4691 pa_log_info("Connection died.");
4694 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4695 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4697 pa_assert(p);
4698 pa_native_connection_assert_ref(c);
4700 native_connection_send_memblock(c);
4703 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4704 pa_thread_mq *q;
4706 if (!(q = pa_thread_mq_get()))
4707 pa_pstream_send_revoke(p, block_id);
4708 else
4709 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4712 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4713 pa_thread_mq *q;
4715 if (!(q = pa_thread_mq_get()))
4716 pa_pstream_send_release(p, block_id);
4717 else
4718 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4721 /*** client callbacks ***/
4723 static void client_kill_cb(pa_client *c) {
4724 pa_assert(c);
4726 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4727 pa_log_info("Connection killed.");
4730 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4731 pa_tagstruct *t;
4732 pa_native_connection *c;
4734 pa_assert(client);
4735 c = PA_NATIVE_CONNECTION(client->userdata);
4736 pa_native_connection_assert_ref(c);
4738 if (c->version < 15)
4739 return;
4741 t = pa_tagstruct_new(NULL, 0);
4742 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4743 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4744 pa_tagstruct_puts(t, event);
4745 pa_tagstruct_put_proplist(t, pl);
4746 pa_pstream_send_tagstruct(c->pstream, t);
4749 /*** module entry points ***/
4751 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4752 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4754 pa_assert(m);
4755 pa_native_connection_assert_ref(c);
4756 pa_assert(c->auth_timeout_event == e);
4758 if (!c->authorized) {
4759 native_connection_unlink(c);
4760 pa_log_info("Connection terminated due to authentication timeout.");
4764 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4765 pa_native_connection *c;
4766 char pname[128];
4767 pa_client *client;
4768 pa_client_new_data data;
4770 pa_assert(p);
4771 pa_assert(io);
4772 pa_assert(o);
4774 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4775 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4776 pa_iochannel_free(io);
4777 return;
4780 pa_client_new_data_init(&data);
4781 data.module = o->module;
4782 data.driver = __FILE__;
4783 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4784 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4785 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4786 client = pa_client_new(p->core, &data);
4787 pa_client_new_data_done(&data);
4789 if (!client)
4790 return;
4792 c = pa_msgobject_new(pa_native_connection);
4793 c->parent.parent.free = native_connection_free;
4794 c->parent.process_msg = native_connection_process_msg;
4795 c->protocol = p;
4796 c->options = pa_native_options_ref(o);
4797 c->authorized = FALSE;
4799 if (o->auth_anonymous) {
4800 pa_log_info("Client authenticated anonymously.");
4801 c->authorized = TRUE;
4804 if (!c->authorized &&
4805 o->auth_ip_acl &&
4806 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4808 pa_log_info("Client authenticated by IP ACL.");
4809 c->authorized = TRUE;
4812 if (!c->authorized)
4813 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4814 else
4815 c->auth_timeout_event = NULL;
4817 c->is_local = pa_iochannel_socket_is_local(io);
4818 c->version = 8;
4820 c->client = client;
4821 c->client->kill = client_kill_cb;
4822 c->client->send_event = client_send_event_cb;
4823 c->client->userdata = c;
4825 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4826 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4827 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4828 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4829 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4830 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4831 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4833 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4835 c->record_streams = pa_idxset_new(NULL, NULL);
4836 c->output_streams = pa_idxset_new(NULL, NULL);
4838 c->rrobin_index = PA_IDXSET_INVALID;
4839 c->subscription = NULL;
4841 pa_idxset_put(p->connections, c, NULL);
4843 #ifdef HAVE_CREDS
4844 if (pa_iochannel_creds_supported(io))
4845 pa_iochannel_creds_enable(io);
4846 #endif
4848 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4851 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4852 pa_native_connection *c;
4853 void *state = NULL;
4855 pa_assert(p);
4856 pa_assert(m);
4858 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4859 if (c->options->module == m)
4860 native_connection_unlink(c);
4863 static pa_native_protocol* native_protocol_new(pa_core *c) {
4864 pa_native_protocol *p;
4865 pa_native_hook_t h;
4867 pa_assert(c);
4869 p = pa_xnew(pa_native_protocol, 1);
4870 PA_REFCNT_INIT(p);
4871 p->core = c;
4872 p->connections = pa_idxset_new(NULL, NULL);
4874 p->servers = NULL;
4876 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4878 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4879 pa_hook_init(&p->hooks[h], p);
4881 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4883 return p;
4886 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4887 pa_native_protocol *p;
4889 if ((p = pa_shared_get(c, "native-protocol")))
4890 return pa_native_protocol_ref(p);
4892 return native_protocol_new(c);
4895 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4896 pa_assert(p);
4897 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4899 PA_REFCNT_INC(p);
4901 return p;
4904 void pa_native_protocol_unref(pa_native_protocol *p) {
4905 pa_native_connection *c;
4906 pa_native_hook_t h;
4908 pa_assert(p);
4909 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4911 if (PA_REFCNT_DEC(p) > 0)
4912 return;
4914 while ((c = pa_idxset_first(p->connections, NULL)))
4915 native_connection_unlink(c);
4917 pa_idxset_free(p->connections, NULL, NULL);
4919 pa_strlist_free(p->servers);
4921 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4922 pa_hook_done(&p->hooks[h]);
4924 pa_hashmap_free(p->extensions, NULL, NULL);
4926 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4928 pa_xfree(p);
4931 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
4932 pa_assert(p);
4933 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4934 pa_assert(name);
4936 p->servers = pa_strlist_prepend(p->servers, name);
4938 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4941 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
4942 pa_assert(p);
4943 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4944 pa_assert(name);
4946 p->servers = pa_strlist_remove(p->servers, name);
4948 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4951 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
4952 pa_assert(p);
4953 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4955 return p->hooks;
4958 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
4959 pa_assert(p);
4960 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4962 return p->servers;
4965 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
4966 pa_assert(p);
4967 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4968 pa_assert(m);
4969 pa_assert(cb);
4970 pa_assert(!pa_hashmap_get(p->extensions, m));
4972 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
4973 return 0;
4976 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
4977 pa_assert(p);
4978 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4979 pa_assert(m);
4981 pa_assert_se(pa_hashmap_remove(p->extensions, m));
4984 pa_native_options* pa_native_options_new(void) {
4985 pa_native_options *o;
4987 o = pa_xnew0(pa_native_options, 1);
4988 PA_REFCNT_INIT(o);
4990 return o;
4993 pa_native_options* pa_native_options_ref(pa_native_options *o) {
4994 pa_assert(o);
4995 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4997 PA_REFCNT_INC(o);
4999 return o;
5002 void pa_native_options_unref(pa_native_options *o) {
5003 pa_assert(o);
5004 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5006 if (PA_REFCNT_DEC(o) > 0)
5007 return;
5009 pa_xfree(o->auth_group);
5011 if (o->auth_ip_acl)
5012 pa_ip_acl_free(o->auth_ip_acl);
5014 if (o->auth_cookie)
5015 pa_auth_cookie_unref(o->auth_cookie);
5017 pa_xfree(o);
5020 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
5021 pa_bool_t enabled;
5022 const char *acl;
5024 pa_assert(o);
5025 pa_assert(PA_REFCNT_VALUE(o) >= 1);
5026 pa_assert(ma);
5028 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
5029 pa_log("auth-anonymous= expects a boolean argument.");
5030 return -1;
5033 enabled = TRUE;
5034 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
5035 pa_log("auth-group-enabled= expects a boolean argument.");
5036 return -1;
5039 pa_xfree(o->auth_group);
5040 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
5042 #ifndef HAVE_CREDS
5043 if (o->auth_group)
5044 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5045 #endif
5047 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
5048 pa_ip_acl *ipa;
5050 if (!(ipa = pa_ip_acl_new(acl))) {
5051 pa_log("Failed to parse IP ACL '%s'", acl);
5052 return -1;
5055 if (o->auth_ip_acl)
5056 pa_ip_acl_free(o->auth_ip_acl);
5058 o->auth_ip_acl = ipa;
5061 enabled = TRUE;
5062 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
5063 pa_log("auth-cookie-enabled= expects a boolean argument.");
5064 return -1;
5067 if (o->auth_cookie)
5068 pa_auth_cookie_unref(o->auth_cookie);
5070 if (enabled) {
5071 const char *cn;
5073 /* The new name for this is 'auth-cookie', for compat reasons
5074 * we check the old name too */
5075 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
5076 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
5077 cn = PA_NATIVE_COOKIE_FILE;
5079 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
5080 return -1;
5082 } else
5083 o->auth_cookie = NULL;
5085 return 0;
5088 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
5089 pa_native_connection_assert_ref(c);
5091 return c->pstream;
5094 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
5095 pa_native_connection_assert_ref(c);
5097 return c->client;